Thu, 02 Dec 2010 01:31:05 +0000
indicate supervisor state in unknown reg printfs
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5 #include <malloc.h>
6 #include <string.h>
8 #include "SDL.h"
10 #include "musashi/m68k.h"
11 #include "version.h"
12 #include "state.h"
14 void FAIL(char *err)
15 {
16 state_done();
17 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
18 exit(EXIT_FAILURE);
19 }
21 /***********************************
22 * Array read/write utility macros
23 * "Don't Repeat Yourself" :)
24 ***********************************/
26 /// Array read, 32-bit
27 #define RD32(array, address, andmask) \
28 (((uint32_t)array[(address + 0) & (andmask)] << 24) | \
29 ((uint32_t)array[(address + 1) & (andmask)] << 16) | \
30 ((uint32_t)array[(address + 2) & (andmask)] << 8) | \
31 ((uint32_t)array[(address + 3) & (andmask)]))
33 /// Array read, 16-bit
34 #define RD16(array, address, andmask) \
35 (((uint32_t)array[(address + 0) & (andmask)] << 8) | \
36 ((uint32_t)array[(address + 1) & (andmask)]))
38 /// Array read, 8-bit
39 #define RD8(array, address, andmask) \
40 ((uint32_t)array[(address + 0) & (andmask)])
42 /// Array write, 32-bit
43 #define WR32(array, address, andmask, value) { \
44 array[(address + 0) & (andmask)] = (value >> 24) & 0xff; \
45 array[(address + 1) & (andmask)] = (value >> 16) & 0xff; \
46 array[(address + 2) & (andmask)] = (value >> 8) & 0xff; \
47 array[(address + 3) & (andmask)] = value & 0xff; \
48 }
50 /// Array write, 16-bit
51 #define WR16(array, address, andmask, value) { \
52 array[(address + 0) & (andmask)] = (value >> 8) & 0xff; \
53 array[(address + 1) & (andmask)] = value & 0xff; \
54 }
56 /// Array write, 8-bit
57 #define WR8(array, address, andmask, value) \
58 array[(address + 0) & (andmask)] = value & 0xff;
61 /********************************************************
62 * m68k memory read/write support functions for Musashi
63 ********************************************************/
65 // read m68k memory
66 uint32_t m68k_read_memory_32(uint32_t address)
67 {
68 uint32_t data = 0xFFFFFFFF;
70 // If ROMLMAP is set, force system to access ROM
71 if (!state.romlmap)
72 address |= 0x800000;
74 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
75 // ROM access
76 data = RD32(state.rom, address, ROM_SIZE - 1);
77 } else if (address <= (state.ram_size - 1)) {
78 // RAM access -- TODO: mapping
79 data = RD32(state.ram, address, state.ram_size - 1);
80 } else if ((address >= 0x420000) && (address <= 0x427FFF)) {
81 // VRAM access
82 data = RD32(state.vram, address, 0x7FFF);
83 } else if ((address >= 0x400000) && (address <= 0x4007FF)) {
84 // Map RAM access
85 data = RD32(state.map, address, 0x7FF);
86 } else {
87 // I/O register -- TODO
88 printf("RD32 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
89 }
90 return data;
91 }
93 uint32_t m68k_read_memory_16(uint32_t address)
94 {
95 uint16_t data = 0xFFFF;
97 // If ROMLMAP is set, force system to access ROM
98 if (!state.romlmap)
99 address |= 0x800000;
101 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
102 // ROM access
103 data = RD16(state.rom, address, ROM_SIZE - 1);
104 } else if (address <= (state.ram_size - 1)) {
105 // RAM access -- TODO: mapping
106 data = RD16(state.ram, address, state.ram_size - 1);
107 } else if ((address >= 0x420000) && (address <= 0x427FFF)) {
108 // VRAM access
109 data = RD16(state.vram, address, 0x7FFF);
110 } else if ((address >= 0x400000) && (address <= 0x4007FF)) {
111 // Map RAM access
112 data = RD16(state.map, address, 0x7FF);
113 } else {
114 // I/O register -- TODO
115 printf("RD16 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
116 }
118 return data;
119 }
121 uint32_t m68k_read_memory_8(uint32_t address)
122 {
123 uint8_t data = 0xFF;
125 // If ROMLMAP is set, force system to access ROM
126 if (!state.romlmap)
127 address |= 0x800000;
129 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
130 // ROM access
131 data = RD8(state.rom, address, ROM_SIZE - 1);
132 } else if (address <= (state.ram_size - 1)) {
133 // RAM access -- TODO: mapping
134 data = RD8(state.ram, address, state.ram_size - 1);
135 } else if ((address >= 0x420000) && (address <= 0x427FFF)) {
136 // VRAM access
137 data = RD8(state.vram, address, 0x7FFF);
138 } else if ((address >= 0x400000) && (address <= 0x4007FF)) {
139 // Map RAM access
140 data = RD8(state.map, address, 0x7FF);
141 } else {
142 // I/O register -- TODO
143 printf("RD08 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
144 }
146 return data;
147 }
149 // write m68k memory
150 void m68k_write_memory_32(uint32_t address, uint32_t value)
151 {
152 // If ROMLMAP is set, force system to access ROM
153 if (!state.romlmap)
154 address |= 0x800000;
156 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
157 // ROM access
158 // TODO: bus error here? can't write to rom!
159 } else if (address <= (state.ram_size - 1)) {
160 // RAM -- TODO: mapping
161 WR32(state.ram, address, state.ram_size - 1, value);
162 } else if ((address >= 0x420000) && (address <= 0x427FFF)) {
163 // VRAM access
164 WR32(state.vram, address, 0x7fff, value);
165 } else if ((address >= 0x400000) && (address <= 0x4007FF)) {
166 // Map RAM access
167 WR32(state.map, address, 0x7FF, value);
168 } else {
169 switch (address) {
170 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000); break; // GCR3: ROMLMAP
171 default: printf("WR32 0x%08X ==> 0x%08X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : ""); break;
172 }
173 }
174 }
176 void m68k_write_memory_16(uint32_t address, uint32_t value)
177 {
178 // If ROMLMAP is set, force system to access ROM
179 if (!state.romlmap)
180 address |= 0x800000;
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 - 1)) {
186 // RAM access -- TODO: mapping
187 WR16(state.ram, address, state.ram_size - 1, value);
188 } else if ((address >= 0x420000) && (address <= 0x427FFF)) {
189 // VRAM access
190 WR16(state.vram, address, 0x7fff, value);
191 } else if ((address >= 0x400000) && (address <= 0x4007FF)) {
192 // Map RAM access
193 WR16(state.map, address, 0x7FF, value);
194 } else {
195 switch (address) {
196 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000); break; // GCR3: ROMLMAP
197 default: printf("WR16 0x%08X ==> 0x%04X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : ""); break;
198 }
199 if (address == 0x4A0000) {
200 printf("\tLED WRITE: %s %s %s %s\n",
201 value & 0x800 ? "-" : "R",
202 value & 0x400 ? "-" : "G",
203 value & 0x200 ? "-" : "Y",
204 value & 0x100 ? "-" : "R"
205 );
206 }
207 }
208 }
210 void m68k_write_memory_8(uint32_t address, uint32_t value)
211 {
212 // If ROMLMAP is set, force system to access ROM
213 if (!state.romlmap)
214 address |= 0x800000;
216 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
217 // ROM access
218 // TODO: bus error here? can't write to rom!
219 } else if (address <= (state.ram_size - 1)) {
220 // RAM access -- TODO: mapping
221 WR8(state.ram, address, state.ram_size - 1, value);
222 } else if ((address >= 0x420000) && (address <= 0x427FFF)) {
223 // VRAM access
224 WR8(state.vram, address, 0x7fff, value);
225 } else if ((address >= 0x400000) && (address <= 0x4007FF)) {
226 // Map RAM access
227 WR8(state.map, address, 0x7FF, value);
228 } else {
229 switch (address) {
230 case 0xE43000: state.romlmap = ((value & 0x80) == 0x80); break; // GCR3: ROMLMAP
231 default: printf("WR08 0x%08X ==> 0x%02X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : ""); break;
232 }
233 }
234 }
236 // for the disassembler
237 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
238 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
239 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
242 /****************************
243 * blessed be thy main()...
244 ****************************/
246 int main(void)
247 {
248 // copyright banner
249 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
250 printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
251 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
252 printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
253 printf("Compiler: %s\n", VER_COMPILER);
254 printf("CFLAGS: %s\n", VER_CFLAGS);
255 printf("\n");
257 // set up system state
258 // 512K of RAM
259 state_init(512*1024);
261 // set up musashi and reset the CPU
262 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
263 m68k_pulse_reset();
265 // Set up SDL
266 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
267 printf("Could not initialise SDL: %s.\n", SDL_GetError());
268 exit(EXIT_FAILURE);
269 }
271 // Make sure SDL cleans up after itself
272 atexit(SDL_Quit);
274 // Set up the video display
275 SDL_Surface *screen = NULL;
276 if ((screen = SDL_SetVideoMode(720, 384, 8, SDL_SWSURFACE | SDL_ANYFORMAT)) == NULL) {
277 printf("Could not find a suitable video mode: %s.\n", SDL_GetError());
278 exit(EXIT_FAILURE);
279 }
280 printf("Set %dx%d at %d bits-per-pixel mode\n", screen->w, screen->h, screen->format->BitsPerPixel);
281 SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee");
283 /***
284 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
285 * around 60Hz (???), with a 60Hz periodic interrupt.
286 */
287 const uint32_t TIMESLOT_FREQUENCY = 240; // Hz
288 const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
289 const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
290 uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
291 uint32_t clock_cycles = 0;
292 bool exitEmu = false;
293 for (;;) {
294 // Run the CPU for however many cycles we need to. CPU core clock is
295 // 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
296 // 41667 cycles per timeslot.
297 clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
299 // TODO: run DMA here
301 // Is it time to run the 60Hz periodic interrupt yet?
302 if (clock_cycles > CLOCKS_PER_60HZ) {
303 // TODO: refresh screen
304 // TODO: trigger periodic interrupt (if enabled)
305 // decrement clock cycle counter, we've handled the intr.
306 clock_cycles -= CLOCKS_PER_60HZ;
307 }
309 // make sure frame rate is equal to real time
310 uint32_t now = SDL_GetTicks();
311 if (now < next_timeslot) {
312 // timeslot finished early -- eat up some time
313 SDL_Delay(next_timeslot - now);
314 } else {
315 // timeslot finished late -- skip ahead to gain time
316 // TODO: if this happens a lot, we should let the user know
317 // that their PC might not be fast enough...
318 next_timeslot = now;
319 }
320 // advance to the next timeslot
321 next_timeslot += MILLISECS_PER_TIMESLOT;
323 // if we've been asked to exit the emulator, then do so.
324 if (exitEmu) break;
325 }
327 // shut down and exit
328 SDL_Quit();
330 return 0;
331 }