Fri, 12 Apr 2013 16:26:25 +0100
Don't set PS1 if there is a level-7 interrupt or bus error
PS1 should only be set if the page was originally present (PS1 or PS0 set). If
PS0 and PS1 are clear (page not present) then do NOT set PS1.
Once again the TRM is blatantly and spectacularly wrong...
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
15 //#define EMPTY 0x00000000UL
17 /******************
18 * Memory mapping
19 ******************/
21 /// Set a page bit
22 #define MAP_SET_PAGEBIT(addr, bit) state.map[(MAP_ADDR_TO_PAGE(addr))*2] |= ((uint8_t)bit << 2)
23 /// Clear a page bit
24 #define MAP_CLR_PAGEBIT(addr, bit) state.map[(MAP_ADDR_TO_PAGE(addr))*2] &= ~((uint8_t)bit << 2)
27 /********************************************************
28 * m68k memory read/write support functions for Musashi
29 ********************************************************/
31 /**
32 * @brief Check memory access permissions for a write operation.
33 * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but
34 * gcc throws warnings when you have a return-with-value in a void
35 * function, even if the return-with-value is completely unreachable.
36 * Similarly it doesn't like it if you have a return without a value
37 * in a non-void function, even if it's impossible to ever reach the
38 * return-with-no-value. UGH!
39 */
40 /*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
41 #define ACCESS_CHECK_WR(address, bits) \
42 do { \
43 if (access_check_cpu(address, bits, true)) { \
44 return; \
45 } \
46 } while (0)
47 /*}}}*/
49 /**
50 * @brief Check memory access permissions for a read operation.
51 * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but
52 * gcc throws warnings when you have a return-with-value in a void
53 * function, even if the return-with-value is completely unreachable.
54 * Similarly it doesn't like it if you have a return without a value
55 * in a non-void function, even if it's impossible to ever reach the
56 * return-with-no-value. UGH!
57 */
58 /*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
59 #define ACCESS_CHECK_RD(address, bits) \
60 do { \
61 if (access_check_cpu(address, bits, false)) { \
62 if (bits == 32) \
63 return EMPTY & 0xFFFFFFFF; \
64 else \
65 return EMPTY & ((1UL << bits)-1); \
66 } \
67 } while (0)
68 /*}}}*/
71 /**
72 * Update the page bits for a given memory address
73 *
74 * @param addr Memory address being accessed
75 * @param l7intr Set to <i>true</i> if a level-seven interrupt has been
76 * signalled (even if <b>ENABLE ERROR</b> isn't set).
77 * @param write Set to <i>true</i> if the address is being written to.
78 */
79 static void update_page_bits(uint32_t addr, bool l7intr, bool write)
80 {
81 bool ps0_state = false;
83 // Don't try and update pagebits for non-RAM addresses
84 if (addr > 0x3FFFFF)
85 return;
87 if (l7intr) {
88 // if (!(MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) {
89 // FIXME FUCKUP The ruddy TRM is wrong AGAIN! If above line is uncommented, Really Bad Things Happen.
90 if ((MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) {
91 // Level 7 interrupt, PS0 set, PS1 don't-care. Set PS0.
92 ps0_state = true;
93 }
94 } else {
95 // No L7 interrupt
96 if ((write && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS1) && (MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) ||
97 (write && (MAP_PAGEBITS(addr) & PAGE_BIT_PS1) && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) ||
98 ( (MAP_PAGEBITS(addr) & PAGE_BIT_PS1) && (MAP_PAGEBITS(addr) & PAGE_BIT_PS0))) /* NOTE -- Once again, this case was missing from the PAL equations in the TRM... */
99 {
100 // No L7 interrupt, PS[1:0] = 0b01, write
101 // No L7 interrupt, PS[1:0] = 0b10, write
102 ps0_state = true;
103 }
104 }
106 #ifdef MAPRAM_BIT_TEST
107 LOG("Starting Mapram Bit Test");
108 state.map[0] = state.map[1] = 0;
109 LOG("Start = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
110 MAP_SET_PAGEBIT(0, PAGE_BIT_WE);
111 LOG("Set WE = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
112 MAP_SET_PAGEBIT(0, PAGE_BIT_PS1);
113 LOG("Set PS1 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
114 MAP_SET_PAGEBIT(0, PAGE_BIT_PS0);
115 LOG("Set PS0 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
117 MAP_CLR_PAGEBIT(0, PAGE_BIT_WE);
118 LOG("Clr WE = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
119 MAP_CLR_PAGEBIT(0, PAGE_BIT_PS1);
120 LOG("Clr PS1 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
121 MAP_CLR_PAGEBIT(0, PAGE_BIT_PS0);
122 LOG("Clr PS0 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
123 exit(-1);
124 #endif
126 if (!l7intr) {
127 // PS1 is always set on access if no fault
128 MAP_SET_PAGEBIT(addr, PAGE_BIT_PS1);
130 // Update PS0
131 if (ps0_state) {
132 MAP_SET_PAGEBIT(addr, PAGE_BIT_PS0);
133 } else {
134 MAP_CLR_PAGEBIT(addr, PAGE_BIT_PS0);
135 }
136 }
138 #ifdef MAPRAM_DEBUG_MESSAGES
139 uint16_t new_pagebit2 = MAP_PAGEBITS(addr);
140 switch (addr) {
141 case 0x000000:
142 case 0x001000:
143 case 0x002000:
144 case 0x003000:
145 case 0x004000:
146 case 0x033000:
147 case 0x034000:
148 case 0x035000:
149 LOG("Addr %08X %s MapNew %04X Page %04X -- Pagebit update -- ps0 %d, old %s%s => %s%s => %s%s",
150 addr,
151 write ? "Wr" : "Rd",
152 MAPRAM_ADDR(addr),
153 MAP_ADDR_TO_PAGE(addr),
154 ps0_state,
155 old_pagebits & PAGE_BIT_PS0 ? "PS0" : "",
156 old_pagebits & PAGE_BIT_PS1 ? "PS1" : "",
157 new_pagebit1 & PAGE_BIT_PS0 ? "PS0" : "",
158 new_pagebit1 & PAGE_BIT_PS1 ? "PS1" : "",
159 new_pagebit2 & PAGE_BIT_PS0 ? "PS0" : "",
160 new_pagebit2 & PAGE_BIT_PS1 ? "PS1" : ""
161 );
162 default:
163 break;
164 }
165 #endif // MAPRAM_DEBUG_MESSAGES
166 }
168 bool access_check_dma(void)
169 {
170 // TODO FIXME BUGBUG Sanity check - Make sure DMAC is only accessing RAM addresses
172 // DMA access check -- make sure the page is mapped in
173 if (!(MAP_PAGEBITS(state.dma_address) & PAGE_BIT_PS0) && !(MAP_PAGEBITS(state.dma_address) & PAGE_BIT_PS1)) {
174 // DMA access to page which is not mapped in.
175 // Level 7 interrupt, page fault, DMA invoked
176 state.genstat = 0xABFF
177 | (state.dma_reading ? 0x4000 : 0)
178 | (state.pie ? 0x0400 : 0);
180 // XXX: Check all this stuff.
181 state.bsr0 = 0x3C00;
182 state.bsr0 |= (state.dma_address >> 16);
183 state.bsr1 = state.dma_address & 0xffff;
185 // Update page bits for this transfer
186 update_page_bits(state.dma_address, true, !state.dma_reading);
188 // XXX: is this right?
189 // Fire a Level 7 interrupt
190 /*if (state.ee)*/ m68k_set_irq(7);
192 LOG("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
193 return false;
194 } else {
195 // No errors. Just update the page bits.
196 update_page_bits(state.dma_address, false, !state.dma_reading);
197 return true;
198 }
199 }
201 /**
202 * Check memory access permissions for a CPU memory access.
203 *
204 * @param addr Virtual memory address being accessed (from CPU address bus).
205 * @param bits Word size of this transfer (8, 16 or 32 bits).
206 * @param write <i>true</i> if this is a write operation, <i>false</i> if it is a read operation.
207 * @return <i>true</i> if the access was denied and a level-7 interrupt and/or bus error raised.
208 * <i>false</i> if the access was allowed.
209 */
210 bool access_check_cpu(uint32_t addr, int bits, bool write)
211 {
212 bool supervisor = (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000);
213 bool fault = false;
215 // TODO FIXME BUGBUG? Do we need to check for supervisor access here?
216 if ((addr >= 0x000000) && (addr <= 0x3FFFFF) && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS1) && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) {
217 // (A) Page Fault -- user access to page which is not mapped in
218 // Level 7 Interrupt, Bus Error, regs=PAGEFAULT
219 if (write) {
220 state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0);
221 } else {
222 state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0);
223 }
224 fault = true;
225 } else if (!supervisor && (addr >= 0x000000) && (addr <= 0x07FFFF)) {
226 // (B) User attempted to access the kernel
227 // Level 7 Interrupt, Bus Error, regs=KERNEL
228 if (write) {
229 // XXX: BUGBUG? Is this correct?
230 state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0);
231 } else {
232 state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0);
233 }
234 fault = true;
235 } else if (!supervisor && write && (addr >= 0x000000) && (addr <= 0x3FFFFF) && !(MAP_PAGEBITS(addr) & PAGE_BIT_WE)) {
236 // (C) User attempted to write to a page which is not write enabled
237 // Level 7 Interrupt, Bus Error, regs=WRITE_EN
238 if (write) {
239 // XXX: BUGBUG? Is this correct?
240 state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0);
241 } else {
242 state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0);
243 }
244 fault = true;
245 } else if (!supervisor && (addr >= 0x400000) && (addr <= 0xFFFFFF)) {
246 // (D) UIE - user I/O exception
247 // Bus Error only, regs=UIE
248 if (write) {
249 state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0);
250 } else {
251 state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0);
252 }
253 fault = true;
254 }
256 unsigned char pagebits_preup = MAP_PAGEBITS(addr & 0x3fffff);
258 // Update the page bits first
259 update_page_bits(addr, fault, write);
261 if (fault) {
262 if (bits >= 16)
263 state.bsr0 = 0x7C00;
264 else
265 state.bsr0 = (addr & 1) ? 0x7E00 : 0x7D00;
266 // FIXME? Physical or virtual address here?
267 state.bsr0 |= (addr >> 16);
268 state.bsr1 = addr & 0xffff;
270 LOG("CPU Bus Error or L7Intr while %s, vaddr %08X, map %08X, pagebits 0x%02X=>0x%02X bsr0=%04X bsr1=%04X genstat=%04X",
271 write ? "writing" : "reading", addr,
272 MAPRAM_ADDR(addr & 0x3fffff),
273 pagebits_preup,
274 MAP_PAGEBITS(addr & 0x3fffff),
275 state.bsr0, state.bsr1, state.genstat);
277 // FIXME? BUGBUG? Does EE disable one or both of these?
278 // /*if (state.ee)*/ m68k_set_irq(7);
279 /*if (state.ee)*/ m68k_pulse_bus_error();
280 }
282 return fault;
283 }
285 // Logging macros
286 #define LOG_NOT_HANDLED_R(bits) \
287 if (!handled) fprintf(stderr, "unhandled read%02d, addr=0x%08X\n", bits, address);
289 #define LOG_NOT_HANDLED_W(bits) \
290 if (!handled) fprintf(stderr, "unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
292 /********************************************************
293 * I/O read/write functions
294 ********************************************************/
296 /**
297 * Issue a warning if a read operation is made with an invalid size
298 */
299 inline static void ENFORCE_SIZE(int bits, uint32_t address, bool read, int allowed, char *regname)
300 {
301 assert((bits == 8) || (bits == 16) || (bits == 32));
302 if ((bits & allowed) == 0) {
303 LOG("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
304 }
305 }
307 inline static void ENFORCE_SIZE_R(int bits, uint32_t address, int allowed, char *regname)
308 {
309 ENFORCE_SIZE(bits, address, true, allowed, regname);
310 }
312 inline static void ENFORCE_SIZE_W(int bits, uint32_t address, int allowed, char *regname)
313 {
314 ENFORCE_SIZE(bits, address, false, allowed, regname);
315 }
317 void IoWrite(uint32_t address, uint32_t data, int bits)/*{{{*/
318 {
319 bool handled = false;
321 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
322 // I/O register space, zone A
323 switch (address & 0x0F0000) {
324 case 0x010000: // General Status Register
325 if (bits == 16)
326 state.genstat = (data & 0xffff);
327 else if (bits == 8) {
328 if (address & 0)
329 state.genstat = data;
330 else
331 state.genstat = data << 8;
332 }
333 handled = true;
334 break;
335 case 0x030000: // Bus Status Register 0
336 break;
337 case 0x040000: // Bus Status Register 1
338 break;
339 case 0x050000: // Phone status
340 break;
341 case 0x060000: // DMA Count
342 ENFORCE_SIZE_W(bits, address, 16, "DMACOUNT");
343 state.dma_count = (data & 0x3FFF);
344 state.idmarw = ((data & 0x4000) == 0x4000);
345 state.dmaen = ((data & 0x8000) == 0x8000);
346 // This handles the "dummy DMA transfer" mentioned in the docs
347 // disabled because it causes the floppy test to fail
348 #if 0
349 if (!state.idmarw){
350 if (access_check_dma(true)){
351 uint32_t newAddr = mapAddr(state.dma_address, true);
352 // RAM access
353 if (newAddr <= 0x1fffff)
354 WR16(state.base_ram, newAddr, state.base_ram_size - 1, 0xFF);
355 else if (address <= 0x3FFFFF)
356 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, 0xFF);
357 }
358 }
359 #endif
360 state.dma_count++;
361 handled = true;
362 break;
363 case 0x070000: // Line Printer Status Register
364 break;
365 case 0x080000: // Real Time Clock
366 LOGS("REAL TIME CLOCK WRITE");
367 break;
368 case 0x090000: // Phone registers
369 switch (address & 0x0FF000) {
370 case 0x090000: // Handset relay
371 case 0x098000:
372 break;
373 case 0x091000: // Line select 2
374 case 0x099000:
375 break;
376 case 0x092000: // Hook relay 1
377 case 0x09A000:
378 break;
379 case 0x093000: // Hook relay 2
380 case 0x09B000:
381 break;
382 case 0x094000: // Line 1 hold
383 case 0x09C000:
384 break;
385 case 0x095000: // Line 2 hold
386 case 0x09D000:
387 break;
388 case 0x096000: // Line 1 A-lead
389 case 0x09E000:
390 break;
391 case 0x097000: // Line 2 A-lead
392 case 0x09F000:
393 break;
394 }
395 break;
396 case 0x0A0000: // Miscellaneous Control Register
397 ENFORCE_SIZE_W(bits, address, 16, "MISCCON");
398 // TODO: handle the ctrl bits properly
399 if (data & 0x8000){
400 state.timer_enabled = 1;
401 }else{
402 state.timer_enabled = 0;
403 state.timer_asserted = 0;
404 }
405 state.dma_reading = (data & 0x4000);
406 if (state.leds != ((~data & 0xF00) >> 8)) {
407 state.leds = (~data & 0xF00) >> 8;
408 #ifdef SHOW_LEDS
409 printf("LEDs: %s %s %s %s\n",
410 (state.leds & 8) ? "R" : "-",
411 (state.leds & 4) ? "G" : "-",
412 (state.leds & 2) ? "Y" : "-",
413 (state.leds & 1) ? "R" : "-");
414 #endif
415 }
416 handled = true;
417 break;
418 case 0x0B0000: // TM/DIALWR
419 break;
420 case 0x0C0000: // Clear Status Register
421 state.genstat = 0xFFFF;
422 state.bsr0 = 0xFFFF;
423 state.bsr1 = 0xFFFF;
424 handled = true;
425 break;
426 case 0x0D0000: // DMA Address Register
427 if (address & 0x004000) {
428 // A14 high -- set most significant bits
429 state.dma_address = (state.dma_address & 0x1fe) | ((address & 0x3ffe) << 8);
430 } else {
431 // A14 low -- set least significant bits
432 state.dma_address = (state.dma_address & 0x3ffe00) | (address & 0x1fe);
433 }
434 handled = true;
435 break;
436 case 0x0E0000: // Disk Control Register
437 {
438 bool fd_selected;
439 bool hd_selected;
440 ENFORCE_SIZE_W(bits, address, 16, "DISKCON");
441 // B7 = FDD controller reset
442 if ((data & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
443 // B6 = drive 0 select
444 fd_selected = (data & 0x40) != 0;
445 // B5 = motor enable -- TODO
446 // B4 = HDD controller reset
447 if ((data & 0x10) == 0) wd2010_reset(&state.hdc_ctx);
448 // B3 = HDD0 select
449 hd_selected = (data & 0x08) != 0;
450 // B2,1,0 = HDD0 head select -- TODO?
451 if (hd_selected && !state.hd_selected){
452 state.fd_selected = false;
453 state.hd_selected = true;
454 }else if (fd_selected && !state.fd_selected){
455 state.hd_selected = false;
456 state.fd_selected = true;
457 }
458 handled = true;
459 break;
460 }
461 case 0x0F0000: // Line Printer Data Register
462 break;
463 }
464 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
465 // I/O register space, zone B
466 switch (address & 0xF00000) {
467 case 0xC00000: // Expansion slots
468 case 0xD00000:
469 switch (address & 0xFC0000) {
470 case 0xC00000: // Expansion slot 0
471 case 0xC40000: // Expansion slot 1
472 case 0xC80000: // Expansion slot 2
473 case 0xCC0000: // Expansion slot 3
474 case 0xD00000: // Expansion slot 4
475 case 0xD40000: // Expansion slot 5
476 case 0xD80000: // Expansion slot 6
477 case 0xDC0000: // Expansion slot 7
478 fprintf(stderr, "NOTE: WR%d to expansion card space, addr=0x%08X, data=0x%08X\n", bits, address, data);
479 handled = true;
480 break;
481 }
482 break;
483 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
484 case 0xF00000:
485 switch (address & 0x070000) {
486 case 0x000000: // [ef][08]xxxx ==> WD2010 hard disc controller
487 wd2010_write_reg(&state.hdc_ctx, (address >> 1) & 7, data);
488 handled = true;
489 break;
490 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
491 /*ENFORCE_SIZE_W(bits, address, 16, "FDC REGISTERS");*/
492 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, data);
493 handled = true;
494 break;
495 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
496 // MCR2 - UNIX PC Rev. P5.1 HDD head select b3 and potential HDD#2 select
497 wd2010_write_reg(&state.hdc_ctx, UNIXPC_REG_MCR2, data);
498 handled = true;
499 break;
500 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
501 LOGS("REAL TIME CLOCK DATA WRITE");
502 break;
503 case 0x040000: // [ef][4c]xxxx ==> General Control Register
504 switch (address & 0x077000) {
505 case 0x040000: // [ef][4c][08]xxx ==> EE
506 // Error Enable. If =0, Level7 intrs and bus errors are masked.
507 ENFORCE_SIZE_W(bits, address, 16, "EE");
508 state.ee = ((data & 0x8000) == 0x8000);
509 handled = true;
510 break;
511 case 0x041000: // [ef][4c][19]xxx ==> PIE
512 ENFORCE_SIZE_W(bits, address, 16, "PIE");
513 state.pie = ((data & 0x8000) == 0x8000);
514 handled = true;
515 break;
516 case 0x042000: // [ef][4c][2A]xxx ==> BP
517 break;
518 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
519 ENFORCE_SIZE_W(bits, address, 16, "ROMLMAP");
520 state.romlmap = ((data & 0x8000) == 0x8000);
521 handled = true;
522 break;
523 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
524 ENFORCE_SIZE_W(bits, address, 16, "L1 MODEM");
525 break;
526 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
527 ENFORCE_SIZE_W(bits, address, 16, "L2 MODEM");
528 break;
529 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
530 ENFORCE_SIZE_W(bits, address, 16, "D/N CONNECT");
531 break;
532 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
533 ENFORCE_SIZE_W(bits, address, 16, "WHOLE SCREEN REVERSE VIDEO");
534 break;
535 }
536 case 0x050000: // [ef][5d]xxxx ==> 8274
537 break;
538 case 0x060000: // [ef][6e]xxxx ==> Control regs
539 switch (address & 0x07F000) {
540 default:
541 break;
542 }
543 break;
544 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
545 // TODO: figure out which sizes are valid (probably just 8 and 16)
546 // ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
547 if (bits == 8) {
548 #ifdef LOG_KEYBOARD_WRITES
549 LOG("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
550 #endif
551 keyboard_write(&state.kbd, (address >> 1) & 3, data);
552 handled = true;
553 } else if (bits == 16) {
554 #ifdef LOG_KEYBOARD_WRITES
555 LOG("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
556 #endif
557 keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
558 handled = true;
559 }
560 break;
561 }
562 }
563 }
565 LOG_NOT_HANDLED_W(bits);
566 }/*}}}*/
568 uint32_t IoRead(uint32_t address, int bits)/*{{{*/
569 {
570 bool handled = false;
571 uint32_t data = EMPTY & 0xFFFFFFFF;
573 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
574 // I/O register space, zone A
575 switch (address & 0x0F0000) {
576 case 0x010000: // General Status Register
577 /* ENFORCE_SIZE_R(bits, address, 16, "GENSTAT"); */
578 if (bits == 32) {
579 return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
580 } else if (bits == 16) {
581 return (uint16_t)state.genstat;
582 } else {
583 return (uint8_t)(state.genstat & 0xff);
584 }
585 break;
586 case 0x030000: // Bus Status Register 0
587 ENFORCE_SIZE_R(bits, address, 16, "BSR0");
588 return ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
589 break;
590 case 0x040000: // Bus Status Register 1
591 ENFORCE_SIZE_R(bits, address, 16, "BSR1");
592 return ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
593 break;
594 case 0x050000: // Phone status
595 ENFORCE_SIZE_R(bits, address, 8 | 16, "PHONE STATUS");
596 break;
597 case 0x060000: // DMA Count
598 // TODO: U/OERR- is always inactive (bit set)... or should it be = DMAEN+?
599 // Bit 14 is always unused, so leave it set
600 ENFORCE_SIZE_R(bits, address, 16, "DMACOUNT");
601 return (state.dma_count & 0x3fff) | 0xC000;
602 break;
603 case 0x070000: // Line Printer Status Register
604 data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD
605 data |= wd2797_get_irq(&state.fdc_ctx) ? 0x00080008 : 0;
606 data |= wd2010_get_irq(&state.hdc_ctx) ? 0x00040004 : 0;
607 return data;
608 break;
609 case 0x080000: // Real Time Clock
610 LOGS("REAL TIME CLOCK READ");
611 break;
612 case 0x090000: // Phone registers
613 switch (address & 0x0FF000) {
614 case 0x090000: // Handset relay
615 case 0x098000:
616 break;
617 case 0x091000: // Line select 2
618 case 0x099000:
619 break;
620 case 0x092000: // Hook relay 1
621 case 0x09A000:
622 break;
623 case 0x093000: // Hook relay 2
624 case 0x09B000:
625 break;
626 case 0x094000: // Line 1 hold
627 case 0x09C000:
628 break;
629 case 0x095000: // Line 2 hold
630 case 0x09D000:
631 break;
632 case 0x096000: // Line 1 A-lead
633 case 0x09E000:
634 break;
635 case 0x097000: // Line 2 A-lead
636 case 0x09F000:
637 break;
638 }
639 break;
640 case 0x0A0000: // Miscellaneous Control Register -- write only!
641 handled = true;
642 break;
643 case 0x0B0000: // TM/DIALWR
644 break;
645 case 0x0C0000: // Clear Status Register -- write only!
646 handled = true;
647 break;
648 case 0x0D0000: // DMA Address Register
649 break;
650 case 0x0E0000: // Disk Control Register
651 break;
652 case 0x0F0000: // Line Printer Data Register
653 break;
654 }
655 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
656 // I/O register space, zone B
657 switch (address & 0xF00000) {
658 case 0xC00000: // Expansion slots
659 case 0xD00000:
660 switch (address & 0xFC0000) {
661 case 0xC00000: // Expansion slot 0
662 case 0xC40000: // Expansion slot 1
663 case 0xC80000: // Expansion slot 2
664 case 0xCC0000: // Expansion slot 3
665 case 0xD00000: // Expansion slot 4
666 case 0xD40000: // Expansion slot 5
667 case 0xD80000: // Expansion slot 6
668 case 0xDC0000: // Expansion slot 7
669 fprintf(stderr, "NOTE: RD%d from expansion card space, addr=0x%08X\n", bits, address);
670 handled = true;
671 break;
672 }
673 break;
674 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
675 case 0xF00000:
676 switch (address & 0x070000) {
677 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
678 return (wd2010_read_reg(&state.hdc_ctx, (address >> 1) & 7));
680 break;
681 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
682 /*ENFORCE_SIZE_R(bits, address, 16, "FDC REGISTERS");*/
683 return wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
684 break;
685 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
686 break;
687 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
688 LOGS("REAL TIME CLOCK DATA READ");
689 break;
690 case 0x040000: // [ef][4c]xxxx ==> General Control Register
691 switch (address & 0x077000) {
692 case 0x040000: // [ef][4c][08]xxx ==> EE
693 case 0x041000: // [ef][4c][19]xxx ==> PIE
694 case 0x042000: // [ef][4c][2A]xxx ==> BP
695 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
696 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
697 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
698 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
699 // All write-only registers... TODO: bus error?
700 handled = true;
701 break;
702 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
703 break;
704 }
705 break;
706 case 0x050000: // [ef][5d]xxxx ==> 8274
707 break;
708 case 0x060000: // [ef][6e]xxxx ==> Control regs
709 switch (address & 0x07F000) {
710 default:
711 break;
712 }
713 break;
714 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
715 // TODO: figure out which sizes are valid (probably just 8 and 16)
716 //ENFORCE_SIZE_R(bits, address, 16, "KEYBOARD CONTROLLER");
717 {
718 if (bits == 8) {
719 return keyboard_read(&state.kbd, (address >> 1) & 3);
720 } else {
721 return keyboard_read(&state.kbd, (address >> 1) & 3) << 8;
722 }
723 return data;
724 }
725 break;
726 }
727 }
728 }
730 LOG_NOT_HANDLED_R(bits);
732 return data;
733 }/*}}}*/
736 /********************************************************
737 * m68k memory read/write support functions for Musashi
738 ********************************************************/
740 /**
741 * @brief Read M68K memory, 32-bit
742 */
743 uint32_t m68k_read_memory_32(uint32_t address)/*{{{*/
744 {
745 uint32_t data = EMPTY & 0xFFFFFFFF;
747 // If ROMLMAP is set, force system to access ROM
748 if (!state.romlmap)
749 address |= 0x800000;
751 // Check access permissions
752 ACCESS_CHECK_RD(address, 32);
754 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
755 // ROM access
756 return RD32(state.rom, address, ROM_SIZE - 1);
757 } else if (address <= 0x3fffff) {
758 // RAM access
759 uint32_t newAddr = MAP_ADDR(address);
761 if (newAddr <= 0x1fffff) {
762 // Base memory wraps around
763 return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
764 } else {
765 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
766 return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
767 else
768 return EMPTY & 0xffffffff;
769 }
770 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
771 // I/O register space, zone A
772 switch (address & 0x0F0000) {
773 case 0x000000: // Map RAM access
774 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
775 return RD32(state.map, address, 0x7FF);
776 break;
777 case 0x020000: // Video RAM
778 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
779 return RD32(state.vram, address, 0x7FFF);
780 break;
781 default:
782 return IoRead(address, 32);
783 }
784 } else {
785 return IoRead(address, 32);
786 }
788 return data;
789 }/*}}}*/
791 /**
792 * @brief Read M68K memory, 16-bit
793 */
794 uint32_t m68k_read_memory_16(uint32_t address)/*{{{*/
795 {
796 uint16_t data = EMPTY & 0xFFFF;
798 // If ROMLMAP is set, force system to access ROM
799 if (!state.romlmap)
800 address |= 0x800000;
802 // Check access permissions
803 ACCESS_CHECK_RD(address, 16);
805 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
806 // ROM access
807 data = RD16(state.rom, address, ROM_SIZE - 1);
808 } else if (address <= 0x3fffff) {
809 // RAM access
810 uint32_t newAddr = MAP_ADDR(address);
812 if (newAddr <= 0x1fffff) {
813 // Base memory wraps around
814 return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
815 } else {
816 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
817 return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
818 else
819 return EMPTY & 0xffff;
820 }
821 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
822 // I/O register space, zone A
823 switch (address & 0x0F0000) {
824 case 0x000000: // Map RAM access
825 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
826 data = RD16(state.map, address, 0x7FF);
827 break;
828 case 0x020000: // Video RAM
829 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
830 data = RD16(state.vram, address, 0x7FFF);
831 break;
832 default:
833 data = IoRead(address, 16);
834 }
835 } else {
836 data = IoRead(address, 16);
837 }
839 return data;
840 }/*}}}*/
842 /**
843 * @brief Read M68K memory, 8-bit
844 */
845 uint32_t m68k_read_memory_8(uint32_t address)/*{{{*/
846 {
847 uint8_t data = EMPTY & 0xFF;
849 // If ROMLMAP is set, force system to access ROM
850 if (!state.romlmap)
851 address |= 0x800000;
853 // Check access permissions
854 ACCESS_CHECK_RD(address, 8);
856 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
857 // ROM access
858 data = RD8(state.rom, address, ROM_SIZE - 1);
859 } else if (address <= 0x3fffff) {
860 // RAM access
861 uint32_t newAddr = MAP_ADDR(address);
863 if (newAddr <= 0x1fffff) {
864 // Base memory wraps around
865 return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
866 } else {
867 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
868 return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
869 else
870 return EMPTY & 0xff;
871 }
872 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
873 // I/O register space, zone A
874 switch (address & 0x0F0000) {
875 case 0x000000: // Map RAM access
876 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
877 data = RD8(state.map, address, 0x7FF);
878 break;
879 case 0x020000: // Video RAM
880 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
881 data = RD8(state.vram, address, 0x7FFF);
882 break;
883 default:
884 data = IoRead(address, 8);
885 }
886 } else {
887 data = IoRead(address, 8);
888 }
890 return data;
891 }/*}}}*/
893 /**
894 * @brief Write M68K memory, 32-bit
895 */
896 void m68k_write_memory_32(uint32_t address, uint32_t value)/*{{{*/
897 {
898 // If ROMLMAP is set, force system to access ROM
899 if (!state.romlmap)
900 address |= 0x800000;
902 // Check access permissions
903 ACCESS_CHECK_WR(address, 32);
905 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
906 // ROM access
907 } else if (address <= 0x3FFFFF) {
908 // RAM access
909 uint32_t newAddr = MAP_ADDR(address);
911 if (newAddr <= 0x1fffff) {
912 if (newAddr < state.base_ram_size) {
913 WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
914 }
915 } else {
916 if ((newAddr - 0x200000) < state.exp_ram_size) {
917 WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
918 }
919 }
920 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
921 // I/O register space, zone A
922 switch (address & 0x0F0000) {
923 case 0x000000: // Map RAM access
924 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X\n", address);
925 WR32(state.map, address, 0x7FF, value);
926 break;
927 case 0x020000: // Video RAM
928 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X\n", address);
929 WR32(state.vram, address, 0x7FFF, value);
930 break;
931 default:
932 IoWrite(address, value, 32);
933 }
934 } else {
935 IoWrite(address, value, 32);
936 }
937 }/*}}}*/
939 /**
940 * @brief Write M68K memory, 16-bit
941 */
942 void m68k_write_memory_16(uint32_t address, uint32_t value)/*{{{*/
943 {
944 // If ROMLMAP is set, force system to access ROM
945 if (!state.romlmap)
946 address |= 0x800000;
948 // Check access permissions
949 ACCESS_CHECK_WR(address, 16);
951 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
952 // ROM access
953 } else if (address <= 0x3FFFFF) {
954 // RAM access
955 uint32_t newAddr = MAP_ADDR(address);
957 if (newAddr <= 0x1fffff) {
958 if (newAddr < state.base_ram_size) {
959 WR16(state.base_ram, newAddr, state.base_ram_size - 1, value);
960 }
961 } else {
962 if ((newAddr - 0x200000) < state.exp_ram_size) {
963 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
964 }
965 }
966 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
967 // I/O register space, zone A
968 switch (address & 0x0F0000) {
969 case 0x000000: // Map RAM access
970 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
971 WR16(state.map, address, 0x7FF, value);
972 break;
973 case 0x020000: // Video RAM
974 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
975 WR16(state.vram, address, 0x7FFF, value);
976 break;
977 default:
978 IoWrite(address, value, 16);
979 }
980 } else {
981 IoWrite(address, value, 16);
982 }
983 }/*}}}*/
985 /**
986 * @brief Write M68K memory, 8-bit
987 */
988 void m68k_write_memory_8(uint32_t address, uint32_t value)/*{{{*/
989 {
990 // If ROMLMAP is set, force system to access ROM
991 if (!state.romlmap)
992 address |= 0x800000;
994 // Check access permissions
995 ACCESS_CHECK_WR(address, 8);
997 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
998 // ROM access (read only!)
999 } else if (address <= 0x3FFFFF) {
1000 // RAM access
1001 uint32_t newAddr = MAP_ADDR(address);
1003 if (newAddr <= 0x1fffff) {
1004 if (newAddr < state.base_ram_size) {
1005 WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
1006 }
1007 } else {
1008 if ((newAddr - 0x200000) < state.exp_ram_size) {
1009 WR8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
1010 }
1011 }
1012 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
1013 // I/O register space, zone A
1014 switch (address & 0x0F0000) {
1015 case 0x000000: // Map RAM access
1016 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
1017 WR8(state.map, address, 0x7FF, value);
1018 break;
1019 case 0x020000: // Video RAM
1020 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
1021 WR8(state.vram, address, 0x7FFF, value);
1022 break;
1023 default:
1024 IoWrite(address, value, 8);
1025 }
1026 } else {
1027 IoWrite(address, value, 8);
1028 }
1029 }/*}}}*/
1032 // for the disassembler
1033 uint32_t m68k_read_disassembler_32(uint32_t addr)
1034 {
1035 if (addr < 0x400000) {
1036 // XXX FIXME BUGBUG update this to use the new mapper macros!
1037 uint16_t page = (addr >> 12) & 0x3FF;
1038 uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
1039 uint32_t newAddr = (new_page_addr << 12) + (addr & 0xFFF);
1040 if (newAddr <= 0x1fffff) {
1041 if (newAddr >= state.base_ram_size)
1042 return EMPTY;
1043 else
1044 return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
1045 } else {
1046 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
1047 return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
1048 else
1049 return EMPTY;
1050 }
1051 } else {
1052 LOG("WARNING: Disassembler RD32 out of range 0x%08X\n", addr);
1053 return EMPTY;
1054 }
1055 }
1057 uint32_t m68k_read_disassembler_16(uint32_t addr)
1058 {
1059 if (addr < 0x400000) {
1060 uint16_t page = (addr >> 12) & 0x3FF;
1061 uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
1062 uint32_t newAddr = (new_page_addr << 12) + (addr & 0xFFF);
1063 if (newAddr <= 0x1fffff) {
1064 if (newAddr >= state.base_ram_size)
1065 return EMPTY & 0xffff;
1066 else
1067 return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
1068 } else {
1069 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
1070 return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
1071 else
1072 return EMPTY & 0xffff;
1073 }
1074 } else {
1075 LOG("WARNING: Disassembler RD16 out of range 0x%08X\n", addr);
1076 return EMPTY & 0xffff;
1077 }
1078 }
1080 uint32_t m68k_read_disassembler_8 (uint32_t addr)
1081 {
1082 if (addr < 0x400000) {
1083 uint16_t page = (addr >> 12) & 0x3FF;
1084 uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
1085 uint32_t newAddr = (new_page_addr << 12) + (addr & 0xFFF);
1086 if (newAddr <= 0x1fffff) {
1087 if (newAddr >= state.base_ram_size)
1088 return EMPTY & 0xff;
1089 else
1090 return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
1091 } else {
1092 if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
1093 return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
1094 else
1095 return EMPTY & 0xff;
1096 }
1097 } else {
1098 LOG("WARNING: Disassembler RD8 out of range 0x%08X\n", addr);
1099 return EMPTY & 0xff;
1100 }
1101 }