Thu, 02 Dec 2010 22:40:13 +0000
remove redundant debug printf
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;
60 /******************
61 * Memory mapping
62 ******************/
64 #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
66 uint32_t mapAddr(uint32_t addr, bool writing)
67 {
68 if (addr < 0x400000) {
69 // RAM access. Check against the Map RAM
70 // Start by getting the original page address
71 uint16_t page = (addr >> 12) & 0x3FF;
73 // Look it up in the map RAM and get the physical page address
74 uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
76 // Update the Page Status bits
77 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
78 if (pagebits != 0) {
79 if (writing)
80 state.map[page*2] |= 0x60; // Page written to (dirty)
81 else
82 state.map[page*2] |= 0x40; // Page accessed but not written
83 }
85 // Return the address with the new physical page spliced in
86 return (new_page_addr << 12) + (addr & 0xFFF);
87 } else {
88 // I/O, VRAM or MapRAM space; no mapping is performed or required
89 // TODO: assert here?
90 return addr;
91 }
92 }
94 typedef enum {
95 MEM_ALLOWED = 0,
96 MEM_PAGEFAULT, // Page fault -- page not present
97 MEM_PAGE_NO_WE, // Page not write enabled
98 MEM_KERNEL, // User attempted to access kernel memory
99 MEM_UIE // User Nonmemory Location Access
100 } MEM_STATUS;
102 // check memory access permissions
103 MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)
104 {
105 // Are we in Supervisor mode?
106 if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
107 // Yes. We can do anything we like.
108 return MEM_ALLOWED;
110 // If we're here, then we must be in User mode.
111 // Check that the user didn't access memory outside of the RAM area
112 if (addr >= 0x400000)
113 return MEM_UIE;
115 // This leaves us with Page Fault checking. Get the page bits for this page.
116 uint16_t page = (addr >> 12) & 0x3FF;
117 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07;
119 // Check page is present
120 if ((pagebits & 0x03) == 0)
121 return MEM_PAGEFAULT;
123 // User attempt to access the kernel
124 // A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
125 if (((addr >> 19) & 0x0F) == 0)
126 return MEM_KERNEL;
128 // Check page is write enabled
129 if ((pagebits & 0x04) == 0)
130 return MEM_PAGE_NO_WE;
132 // Page access allowed.
133 return MEM_ALLOWED;
134 }
136 #undef MAPRAM
138 /********************************************************
139 * m68k memory read/write support functions for Musashi
140 ********************************************************/
142 /**
143 * @brief Check memory access permissions for a write operation.
144 * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but
145 * gcc throws warnings when you have a return-with-value in a void
146 * function, even if the return-with-value is completely unreachable.
147 * Similarly it doesn't like it if you have a return without a value
148 * in a non-void function, even if it's impossible to ever reach the
149 * return-with-no-value. UGH!
150 */
151 #define ACCESS_CHECK_WR(address, bits) do { \
152 bool fault = false; \
153 /* MEM_STATUS st; */ \
154 switch (checkMemoryAccess(address, true)) { \
155 case MEM_ALLOWED: \
156 /* Access allowed */ \
157 break; \
158 case MEM_PAGEFAULT: \
159 /* Page fault */ \
160 state.genstat = 0x8FFF; \
161 fault = true; \
162 break; \
163 case MEM_UIE: \
164 /* User access to memory above 4MB */ \
165 state.genstat = 0x9EFF; \
166 fault = true; \
167 break; \
168 case MEM_KERNEL: \
169 case MEM_PAGE_NO_WE: \
170 /* kernel access or page not write enabled */ \
171 /* TODO: which regs need setting? */ \
172 fault = true; \
173 break; \
174 } \
175 \
176 if (fault) { \
177 if (bits >= 16) \
178 state.bsr0 = 0x7F00; \
179 else \
180 state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00; \
181 state.bsr0 |= (address >> 16); \
182 state.bsr1 = address & 0xffff; \
183 printf("ERR: BusError WR\n"); \
184 m68k_pulse_bus_error(); \
185 return; \
186 } \
187 } while (false)
189 /**
190 * @brief Check memory access permissions for a read operation.
191 * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but
192 * gcc throws warnings when you have a return-with-value in a void
193 * function, even if the return-with-value is completely unreachable.
194 * Similarly it doesn't like it if you have a return without a value
195 * in a non-void function, even if it's impossible to ever reach the
196 * return-with-no-value. UGH!
197 */
198 #define ACCESS_CHECK_RD(address, bits) do { \
199 bool fault = false; \
200 /* MEM_STATUS st; */ \
201 switch (checkMemoryAccess(address, false)) { \
202 case MEM_ALLOWED: \
203 /* Access allowed */ \
204 break; \
205 case MEM_PAGEFAULT: \
206 /* Page fault */ \
207 state.genstat = 0x8FFF; \
208 fault = true; \
209 break; \
210 case MEM_UIE: \
211 /* User access to memory above 4MB */ \
212 state.genstat = 0x9EFF; \
213 fault = true; \
214 break; \
215 case MEM_KERNEL: \
216 case MEM_PAGE_NO_WE: \
217 /* kernel access or page not write enabled */ \
218 /* TODO: which regs need setting? */ \
219 fault = true; \
220 break; \
221 } \
222 \
223 if (fault) { \
224 if (bits >= 16) \
225 state.bsr0 = 0x7F00; \
226 else \
227 state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00; \
228 state.bsr0 |= (address >> 16); \
229 state.bsr1 = address & 0xffff; \
230 printf("ERR: BusError RD\n"); \
231 m68k_pulse_bus_error(); \
232 return 0xFFFFFFFF; \
233 } \
234 } while (false)
236 // Logging macros
237 #define LOG_NOT_HANDLED_R(bits) \
238 do { \
239 if (!handled) \
240 printf("unhandled read%02d, addr=0x%08X\n", bits, address); \
241 } while (0);
243 #define LOG_NOT_HANDLED_W(bits) \
244 do { \
245 if (!handled) \
246 printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, value); \
247 } while (0);
249 /**
250 * @brief Read M68K memory, 32-bit
251 */
252 uint32_t m68k_read_memory_32(uint32_t address)
253 {
254 uint32_t data = 0xFFFFFFFF;
255 bool handled = false;
257 // If ROMLMAP is set, force system to access ROM
258 if (!state.romlmap)
259 address |= 0x800000;
261 // Check access permissions
262 ACCESS_CHECK_RD(address, 32);
264 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
265 // ROM access
266 data = RD32(state.rom, address, ROM_SIZE - 1);
267 handled = true;
268 } else if (address <= (state.ram_size - 1)) {
269 // RAM access
270 data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1);
271 handled = true;
272 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
273 // I/O register space, zone A
274 switch (address & 0x0F0000) {
275 case 0x000000: // Map RAM access
276 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
277 data = RD32(state.map, address, 0x7FF);
278 handled = true;
279 break;
280 case 0x010000: // General Status Register
281 data = ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
282 handled = true;
283 break;
284 case 0x020000: // Video RAM
285 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
286 data = RD32(state.vram, address, 0x7FFF);
287 handled = true;
288 break;
289 case 0x030000: // Bus Status Register 0
290 data = ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
291 handled = true;
292 break;
293 case 0x040000: // Bus Status Register 1
294 data = ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
295 handled = true;
296 break;
297 case 0x050000: // Phone status
298 break;
299 case 0x060000: // DMA Count
300 break;
301 case 0x070000: // Line Printer Status Register
302 break;
303 case 0x080000: // Real Time Clock
304 break;
305 case 0x090000: // Phone registers
306 switch (address & 0x0FF000) {
307 case 0x090000: // Handset relay
308 case 0x098000:
309 break;
310 case 0x091000: // Line select 2
311 case 0x099000:
312 break;
313 case 0x092000: // Hook relay 1
314 case 0x09A000:
315 break;
316 case 0x093000: // Hook relay 2
317 case 0x09B000:
318 break;
319 case 0x094000: // Line 1 hold
320 case 0x09C000:
321 break;
322 case 0x095000: // Line 2 hold
323 case 0x09D000:
324 break;
325 case 0x096000: // Line 1 A-lead
326 case 0x09E000:
327 break;
328 case 0x097000: // Line 2 A-lead
329 case 0x09F000:
330 break;
331 }
332 break;
333 case 0x0A0000: // Miscellaneous Control Register
334 break;
335 case 0x0B0000: // TM/DIALWR
336 break;
337 case 0x0C0000: // CSR
338 break;
339 case 0x0D0000: // DMA Address Register
340 break;
341 case 0x0E0000: // Disk Control Register
342 break;
343 case 0x0F0000: // Line Printer Data Register
344 break;
345 }
346 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
347 // I/O register space, zone B
348 switch (address & 0xF00000) {
349 case 0xC00000: // Expansion slots
350 case 0xD00000:
351 switch (address & 0xFC0000) {
352 case 0xC00000: // Expansion slot 0
353 case 0xC40000: // Expansion slot 1
354 case 0xC80000: // Expansion slot 2
355 case 0xCC0000: // Expansion slot 3
356 case 0xD00000: // Expansion slot 4
357 case 0xD40000: // Expansion slot 5
358 case 0xD80000: // Expansion slot 6
359 case 0xDC0000: // Expansion slot 7
360 fprintf(stderr, "NOTE: RD32 from expansion card space, addr=0x%08X\n", address);
361 break;
362 }
363 break;
364 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
365 case 0xF00000:
366 switch (address & 0x070000) {
367 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
368 break;
369 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
370 break;
371 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
372 break;
373 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
374 break;
375 case 0x040000: // [ef][4c]xxxx ==> General Control Register
376 switch (address & 0x077000) {
377 case 0x040000: // [ef][4c][08]xxx ==> EE
378 break;
379 case 0x041000: // [ef][4c][19]xxx ==> P1E
380 break;
381 case 0x042000: // [ef][4c][2A]xxx ==> BP
382 break;
383 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
384 break;
385 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
386 break;
387 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
388 break;
389 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
390 break;
391 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
392 break;
393 }
394 break;
395 case 0x050000: // [ef][5d]xxxx ==> 8274
396 break;
397 case 0x060000: // [ef][6e]xxxx ==> Control regs
398 switch (address & 0x07F000) {
399 default:
400 break;
401 }
402 break;
403 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
404 break;
405 }
406 }
407 }
409 LOG_NOT_HANDLED_R(32);
410 return data;
411 }
413 /**
414 * @brief Read M68K memory, 16-bit
415 */
416 uint32_t m68k_read_memory_16(uint32_t address)
417 {
418 uint16_t data = 0xFFFF;
419 bool handled = false;
421 // If ROMLMAP is set, force system to access ROM
422 if (!state.romlmap)
423 address |= 0x800000;
425 // Check access permissions
426 ACCESS_CHECK_RD(address, 16);
428 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
429 // ROM access
430 data = RD16(state.rom, address, ROM_SIZE - 1);
431 handled = true;
432 } else if (address <= (state.ram_size - 1)) {
433 // RAM access
434 data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1);
435 handled = true;
436 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
437 // I/O register space, zone A
438 switch (address & 0x0F0000) {
439 case 0x000000: // Map RAM access
440 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
441 data = RD16(state.map, address, 0x7FF);
442 handled = true;
443 break;
444 case 0x010000: // General Status Register
445 data = state.genstat;
446 handled = true;
447 break;
448 case 0x020000: // Video RAM
449 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
450 data = RD16(state.vram, address, 0x7FFF);
451 handled = true;
452 break;
453 case 0x030000: // Bus Status Register 0
454 data = state.bsr0;
455 handled = true;
456 break;
457 case 0x040000: // Bus Status Register 1
458 data = state.bsr1;
459 handled = true;
460 break;
461 case 0x050000: // Phone status
462 break;
463 case 0x060000: // DMA Count
464 break;
465 case 0x070000: // Line Printer Status Register
466 break;
467 case 0x080000: // Real Time Clock
468 break;
469 case 0x090000: // Phone registers
470 switch (address & 0x0FF000) {
471 case 0x090000: // Handset relay
472 case 0x098000:
473 break;
474 case 0x091000: // Line select 2
475 case 0x099000:
476 break;
477 case 0x092000: // Hook relay 1
478 case 0x09A000:
479 break;
480 case 0x093000: // Hook relay 2
481 case 0x09B000:
482 break;
483 case 0x094000: // Line 1 hold
484 case 0x09C000:
485 break;
486 case 0x095000: // Line 2 hold
487 case 0x09D000:
488 break;
489 case 0x096000: // Line 1 A-lead
490 case 0x09E000:
491 break;
492 case 0x097000: // Line 2 A-lead
493 case 0x09F000:
494 break;
495 }
496 break;
497 case 0x0A0000: // Miscellaneous Control Register
498 break;
499 case 0x0B0000: // TM/DIALWR
500 break;
501 case 0x0C0000: // CSR
502 break;
503 case 0x0D0000: // DMA Address Register
504 break;
505 case 0x0E0000: // Disk Control Register
506 break;
507 case 0x0F0000: // Line Printer Data Register
508 break;
509 }
510 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
511 // I/O register space, zone B
512 switch (address & 0xF00000) {
513 case 0xC00000: // Expansion slots
514 case 0xD00000:
515 switch (address & 0xFC0000) {
516 case 0xC00000: // Expansion slot 0
517 case 0xC40000: // Expansion slot 1
518 case 0xC80000: // Expansion slot 2
519 case 0xCC0000: // Expansion slot 3
520 case 0xD00000: // Expansion slot 4
521 case 0xD40000: // Expansion slot 5
522 case 0xD80000: // Expansion slot 6
523 case 0xDC0000: // Expansion slot 7
524 fprintf(stderr, "NOTE: RD16 from expansion card space, addr=0x%08X\n", address);
525 break;
526 }
527 break;
528 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
529 case 0xF00000:
530 switch (address & 0x070000) {
531 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
532 break;
533 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
534 break;
535 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
536 break;
537 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
538 break;
539 case 0x040000: // [ef][4c]xxxx ==> General Control Register
540 switch (address & 0x077000) {
541 case 0x040000: // [ef][4c][08]xxx ==> EE
542 break;
543 case 0x041000: // [ef][4c][19]xxx ==> P1E
544 break;
545 case 0x042000: // [ef][4c][2A]xxx ==> BP
546 break;
547 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
548 break;
549 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
550 break;
551 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
552 break;
553 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
554 break;
555 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
556 break;
557 }
558 break;
559 case 0x050000: // [ef][5d]xxxx ==> 8274
560 break;
561 case 0x060000: // [ef][6e]xxxx ==> Control regs
562 switch (address & 0x07F000) {
563 default:
564 break;
565 }
566 break;
567 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
568 break;
569 }
570 }
571 }
573 LOG_NOT_HANDLED_R(32);
574 return data;
575 }
577 /**
578 * @brief Read M68K memory, 8-bit
579 */
580 uint32_t m68k_read_memory_8(uint32_t address)
581 {
582 uint8_t data = 0xFF;
583 bool handled = false;
585 // If ROMLMAP is set, force system to access ROM
586 if (!state.romlmap)
587 address |= 0x800000;
589 // Check access permissions
590 ACCESS_CHECK_RD(address, 8);
592 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
593 // ROM access
594 data = RD8(state.rom, address, ROM_SIZE - 1);
595 handled = true;
596 } else if (address <= (state.ram_size - 1)) {
597 // RAM access
598 data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1);
599 handled = true;
600 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
601 // I/O register space, zone A
602 switch (address & 0x0F0000) {
603 case 0x000000: // Map RAM access
604 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
605 data = RD8(state.map, address, 0x7FF);
606 handled = true;
607 break;
608 case 0x010000: // General Status Register
609 if ((address & 1) == 0)
610 data = (state.genstat >> 8) & 0xff;
611 else
612 data = (state.genstat) & 0xff;
613 handled = true;
614 break;
615 case 0x020000: // Video RAM
616 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
617 data = RD8(state.vram, address, 0x7FFF);
618 handled = true;
619 break;
620 case 0x030000: // Bus Status Register 0
621 if ((address & 1) == 0)
622 data = (state.bsr0 >> 8) & 0xff;
623 else
624 data = (state.bsr0) & 0xff;
625 handled = true;
626 break;
627 case 0x040000: // Bus Status Register 1
628 if ((address & 1) == 0)
629 data = (state.bsr1 >> 8) & 0xff;
630 else
631 data = (state.bsr1) & 0xff;
632 handled = true;
633 break;
634 case 0x050000: // Phone status
635 break;
636 case 0x060000: // DMA Count
637 break;
638 case 0x070000: // Line Printer Status Register
639 break;
640 case 0x080000: // Real Time Clock
641 break;
642 case 0x090000: // Phone registers
643 switch (address & 0x0FF000) {
644 case 0x090000: // Handset relay
645 case 0x098000:
646 break;
647 case 0x091000: // Line select 2
648 case 0x099000:
649 break;
650 case 0x092000: // Hook relay 1
651 case 0x09A000:
652 break;
653 case 0x093000: // Hook relay 2
654 case 0x09B000:
655 break;
656 case 0x094000: // Line 1 hold
657 case 0x09C000:
658 break;
659 case 0x095000: // Line 2 hold
660 case 0x09D000:
661 break;
662 case 0x096000: // Line 1 A-lead
663 case 0x09E000:
664 break;
665 case 0x097000: // Line 2 A-lead
666 case 0x09F000:
667 break;
668 }
669 break;
670 case 0x0A0000: // Miscellaneous Control Register
671 break;
672 case 0x0B0000: // TM/DIALWR
673 break;
674 case 0x0C0000: // CSR
675 break;
676 case 0x0D0000: // DMA Address Register
677 break;
678 case 0x0E0000: // Disk Control Register
679 break;
680 case 0x0F0000: // Line Printer Data Register
681 break;
682 }
683 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
684 // I/O register space, zone B
685 switch (address & 0xF00000) {
686 case 0xC00000: // Expansion slots
687 case 0xD00000:
688 switch (address & 0xFC0000) {
689 case 0xC00000: // Expansion slot 0
690 case 0xC40000: // Expansion slot 1
691 case 0xC80000: // Expansion slot 2
692 case 0xCC0000: // Expansion slot 3
693 case 0xD00000: // Expansion slot 4
694 case 0xD40000: // Expansion slot 5
695 case 0xD80000: // Expansion slot 6
696 case 0xDC0000: // Expansion slot 7
697 fprintf(stderr, "NOTE: RD8 from expansion card space, addr=0x%08X\n", address);
698 break;
699 }
700 break;
701 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
702 case 0xF00000:
703 switch (address & 0x070000) {
704 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
705 break;
706 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
707 break;
708 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
709 break;
710 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
711 break;
712 case 0x040000: // [ef][4c]xxxx ==> General Control Register
713 switch (address & 0x077000) {
714 case 0x040000: // [ef][4c][08]xxx ==> EE
715 break;
716 case 0x041000: // [ef][4c][19]xxx ==> P1E
717 break;
718 case 0x042000: // [ef][4c][2A]xxx ==> BP
719 break;
720 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
721 break;
722 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
723 break;
724 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
725 break;
726 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
727 break;
728 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
729 break;
730 }
731 case 0x050000: // [ef][5d]xxxx ==> 8274
732 break;
733 case 0x060000: // [ef][6e]xxxx ==> Control regs
734 switch (address & 0x07F000) {
735 default:
736 break;
737 }
738 break;
739 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
740 break;
741 }
742 }
743 }
745 LOG_NOT_HANDLED_R(8);
747 return data;
748 }
750 /**
751 * @brief Write M68K memory, 32-bit
752 */
753 void m68k_write_memory_32(uint32_t address, uint32_t value)
754 {
755 bool handled = false;
757 // If ROMLMAP is set, force system to access ROM
758 if (!state.romlmap)
759 address |= 0x800000;
761 // Check access permissions
762 ACCESS_CHECK_WR(address, 32);
764 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
765 // ROM access
766 handled = true;
767 } else if (address <= (state.ram_size - 1)) {
768 // RAM access
769 WR32(state.ram, mapAddr(address, false), state.ram_size - 1, value);
770 handled = true;
771 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
772 // I/O register space, zone A
773 switch (address & 0x0F0000) {
774 case 0x000000: // Map RAM access
775 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
776 WR32(state.map, address, 0x7FF, value);
777 handled = true;
778 break;
779 case 0x010000: // General Status Register
780 state.genstat = (value & 0xffff);
781 handled = true;
782 break;
783 case 0x020000: // Video RAM
784 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
785 WR32(state.vram, address, 0x7FFF, value);
786 handled = true;
787 break;
788 case 0x030000: // Bus Status Register 0
789 break;
790 case 0x040000: // Bus Status Register 1
791 break;
792 case 0x050000: // Phone status
793 break;
794 case 0x060000: // DMA Count
795 break;
796 case 0x070000: // Line Printer Status Register
797 break;
798 case 0x080000: // Real Time Clock
799 break;
800 case 0x090000: // Phone registers
801 switch (address & 0x0FF000) {
802 case 0x090000: // Handset relay
803 case 0x098000:
804 break;
805 case 0x091000: // Line select 2
806 case 0x099000:
807 break;
808 case 0x092000: // Hook relay 1
809 case 0x09A000:
810 break;
811 case 0x093000: // Hook relay 2
812 case 0x09B000:
813 break;
814 case 0x094000: // Line 1 hold
815 case 0x09C000:
816 break;
817 case 0x095000: // Line 2 hold
818 case 0x09D000:
819 break;
820 case 0x096000: // Line 1 A-lead
821 case 0x09E000:
822 break;
823 case 0x097000: // Line 2 A-lead
824 case 0x09F000:
825 break;
826 }
827 break;
828 case 0x0A0000: // Miscellaneous Control Register
829 break;
830 case 0x0B0000: // TM/DIALWR
831 break;
832 case 0x0C0000: // CSR
833 break;
834 case 0x0D0000: // DMA Address Register
835 break;
836 case 0x0E0000: // Disk Control Register
837 break;
838 case 0x0F0000: // Line Printer Data Register
839 break;
840 }
841 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
842 // I/O register space, zone B
843 switch (address & 0xF00000) {
844 case 0xC00000: // Expansion slots
845 case 0xD00000:
846 switch (address & 0xFC0000) {
847 case 0xC00000: // Expansion slot 0
848 case 0xC40000: // Expansion slot 1
849 case 0xC80000: // Expansion slot 2
850 case 0xCC0000: // Expansion slot 3
851 case 0xD00000: // Expansion slot 4
852 case 0xD40000: // Expansion slot 5
853 case 0xD80000: // Expansion slot 6
854 case 0xDC0000: // Expansion slot 7
855 fprintf(stderr, "NOTE: WR32 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
856 handled = true;
857 break;
858 }
859 break;
860 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
861 case 0xF00000:
862 switch (address & 0x070000) {
863 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
864 break;
865 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
866 break;
867 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
868 break;
869 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
870 break;
871 case 0x040000: // [ef][4c]xxxx ==> General Control Register
872 switch (address & 0x077000) {
873 case 0x040000: // [ef][4c][08]xxx ==> EE
874 break;
875 case 0x041000: // [ef][4c][19]xxx ==> P1E
876 break;
877 case 0x042000: // [ef][4c][2A]xxx ==> BP
878 break;
879 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
880 state.romlmap = ((value & 0x8000) == 0x8000);
881 break;
882 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
883 break;
884 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
885 break;
886 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
887 break;
888 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
889 break;
890 }
891 case 0x050000: // [ef][5d]xxxx ==> 8274
892 break;
893 case 0x060000: // [ef][6e]xxxx ==> Control regs
894 switch (address & 0x07F000) {
895 default:
896 break;
897 }
898 break;
899 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
900 break;
901 }
902 }
903 }
905 LOG_NOT_HANDLED_W(32);
906 }
908 /**
909 * @brief Write M68K memory, 16-bit
910 */
911 void m68k_write_memory_16(uint32_t address, uint32_t value)
912 {
913 bool handled = false;
915 // If ROMLMAP is set, force system to access ROM
916 if (!state.romlmap)
917 address |= 0x800000;
919 // Check access permissions
920 ACCESS_CHECK_WR(address, 16);
922 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
923 // ROM access
924 handled = true;
925 } else if (address <= (state.ram_size - 1)) {
926 // RAM access
927 WR16(state.ram, mapAddr(address, false), state.ram_size - 1, value);
928 handled = true;
929 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
930 // I/O register space, zone A
931 switch (address & 0x0F0000) {
932 case 0x000000: // Map RAM access
933 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
934 WR16(state.map, address, 0x7FF, value);
935 handled = true;
936 break;
937 case 0x010000: // General Status Register (read only)
938 handled = true;
939 break;
940 case 0x020000: // Video RAM
941 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
942 WR16(state.vram, address, 0x7FFF, value);
943 handled = true;
944 break;
945 case 0x030000: // Bus Status Register 0 (read only)
946 handled = true;
947 break;
948 case 0x040000: // Bus Status Register 1 (read only)
949 handled = true;
950 break;
951 case 0x050000: // Phone status
952 break;
953 case 0x060000: // DMA Count
954 break;
955 case 0x070000: // Line Printer Status Register
956 break;
957 case 0x080000: // Real Time Clock
958 break;
959 case 0x090000: // Phone registers
960 switch (address & 0x0FF000) {
961 case 0x090000: // Handset relay
962 case 0x098000:
963 break;
964 case 0x091000: // Line select 2
965 case 0x099000:
966 break;
967 case 0x092000: // Hook relay 1
968 case 0x09A000:
969 break;
970 case 0x093000: // Hook relay 2
971 case 0x09B000:
972 break;
973 case 0x094000: // Line 1 hold
974 case 0x09C000:
975 break;
976 case 0x095000: // Line 2 hold
977 case 0x09D000:
978 break;
979 case 0x096000: // Line 1 A-lead
980 case 0x09E000:
981 break;
982 case 0x097000: // Line 2 A-lead
983 case 0x09F000:
984 break;
985 }
986 break;
987 case 0x0A0000: // Miscellaneous Control Register
988 break;
989 case 0x0B0000: // TM/DIALWR
990 break;
991 case 0x0C0000: // CSR
992 break;
993 case 0x0D0000: // DMA Address Register
994 break;
995 case 0x0E0000: // Disk Control Register
996 break;
997 case 0x0F0000: // Line Printer Data Register
998 break;
999 }
1000 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
1001 // I/O register space, zone B
1002 switch (address & 0xF00000) {
1003 case 0xC00000: // Expansion slots
1004 case 0xD00000:
1005 switch (address & 0xFC0000) {
1006 case 0xC00000: // Expansion slot 0
1007 case 0xC40000: // Expansion slot 1
1008 case 0xC80000: // Expansion slot 2
1009 case 0xCC0000: // Expansion slot 3
1010 case 0xD00000: // Expansion slot 4
1011 case 0xD40000: // Expansion slot 5
1012 case 0xD80000: // Expansion slot 6
1013 case 0xDC0000: // Expansion slot 7
1014 fprintf(stderr, "NOTE: WR16 to expansion card space, addr=0x%08X, data=0x%04X\n", address, value);
1015 break;
1016 }
1017 break;
1018 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
1019 case 0xF00000:
1020 switch (address & 0x070000) {
1021 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
1022 break;
1023 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
1024 break;
1025 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
1026 break;
1027 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
1028 break;
1029 case 0x040000: // [ef][4c]xxxx ==> General Control Register
1030 switch (address & 0x077000) {
1031 case 0x040000: // [ef][4c][08]xxx ==> EE
1032 break;
1033 case 0x041000: // [ef][4c][19]xxx ==> P1E
1034 break;
1035 case 0x042000: // [ef][4c][2A]xxx ==> BP
1036 break;
1037 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
1038 state.romlmap = ((value & 0x8000) == 0x8000);
1039 handled = true;
1040 break;
1041 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
1042 break;
1043 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
1044 break;
1045 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
1046 break;
1047 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
1048 break;
1049 }
1050 case 0x050000: // [ef][5d]xxxx ==> 8274
1051 break;
1052 case 0x060000: // [ef][6e]xxxx ==> Control regs
1053 switch (address & 0x07F000) {
1054 default:
1055 break;
1056 }
1057 break;
1058 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
1059 break;
1060 }
1061 }
1062 }
1064 LOG_NOT_HANDLED_W(16);
1065 }
1067 /**
1068 * @brief Write M68K memory, 8-bit
1069 */
1070 void m68k_write_memory_8(uint32_t address, uint32_t value)
1071 {
1072 bool handled = false;
1074 // If ROMLMAP is set, force system to access ROM
1075 if (!state.romlmap)
1076 address |= 0x800000;
1078 // Check access permissions
1079 ACCESS_CHECK_WR(address, 8);
1081 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
1082 // ROM access (read only!)
1083 handled = true;
1084 } else if (address <= (state.ram_size - 1)) {
1085 // RAM access
1086 WR8(state.ram, mapAddr(address, false), state.ram_size - 1, value);
1087 handled = true;
1088 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
1089 // I/O register space, zone A
1090 switch (address & 0x0F0000) {
1091 case 0x000000: // Map RAM access
1092 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=%08X, data=%02X\n", address, value);
1093 WR8(state.map, address, 0x7FF, value);
1094 handled = true;
1095 break;
1096 case 0x010000: // General Status Register
1097 handled = true;
1098 break;
1099 case 0x020000: // Video RAM
1100 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=%08X\n, data=0x%02X", address, value);
1101 WR8(state.vram, address, 0x7FFF, value);
1102 handled = true;
1103 break;
1104 case 0x030000: // Bus Status Register 0
1105 handled = true;
1106 break;
1107 case 0x040000: // Bus Status Register 1
1108 handled = true;
1109 break;
1110 case 0x050000: // Phone status
1111 break;
1112 case 0x060000: // DMA Count
1113 break;
1114 case 0x070000: // Line Printer Status Register
1115 break;
1116 case 0x080000: // Real Time Clock
1117 break;
1118 case 0x090000: // Phone registers
1119 switch (address & 0x0FF000) {
1120 case 0x090000: // Handset relay
1121 case 0x098000:
1122 break;
1123 case 0x091000: // Line select 2
1124 case 0x099000:
1125 break;
1126 case 0x092000: // Hook relay 1
1127 case 0x09A000:
1128 break;
1129 case 0x093000: // Hook relay 2
1130 case 0x09B000:
1131 break;
1132 case 0x094000: // Line 1 hold
1133 case 0x09C000:
1134 break;
1135 case 0x095000: // Line 2 hold
1136 case 0x09D000:
1137 break;
1138 case 0x096000: // Line 1 A-lead
1139 case 0x09E000:
1140 break;
1141 case 0x097000: // Line 2 A-lead
1142 case 0x09F000:
1143 break;
1144 }
1145 break;
1146 case 0x0A0000: // Miscellaneous Control Register
1147 break;
1148 case 0x0B0000: // TM/DIALWR
1149 break;
1150 case 0x0C0000: // CSR
1151 break;
1152 case 0x0D0000: // DMA Address Register
1153 break;
1154 case 0x0E0000: // Disk Control Register
1155 break;
1156 case 0x0F0000: // Line Printer Data Register
1157 break;
1158 }
1159 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
1160 // I/O register space, zone B
1161 switch (address & 0xF00000) {
1162 case 0xC00000: // Expansion slots
1163 case 0xD00000:
1164 switch (address & 0xFC0000) {
1165 case 0xC00000: // Expansion slot 0
1166 case 0xC40000: // Expansion slot 1
1167 case 0xC80000: // Expansion slot 2
1168 case 0xCC0000: // Expansion slot 3
1169 case 0xD00000: // Expansion slot 4
1170 case 0xD40000: // Expansion slot 5
1171 case 0xD80000: // Expansion slot 6
1172 case 0xDC0000: // Expansion slot 7
1173 fprintf(stderr, "NOTE: WR8 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
1174 break;
1175 }
1176 break;
1177 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
1178 case 0xF00000:
1179 switch (address & 0x070000) {
1180 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
1181 break;
1182 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
1183 break;
1184 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
1185 break;
1186 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
1187 break;
1188 case 0x040000: // [ef][4c]xxxx ==> General Control Register
1189 switch (address & 0x077000) {
1190 case 0x040000: // [ef][4c][08]xxx ==> EE
1191 break;
1192 case 0x041000: // [ef][4c][19]xxx ==> P1E
1193 break;
1194 case 0x042000: // [ef][4c][2A]xxx ==> BP
1195 break;
1196 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
1197 if ((address & 1) == 0)
1198 state.romlmap = ((value & 0x80) == 0x80);
1199 handled = true;
1200 break;
1201 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
1202 break;
1203 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
1204 break;
1205 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
1206 break;
1207 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
1208 break;
1209 }
1210 case 0x050000: // [ef][5d]xxxx ==> 8274
1211 break;
1212 case 0x060000: // [ef][6e]xxxx ==> Control regs
1213 switch (address & 0x07F000) {
1214 default:
1215 break;
1216 }
1217 break;
1218 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
1219 break;
1220 default:
1221 fprintf(stderr, "NOTE: WR8 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value);
1222 break;
1223 }
1224 }
1225 }
1227 LOG_NOT_HANDLED_W(8);
1228 }
1231 // for the disassembler
1232 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
1233 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
1234 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
1237 /****************************
1238 * blessed be thy main()...
1239 ****************************/
1241 int main(void)
1242 {
1243 // copyright banner
1244 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
1245 printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
1246 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
1247 printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
1248 printf("Compiler: %s\n", VER_COMPILER);
1249 printf("CFLAGS: %s\n", VER_CFLAGS);
1250 printf("\n");
1252 // set up system state
1253 // 512K of RAM
1254 state_init(512*1024);
1256 // set up musashi and reset the CPU
1257 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
1258 m68k_pulse_reset();
1260 // Set up SDL
1261 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
1262 printf("Could not initialise SDL: %s.\n", SDL_GetError());
1263 exit(EXIT_FAILURE);
1264 }
1266 // Make sure SDL cleans up after itself
1267 atexit(SDL_Quit);
1269 // Set up the video display
1270 SDL_Surface *screen = NULL;
1271 if ((screen = SDL_SetVideoMode(720, 384, 8, SDL_SWSURFACE | SDL_ANYFORMAT)) == NULL) {
1272 printf("Could not find a suitable video mode: %s.\n", SDL_GetError());
1273 exit(EXIT_FAILURE);
1274 }
1275 printf("Set %dx%d at %d bits-per-pixel mode\n\n", screen->w, screen->h, screen->format->BitsPerPixel);
1276 SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee");
1278 /***
1279 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
1280 * around 60Hz (???), with a 60Hz periodic interrupt.
1281 */
1282 const uint32_t TIMESLOT_FREQUENCY = 240; // Hz
1283 const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
1284 const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
1285 uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
1286 uint32_t clock_cycles = 0;
1287 bool exitEmu = false;
1288 for (;;) {
1289 // Run the CPU for however many cycles we need to. CPU core clock is
1290 // 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
1291 // 41667 cycles per timeslot.
1292 clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
1294 // TODO: run DMA here
1296 // Is it time to run the 60Hz periodic interrupt yet?
1297 if (clock_cycles > CLOCKS_PER_60HZ) {
1298 // TODO: refresh screen
1299 // TODO: trigger periodic interrupt (if enabled)
1300 // decrement clock cycle counter, we've handled the intr.
1301 clock_cycles -= CLOCKS_PER_60HZ;
1302 }
1304 // make sure frame rate is equal to real time
1305 uint32_t now = SDL_GetTicks();
1306 if (now < next_timeslot) {
1307 // timeslot finished early -- eat up some time
1308 SDL_Delay(next_timeslot - now);
1309 } else {
1310 // timeslot finished late -- skip ahead to gain time
1311 // TODO: if this happens a lot, we should let the user know
1312 // that their PC might not be fast enough...
1313 next_timeslot = now;
1314 }
1315 // advance to the next timeslot
1316 next_timeslot += MILLISECS_PER_TIMESLOT;
1318 // if we've been asked to exit the emulator, then do so.
1319 if (exitEmu) break;
1320 }
1322 // shut down and exit
1323 SDL_Quit();
1325 return 0;
1326 }