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