Mon, 14 Jan 2013 09:50:37 +0000
Max out system memory by default
Set the system memory to 2MiB base, 2MiB ext. This is a fully loaded 3B1
motherboard with a RAM expansion board. 512KiB base/no ext is the minimum
which can be specified (e.g. kernel memory map area only) but does not leave
any room for userspace. The kernel doesn't like that and doesn't handle it
gracefully...!
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 }/*}}}*/
114 #undef MAPRAM
117 /********************************************************
118 * m68k memory read/write support functions for Musashi
119 ********************************************************/
121 /**
122 * @brief Check memory access permissions for a write operation.
123 * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but
124 * gcc throws warnings when you have a return-with-value in a void
125 * function, even if the return-with-value is completely unreachable.
126 * Similarly it doesn't like it if you have a return without a value
127 * in a non-void function, even if it's impossible to ever reach the
128 * return-with-no-value. UGH!
129 */
130 /*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
131 #define ACCESS_CHECK_WR(address, bits) \
132 do { \
133 bool fault = false; \
134 MEM_STATUS st; \
135 switch (st = checkMemoryAccess(address, true)) { \
136 case MEM_ALLOWED: \
137 /* Access allowed */ \
138 break; \
139 case MEM_PAGEFAULT: \
140 /* Page fault */ \
141 state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0); \
142 fault = true; \
143 break; \
144 case MEM_UIE: \
145 /* User access to memory above 4MB */ \
146 state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0); \
147 fault = true; \
148 break; \
149 case MEM_KERNEL: \
150 case MEM_PAGE_NO_WE: \
151 /* kernel access or page not write enabled */ \
152 /* XXX: is this the correct value? */ \
153 state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0); \
154 fault = true; \
155 break; \
156 } \
157 \
158 if (fault) { \
159 if (bits >= 16) \
160 state.bsr0 = 0x7C00; \
161 else \
162 state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \
163 state.bsr0 |= (address >> 16); \
164 state.bsr1 = address & 0xffff; \
165 LOG("Bus Error while writing, addr %08X, statcode %d", address, st); \
166 if (state.ee) m68k_pulse_bus_error(); \
167 return; \
168 } \
169 } while (0)
170 /*}}}*/
172 /**
173 * @brief Check memory access permissions for a read operation.
174 * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but
175 * gcc throws warnings when you have a return-with-value in a void
176 * function, even if the return-with-value is completely unreachable.
177 * Similarly it doesn't like it if you have a return without a value
178 * in a non-void function, even if it's impossible to ever reach the
179 * return-with-no-value. UGH!
180 */
181 /*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
182 #define ACCESS_CHECK_RD(address, bits) \
183 do { \
184 bool fault = false; \
185 MEM_STATUS st; \
186 switch (st = checkMemoryAccess(address, false)) { \
187 case MEM_ALLOWED: \
188 /* Access allowed */ \
189 break; \
190 case MEM_PAGEFAULT: \
191 /* Page fault */ \
192 state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0); \
193 fault = true; \
194 break; \
195 case MEM_UIE: \
196 /* User access to memory above 4MB */ \
197 state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0); \
198 fault = true; \
199 break; \
200 case MEM_KERNEL: \
201 case MEM_PAGE_NO_WE: \
202 /* kernel access or page not write enabled */ \
203 /* XXX: is this the correct value? */ \
204 state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0); \
205 fault = true; \
206 break; \
207 } \
208 \
209 if (fault) { \
210 if (bits >= 16) \
211 state.bsr0 = 0x7C00; \
212 else \
213 state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \
214 state.bsr0 |= (address >> 16); \
215 state.bsr1 = address & 0xffff; \
216 LOG("Bus Error while reading, addr %08X, statcode %d", address, st); \
217 if (state.ee) m68k_pulse_bus_error(); \
218 if (bits == 32) \
219 return EMPTY & 0xFFFFFFFF; \
220 else \
221 return EMPTY & ((1UL << bits)-1); \
222 } \
223 } while (0)
224 /*}}}*/
226 bool access_check_dma(int reading)
227 {
228 // Check memory access permissions
229 bool access_ok;
230 switch (checkMemoryAccess(state.dma_address, !reading)) {
231 case MEM_PAGEFAULT:
232 // Page fault
233 state.genstat = 0xABFF
234 | (reading ? 0x4000 : 0)
235 | (state.pie ? 0x0400 : 0);
236 access_ok = false;
237 break;
239 case MEM_UIE:
240 // User access to memory above 4MB
241 // FIXME? Shouldn't be possible with DMA... assert this?
242 state.genstat = 0xBAFF
243 | (reading ? 0x4000 : 0)
244 | (state.pie ? 0x0400 : 0);
245 access_ok = false;
246 break;
248 case MEM_KERNEL:
249 case MEM_PAGE_NO_WE:
250 // Kernel access or page not write enabled
251 /* XXX: is this correct? */
252 state.genstat = 0xBBFF
253 | (reading ? 0x4000 : 0)
254 | (state.pie ? 0x0400 : 0);
255 access_ok = false;
256 break;
258 case MEM_ALLOWED:
259 access_ok = true;
260 break;
261 }
262 if (!access_ok) {
263 state.bsr0 = 0x3C00;
264 state.bsr0 |= (state.dma_address >> 16);
265 state.bsr1 = state.dma_address & 0xffff;
266 if (state.ee) m68k_set_irq(7);
267 printf("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
268 }
269 return (access_ok);
270 }
272 // Logging macros
273 #define LOG_NOT_HANDLED_R(bits) \
274 if (!handled) printf("unhandled read%02d, addr=0x%08X\n", bits, address);
276 #define LOG_NOT_HANDLED_W(bits) \
277 if (!handled) printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
279 /********************************************************
280 * I/O read/write functions
281 ********************************************************/
283 /**
284 * Issue a warning if a read operation is made with an invalid size
285 */
286 inline static void ENFORCE_SIZE(int bits, uint32_t address, bool read, int allowed, char *regname)
287 {
288 assert((bits == 8) || (bits == 16) || (bits == 32));
289 if ((bits & allowed) == 0) {
290 printf("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
291 }
292 }
294 inline static void ENFORCE_SIZE_R(int bits, uint32_t address, int allowed, char *regname)
295 {
296 ENFORCE_SIZE(bits, address, true, allowed, regname);
297 }
299 inline static void ENFORCE_SIZE_W(int bits, uint32_t address, int allowed, char *regname)
300 {
301 ENFORCE_SIZE(bits, address, false, allowed, regname);
302 }
304 void IoWrite(uint32_t address, uint32_t data, int bits)/*{{{*/
305 {
306 bool handled = false;
308 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
309 // I/O register space, zone A
310 switch (address & 0x0F0000) {
311 case 0x010000: // General Status Register
312 if (bits == 16)
313 state.genstat = (data & 0xffff);
314 else if (bits == 8) {
315 if (address & 0)
316 state.genstat = data;
317 else
318 state.genstat = data << 8;
319 }
320 handled = true;
321 break;
322 case 0x030000: // Bus Status Register 0
323 break;
324 case 0x040000: // Bus Status Register 1
325 break;
326 case 0x050000: // Phone status
327 break;
328 case 0x060000: // DMA Count
329 ENFORCE_SIZE_W(bits, address, 16, "DMACOUNT");
330 state.dma_count = (data & 0x3FFF);
331 state.idmarw = ((data & 0x4000) == 0x4000);
332 state.dmaen = ((data & 0x8000) == 0x8000);
333 // This handles the "dummy DMA transfer" mentioned in the docs
334 // disabled because it causes the floppy test to fail
335 #if 0
336 if (!state.idmarw){
337 if (access_check_dma(true)){
338 uint32_t newAddr = mapAddr(state.dma_address, true);
339 // RAM access
340 if (newAddr <= 0x1fffff)
341 WR16(state.base_ram, newAddr, state.base_ram_size - 1, 0xFF);
342 else if (address <= 0x3FFFFF)
343 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, 0xFF);
344 }
345 }
346 #endif
347 state.dma_count++;
348 handled = true;
349 break;
350 case 0x070000: // Line Printer Status Register
351 break;
352 case 0x080000: // Real Time Clock
353 break;
354 case 0x090000: // Phone registers
355 switch (address & 0x0FF000) {
356 case 0x090000: // Handset relay
357 case 0x098000:
358 break;
359 case 0x091000: // Line select 2
360 case 0x099000:
361 break;
362 case 0x092000: // Hook relay 1
363 case 0x09A000:
364 break;
365 case 0x093000: // Hook relay 2
366 case 0x09B000:
367 break;
368 case 0x094000: // Line 1 hold
369 case 0x09C000:
370 break;
371 case 0x095000: // Line 2 hold
372 case 0x09D000:
373 break;
374 case 0x096000: // Line 1 A-lead
375 case 0x09E000:
376 break;
377 case 0x097000: // Line 2 A-lead
378 case 0x09F000:
379 break;
380 }
381 break;
382 case 0x0A0000: // Miscellaneous Control Register
383 ENFORCE_SIZE_W(bits, address, 16, "MISCCON");
384 // TODO: handle the ctrl bits properly
385 if (data & 0x8000){
386 state.timer_enabled = 1;
387 }else{
388 state.timer_enabled = 0;
389 state.timer_asserted = 0;
390 }
391 state.dma_reading = (data & 0x4000);
392 if (state.leds != ((~data & 0xF00) >> 8)) {
393 state.leds = (~data & 0xF00) >> 8;
394 #ifdef SHOW_LEDS
395 printf("LEDs: %s %s %s %s\n",
396 (state.leds & 8) ? "R" : "-",
397 (state.leds & 4) ? "G" : "-",
398 (state.leds & 2) ? "Y" : "-",
399 (state.leds & 1) ? "R" : "-");
400 #endif
401 }
402 handled = true;
403 break;
404 case 0x0B0000: // TM/DIALWR
405 break;
406 case 0x0C0000: // Clear Status Register
407 state.genstat = 0xFFFF;
408 state.bsr0 = 0xFFFF;
409 state.bsr1 = 0xFFFF;
410 handled = true;
411 break;
412 case 0x0D0000: // DMA Address Register
413 if (address & 0x004000) {
414 // A14 high -- set most significant bits
415 state.dma_address = (state.dma_address & 0x1fe) | ((address & 0x3ffe) << 8);
416 } else {
417 // A14 low -- set least significant bits
418 state.dma_address = (state.dma_address & 0x3ffe00) | (address & 0x1fe);
419 }
420 handled = true;
421 break;
422 case 0x0E0000: // Disk Control Register
423 {
424 bool fd_selected;
425 bool hd_selected;
426 ENFORCE_SIZE_W(bits, address, 16, "DISKCON");
427 // B7 = FDD controller reset
428 if ((data & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
429 // B6 = drive 0 select
430 fd_selected = (data & 0x40) != 0;
431 // B5 = motor enable -- TODO
432 // B4 = HDD controller reset
433 if ((data & 0x10) == 0) wd2010_reset(&state.hdc_ctx);
434 // B3 = HDD0 select
435 hd_selected = (data & 0x08) != 0;
436 // B2,1,0 = HDD0 head select -- TODO?
437 if (hd_selected && !state.hd_selected){
438 state.fd_selected = false;
439 state.hd_selected = true;
440 }else if (fd_selected && !state.fd_selected){
441 state.hd_selected = false;
442 state.fd_selected = true;
443 }
444 handled = true;
445 break;
446 }
447 case 0x0F0000: // Line Printer Data Register
448 break;
449 }
450 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
451 // I/O register space, zone B
452 switch (address & 0xF00000) {
453 case 0xC00000: // Expansion slots
454 case 0xD00000:
455 switch (address & 0xFC0000) {
456 case 0xC00000: // Expansion slot 0
457 case 0xC40000: // Expansion slot 1
458 case 0xC80000: // Expansion slot 2
459 case 0xCC0000: // Expansion slot 3
460 case 0xD00000: // Expansion slot 4
461 case 0xD40000: // Expansion slot 5
462 case 0xD80000: // Expansion slot 6
463 case 0xDC0000: // Expansion slot 7
464 fprintf(stderr, "NOTE: WR%d to expansion card space, addr=0x%08X, data=0x%08X\n", bits, address, data);
465 handled = true;
466 break;
467 }
468 break;
469 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
470 case 0xF00000:
471 switch (address & 0x070000) {
472 case 0x000000: // [ef][08]xxxx ==> WD2010 hard disc controller
473 wd2010_write_reg(&state.hdc_ctx, (address >> 1) & 7, data);
474 handled = true;
475 break;
476 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
477 /*ENFORCE_SIZE_W(bits, address, 16, "FDC REGISTERS");*/
478 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, data);
479 handled = true;
480 break;
481 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
482 // MCR2 - UNIX PC Rev. P5.1 HDD head select b3 and potential HDD#2 select
483 wd2010_write_reg(&state.hdc_ctx, UNIXPC_REG_MCR2, data);
484 handled = true;
485 break;
486 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
487 break;
488 case 0x040000: // [ef][4c]xxxx ==> General Control Register
489 switch (address & 0x077000) {
490 case 0x040000: // [ef][4c][08]xxx ==> EE
491 // Error Enable. If =0, Level7 intrs and bus errors are masked.
492 ENFORCE_SIZE_W(bits, address, 16, "EE");
493 state.ee = ((data & 0x8000) == 0x8000);
494 handled = true;
495 break;
496 case 0x041000: // [ef][4c][19]xxx ==> PIE
497 ENFORCE_SIZE_W(bits, address, 16, "PIE");
498 state.pie = ((data & 0x8000) == 0x8000);
499 handled = true;
500 break;
501 case 0x042000: // [ef][4c][2A]xxx ==> BP
502 break;
503 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
504 ENFORCE_SIZE_W(bits, address, 16, "ROMLMAP");
505 state.romlmap = ((data & 0x8000) == 0x8000);
506 handled = true;
507 break;
508 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
509 ENFORCE_SIZE_W(bits, address, 16, "L1 MODEM");
510 break;
511 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
512 ENFORCE_SIZE_W(bits, address, 16, "L2 MODEM");
513 break;
514 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
515 ENFORCE_SIZE_W(bits, address, 16, "D/N CONNECT");
516 break;
517 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
518 ENFORCE_SIZE_W(bits, address, 16, "WHOLE SCREEN REVERSE VIDEO");
519 break;
520 }
521 case 0x050000: // [ef][5d]xxxx ==> 8274
522 break;
523 case 0x060000: // [ef][6e]xxxx ==> Control regs
524 switch (address & 0x07F000) {
525 default:
526 break;
527 }
528 break;
529 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
530 // TODO: figure out which sizes are valid (probably just 8 and 16)
531 // ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
532 if (bits == 8) {
533 printf("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
534 keyboard_write(&state.kbd, (address >> 1) & 3, data);
535 handled = true;
536 } else if (bits == 16) {
537 printf("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
538 keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
539 handled = true;
540 }
541 break;
542 }
543 }
544 }
546 LOG_NOT_HANDLED_W(bits);
547 }/*}}}*/
549 uint32_t IoRead(uint32_t address, int bits)/*{{{*/
550 {
551 bool handled = false;
552 uint32_t data = EMPTY & 0xFFFFFFFF;
554 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
555 // I/O register space, zone A
556 switch (address & 0x0F0000) {
557 case 0x010000: // General Status Register
558 /* ENFORCE_SIZE_R(bits, address, 16, "GENSTAT"); */
559 if (bits == 32) {
560 return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
561 } else if (bits == 16) {
562 return (uint16_t)state.genstat;
563 } else {
564 return (uint8_t)(state.genstat & 0xff);
565 }
566 break;
567 case 0x030000: // Bus Status Register 0
568 ENFORCE_SIZE_R(bits, address, 16, "BSR0");
569 return ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
570 break;
571 case 0x040000: // Bus Status Register 1
572 ENFORCE_SIZE_R(bits, address, 16, "BSR1");
573 return ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
574 break;
575 case 0x050000: // Phone status
576 ENFORCE_SIZE_R(bits, address, 8 | 16, "PHONE STATUS");
577 break;
578 case 0x060000: // DMA Count
579 // TODO: U/OERR- is always inactive (bit set)... or should it be = DMAEN+?
580 // Bit 14 is always unused, so leave it set
581 ENFORCE_SIZE_R(bits, address, 16, "DMACOUNT");
582 return (state.dma_count & 0x3fff) | 0xC000;
583 break;
584 case 0x070000: // Line Printer Status Register
585 data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD
586 data |= wd2797_get_irq(&state.fdc_ctx) ? 0x00080008 : 0;
587 data |= wd2010_get_irq(&state.hdc_ctx) ? 0x00040004 : 0;
588 return data;
589 break;
590 case 0x080000: // Real Time Clock
591 printf("READ NOTIMP: Realtime Clock\n");
592 break;
593 case 0x090000: // Phone registers
594 switch (address & 0x0FF000) {
595 case 0x090000: // Handset relay
596 case 0x098000:
597 break;
598 case 0x091000: // Line select 2
599 case 0x099000:
600 break;
601 case 0x092000: // Hook relay 1
602 case 0x09A000:
603 break;
604 case 0x093000: // Hook relay 2
605 case 0x09B000:
606 break;
607 case 0x094000: // Line 1 hold
608 case 0x09C000:
609 break;
610 case 0x095000: // Line 2 hold
611 case 0x09D000:
612 break;
613 case 0x096000: // Line 1 A-lead
614 case 0x09E000:
615 break;
616 case 0x097000: // Line 2 A-lead
617 case 0x09F000:
618 break;
619 }
620 break;
621 case 0x0A0000: // Miscellaneous Control Register -- write only!
622 handled = true;
623 break;
624 case 0x0B0000: // TM/DIALWR
625 break;
626 case 0x0C0000: // Clear Status Register -- write only!
627 handled = true;
628 break;
629 case 0x0D0000: // DMA Address Register
630 break;
631 case 0x0E0000: // Disk Control Register
632 break;
633 case 0x0F0000: // Line Printer Data Register
634 break;
635 }
636 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
637 // I/O register space, zone B
638 switch (address & 0xF00000) {
639 case 0xC00000: // Expansion slots
640 case 0xD00000:
641 switch (address & 0xFC0000) {
642 case 0xC00000: // Expansion slot 0
643 case 0xC40000: // Expansion slot 1
644 case 0xC80000: // Expansion slot 2
645 case 0xCC0000: // Expansion slot 3
646 case 0xD00000: // Expansion slot 4
647 case 0xD40000: // Expansion slot 5
648 case 0xD80000: // Expansion slot 6
649 case 0xDC0000: // Expansion slot 7
650 fprintf(stderr, "NOTE: RD%d from expansion card space, addr=0x%08X\n", bits, address);
651 handled = true;
652 break;
653 }
654 break;
655 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
656 case 0xF00000:
657 switch (address & 0x070000) {
658 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
659 return (wd2010_read_reg(&state.hdc_ctx, (address >> 1) & 7));
661 break;
662 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
663 /*ENFORCE_SIZE_R(bits, address, 16, "FDC REGISTERS");*/
664 return wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
665 break;
666 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
667 break;
668 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
669 break;
670 case 0x040000: // [ef][4c]xxxx ==> General Control Register
671 switch (address & 0x077000) {
672 case 0x040000: // [ef][4c][08]xxx ==> EE
673 case 0x041000: // [ef][4c][19]xxx ==> PIE
674 case 0x042000: // [ef][4c][2A]xxx ==> BP
675 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
676 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
677 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
678 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
679 // All write-only registers... TODO: bus error?
680 handled = true;
681 break;
682 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
683 break;
684 }
685 break;
686 case 0x050000: // [ef][5d]xxxx ==> 8274
687 break;
688 case 0x060000: // [ef][6e]xxxx ==> Control regs
689 switch (address & 0x07F000) {
690 default:
691 break;
692 }
693 break;
694 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
695 // TODO: figure out which sizes are valid (probably just 8 and 16)
696 //ENFORCE_SIZE_R(bits, address, 16, "KEYBOARD CONTROLLER");
697 {
698 if (bits == 8) {
699 return keyboard_read(&state.kbd, (address >> 1) & 3);
700 } else {
701 return keyboard_read(&state.kbd, (address >> 1) & 3) << 8;
702 }
703 return data;
704 }
705 break;
706 }
707 }
708 }
710 LOG_NOT_HANDLED_R(bits);
712 return data;
713 }/*}}}*/
716 /********************************************************
717 * m68k memory read/write support functions for Musashi
718 ********************************************************/
720 /**
721 * @brief Read M68K memory, 32-bit
722 */
723 uint32_t m68k_read_memory_32(uint32_t address)/*{{{*/
724 {
725 uint32_t data = EMPTY & 0xFFFFFFFF;
727 // If ROMLMAP is set, force system to access ROM
728 if (!state.romlmap)
729 address |= 0x800000;
731 // Check access permissions
732 ACCESS_CHECK_RD(address, 32);
734 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
735 // ROM access
736 return RD32(state.rom, address, ROM_SIZE - 1);
737 } else if (address <= 0x3fffff) {
738 // RAM access
739 uint32_t newAddr = mapAddr(address, false);
740 if (newAddr <= 0x1fffff) {
741 if (newAddr >= state.base_ram_size)
742 return EMPTY & 0xffffffff;
743 else
744 return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
745 } else {
746 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
747 return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
748 else
749 return EMPTY & 0xffffffff;
750 }
751 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
752 // I/O register space, zone A
753 switch (address & 0x0F0000) {
754 case 0x000000: // Map RAM access
755 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
756 return RD32(state.map, address, 0x7FF);
757 break;
758 case 0x020000: // Video RAM
759 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
760 return RD32(state.vram, address, 0x7FFF);
761 break;
762 default:
763 return IoRead(address, 32);
764 }
765 } else {
766 return IoRead(address, 32);
767 }
769 return data;
770 }/*}}}*/
772 /**
773 * @brief Read M68K memory, 16-bit
774 */
775 uint32_t m68k_read_memory_16(uint32_t address)/*{{{*/
776 {
777 uint16_t data = EMPTY & 0xFFFF;
779 // If ROMLMAP is set, force system to access ROM
780 if (!state.romlmap)
781 address |= 0x800000;
783 // Check access permissions
784 ACCESS_CHECK_RD(address, 16);
786 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
787 // ROM access
788 data = RD16(state.rom, address, ROM_SIZE - 1);
789 } else if (address <= 0x3fffff) {
790 // RAM access
791 uint32_t newAddr = mapAddr(address, false);
792 if (newAddr <= 0x1fffff) {
793 if (newAddr >= state.base_ram_size)
794 return EMPTY & 0xffff;
795 else
796 return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
797 } else {
798 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
799 return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
800 else
801 return EMPTY & 0xffff;
802 }
803 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
804 // I/O register space, zone A
805 switch (address & 0x0F0000) {
806 case 0x000000: // Map RAM access
807 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
808 data = RD16(state.map, address, 0x7FF);
809 break;
810 case 0x020000: // Video RAM
811 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
812 data = RD16(state.vram, address, 0x7FFF);
813 break;
814 default:
815 data = IoRead(address, 16);
816 }
817 } else {
818 data = IoRead(address, 16);
819 }
821 return data;
822 }/*}}}*/
824 /**
825 * @brief Read M68K memory, 8-bit
826 */
827 uint32_t m68k_read_memory_8(uint32_t address)/*{{{*/
828 {
829 uint8_t data = EMPTY & 0xFF;
831 // If ROMLMAP is set, force system to access ROM
832 if (!state.romlmap)
833 address |= 0x800000;
835 // Check access permissions
836 ACCESS_CHECK_RD(address, 8);
838 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
839 // ROM access
840 data = RD8(state.rom, address, ROM_SIZE - 1);
841 } else if (address <= 0x3fffff) {
842 // RAM access
843 uint32_t newAddr = mapAddr(address, false);
844 if (newAddr <= 0x1fffff) {
845 if (newAddr >= state.base_ram_size)
846 return EMPTY & 0xff;
847 else
848 return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
849 } else {
850 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
851 return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
852 else
853 return EMPTY & 0xff;
854 }
855 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
856 // I/O register space, zone A
857 switch (address & 0x0F0000) {
858 case 0x000000: // Map RAM access
859 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
860 data = RD8(state.map, address, 0x7FF);
861 break;
862 case 0x020000: // Video RAM
863 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
864 data = RD8(state.vram, address, 0x7FFF);
865 break;
866 default:
867 data = IoRead(address, 8);
868 }
869 } else {
870 data = IoRead(address, 8);
871 }
873 return data;
874 }/*}}}*/
876 /**
877 * @brief Write M68K memory, 32-bit
878 */
879 void m68k_write_memory_32(uint32_t address, uint32_t value)/*{{{*/
880 {
881 // If ROMLMAP is set, force system to access ROM
882 if (!state.romlmap)
883 address |= 0x800000;
885 // Check access permissions
886 ACCESS_CHECK_WR(address, 32);
888 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
889 // ROM access
890 } else if (address <= 0x3FFFFF) {
891 // RAM access
892 uint32_t newAddr = mapAddr(address, true);
893 if (newAddr <= 0x1fffff) {
894 if (newAddr < state.base_ram_size) {
895 WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
896 }
897 } else {
898 if ((newAddr - 0x200000) < state.exp_ram_size) {
899 WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
900 }
901 }
902 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
903 // I/O register space, zone A
904 switch (address & 0x0F0000) {
905 case 0x000000: // Map RAM access
906 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X\n", address);
907 WR32(state.map, address, 0x7FF, value);
908 break;
909 case 0x020000: // Video RAM
910 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X\n", address);
911 WR32(state.vram, address, 0x7FFF, value);
912 break;
913 default:
914 IoWrite(address, value, 32);
915 }
916 } else {
917 IoWrite(address, value, 32);
918 }
919 }/*}}}*/
921 /**
922 * @brief Write M68K memory, 16-bit
923 */
924 void m68k_write_memory_16(uint32_t address, uint32_t value)/*{{{*/
925 {
926 // If ROMLMAP is set, force system to access ROM
927 if (!state.romlmap)
928 address |= 0x800000;
930 // Check access permissions
931 ACCESS_CHECK_WR(address, 16);
933 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
934 // ROM access
935 } else if (address <= 0x3FFFFF) {
936 // RAM access
937 uint32_t newAddr = mapAddr(address, true);
939 if (newAddr <= 0x1fffff) {
940 if (newAddr < state.base_ram_size) {
941 WR16(state.base_ram, newAddr, state.base_ram_size - 1, value);
942 }
943 } else {
944 if ((newAddr - 0x200000) < state.exp_ram_size) {
945 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
946 }
947 }
948 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
949 // I/O register space, zone A
950 switch (address & 0x0F0000) {
951 case 0x000000: // Map RAM access
952 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
953 WR16(state.map, address, 0x7FF, value);
954 break;
955 case 0x020000: // Video RAM
956 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
957 WR16(state.vram, address, 0x7FFF, value);
958 break;
959 default:
960 IoWrite(address, value, 16);
961 }
962 } else {
963 IoWrite(address, value, 16);
964 }
965 }/*}}}*/
967 /**
968 * @brief Write M68K memory, 8-bit
969 */
970 void m68k_write_memory_8(uint32_t address, uint32_t value)/*{{{*/
971 {
972 // If ROMLMAP is set, force system to access ROM
973 if (!state.romlmap)
974 address |= 0x800000;
976 // Check access permissions
977 ACCESS_CHECK_WR(address, 8);
979 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
980 // ROM access (read only!)
981 } else if (address <= 0x3FFFFF) {
982 // RAM access
983 uint32_t newAddr = mapAddr(address, true);
984 if (newAddr <= 0x1fffff) {
985 if (newAddr < state.base_ram_size) {
986 WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
987 }
988 } else {
989 if ((newAddr - 0x200000) < state.exp_ram_size) {
990 WR8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
991 }
992 }
993 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
994 // I/O register space, zone A
995 switch (address & 0x0F0000) {
996 case 0x000000: // Map RAM access
997 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
998 WR8(state.map, address, 0x7FF, value);
999 break;
1000 case 0x020000: // Video RAM
1001 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
1002 WR8(state.vram, address, 0x7FFF, value);
1003 break;
1004 default:
1005 IoWrite(address, value, 8);
1006 }
1007 } else {
1008 IoWrite(address, value, 8);
1009 }
1010 }/*}}}*/
1013 // for the disassembler
1014 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
1015 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
1016 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }