Sat, 17 Nov 2012 19:18:29 +0000
add HDD support + fixes
Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-Message-ID: <50A772FC.8020009@gmail.com>
I have added floppy write support, full hard disk emulation, and proper handling of DMA page faults to FreeBee. I also fixed the floppy step commands, changed the "force interrupt" floppy command to generate a type 1 status, and changed the DMA address counter to reset to 3fff when a transfer completes (which is what Unix seems to expect - without it, the kernel says that the floppy isn't ready). The floppy, hard disk, and DMA page fault tests all pass. Initializing hard disks and floppies also works (the geometry for both is still fixed by the size of the image, though, and format commands only appear to succeed, but they don't modify the image). Unix still doesn't run, though (it hangs after reading some sectors from the floppy).
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5 #include <assert.h>
6 #include "musashi/m68k.h"
7 #include "state.h"
8 #include "utils.h"
9 #include "memory.h"
11 /******************
12 * Memory mapping
13 ******************/
15 #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
17 uint32_t mapAddr(uint32_t addr, bool writing)/*{{{*/
18 {
19 if (addr < 0x400000) {
20 // RAM access. Check against the Map RAM
21 // Start by getting the original page address
22 uint16_t page = (addr >> 12) & 0x3FF;
24 // Look it up in the map RAM and get the physical page address
25 uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
27 // Update the Page Status bits
28 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
29 // Pagebits --
30 // 0 = not present
31 // 1 = present but not accessed
32 // 2 = present, accessed (read from)
33 // 3 = present, dirty (written to)
34 switch (pagebits) {
35 case 0:
36 // Page not present
37 // This should cause a page fault
38 LOGS("Whoa! Pagebit update, when the page is not present!");
39 break;
41 case 1:
42 // Page present -- first access
43 state.map[page*2] &= 0x9F; // turn off "present" bit (but not write enable!)
44 if (writing)
45 state.map[page*2] |= 0x60; // Page written to (dirty)
46 else
47 state.map[page*2] |= 0x40; // Page accessed but not written
48 break;
50 case 2:
51 case 3:
52 // Page present, 2nd or later access
53 if (writing)
54 state.map[page*2] |= 0x60; // Page written to (dirty)
55 break;
56 }
58 // Return the address with the new physical page spliced in
59 return (new_page_addr << 12) + (addr & 0xFFF);
60 } else {
61 // I/O, VRAM or MapRAM space; no mapping is performed or required
62 // TODO: assert here?
63 return addr;
64 }
65 }/*}}}*/
67 MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)/*{{{*/
68 {
69 // Get the page bits for this page.
70 uint16_t page = (addr >> 12) & 0x3FF;
71 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07;
73 // Check page is present (but only for RAM zone)
74 if ((addr < 0x400000) && ((pagebits & 0x03) == 0)) {
75 LOG("Page not mapped in: addr %08X, page %04X, mapbits %04X", addr, page, MAPRAM(page));
76 return MEM_PAGEFAULT;
77 }
79 // Are we in Supervisor mode?
80 if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
81 // Yes. We can do anything we like.
82 return MEM_ALLOWED;
84 // If we're here, then we must be in User mode.
85 // Check that the user didn't access memory outside of the RAM area
86 if (addr >= 0x400000) {
87 LOGS("User accessed privileged memory");
88 return MEM_UIE;
89 }
91 // User attempt to access the kernel
92 // A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
93 if (((addr >> 19) & 0x0F) == 0) {
94 LOGS("Attempt by user code to access kernel space");
95 return MEM_KERNEL;
96 }
98 // Check page is write enabled
99 if (writing && ((pagebits & 0x04) == 0)) {
100 LOG("Page not write enabled: inaddr %08X, page %04X, mapram %04X [%02X %02X], pagebits %d",
101 addr, page, MAPRAM(page), state.map[page*2], state.map[(page*2)+1], pagebits);
102 return MEM_PAGE_NO_WE;
103 }
105 // Page access allowed.
106 return MEM_ALLOWED;
107 }/*}}}*/
109 #undef MAPRAM
112 /********************************************************
113 * m68k memory read/write support functions for Musashi
114 ********************************************************/
116 /**
117 * @brief Check memory access permissions for a write operation.
118 * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but
119 * gcc throws warnings when you have a return-with-value in a void
120 * function, even if the return-with-value is completely unreachable.
121 * Similarly it doesn't like it if you have a return without a value
122 * in a non-void function, even if it's impossible to ever reach the
123 * return-with-no-value. UGH!
124 */
125 /*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
126 #define ACCESS_CHECK_WR(address, bits) \
127 do { \
128 bool fault = false; \
129 MEM_STATUS st; \
130 switch (st = checkMemoryAccess(address, true)) { \
131 case MEM_ALLOWED: \
132 /* Access allowed */ \
133 break; \
134 case MEM_PAGEFAULT: \
135 /* Page fault */ \
136 state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0); \
137 fault = true; \
138 break; \
139 case MEM_UIE: \
140 /* User access to memory above 4MB */ \
141 state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0); \
142 fault = true; \
143 break; \
144 case MEM_KERNEL: \
145 case MEM_PAGE_NO_WE: \
146 /* kernel access or page not write enabled */ \
147 /* XXX: is this the correct value? */ \
148 state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0); \
149 fault = true; \
150 break; \
151 } \
152 \
153 if (fault) { \
154 if (bits >= 16) \
155 state.bsr0 = 0x7C00; \
156 else \
157 state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \
158 state.bsr0 |= (address >> 16); \
159 state.bsr1 = address & 0xffff; \
160 LOG("Bus Error while writing, addr %08X, statcode %d", address, st); \
161 if (state.ee) m68k_pulse_bus_error(); \
162 return; \
163 } \
164 } while (0)
165 /*}}}*/
167 /**
168 * @brief Check memory access permissions for a read operation.
169 * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but
170 * gcc throws warnings when you have a return-with-value in a void
171 * function, even if the return-with-value is completely unreachable.
172 * Similarly it doesn't like it if you have a return without a value
173 * in a non-void function, even if it's impossible to ever reach the
174 * return-with-no-value. UGH!
175 */
176 /*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
177 #define ACCESS_CHECK_RD(address, bits) \
178 do { \
179 bool fault = false; \
180 MEM_STATUS st; \
181 switch (st = checkMemoryAccess(address, false)) { \
182 case MEM_ALLOWED: \
183 /* Access allowed */ \
184 break; \
185 case MEM_PAGEFAULT: \
186 /* Page fault */ \
187 state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0); \
188 fault = true; \
189 break; \
190 case MEM_UIE: \
191 /* User access to memory above 4MB */ \
192 state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0); \
193 fault = true; \
194 break; \
195 case MEM_KERNEL: \
196 case MEM_PAGE_NO_WE: \
197 /* kernel access or page not write enabled */ \
198 /* XXX: is this the correct value? */ \
199 state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0); \
200 fault = true; \
201 break; \
202 } \
203 \
204 if (fault) { \
205 if (bits >= 16) \
206 state.bsr0 = 0x7C00; \
207 else \
208 state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \
209 state.bsr0 |= (address >> 16); \
210 state.bsr1 = address & 0xffff; \
211 LOG("Bus Error while reading, addr %08X, statcode %d", address, st); \
212 if (state.ee) m68k_pulse_bus_error(); \
213 return 0xFFFFFFFF; \
214 } \
215 } while (0)
216 /*}}}*/
218 bool access_check_dma(int reading)
219 {
220 // Check memory access permissions
221 bool access_ok;
222 switch (checkMemoryAccess(state.dma_address, !reading)) {
223 case MEM_PAGEFAULT:
224 // Page fault
225 state.genstat = 0xABFF
226 | (reading ? 0x4000 : 0)
227 | (state.pie ? 0x0400 : 0);
228 access_ok = false;
229 break;
231 case MEM_UIE:
232 // User access to memory above 4MB
233 // FIXME? Shouldn't be possible with DMA... assert this?
234 state.genstat = 0xBAFF
235 | (reading ? 0x4000 : 0)
236 | (state.pie ? 0x0400 : 0);
237 access_ok = false;
238 break;
240 case MEM_KERNEL:
241 case MEM_PAGE_NO_WE:
242 // Kernel access or page not write enabled
243 /* XXX: is this correct? */
244 state.genstat = 0xBBFF
245 | (reading ? 0x4000 : 0)
246 | (state.pie ? 0x0400 : 0);
247 access_ok = false;
248 break;
250 case MEM_ALLOWED:
251 access_ok = true;
252 break;
253 }
254 if (!access_ok) {
255 state.bsr0 = 0x3C00;
256 state.bsr0 |= (state.dma_address >> 16);
257 state.bsr1 = state.dma_address & 0xffff;
258 if (state.ee) m68k_set_irq(7);
259 printf("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
260 }
261 return (access_ok);
262 }
264 // Logging macros
265 #define LOG_NOT_HANDLED_R(bits) \
266 if (!handled) printf("unhandled read%02d, addr=0x%08X\n", bits, address);
268 #define LOG_NOT_HANDLED_W(bits) \
269 if (!handled) printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
271 /********************************************************
272 * I/O read/write functions
273 ********************************************************/
275 /**
276 * Issue a warning if a read operation is made with an invalid size
277 */
278 inline static void ENFORCE_SIZE(int bits, uint32_t address, bool read, int allowed, char *regname)
279 {
280 assert((bits == 8) || (bits == 16) || (bits == 32));
281 if ((bits & allowed) == 0) {
282 printf("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
283 }
284 }
286 inline static void ENFORCE_SIZE_R(int bits, uint32_t address, int allowed, char *regname)
287 {
288 ENFORCE_SIZE(bits, address, true, allowed, regname);
289 }
291 inline static void ENFORCE_SIZE_W(int bits, uint32_t address, int allowed, char *regname)
292 {
293 ENFORCE_SIZE(bits, address, false, allowed, regname);
294 }
296 void IoWrite(uint32_t address, uint32_t data, int bits)/*{{{*/
297 {
298 bool handled = false;
300 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
301 // I/O register space, zone A
302 switch (address & 0x0F0000) {
303 case 0x010000: // General Status Register
304 if (bits == 16)
305 state.genstat = (data & 0xffff);
306 else if (bits == 8) {
307 if (address & 0)
308 state.genstat = data;
309 else
310 state.genstat = data << 8;
311 }
312 handled = true;
313 break;
314 case 0x030000: // Bus Status Register 0
315 break;
316 case 0x040000: // Bus Status Register 1
317 break;
318 case 0x050000: // Phone status
319 break;
320 case 0x060000: // DMA Count
321 ENFORCE_SIZE_W(bits, address, 16, "DMACOUNT");
322 state.dma_count = (data & 0x3FFF);
323 state.idmarw = ((data & 0x4000) == 0x4000);
324 state.dmaen = ((data & 0x8000) == 0x8000);
325 // This handles the "dummy DMA transfer" mentioned in the docs
326 // disabled because it causes the floppy test to fail
327 #if 0
328 if (!state.idmarw){
329 if (access_check_dma(true)){
330 uint32_t newAddr = mapAddr(state.dma_address, true);
331 // RAM access
332 if (newAddr <= 0x1fffff)
333 WR16(state.base_ram, newAddr, state.base_ram_size - 1, 0xFF);
334 else if (address <= 0x3FFFFF)
335 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, 0xFF);
336 }
337 }
338 #endif
339 state.dma_count++;
340 handled = true;
341 break;
342 case 0x070000: // Line Printer Status Register
343 break;
344 case 0x080000: // Real Time Clock
345 break;
346 case 0x090000: // Phone registers
347 switch (address & 0x0FF000) {
348 case 0x090000: // Handset relay
349 case 0x098000:
350 break;
351 case 0x091000: // Line select 2
352 case 0x099000:
353 break;
354 case 0x092000: // Hook relay 1
355 case 0x09A000:
356 break;
357 case 0x093000: // Hook relay 2
358 case 0x09B000:
359 break;
360 case 0x094000: // Line 1 hold
361 case 0x09C000:
362 break;
363 case 0x095000: // Line 2 hold
364 case 0x09D000:
365 break;
366 case 0x096000: // Line 1 A-lead
367 case 0x09E000:
368 break;
369 case 0x097000: // Line 2 A-lead
370 case 0x09F000:
371 break;
372 }
373 break;
374 case 0x0A0000: // Miscellaneous Control Register
375 ENFORCE_SIZE_W(bits, address, 16, "MISCCON");
376 // TODO: handle the ctrl bits properly
377 if (data & 0x8000){
378 state.timer_enabled = 1;
379 }else{
380 state.timer_enabled = 0;
381 state.timer_asserted = 0;
382 }
383 state.dma_reading = (data & 0x4000);
384 if (state.leds != ((~data & 0xF00) >> 8)) {
385 state.leds = (~data & 0xF00) >> 8;
386 printf("LEDs: %s %s %s %s\n",
387 (state.leds & 8) ? "R" : "-",
388 (state.leds & 4) ? "G" : "-",
389 (state.leds & 2) ? "Y" : "-",
390 (state.leds & 1) ? "R" : "-");
391 }
392 handled = true;
393 break;
394 case 0x0B0000: // TM/DIALWR
395 break;
396 case 0x0C0000: // Clear Status Register
397 state.genstat = 0xFFFF;
398 state.bsr0 = 0xFFFF;
399 state.bsr1 = 0xFFFF;
400 handled = true;
401 break;
402 case 0x0D0000: // DMA Address Register
403 if (address & 0x004000) {
404 // A14 high -- set most significant bits
405 state.dma_address = (state.dma_address & 0x1fe) | ((address & 0x3ffe) << 8);
406 } else {
407 // A14 low -- set least significant bits
408 state.dma_address = (state.dma_address & 0x3ffe00) | (address & 0x1fe);
409 }
410 handled = true;
411 break;
412 case 0x0E0000: // Disk Control Register
413 {
414 bool fd_selected;
415 bool hd_selected;
416 ENFORCE_SIZE_W(bits, address, 16, "DISKCON");
417 // B7 = FDD controller reset
418 if ((data & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
419 // B6 = drive 0 select
420 fd_selected = (data & 0x40) != 0;
421 // B5 = motor enable -- TODO
422 // B4 = HDD controller reset
423 if ((data & 0x10) == 0) wd2010_reset(&state.hdc_ctx);
424 // B3 = HDD0 select
425 hd_selected = (data & 0x08) != 0;
426 // B2,1,0 = HDD0 head select -- TODO?
427 if (hd_selected && !state.hd_selected){
428 state.fd_selected = false;
429 state.hd_selected = true;
430 }else if (fd_selected && !state.fd_selected){
431 state.hd_selected = false;
432 state.fd_selected = true;
433 }
434 handled = true;
435 break;
436 }
437 case 0x0F0000: // Line Printer Data Register
438 break;
439 }
440 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
441 // I/O register space, zone B
442 switch (address & 0xF00000) {
443 case 0xC00000: // Expansion slots
444 case 0xD00000:
445 switch (address & 0xFC0000) {
446 case 0xC00000: // Expansion slot 0
447 case 0xC40000: // Expansion slot 1
448 case 0xC80000: // Expansion slot 2
449 case 0xCC0000: // Expansion slot 3
450 case 0xD00000: // Expansion slot 4
451 case 0xD40000: // Expansion slot 5
452 case 0xD80000: // Expansion slot 6
453 case 0xDC0000: // Expansion slot 7
454 fprintf(stderr, "NOTE: WR%d to expansion card space, addr=0x%08X, data=0x%08X\n", bits, address, data);
455 handled = true;
456 break;
457 }
458 break;
459 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
460 case 0xF00000:
461 switch (address & 0x070000) {
462 case 0x000000: // [ef][08]xxxx ==> WD2010 hard disc controller
463 wd2010_write_reg(&state.hdc_ctx, (address >> 1) & 7, data);
464 handled = true;
465 break;
466 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
467 /*ENFORCE_SIZE_W(bits, address, 16, "FDC REGISTERS");*/
468 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, data);
469 handled = true;
470 break;
471 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
472 /*TODO: implement P5.1 second hard drive select*/
473 break;
474 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
475 break;
476 case 0x040000: // [ef][4c]xxxx ==> General Control Register
477 switch (address & 0x077000) {
478 case 0x040000: // [ef][4c][08]xxx ==> EE
479 // Error Enable. If =0, Level7 intrs and bus errors are masked.
480 ENFORCE_SIZE_W(bits, address, 16, "EE");
481 state.ee = ((data & 0x8000) == 0x8000);
482 handled = true;
483 break;
484 case 0x041000: // [ef][4c][19]xxx ==> PIE
485 ENFORCE_SIZE_W(bits, address, 16, "PIE");
486 state.pie = ((data & 0x8000) == 0x8000);
487 handled = true;
488 break;
489 case 0x042000: // [ef][4c][2A]xxx ==> BP
490 break;
491 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
492 ENFORCE_SIZE_W(bits, address, 16, "ROMLMAP");
493 state.romlmap = ((data & 0x8000) == 0x8000);
494 handled = true;
495 break;
496 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
497 ENFORCE_SIZE_W(bits, address, 16, "L1 MODEM");
498 break;
499 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
500 ENFORCE_SIZE_W(bits, address, 16, "L2 MODEM");
501 break;
502 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
503 ENFORCE_SIZE_W(bits, address, 16, "D/N CONNECT");
504 break;
505 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
506 ENFORCE_SIZE_W(bits, address, 16, "WHOLE SCREEN REVERSE VIDEO");
507 break;
508 }
509 case 0x050000: // [ef][5d]xxxx ==> 8274
510 break;
511 case 0x060000: // [ef][6e]xxxx ==> Control regs
512 switch (address & 0x07F000) {
513 default:
514 break;
515 }
516 break;
517 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
518 // TODO: figure out which sizes are valid (probably just 8 and 16)
519 // ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
520 if (bits == 8) {
521 printf("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
522 keyboard_write(&state.kbd, (address >> 1) & 3, data);
523 handled = true;
524 } else if (bits == 16) {
525 printf("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
526 keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
527 handled = true;
528 }
529 break;
530 }
531 }
532 }
534 LOG_NOT_HANDLED_W(bits);
535 }/*}}}*/
537 uint32_t IoRead(uint32_t address, int bits)/*{{{*/
538 {
539 bool handled = false;
540 uint32_t data = 0xFFFFFFFF;
542 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
543 // I/O register space, zone A
544 switch (address & 0x0F0000) {
545 case 0x010000: // General Status Register
546 ENFORCE_SIZE_R(bits, address, 16, "GENSTAT");
547 return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
548 break;
549 case 0x030000: // Bus Status Register 0
550 ENFORCE_SIZE_R(bits, address, 16, "BSR0");
551 return ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
552 break;
553 case 0x040000: // Bus Status Register 1
554 ENFORCE_SIZE_R(bits, address, 16, "BSR1");
555 return ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
556 break;
557 case 0x050000: // Phone status
558 ENFORCE_SIZE_R(bits, address, 8 | 16, "PHONE STATUS");
559 break;
560 case 0x060000: // DMA Count
561 // TODO: U/OERR- is always inactive (bit set)... or should it be = DMAEN+?
562 // Bit 14 is always unused, so leave it set
563 ENFORCE_SIZE_R(bits, address, 16, "DMACOUNT");
564 return (state.dma_count & 0x3fff) | 0xC000;
565 break;
566 case 0x070000: // Line Printer Status Register
567 data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD
568 data |= wd2797_get_irq(&state.fdc_ctx) ? 0x00080008 : 0;
569 data |= wd2010_get_irq(&state.hdc_ctx) ? 0x00040004 : 0;
570 return data;
571 break;
572 case 0x080000: // Real Time Clock
573 printf("READ NOTIMP: Realtime Clock\n");
574 break;
575 case 0x090000: // Phone registers
576 switch (address & 0x0FF000) {
577 case 0x090000: // Handset relay
578 case 0x098000:
579 break;
580 case 0x091000: // Line select 2
581 case 0x099000:
582 break;
583 case 0x092000: // Hook relay 1
584 case 0x09A000:
585 break;
586 case 0x093000: // Hook relay 2
587 case 0x09B000:
588 break;
589 case 0x094000: // Line 1 hold
590 case 0x09C000:
591 break;
592 case 0x095000: // Line 2 hold
593 case 0x09D000:
594 break;
595 case 0x096000: // Line 1 A-lead
596 case 0x09E000:
597 break;
598 case 0x097000: // Line 2 A-lead
599 case 0x09F000:
600 break;
601 }
602 break;
603 case 0x0A0000: // Miscellaneous Control Register -- write only!
604 handled = true;
605 break;
606 case 0x0B0000: // TM/DIALWR
607 break;
608 case 0x0C0000: // Clear Status Register -- write only!
609 handled = true;
610 break;
611 case 0x0D0000: // DMA Address Register
612 break;
613 case 0x0E0000: // Disk Control Register
614 break;
615 case 0x0F0000: // Line Printer Data Register
616 break;
617 }
618 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
619 // I/O register space, zone B
620 switch (address & 0xF00000) {
621 case 0xC00000: // Expansion slots
622 case 0xD00000:
623 switch (address & 0xFC0000) {
624 case 0xC00000: // Expansion slot 0
625 case 0xC40000: // Expansion slot 1
626 case 0xC80000: // Expansion slot 2
627 case 0xCC0000: // Expansion slot 3
628 case 0xD00000: // Expansion slot 4
629 case 0xD40000: // Expansion slot 5
630 case 0xD80000: // Expansion slot 6
631 case 0xDC0000: // Expansion slot 7
632 fprintf(stderr, "NOTE: RD%d from expansion card space, addr=0x%08X\n", bits, address);
633 handled = true;
634 break;
635 }
636 break;
637 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
638 case 0xF00000:
639 switch (address & 0x070000) {
640 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
641 return (wd2010_read_reg(&state.hdc_ctx, (address >> 1) & 7));
643 break;
644 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
645 /*ENFORCE_SIZE_R(bits, address, 16, "FDC REGISTERS");*/
646 return wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
647 break;
648 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
649 break;
650 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
651 break;
652 case 0x040000: // [ef][4c]xxxx ==> General Control Register
653 switch (address & 0x077000) {
654 case 0x040000: // [ef][4c][08]xxx ==> EE
655 case 0x041000: // [ef][4c][19]xxx ==> PIE
656 case 0x042000: // [ef][4c][2A]xxx ==> BP
657 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
658 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
659 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
660 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
661 // All write-only registers... TODO: bus error?
662 handled = true;
663 break;
664 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
665 break;
666 }
667 break;
668 case 0x050000: // [ef][5d]xxxx ==> 8274
669 break;
670 case 0x060000: // [ef][6e]xxxx ==> Control regs
671 switch (address & 0x07F000) {
672 default:
673 break;
674 }
675 break;
676 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
677 // TODO: figure out which sizes are valid (probably just 8 and 16)
678 //ENFORCE_SIZE_R(bits, address, 16, "KEYBOARD CONTROLLER");
679 {
680 if (bits == 8) {
681 return keyboard_read(&state.kbd, (address >> 1) & 3);
682 } else {
683 return keyboard_read(&state.kbd, (address >> 1) & 3) << 8;
684 }
685 return data;
686 }
687 break;
688 }
689 }
690 }
692 LOG_NOT_HANDLED_R(bits);
694 return data;
695 }/*}}}*/
698 /********************************************************
699 * m68k memory read/write support functions for Musashi
700 ********************************************************/
702 /**
703 * @brief Read M68K memory, 32-bit
704 */
705 uint32_t m68k_read_memory_32(uint32_t address)/*{{{*/
706 {
707 uint32_t data = 0xFFFFFFFF;
709 // If ROMLMAP is set, force system to access ROM
710 if (!state.romlmap)
711 address |= 0x800000;
713 // Check access permissions
714 ACCESS_CHECK_RD(address, 32);
716 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
717 // ROM access
718 return RD32(state.rom, address, ROM_SIZE - 1);
719 } else if (address <= 0x3fffff) {
720 // RAM access
721 uint32_t newAddr = mapAddr(address, false);
722 if (newAddr <= 0x1fffff) {
723 return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
724 } else {
725 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
726 return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
727 else
728 return 0xffffffff;
729 }
730 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
731 // I/O register space, zone A
732 switch (address & 0x0F0000) {
733 case 0x000000: // Map RAM access
734 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
735 return RD32(state.map, address, 0x7FF);
736 break;
737 case 0x020000: // Video RAM
738 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
739 return RD32(state.vram, address, 0x7FFF);
740 break;
741 default:
742 return IoRead(address, 32);
743 }
744 } else {
745 return IoRead(address, 32);
746 }
748 return data;
749 }/*}}}*/
751 /**
752 * @brief Read M68K memory, 16-bit
753 */
754 uint32_t m68k_read_memory_16(uint32_t address)/*{{{*/
755 {
756 uint16_t data = 0xFFFF;
758 // If ROMLMAP is set, force system to access ROM
759 if (!state.romlmap)
760 address |= 0x800000;
762 // Check access permissions
763 ACCESS_CHECK_RD(address, 16);
765 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
766 // ROM access
767 data = RD16(state.rom, address, ROM_SIZE - 1);
768 } else if (address <= 0x3fffff) {
769 // RAM access
770 uint32_t newAddr = mapAddr(address, false);
771 if (newAddr <= 0x1fffff) {
772 return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
773 } else {
774 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
775 return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
776 else
777 return 0xffff;
778 }
779 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
780 // I/O register space, zone A
781 switch (address & 0x0F0000) {
782 case 0x000000: // Map RAM access
783 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
784 data = RD16(state.map, address, 0x7FF);
785 break;
786 case 0x020000: // Video RAM
787 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
788 data = RD16(state.vram, address, 0x7FFF);
789 break;
790 default:
791 data = IoRead(address, 16);
792 }
793 } else {
794 data = IoRead(address, 16);
795 }
797 return data;
798 }/*}}}*/
800 /**
801 * @brief Read M68K memory, 8-bit
802 */
803 uint32_t m68k_read_memory_8(uint32_t address)/*{{{*/
804 {
805 uint8_t data = 0xFF;
807 // If ROMLMAP is set, force system to access ROM
808 if (!state.romlmap)
809 address |= 0x800000;
811 // Check access permissions
812 ACCESS_CHECK_RD(address, 8);
814 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
815 // ROM access
816 data = RD8(state.rom, address, ROM_SIZE - 1);
817 } else if (address <= 0x3fffff) {
818 // RAM access
819 uint32_t newAddr = mapAddr(address, false);
820 if (newAddr <= 0x1fffff) {
821 return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
822 } else {
823 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
824 return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
825 else
826 return 0xff;
827 }
828 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
829 // I/O register space, zone A
830 switch (address & 0x0F0000) {
831 case 0x000000: // Map RAM access
832 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
833 data = RD8(state.map, address, 0x7FF);
834 break;
835 case 0x020000: // Video RAM
836 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
837 data = RD8(state.vram, address, 0x7FFF);
838 break;
839 default:
840 data = IoRead(address, 8);
841 }
842 } else {
843 data = IoRead(address, 8);
844 }
846 return data;
847 }/*}}}*/
849 /**
850 * @brief Write M68K memory, 32-bit
851 */
852 void m68k_write_memory_32(uint32_t address, uint32_t value)/*{{{*/
853 {
854 // If ROMLMAP is set, force system to access ROM
855 if (!state.romlmap)
856 address |= 0x800000;
858 // Check access permissions
859 ACCESS_CHECK_WR(address, 32);
861 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
862 // ROM access
863 } else if (address <= 0x3FFFFF) {
864 // RAM access
865 uint32_t newAddr = mapAddr(address, true);
866 if (newAddr <= 0x1fffff)
867 WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
868 else
869 WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
870 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
871 // I/O register space, zone A
872 switch (address & 0x0F0000) {
873 case 0x000000: // Map RAM access
874 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X\n", address);
875 WR32(state.map, address, 0x7FF, value);
876 break;
877 case 0x020000: // Video RAM
878 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X\n", address);
879 WR32(state.vram, address, 0x7FFF, value);
880 break;
881 default:
882 IoWrite(address, value, 32);
883 }
884 } else {
885 IoWrite(address, value, 32);
886 }
887 }/*}}}*/
889 /**
890 * @brief Write M68K memory, 16-bit
891 */
892 void m68k_write_memory_16(uint32_t address, uint32_t value)/*{{{*/
893 {
894 // If ROMLMAP is set, force system to access ROM
895 if (!state.romlmap)
896 address |= 0x800000;
898 // Check access permissions
899 ACCESS_CHECK_WR(address, 16);
901 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
902 // ROM access
903 } else if (address <= 0x3FFFFF) {
904 // RAM access
905 uint32_t newAddr = mapAddr(address, true);
907 if (newAddr <= 0x1fffff)
908 WR16(state.base_ram, newAddr, state.base_ram_size - 1, value);
909 else
910 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
911 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
912 // I/O register space, zone A
913 switch (address & 0x0F0000) {
914 case 0x000000: // Map RAM access
915 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
916 WR16(state.map, address, 0x7FF, value);
917 break;
918 case 0x020000: // Video RAM
919 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
920 WR16(state.vram, address, 0x7FFF, value);
921 break;
922 default:
923 IoWrite(address, value, 16);
924 }
925 } else {
926 IoWrite(address, value, 16);
927 }
928 }/*}}}*/
930 /**
931 * @brief Write M68K memory, 8-bit
932 */
933 void m68k_write_memory_8(uint32_t address, uint32_t value)/*{{{*/
934 {
935 // If ROMLMAP is set, force system to access ROM
936 if (!state.romlmap)
937 address |= 0x800000;
939 // Check access permissions
940 ACCESS_CHECK_WR(address, 8);
942 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
943 // ROM access (read only!)
944 } else if (address <= 0x3FFFFF) {
945 // RAM access
946 uint32_t newAddr = mapAddr(address, true);
947 if (newAddr <= 0x1fffff)
948 WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
949 else
950 WR8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
951 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
952 // I/O register space, zone A
953 switch (address & 0x0F0000) {
954 case 0x000000: // Map RAM access
955 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
956 WR8(state.map, address, 0x7FF, value);
957 break;
958 case 0x020000: // Video RAM
959 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
960 WR8(state.vram, address, 0x7FFF, value);
961 break;
962 default:
963 IoWrite(address, value, 8);
964 }
965 } else {
966 IoWrite(address, value, 8);
967 }
968 }/*}}}*/
971 // for the disassembler
972 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
973 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
974 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }