Mon, 14 Jan 2013 09:22:12 +0000
More bus error fixes for FreeBee
I have fixed two more bus error handling bugs in FreeBee. First, the CPU core was executing the instruction regardless of whether a bus error occurs when fetching the opcode (which caused it to execute a bogus instruction in such cases). The other one was related to one of my previous fixes - the jump to the bus error vector was at the beginning of the main loop, so it wouldn't be called immediately after the bus error occurred if the timeslot expired, causing the return address to be off.
With these fixes, Unix now runs enough to get into userspace and run the install script (it is also possible to break out and get a shell prompt). However, many commands segfault semi-randomly (or more specifically, it seems that some child processes forked by the shell might be segfaulting before they can exec the command program), so installing the system isn't possible yet. I am not sure exactly what the bug is, but it seems to be related to some function in the shell returning null when the code calling it is assuming that it won't. What the function is, or why it is returning null, I'm not sure (the shell is built without the shared libc and is stripped, making identifying the function harder). I suspect that the function might be in libc, but that is hard to tell.
Author: Andrew Warkentin <andreww591 gmail com>
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 if (bits == 32) \
214 return 0xFFFFFFFF; \
215 else \
216 return (1UL << bits)-1; \
217 } \
218 } while (0)
219 /*}}}*/
221 bool access_check_dma(int reading)
222 {
223 // Check memory access permissions
224 bool access_ok;
225 switch (checkMemoryAccess(state.dma_address, !reading)) {
226 case MEM_PAGEFAULT:
227 // Page fault
228 state.genstat = 0xABFF
229 | (reading ? 0x4000 : 0)
230 | (state.pie ? 0x0400 : 0);
231 access_ok = false;
232 break;
234 case MEM_UIE:
235 // User access to memory above 4MB
236 // FIXME? Shouldn't be possible with DMA... assert this?
237 state.genstat = 0xBAFF
238 | (reading ? 0x4000 : 0)
239 | (state.pie ? 0x0400 : 0);
240 access_ok = false;
241 break;
243 case MEM_KERNEL:
244 case MEM_PAGE_NO_WE:
245 // Kernel access or page not write enabled
246 /* XXX: is this correct? */
247 state.genstat = 0xBBFF
248 | (reading ? 0x4000 : 0)
249 | (state.pie ? 0x0400 : 0);
250 access_ok = false;
251 break;
253 case MEM_ALLOWED:
254 access_ok = true;
255 break;
256 }
257 if (!access_ok) {
258 state.bsr0 = 0x3C00;
259 state.bsr0 |= (state.dma_address >> 16);
260 state.bsr1 = state.dma_address & 0xffff;
261 if (state.ee) m68k_set_irq(7);
262 printf("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
263 }
264 return (access_ok);
265 }
267 // Logging macros
268 #define LOG_NOT_HANDLED_R(bits) \
269 if (!handled) printf("unhandled read%02d, addr=0x%08X\n", bits, address);
271 #define LOG_NOT_HANDLED_W(bits) \
272 if (!handled) printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
274 /********************************************************
275 * I/O read/write functions
276 ********************************************************/
278 /**
279 * Issue a warning if a read operation is made with an invalid size
280 */
281 inline static void ENFORCE_SIZE(int bits, uint32_t address, bool read, int allowed, char *regname)
282 {
283 assert((bits == 8) || (bits == 16) || (bits == 32));
284 if ((bits & allowed) == 0) {
285 printf("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
286 }
287 }
289 inline static void ENFORCE_SIZE_R(int bits, uint32_t address, int allowed, char *regname)
290 {
291 ENFORCE_SIZE(bits, address, true, allowed, regname);
292 }
294 inline static void ENFORCE_SIZE_W(int bits, uint32_t address, int allowed, char *regname)
295 {
296 ENFORCE_SIZE(bits, address, false, allowed, regname);
297 }
299 void IoWrite(uint32_t address, uint32_t data, int bits)/*{{{*/
300 {
301 bool handled = false;
303 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
304 // I/O register space, zone A
305 switch (address & 0x0F0000) {
306 case 0x010000: // General Status Register
307 if (bits == 16)
308 state.genstat = (data & 0xffff);
309 else if (bits == 8) {
310 if (address & 0)
311 state.genstat = data;
312 else
313 state.genstat = data << 8;
314 }
315 handled = true;
316 break;
317 case 0x030000: // Bus Status Register 0
318 break;
319 case 0x040000: // Bus Status Register 1
320 break;
321 case 0x050000: // Phone status
322 break;
323 case 0x060000: // DMA Count
324 ENFORCE_SIZE_W(bits, address, 16, "DMACOUNT");
325 state.dma_count = (data & 0x3FFF);
326 state.idmarw = ((data & 0x4000) == 0x4000);
327 state.dmaen = ((data & 0x8000) == 0x8000);
328 // This handles the "dummy DMA transfer" mentioned in the docs
329 // disabled because it causes the floppy test to fail
330 #if 0
331 if (!state.idmarw){
332 if (access_check_dma(true)){
333 uint32_t newAddr = mapAddr(state.dma_address, true);
334 // RAM access
335 if (newAddr <= 0x1fffff)
336 WR16(state.base_ram, newAddr, state.base_ram_size - 1, 0xFF);
337 else if (address <= 0x3FFFFF)
338 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, 0xFF);
339 }
340 }
341 #endif
342 state.dma_count++;
343 handled = true;
344 break;
345 case 0x070000: // Line Printer Status Register
346 break;
347 case 0x080000: // Real Time Clock
348 break;
349 case 0x090000: // Phone registers
350 switch (address & 0x0FF000) {
351 case 0x090000: // Handset relay
352 case 0x098000:
353 break;
354 case 0x091000: // Line select 2
355 case 0x099000:
356 break;
357 case 0x092000: // Hook relay 1
358 case 0x09A000:
359 break;
360 case 0x093000: // Hook relay 2
361 case 0x09B000:
362 break;
363 case 0x094000: // Line 1 hold
364 case 0x09C000:
365 break;
366 case 0x095000: // Line 2 hold
367 case 0x09D000:
368 break;
369 case 0x096000: // Line 1 A-lead
370 case 0x09E000:
371 break;
372 case 0x097000: // Line 2 A-lead
373 case 0x09F000:
374 break;
375 }
376 break;
377 case 0x0A0000: // Miscellaneous Control Register
378 ENFORCE_SIZE_W(bits, address, 16, "MISCCON");
379 // TODO: handle the ctrl bits properly
380 if (data & 0x8000){
381 state.timer_enabled = 1;
382 }else{
383 state.timer_enabled = 0;
384 state.timer_asserted = 0;
385 }
386 state.dma_reading = (data & 0x4000);
387 if (state.leds != ((~data & 0xF00) >> 8)) {
388 state.leds = (~data & 0xF00) >> 8;
389 #ifdef SHOW_LEDS
390 printf("LEDs: %s %s %s %s\n",
391 (state.leds & 8) ? "R" : "-",
392 (state.leds & 4) ? "G" : "-",
393 (state.leds & 2) ? "Y" : "-",
394 (state.leds & 1) ? "R" : "-");
395 #endif
396 }
397 handled = true;
398 break;
399 case 0x0B0000: // TM/DIALWR
400 break;
401 case 0x0C0000: // Clear Status Register
402 state.genstat = 0xFFFF;
403 state.bsr0 = 0xFFFF;
404 state.bsr1 = 0xFFFF;
405 handled = true;
406 break;
407 case 0x0D0000: // DMA Address Register
408 if (address & 0x004000) {
409 // A14 high -- set most significant bits
410 state.dma_address = (state.dma_address & 0x1fe) | ((address & 0x3ffe) << 8);
411 } else {
412 // A14 low -- set least significant bits
413 state.dma_address = (state.dma_address & 0x3ffe00) | (address & 0x1fe);
414 }
415 handled = true;
416 break;
417 case 0x0E0000: // Disk Control Register
418 {
419 bool fd_selected;
420 bool hd_selected;
421 ENFORCE_SIZE_W(bits, address, 16, "DISKCON");
422 // B7 = FDD controller reset
423 if ((data & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
424 // B6 = drive 0 select
425 fd_selected = (data & 0x40) != 0;
426 // B5 = motor enable -- TODO
427 // B4 = HDD controller reset
428 if ((data & 0x10) == 0) wd2010_reset(&state.hdc_ctx);
429 // B3 = HDD0 select
430 hd_selected = (data & 0x08) != 0;
431 // B2,1,0 = HDD0 head select -- TODO?
432 if (hd_selected && !state.hd_selected){
433 state.fd_selected = false;
434 state.hd_selected = true;
435 }else if (fd_selected && !state.fd_selected){
436 state.hd_selected = false;
437 state.fd_selected = true;
438 }
439 handled = true;
440 break;
441 }
442 case 0x0F0000: // Line Printer Data Register
443 break;
444 }
445 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
446 // I/O register space, zone B
447 switch (address & 0xF00000) {
448 case 0xC00000: // Expansion slots
449 case 0xD00000:
450 switch (address & 0xFC0000) {
451 case 0xC00000: // Expansion slot 0
452 case 0xC40000: // Expansion slot 1
453 case 0xC80000: // Expansion slot 2
454 case 0xCC0000: // Expansion slot 3
455 case 0xD00000: // Expansion slot 4
456 case 0xD40000: // Expansion slot 5
457 case 0xD80000: // Expansion slot 6
458 case 0xDC0000: // Expansion slot 7
459 fprintf(stderr, "NOTE: WR%d to expansion card space, addr=0x%08X, data=0x%08X\n", bits, address, data);
460 handled = true;
461 break;
462 }
463 break;
464 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
465 case 0xF00000:
466 switch (address & 0x070000) {
467 case 0x000000: // [ef][08]xxxx ==> WD2010 hard disc controller
468 wd2010_write_reg(&state.hdc_ctx, (address >> 1) & 7, data);
469 handled = true;
470 break;
471 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
472 /*ENFORCE_SIZE_W(bits, address, 16, "FDC REGISTERS");*/
473 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, data);
474 handled = true;
475 break;
476 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
477 // MCR2 - UNIX PC Rev. P5.1 HDD head select b3 and potential HDD#2 select
478 wd2010_write_reg(&state.hdc_ctx, UNIXPC_REG_MCR2, data);
479 handled = true;
480 break;
481 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
482 break;
483 case 0x040000: // [ef][4c]xxxx ==> General Control Register
484 switch (address & 0x077000) {
485 case 0x040000: // [ef][4c][08]xxx ==> EE
486 // Error Enable. If =0, Level7 intrs and bus errors are masked.
487 ENFORCE_SIZE_W(bits, address, 16, "EE");
488 state.ee = ((data & 0x8000) == 0x8000);
489 handled = true;
490 break;
491 case 0x041000: // [ef][4c][19]xxx ==> PIE
492 ENFORCE_SIZE_W(bits, address, 16, "PIE");
493 state.pie = ((data & 0x8000) == 0x8000);
494 handled = true;
495 break;
496 case 0x042000: // [ef][4c][2A]xxx ==> BP
497 break;
498 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
499 ENFORCE_SIZE_W(bits, address, 16, "ROMLMAP");
500 state.romlmap = ((data & 0x8000) == 0x8000);
501 handled = true;
502 break;
503 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
504 ENFORCE_SIZE_W(bits, address, 16, "L1 MODEM");
505 break;
506 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
507 ENFORCE_SIZE_W(bits, address, 16, "L2 MODEM");
508 break;
509 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
510 ENFORCE_SIZE_W(bits, address, 16, "D/N CONNECT");
511 break;
512 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
513 ENFORCE_SIZE_W(bits, address, 16, "WHOLE SCREEN REVERSE VIDEO");
514 break;
515 }
516 case 0x050000: // [ef][5d]xxxx ==> 8274
517 break;
518 case 0x060000: // [ef][6e]xxxx ==> Control regs
519 switch (address & 0x07F000) {
520 default:
521 break;
522 }
523 break;
524 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
525 // TODO: figure out which sizes are valid (probably just 8 and 16)
526 // ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
527 if (bits == 8) {
528 printf("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
529 keyboard_write(&state.kbd, (address >> 1) & 3, data);
530 handled = true;
531 } else if (bits == 16) {
532 printf("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
533 keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
534 handled = true;
535 }
536 break;
537 }
538 }
539 }
541 LOG_NOT_HANDLED_W(bits);
542 }/*}}}*/
544 uint32_t IoRead(uint32_t address, int bits)/*{{{*/
545 {
546 bool handled = false;
547 uint32_t data = 0xFFFFFFFF;
549 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
550 // I/O register space, zone A
551 switch (address & 0x0F0000) {
552 case 0x010000: // General Status Register
553 /* ENFORCE_SIZE_R(bits, address, 16, "GENSTAT"); */
554 if (bits == 32) {
555 return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
556 } else if (bits == 16) {
557 return (uint16_t)state.genstat;
558 } else {
559 return (uint8_t)(state.genstat & 0xff);
560 }
561 break;
562 case 0x030000: // Bus Status Register 0
563 ENFORCE_SIZE_R(bits, address, 16, "BSR0");
564 return ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
565 break;
566 case 0x040000: // Bus Status Register 1
567 ENFORCE_SIZE_R(bits, address, 16, "BSR1");
568 return ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
569 break;
570 case 0x050000: // Phone status
571 ENFORCE_SIZE_R(bits, address, 8 | 16, "PHONE STATUS");
572 break;
573 case 0x060000: // DMA Count
574 // TODO: U/OERR- is always inactive (bit set)... or should it be = DMAEN+?
575 // Bit 14 is always unused, so leave it set
576 ENFORCE_SIZE_R(bits, address, 16, "DMACOUNT");
577 return (state.dma_count & 0x3fff) | 0xC000;
578 break;
579 case 0x070000: // Line Printer Status Register
580 data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD
581 data |= wd2797_get_irq(&state.fdc_ctx) ? 0x00080008 : 0;
582 data |= wd2010_get_irq(&state.hdc_ctx) ? 0x00040004 : 0;
583 return data;
584 break;
585 case 0x080000: // Real Time Clock
586 printf("READ NOTIMP: Realtime Clock\n");
587 break;
588 case 0x090000: // Phone registers
589 switch (address & 0x0FF000) {
590 case 0x090000: // Handset relay
591 case 0x098000:
592 break;
593 case 0x091000: // Line select 2
594 case 0x099000:
595 break;
596 case 0x092000: // Hook relay 1
597 case 0x09A000:
598 break;
599 case 0x093000: // Hook relay 2
600 case 0x09B000:
601 break;
602 case 0x094000: // Line 1 hold
603 case 0x09C000:
604 break;
605 case 0x095000: // Line 2 hold
606 case 0x09D000:
607 break;
608 case 0x096000: // Line 1 A-lead
609 case 0x09E000:
610 break;
611 case 0x097000: // Line 2 A-lead
612 case 0x09F000:
613 break;
614 }
615 break;
616 case 0x0A0000: // Miscellaneous Control Register -- write only!
617 handled = true;
618 break;
619 case 0x0B0000: // TM/DIALWR
620 break;
621 case 0x0C0000: // Clear Status Register -- write only!
622 handled = true;
623 break;
624 case 0x0D0000: // DMA Address Register
625 break;
626 case 0x0E0000: // Disk Control Register
627 break;
628 case 0x0F0000: // Line Printer Data Register
629 break;
630 }
631 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
632 // I/O register space, zone B
633 switch (address & 0xF00000) {
634 case 0xC00000: // Expansion slots
635 case 0xD00000:
636 switch (address & 0xFC0000) {
637 case 0xC00000: // Expansion slot 0
638 case 0xC40000: // Expansion slot 1
639 case 0xC80000: // Expansion slot 2
640 case 0xCC0000: // Expansion slot 3
641 case 0xD00000: // Expansion slot 4
642 case 0xD40000: // Expansion slot 5
643 case 0xD80000: // Expansion slot 6
644 case 0xDC0000: // Expansion slot 7
645 fprintf(stderr, "NOTE: RD%d from expansion card space, addr=0x%08X\n", bits, address);
646 handled = true;
647 break;
648 }
649 break;
650 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
651 case 0xF00000:
652 switch (address & 0x070000) {
653 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
654 return (wd2010_read_reg(&state.hdc_ctx, (address >> 1) & 7));
656 break;
657 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
658 /*ENFORCE_SIZE_R(bits, address, 16, "FDC REGISTERS");*/
659 return wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
660 break;
661 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
662 break;
663 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
664 break;
665 case 0x040000: // [ef][4c]xxxx ==> General Control Register
666 switch (address & 0x077000) {
667 case 0x040000: // [ef][4c][08]xxx ==> EE
668 case 0x041000: // [ef][4c][19]xxx ==> PIE
669 case 0x042000: // [ef][4c][2A]xxx ==> BP
670 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
671 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
672 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
673 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
674 // All write-only registers... TODO: bus error?
675 handled = true;
676 break;
677 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
678 break;
679 }
680 break;
681 case 0x050000: // [ef][5d]xxxx ==> 8274
682 break;
683 case 0x060000: // [ef][6e]xxxx ==> Control regs
684 switch (address & 0x07F000) {
685 default:
686 break;
687 }
688 break;
689 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
690 // TODO: figure out which sizes are valid (probably just 8 and 16)
691 //ENFORCE_SIZE_R(bits, address, 16, "KEYBOARD CONTROLLER");
692 {
693 if (bits == 8) {
694 return keyboard_read(&state.kbd, (address >> 1) & 3);
695 } else {
696 return keyboard_read(&state.kbd, (address >> 1) & 3) << 8;
697 }
698 return data;
699 }
700 break;
701 }
702 }
703 }
705 LOG_NOT_HANDLED_R(bits);
707 return data;
708 }/*}}}*/
711 /********************************************************
712 * m68k memory read/write support functions for Musashi
713 ********************************************************/
715 /**
716 * @brief Read M68K memory, 32-bit
717 */
718 uint32_t m68k_read_memory_32(uint32_t address)/*{{{*/
719 {
720 uint32_t data = 0xFFFFFFFF;
722 // If ROMLMAP is set, force system to access ROM
723 if (!state.romlmap)
724 address |= 0x800000;
726 // Check access permissions
727 ACCESS_CHECK_RD(address, 32);
729 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
730 // ROM access
731 return RD32(state.rom, address, ROM_SIZE - 1);
732 } else if (address <= 0x3fffff) {
733 // RAM access
734 uint32_t newAddr = mapAddr(address, false);
735 if (newAddr <= 0x1fffff) {
736 return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
737 } else {
738 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
739 return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
740 else
741 return 0xffffffff;
742 }
743 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
744 // I/O register space, zone A
745 switch (address & 0x0F0000) {
746 case 0x000000: // Map RAM access
747 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
748 return RD32(state.map, address, 0x7FF);
749 break;
750 case 0x020000: // Video RAM
751 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
752 return RD32(state.vram, address, 0x7FFF);
753 break;
754 default:
755 return IoRead(address, 32);
756 }
757 } else {
758 return IoRead(address, 32);
759 }
761 return data;
762 }/*}}}*/
764 /**
765 * @brief Read M68K memory, 16-bit
766 */
767 uint32_t m68k_read_memory_16(uint32_t address)/*{{{*/
768 {
769 uint16_t data = 0xFFFF;
771 // If ROMLMAP is set, force system to access ROM
772 if (!state.romlmap)
773 address |= 0x800000;
775 // Check access permissions
776 ACCESS_CHECK_RD(address, 16);
778 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
779 // ROM access
780 data = RD16(state.rom, address, ROM_SIZE - 1);
781 } else if (address <= 0x3fffff) {
782 // RAM access
783 uint32_t newAddr = mapAddr(address, false);
784 if (newAddr <= 0x1fffff) {
785 return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
786 } else {
787 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
788 return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
789 else
790 return 0xffff;
791 }
792 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
793 // I/O register space, zone A
794 switch (address & 0x0F0000) {
795 case 0x000000: // Map RAM access
796 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
797 data = RD16(state.map, address, 0x7FF);
798 break;
799 case 0x020000: // Video RAM
800 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
801 data = RD16(state.vram, address, 0x7FFF);
802 break;
803 default:
804 data = IoRead(address, 16);
805 }
806 } else {
807 data = IoRead(address, 16);
808 }
810 return data;
811 }/*}}}*/
813 /**
814 * @brief Read M68K memory, 8-bit
815 */
816 uint32_t m68k_read_memory_8(uint32_t address)/*{{{*/
817 {
818 uint8_t data = 0xFF;
820 // If ROMLMAP is set, force system to access ROM
821 if (!state.romlmap)
822 address |= 0x800000;
824 // Check access permissions
825 ACCESS_CHECK_RD(address, 8);
827 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
828 // ROM access
829 data = RD8(state.rom, address, ROM_SIZE - 1);
830 } else if (address <= 0x3fffff) {
831 // RAM access
832 uint32_t newAddr = mapAddr(address, false);
833 if (newAddr <= 0x1fffff) {
834 return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
835 } else {
836 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
837 return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
838 else
839 return 0xff;
840 }
841 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
842 // I/O register space, zone A
843 switch (address & 0x0F0000) {
844 case 0x000000: // Map RAM access
845 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
846 data = RD8(state.map, address, 0x7FF);
847 break;
848 case 0x020000: // Video RAM
849 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
850 data = RD8(state.vram, address, 0x7FFF);
851 break;
852 default:
853 data = IoRead(address, 8);
854 }
855 } else {
856 data = IoRead(address, 8);
857 }
859 return data;
860 }/*}}}*/
862 /**
863 * @brief Write M68K memory, 32-bit
864 */
865 void m68k_write_memory_32(uint32_t address, uint32_t value)/*{{{*/
866 {
867 // If ROMLMAP is set, force system to access ROM
868 if (!state.romlmap)
869 address |= 0x800000;
871 // Check access permissions
872 ACCESS_CHECK_WR(address, 32);
874 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
875 // ROM access
876 } else if (address <= 0x3FFFFF) {
877 // RAM access
878 uint32_t newAddr = mapAddr(address, true);
879 if (newAddr <= 0x1fffff)
880 WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
881 else
882 WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
883 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
884 // I/O register space, zone A
885 switch (address & 0x0F0000) {
886 case 0x000000: // Map RAM access
887 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X\n", address);
888 WR32(state.map, address, 0x7FF, value);
889 break;
890 case 0x020000: // Video RAM
891 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X\n", address);
892 WR32(state.vram, address, 0x7FFF, value);
893 break;
894 default:
895 IoWrite(address, value, 32);
896 }
897 } else {
898 IoWrite(address, value, 32);
899 }
900 }/*}}}*/
902 /**
903 * @brief Write M68K memory, 16-bit
904 */
905 void m68k_write_memory_16(uint32_t address, uint32_t value)/*{{{*/
906 {
907 // If ROMLMAP is set, force system to access ROM
908 if (!state.romlmap)
909 address |= 0x800000;
911 // Check access permissions
912 ACCESS_CHECK_WR(address, 16);
914 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
915 // ROM access
916 } else if (address <= 0x3FFFFF) {
917 // RAM access
918 uint32_t newAddr = mapAddr(address, true);
920 if (newAddr <= 0x1fffff)
921 WR16(state.base_ram, newAddr, state.base_ram_size - 1, value);
922 else
923 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
924 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
925 // I/O register space, zone A
926 switch (address & 0x0F0000) {
927 case 0x000000: // Map RAM access
928 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
929 WR16(state.map, address, 0x7FF, value);
930 break;
931 case 0x020000: // Video RAM
932 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
933 WR16(state.vram, address, 0x7FFF, value);
934 break;
935 default:
936 IoWrite(address, value, 16);
937 }
938 } else {
939 IoWrite(address, value, 16);
940 }
941 }/*}}}*/
943 /**
944 * @brief Write M68K memory, 8-bit
945 */
946 void m68k_write_memory_8(uint32_t address, uint32_t value)/*{{{*/
947 {
948 // If ROMLMAP is set, force system to access ROM
949 if (!state.romlmap)
950 address |= 0x800000;
952 // Check access permissions
953 ACCESS_CHECK_WR(address, 8);
955 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
956 // ROM access (read only!)
957 } else if (address <= 0x3FFFFF) {
958 // RAM access
959 uint32_t newAddr = mapAddr(address, true);
960 if (newAddr <= 0x1fffff)
961 WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
962 else
963 WR8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
964 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
965 // I/O register space, zone A
966 switch (address & 0x0F0000) {
967 case 0x000000: // Map RAM access
968 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
969 WR8(state.map, address, 0x7FF, value);
970 break;
971 case 0x020000: // Video RAM
972 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
973 WR8(state.vram, address, 0x7FFF, value);
974 break;
975 default:
976 IoWrite(address, value, 8);
977 }
978 } else {
979 IoWrite(address, value, 8);
980 }
981 }/*}}}*/
984 // for the disassembler
985 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
986 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
987 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }