Sun, 28 Nov 2010 23:29:00 +0000
add license clarification to boot banner
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5 #include <malloc.h>
6 #include <string.h>
7 #include "musashi/m68k.h"
8 #include "version.h"
10 void state_done(void);
12 void FAIL(char *err)
13 {
14 state_done();
15 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
16 exit(EXIT_FAILURE);
17 }
19 // Maximum size of the Boot PROMs. Must be a binary power of two.
20 #define ROM_SIZE 32768
22 struct {
23 // Boot PROM can be up to 32Kbytes total size
24 uint8_t rom[ROM_SIZE];
26 // Main system RAM
27 uint8_t *ram;
28 size_t ram_size; // number of RAM bytes allocated
30 // GENERAL CONTROL REGISTER
31 bool romlmap;
32 } state;
34 int state_init()
35 {
36 // Free RAM if it's allocated
37 if (state.ram != NULL)
38 free(state.ram);
40 // Initialise hardware registers
41 state.romlmap = false;
43 // Allocate RAM, making sure the user has specified a valid RAM amount first
44 // Basically: 512KiB minimum, 4MiB maximum, in increments of 512KiB.
45 if ((state.ram_size < 512*1024) || ((state.ram_size % (512*1024)) != 0))
46 return -1;
47 state.ram = malloc(state.ram_size);
48 if (state.ram == NULL)
49 return -2;
51 // Load ROMs
52 FILE *r14c, *r15c;
53 r14c = fopen("roms/14c.bin", "rb");
54 if (r14c == NULL) FAIL("unable to open roms/14c.bin");
55 r15c = fopen("roms/15c.bin", "rb");
56 if (r15c == NULL) FAIL("unable to open roms/15c.bin");
58 // get ROM file size
59 fseek(r14c, 0, SEEK_END);
60 size_t romlen = ftell(r14c);
61 fseek(r14c, 0, SEEK_SET);
62 fseek(r15c, 0, SEEK_END);
63 size_t romlen2 = ftell(r15c);
64 fseek(r15c, 0, SEEK_SET);
65 if (romlen2 != romlen) FAIL("ROMs are not the same size!");
66 if ((romlen + romlen2) > ROM_SIZE) FAIL("ROMs are too large to fit in memory!");
68 // sanity checks completed; load the ROMs!
69 uint8_t *romdat1, *romdat2;
70 romdat1 = malloc(romlen);
71 romdat2 = malloc(romlen2);
72 fread(romdat1, 1, romlen, r15c);
73 fread(romdat2, 1, romlen2, r14c);
75 // convert the ROM data
76 for (size_t i=0; i<(romlen + romlen2); i+=2) {
77 state.rom[i+0] = romdat1[i/2];
78 state.rom[i+1] = romdat2[i/2];
79 }
81 // TODO: if ROM buffer not filled, repeat the ROM data we read until it is (wraparound emulation)
83 // free the data arrays and close the files
84 free(romdat1);
85 free(romdat2);
86 fclose(r14c);
87 fclose(r15c);
89 return 0;
90 }
92 void state_done()
93 {
94 if (state.ram != NULL)
95 free(state.ram);
96 }
98 // read m68k memory
99 uint32_t m68k_read_memory_32(uint32_t address)
100 {
101 uint32_t data = 0xFFFFFFFF;
103 printf("RD32 %08X %d", address, state.romlmap);
105 // If ROMLMAP is set, force system to access ROM
106 if (!state.romlmap)
107 address |= 0x800000;
109 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
110 // ROM access
111 data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
112 ((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
113 ((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8) |
114 ((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
115 } else if (address < state.ram_size - 1) {
116 // RAM
117 data = (((uint32_t)state.ram[address + 0] << 24) |
118 ((uint32_t)state.ram[address + 1] << 16) |
119 ((uint32_t)state.ram[address + 2] << 8) |
120 ((uint32_t)state.ram[address + 3]));
121 }
123 printf(" ==> %08X\n", data);
124 return data;
125 }
127 uint32_t m68k_read_memory_16(uint32_t address)
128 {
129 uint16_t data = 0xFFFF;
131 printf("RD16 %08X %d", address, state.romlmap);
133 // If ROMLMAP is set, force system to access ROM
134 if (!state.romlmap)
135 address |= 0x800000;
137 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
138 // ROM access
139 data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
140 (state.rom[(address + 1) & (ROM_SIZE - 1)]));
141 } else if (address < state.ram_size - 1) {
142 // RAM
143 data = ((state.ram[address + 0] << 8) |
144 (state.ram[address + 1]));
145 }
147 printf(" ==> %04X\n", data);
148 return data;
149 }
151 uint32_t m68k_read_memory_8(uint32_t address)
152 {
153 uint8_t data = 0xFF;
155 printf("RD 8 %08X %d ", address, state.romlmap);
157 // If ROMLMAP is set, force system to access ROM
158 if (!state.romlmap)
159 address |= 0x800000;
161 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
162 // ROM access
163 data = state.rom[(address + 0) & (ROM_SIZE - 1)];
164 } else if (address < state.ram_size) {
165 // RAM access
166 data = state.ram[address + 0];
167 }
169 printf("==> %02X\n", data);
170 return data;
171 }
173 // write m68k memory
174 void m68k_write_memory_32(uint32_t address, uint32_t value)
175 {
176 // If ROMLMAP is set, force system to access ROM
177 if (!state.romlmap)
178 address |= 0x800000;
180 printf("WR32 %08X %d %02X\n", address, state.romlmap, value);
182 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
183 // ROM access
184 // TODO: bus error here? can't write to rom!
185 } else if (address < state.ram_size) {
186 // RAM access
187 state.ram[address + 0] = (value >> 24) & 0xff;
188 state.ram[address + 1] = (value >> 16) & 0xff;
189 state.ram[address + 2] = (value >> 8) & 0xff;
190 state.ram[address + 3] = value & 0xff;
191 } else {
192 switch (address) {
193 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
194 }
195 }
196 }
198 void m68k_write_memory_16(uint32_t address, uint32_t value)
199 {
200 // If ROMLMAP is set, force system to access ROM
201 if (!state.romlmap)
202 address |= 0x800000;
204 printf("WR16 %08X %d %02X\n", address, state.romlmap, value);
206 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
207 // ROM access
208 // TODO: bus error here? can't write to rom!
209 } else if (address < state.ram_size) {
210 // RAM access
211 state.ram[address + 0] = (value >> 8) & 0xff;
212 state.ram[address + 1] = value & 0xff;
213 } else {
214 switch (address) {
215 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
216 }
217 }
218 }
220 void m68k_write_memory_8(uint32_t address, uint32_t value)
221 {
222 // If ROMLMAP is set, force system to access ROM
223 if (!state.romlmap)
224 address |= 0x800000;
226 printf("WR 8 %08X %d %02X\n", address, state.romlmap, value);
228 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
229 // ROM access
230 // TODO: bus error here? can't write to rom!
231 } else if (address < state.ram_size) {
232 state.ram[address] = value & 0xff;
233 } else {
234 switch (address) {
235 case 0xE43000: state.romlmap = ((value & 0x80) == 0x80);
236 }
237 }
238 }
240 // for the disassembler
241 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
242 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
243 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
245 int main(void)
246 {
247 // copyright banner
248 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
249 printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
250 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
251 printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
252 printf("Compiler: %s\n", VER_COMPILER);
253 printf("CFLAGS: %s\n", VER_CFLAGS);
254 printf("\n");
256 // set up system state
257 // 512K of RAM
258 state.ram_size = 512*1024;
259 state_init();
261 // set up musashi
262 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
263 m68k_pulse_reset();
265 char dasm[512];
266 m68k_disassemble(dasm, 0x80001a, M68K_CPU_TYPE_68010);
267 printf("%s\n", dasm);
269 // set up SDL
271 // emulation loop!
272 // repeat:
273 // m68k_execute()
274 // m68k_set_irq() every 60ms
275 int32_t dwTimerTickCounter, dwCpuCycles;
276 const int32_t CLOCKS_PER_TIMER_TICK = 10e6/60; //< number of clocks per 60Hz timer tick
278 // initialise emulation variables
279 dwTimerTickCounter = CLOCKS_PER_TIMER_TICK;
280 bool exitEmu = false;
281 for (;;) {
282 dwCpuCycles = m68k_execute(10e6/60);
283 dwTimerTickCounter -= dwCpuCycles;
285 // check for timer tick expiry
286 if (dwTimerTickCounter <= 0) {
287 // TODO: Timer Tick IRQ
289 }
291 if (exitEmu) break;
292 }
294 // shut down and exit
296 return 0;
297 }