src/memory.c

Tue, 15 Nov 2011 10:12:37 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 15 Nov 2011 10:12:37 +0000
changeset 109
2f8afb9e5baa
parent 108
5f7faf5ecbf4
child 112
a392eb8f9806
permissions
-rw-r--r--

[musashi] Fix handling of bus errors

Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-MessageID: <4EC200CE.2020304@gmail.com>

I have fixed the first page fault test failure in FreeBee (the page fault test now hangs rather than errors out, because it is trying to read from the hard drive to test DMA page faults).

There were actually two bugs (the first bug was masking the second one).

First, the ancient version of Musashi that you used is unable to properly resume from bus errors that happen in the middle of certain instructions (some instructions are fetched in stages, with the PC being advanced to each part of the instruction, so basically what happens is the CPU core attempts to read the memory location referenced by the first operand, the bus error occurs, causing the PC to jump to the exception vector, but the faulting instruction is still in the middle of being fetched, so the PC is then advanced past the beginning of the exception handler). I fixed this by delaying the jump to the bus error vector until after the faulting instruction finishes.

The second bug is simpler - you had the UDS and LDS bits in BSR0 inverted (they are supposed to be active low).

     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 				/* FIXME: which regs need setting? */				\
   148 				fault = true;										\
   149 				break;												\
   150 		}															\
   151 																	\
   152 		if (fault) {												\
   153 			if (bits >= 16)											\
   154 				state.bsr0 = 0x7C00;								\
   155 			else													\
   156 				state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00;		\
   157 			state.bsr0 |= (address >> 16);							\
   158 			state.bsr1 = address & 0xffff;							\
   159 			LOG("Bus Error while writing, addr %08X, statcode %d", address, st);		\
   160 			if (state.ee) m68k_pulse_bus_error();					\
   161 			return;													\
   162 		}															\
   163 	} while (0)
   164 /*}}}*/
   166 /**
   167  * @brief Check memory access permissions for a read operation.
   168  * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
   169  * 			gcc throws warnings when you have a return-with-value in a void
   170  * 			function, even if the return-with-value is completely unreachable.
   171  * 			Similarly it doesn't like it if you have a return without a value
   172  * 			in a non-void function, even if it's impossible to ever reach the
   173  * 			return-with-no-value. UGH!
   174  */
   175 /*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
   176 #define ACCESS_CHECK_RD(address, bits)								\
   177 	do {															\
   178 		bool fault = false;											\
   179 		MEM_STATUS st;												\
   180 		switch (st = checkMemoryAccess(address, false)) {			\
   181 			case MEM_ALLOWED:										\
   182 				/* Access allowed */								\
   183 				break;												\
   184 			case MEM_PAGEFAULT:										\
   185 				/* Page fault */									\
   186 				state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0);	\
   187 				fault = true;										\
   188 				break;												\
   189 			case MEM_UIE:											\
   190 				/* User access to memory above 4MB */				\
   191 				state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0);	\
   192 				fault = true;										\
   193 				break;												\
   194 			case MEM_KERNEL:										\
   195 			case MEM_PAGE_NO_WE:									\
   196 				/* kernel access or page not write enabled */		\
   197 				/* FIXME: which regs need setting? */				\
   198 				fault = true;										\
   199 				break;												\
   200 		}															\
   201 																	\
   202 		if (fault) {												\
   203 			if (bits >= 16)											\
   204 				state.bsr0 = 0x7C00;								\
   205 			else													\
   206 				state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00;		\
   207 			state.bsr0 |= (address >> 16);							\
   208 			state.bsr1 = address & 0xffff;							\
   209 			LOG("Bus Error while reading, addr %08X, statcode %d", address, st);		\
   210 			if (state.ee) m68k_pulse_bus_error();					\
   211 			return 0xFFFFFFFF;										\
   212 		}															\
   213 	} while (0)
   214 /*}}}*/
   216 // Logging macros
   217 #define LOG_NOT_HANDLED_R(bits)															\
   218 	if (!handled) printf("unhandled read%02d, addr=0x%08X\n", bits, address);
   220 #define LOG_NOT_HANDLED_W(bits)															\
   221 	if (!handled) printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
   223 /********************************************************
   224  * I/O read/write functions
   225  ********************************************************/
   227 /**
   228  * Issue a warning if a read operation is made with an invalid size
   229  */
   230 inline static void ENFORCE_SIZE(int bits, uint32_t address, bool read, int allowed, char *regname)
   231 {
   232 	assert((bits == 8) || (bits == 16) || (bits == 32));
   233 	if ((bits & allowed) == 0) {
   234 		printf("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
   235 	}
   236 }
   238 inline static void ENFORCE_SIZE_R(int bits, uint32_t address, int allowed, char *regname)
   239 {
   240 	ENFORCE_SIZE(bits, address, true, allowed, regname);
   241 }
   243 inline static void ENFORCE_SIZE_W(int bits, uint32_t address, int allowed, char *regname)
   244 {
   245 	ENFORCE_SIZE(bits, address, false, allowed, regname);
   246 }
   248 void IoWrite(uint32_t address, uint32_t data, int bits)/*{{{*/
   249 {
   250 	bool handled = false;
   252 	if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   253 		// I/O register space, zone A
   254 		switch (address & 0x0F0000) {
   255 			case 0x010000:				// General Status Register
   256 				if (bits == 16)
   257 					state.genstat = (data & 0xffff);
   258 				else if (bits == 8) {
   259 					if (address & 0)
   260 						state.genstat = data;
   261 					else
   262 						state.genstat = data << 8;
   263 				}
   264 				handled = true;
   265 				break;
   266 			case 0x030000:				// Bus Status Register 0
   267 				break;
   268 			case 0x040000:				// Bus Status Register 1
   269 				break;
   270 			case 0x050000:				// Phone status
   271 				break;
   272 			case 0x060000:				// DMA Count
   273 				ENFORCE_SIZE_W(bits, address, 16, "DMACOUNT");
   274 				state.dma_count = (data & 0x3FFF);
   275 				state.idmarw = ((data & 0x4000) == 0x4000);
   276 				state.dmaen = ((data & 0x8000) == 0x8000);
   277 				// This handles the "dummy DMA transfer" mentioned in the docs
   278 				// TODO: access check, peripheral access
   279 				if (!state.idmarw)
   280 					WR32(state.base_ram, mapAddr(address, true), state.base_ram_size - 1, 0xDEAD);
   281 				state.dma_count++;
   282 				handled = true;
   283 				break;
   284 			case 0x070000:				// Line Printer Status Register
   285 				break;
   286 			case 0x080000:				// Real Time Clock
   287 				break;
   288 			case 0x090000:				// Phone registers
   289 				switch (address & 0x0FF000) {
   290 					case 0x090000:		// Handset relay
   291 					case 0x098000:
   292 						break;
   293 					case 0x091000:		// Line select 2
   294 					case 0x099000:
   295 						break;
   296 					case 0x092000:		// Hook relay 1
   297 					case 0x09A000:
   298 						break;
   299 					case 0x093000:		// Hook relay 2
   300 					case 0x09B000:
   301 						break;
   302 					case 0x094000:		// Line 1 hold
   303 					case 0x09C000:
   304 						break;
   305 					case 0x095000:		// Line 2 hold
   306 					case 0x09D000:
   307 						break;
   308 					case 0x096000:		// Line 1 A-lead
   309 					case 0x09E000:
   310 						break;
   311 					case 0x097000:		// Line 2 A-lead
   312 					case 0x09F000:
   313 						break;
   314 				}
   315 				break;
   316 			case 0x0A0000:				// Miscellaneous Control Register
   317 				ENFORCE_SIZE_W(bits, address, 16, "MISCCON");
   318 				// TODO: handle the ctrl bits properly
   319 				// TODO: &0x8000 --> dismiss 60hz intr
   320 				if (data & 0x8000){
   321 					state.timer_enabled = 1;
   322 				}else{
   323 					state.timer_enabled = 0;
   324 					state.timer_asserted = 0;
   325 				}
   326 				state.dma_reading = (data & 0x4000);
   327 				if (state.leds != ((~data & 0xF00) >> 8)) {
   328 					state.leds = (~data & 0xF00) >> 8;
   329 					printf("LEDs: %s %s %s %s\n",
   330 							(state.leds & 8) ? "R" : "-",
   331 							(state.leds & 4) ? "G" : "-",
   332 							(state.leds & 2) ? "Y" : "-",
   333 							(state.leds & 1) ? "R" : "-");
   334 				}
   335 				handled = true;
   336 				break;
   337 			case 0x0B0000:				// TM/DIALWR
   338 				break;
   339 			case 0x0C0000:				// Clear Status Register
   340 				state.genstat = 0xFFFF;
   341 				state.bsr0 = 0xFFFF;
   342 				state.bsr1 = 0xFFFF;
   343 				handled = true;
   344 				break;
   345 			case 0x0D0000:				// DMA Address Register
   346 				if (address & 0x004000) {
   347 					// A14 high -- set most significant bits
   348 					state.dma_address = (state.dma_address & 0x1fe) | ((address & 0x3ffe) << 8);
   349 				} else {
   350 					// A14 low -- set least significant bits
   351 					state.dma_address = (state.dma_address & 0x3ffe00) | (address & 0x1fe);
   352 				}
   353 				handled = true;
   354 				break;
   355 			case 0x0E0000:				// Disk Control Register
   356 				ENFORCE_SIZE_W(bits, address, 16, "DISKCON");
   357 				// B7 = FDD controller reset
   358 				if ((data & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
   359 				// B6 = drive 0 select -- TODO
   360 				// B5 = motor enable -- TODO
   361 				// B4 = HDD controller reset -- TODO
   362 				// B3 = HDD0 select -- TODO
   363 				// B2,1,0 = HDD0 head select
   364 				handled = true;
   365 				break;
   366 			case 0x0F0000:				// Line Printer Data Register
   367 				break;
   368 		}
   369 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   370 		// I/O register space, zone B
   371 		switch (address & 0xF00000) {
   372 			case 0xC00000:				// Expansion slots
   373 			case 0xD00000:
   374 				switch (address & 0xFC0000) {
   375 					case 0xC00000:		// Expansion slot 0
   376 					case 0xC40000:		// Expansion slot 1
   377 					case 0xC80000:		// Expansion slot 2
   378 					case 0xCC0000:		// Expansion slot 3
   379 					case 0xD00000:		// Expansion slot 4
   380 					case 0xD40000:		// Expansion slot 5
   381 					case 0xD80000:		// Expansion slot 6
   382 					case 0xDC0000:		// Expansion slot 7
   383 						fprintf(stderr, "NOTE: WR%d to expansion card space, addr=0x%08X, data=0x%08X\n", bits, address, data);
   384 						handled = true;
   385 						break;
   386 				}
   387 				break;
   388 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   389 			case 0xF00000:
   390 				switch (address & 0x070000) {
   391 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   392 						break;
   393 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   394 						ENFORCE_SIZE_W(bits, address, 16, "FDC REGISTERS");
   395 						wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, data);
   396 						handled = true;
   397 						break;
   398 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   399 						break;
   400 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   401 						break;
   402 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   403 						switch (address & 0x077000) {
   404 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   405 								// Error Enable. If =0, Level7 intrs and bus errors are masked.
   406 								ENFORCE_SIZE_W(bits, address, 16, "EE");
   407 								state.ee = ((data & 0x8000) == 0x8000);
   408 								handled = true;
   409 								break;
   410 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
   411 								ENFORCE_SIZE_W(bits, address, 16, "PIE");
   412 								state.pie = ((data & 0x8000) == 0x8000);
   413 								handled = true;
   414 								break;
   415 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   416 								break;
   417 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   418 								ENFORCE_SIZE_W(bits, address, 16, "ROMLMAP");
   419 								state.romlmap = ((data & 0x8000) == 0x8000);
   420 								handled = true;
   421 								break;
   422 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   423 								ENFORCE_SIZE_W(bits, address, 16, "L1 MODEM");
   424 								break;
   425 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   426 								ENFORCE_SIZE_W(bits, address, 16, "L2 MODEM");
   427 								break;
   428 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   429 								ENFORCE_SIZE_W(bits, address, 16, "D/N CONNECT");
   430 								break;
   431 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   432 								ENFORCE_SIZE_W(bits, address, 16, "WHOLE SCREEN REVERSE VIDEO");
   433 								break;
   434 						}
   435 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   436 						break;
   437 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   438 						switch (address & 0x07F000) {
   439 							default:
   440 								break;
   441 						}
   442 						break;
   443 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   444 						// TODO: figure out which sizes are valid (probably just 8 and 16)
   445 						// ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
   446 						if (bits == 8) {
   447 							printf("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
   448 							keyboard_write(&state.kbd, (address >> 1) & 3, data);
   449 							handled = true;
   450 						} else if (bits == 16) {
   451 							printf("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
   452 							keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
   453 							handled = true;
   454 						}
   455 						break;
   456 				}
   457 		}
   458 	}
   460 	LOG_NOT_HANDLED_W(bits);
   461 }/*}}}*/
   463 uint32_t IoRead(uint32_t address, int bits)/*{{{*/
   464 {
   465 	bool handled = false;
   466 	uint32_t data = 0xFFFFFFFF;
   468 	if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   469 		// I/O register space, zone A
   470 		switch (address & 0x0F0000) {
   471 			case 0x010000:				// General Status Register
   472 				ENFORCE_SIZE_R(bits, address, 16, "GENSTAT");
   473 				return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
   474 				break;
   475 			case 0x030000:				// Bus Status Register 0
   476 				ENFORCE_SIZE_R(bits, address, 16, "BSR0");
   477 				return ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
   478 				break;
   479 			case 0x040000:				// Bus Status Register 1
   480 				ENFORCE_SIZE_R(bits, address, 16, "BSR1");
   481 				return ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
   482 				break;
   483 			case 0x050000:				// Phone status
   484 				ENFORCE_SIZE_R(bits, address, 8 | 16, "PHONE STATUS");
   485 				break;
   486 			case 0x060000:				// DMA Count
   487 				// TODO: U/OERR- is always inactive (bit set)... or should it be = DMAEN+?
   488 				// Bit 14 is always unused, so leave it set
   489 				ENFORCE_SIZE_R(bits, address, 16, "DMACOUNT");
   490 				return (state.dma_count & 0x3fff) | 0xC000;
   491 				break;
   492 			case 0x070000:				// Line Printer Status Register
   493 				data = 0x00120012;	// no parity error, no line printer error, no irqs from FDD or HDD
   494 				data |= wd2797_get_irq(&state.fdc_ctx) ? 0x00080008 : 0;
   495 				return data;
   496 				break;
   497 			case 0x080000:				// Real Time Clock
   498 				printf("READ NOTIMP: Realtime Clock\n");
   499 				break;
   500 			case 0x090000:				// Phone registers
   501 				switch (address & 0x0FF000) {
   502 					case 0x090000:		// Handset relay
   503 					case 0x098000:
   504 						break;
   505 					case 0x091000:		// Line select 2
   506 					case 0x099000:
   507 						break;
   508 					case 0x092000:		// Hook relay 1
   509 					case 0x09A000:
   510 						break;
   511 					case 0x093000:		// Hook relay 2
   512 					case 0x09B000:
   513 						break;
   514 					case 0x094000:		// Line 1 hold
   515 					case 0x09C000:
   516 						break;
   517 					case 0x095000:		// Line 2 hold
   518 					case 0x09D000:
   519 						break;
   520 					case 0x096000:		// Line 1 A-lead
   521 					case 0x09E000:
   522 						break;
   523 					case 0x097000:		// Line 2 A-lead
   524 					case 0x09F000:
   525 						break;
   526 				}
   527 				break;
   528 			case 0x0A0000:				// Miscellaneous Control Register -- write only!
   529 				handled = true;
   530 				break;
   531 			case 0x0B0000:				// TM/DIALWR
   532 				break;
   533 			case 0x0C0000:				// Clear Status Register -- write only!
   534 				handled = true;
   535 				break;
   536 			case 0x0D0000:				// DMA Address Register
   537 				break;
   538 			case 0x0E0000:				// Disk Control Register
   539 				break;
   540 			case 0x0F0000:				// Line Printer Data Register
   541 				break;
   542 		}
   543 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   544 		// I/O register space, zone B
   545 		switch (address & 0xF00000) {
   546 			case 0xC00000:				// Expansion slots
   547 			case 0xD00000:
   548 				switch (address & 0xFC0000) {
   549 					case 0xC00000:		// Expansion slot 0
   550 					case 0xC40000:		// Expansion slot 1
   551 					case 0xC80000:		// Expansion slot 2
   552 					case 0xCC0000:		// Expansion slot 3
   553 					case 0xD00000:		// Expansion slot 4
   554 					case 0xD40000:		// Expansion slot 5
   555 					case 0xD80000:		// Expansion slot 6
   556 					case 0xDC0000:		// Expansion slot 7
   557 						fprintf(stderr, "NOTE: RD%d from expansion card space, addr=0x%08X\n", bits, address);
   558 						handled = true;
   559 						break;
   560 				}
   561 				break;
   562 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   563 			case 0xF00000:
   564 				switch (address & 0x070000) {
   565 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   566 						break;
   567 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   568 						ENFORCE_SIZE_R(bits, address, 16, "FDC REGISTERS");
   569 						return wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
   570 						break;
   571 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   572 						break;
   573 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   574 						break;
   575 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   576 						switch (address & 0x077000) {
   577 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   578 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
   579 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   580 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   581 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   582 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   583 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   584 								// All write-only registers... TODO: bus error?
   585 								handled = true;
   586 								break;
   587 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
   588 								break;
   589 						}
   590 						break;
   591 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   592 						break;
   593 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   594 						switch (address & 0x07F000) {
   595 							default:
   596 								break;
   597 						}
   598 						break;
   599 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   600 						// TODO: figure out which sizes are valid (probably just 8 and 16)
   601 						//ENFORCE_SIZE_R(bits, address, 16, "KEYBOARD CONTROLLER");
   602 						{
   603 							if (bits == 8) {
   604 								return keyboard_read(&state.kbd, (address >> 1) & 3);
   605 							} else {
   606 								return keyboard_read(&state.kbd, (address >> 1) & 3) << 8;
   607 							}
   608 							return data;
   609 						}
   610 						break;
   611 				}
   612 		}
   613 	}
   615 	LOG_NOT_HANDLED_R(bits);
   617 	return data;
   618 }/*}}}*/
   621 /********************************************************
   622  * m68k memory read/write support functions for Musashi
   623  ********************************************************/
   625 /**
   626  * @brief Read M68K memory, 32-bit
   627  */
   628 uint32_t m68k_read_memory_32(uint32_t address)/*{{{*/
   629 {
   630 	uint32_t data = 0xFFFFFFFF;
   632 	// If ROMLMAP is set, force system to access ROM
   633 	if (!state.romlmap)
   634 		address |= 0x800000;
   636 	// Check access permissions
   637 	ACCESS_CHECK_RD(address, 32);
   639 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   640 		// ROM access
   641 		return RD32(state.rom, address, ROM_SIZE - 1);
   642 	} else if (address <= 0x3fffff) {
   643 		// RAM access
   644 		uint32_t newAddr = mapAddr(address, false);
   645 		if (newAddr <= 0x1fffff) {
   646 			return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
   647 		} else {
   648 			if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
   649 				return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
   650 			else
   651 				return 0xffffffff;
   652 		}
   653 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   654 		// I/O register space, zone A
   655 		switch (address & 0x0F0000) {
   656 			case 0x000000:				// Map RAM access
   657 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
   658 				return RD32(state.map, address, 0x7FF);
   659 				break;
   660 			case 0x020000:				// Video RAM
   661 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
   662 				return RD32(state.vram, address, 0x7FFF);
   663 				break;
   664 			default:
   665 				return IoRead(address, 32);
   666 		}
   667 	} else {
   668 		return IoRead(address, 32);
   669 	}
   671 	return data;
   672 }/*}}}*/
   674 /**
   675  * @brief Read M68K memory, 16-bit
   676  */
   677 uint32_t m68k_read_memory_16(uint32_t address)/*{{{*/
   678 {
   679 	uint16_t data = 0xFFFF;
   681 	// If ROMLMAP is set, force system to access ROM
   682 	if (!state.romlmap)
   683 		address |= 0x800000;
   685 	// Check access permissions
   686 	ACCESS_CHECK_RD(address, 16);
   688 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   689 		// ROM access
   690 		data = RD16(state.rom, address, ROM_SIZE - 1);
   691 	} else if (address <= 0x3fffff) {
   692 		// RAM access
   693 		uint32_t newAddr = mapAddr(address, false);
   694 		if (newAddr <= 0x1fffff) {
   695 			return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
   696 		} else {
   697 			if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
   698 				return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
   699 			else
   700 				return 0xffff;
   701 		}
   702 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   703 		// I/O register space, zone A
   704 		switch (address & 0x0F0000) {
   705 			case 0x000000:				// Map RAM access
   706 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
   707 				data = RD16(state.map, address, 0x7FF);
   708 				break;
   709 			case 0x020000:				// Video RAM
   710 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
   711 				data = RD16(state.vram, address, 0x7FFF);
   712 				break;
   713 			default:
   714 				data = IoRead(address, 16);
   715 		}
   716 	} else {
   717 		data = IoRead(address, 16);
   718 	}
   720 	return data;
   721 }/*}}}*/
   723 /**
   724  * @brief Read M68K memory, 8-bit
   725  */
   726 uint32_t m68k_read_memory_8(uint32_t address)/*{{{*/
   727 {
   728 	uint8_t data = 0xFF;
   730 	// If ROMLMAP is set, force system to access ROM
   731 	if (!state.romlmap)
   732 		address |= 0x800000;
   734 	// Check access permissions
   735 	ACCESS_CHECK_RD(address, 8);
   737 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   738 		// ROM access
   739 		data = RD8(state.rom, address, ROM_SIZE - 1);
   740 	} else if (address <= 0x3fffff) {
   741 		// RAM access
   742 		uint32_t newAddr = mapAddr(address, false);
   743 		if (newAddr <= 0x1fffff) {
   744 			return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
   745 		} else {
   746 			if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
   747 				return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
   748 			else
   749 				return 0xff;
   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: RD8 from MapRAM mirror, addr=0x%08X\n", address);
   756 				data = RD8(state.map, address, 0x7FF);
   757 				break;
   758 			case 0x020000:				// Video RAM
   759 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
   760 				data = RD8(state.vram, address, 0x7FFF);
   761 				break;
   762 			default:
   763 				data = IoRead(address, 8);
   764 		}
   765 	} else {
   766 		data = IoRead(address, 8);
   767 	}
   769 	return data;
   770 }/*}}}*/
   772 /**
   773  * @brief Write M68K memory, 32-bit
   774  */
   775 void m68k_write_memory_32(uint32_t address, uint32_t value)/*{{{*/
   776 {
   777 	// If ROMLMAP is set, force system to access ROM
   778 	if (!state.romlmap)
   779 		address |= 0x800000;
   781 	// Check access permissions
   782 	ACCESS_CHECK_WR(address, 32);
   784 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   785 		// ROM access
   786 	} else if (address <= 0x3FFFFF) {
   787 		// RAM access
   788 		uint32_t newAddr = mapAddr(address, true);
   789 		if (newAddr <= 0x1fffff)
   790 			WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
   791 		else
   792 			WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
   793 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   794 		// I/O register space, zone A
   795 		switch (address & 0x0F0000) {
   796 			case 0x000000:				// Map RAM access
   797 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X\n", address);
   798 				WR32(state.map, address, 0x7FF, value);
   799 				break;
   800 			case 0x020000:				// Video RAM
   801 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X\n", address);
   802 				WR32(state.vram, address, 0x7FFF, value);
   803 				break;
   804 			default:
   805 				IoWrite(address, value, 32);
   806 		}
   807 	} else {
   808 		IoWrite(address, value, 32);
   809 	}
   810 }/*}}}*/
   812 /**
   813  * @brief Write M68K memory, 16-bit
   814  */
   815 void m68k_write_memory_16(uint32_t address, uint32_t value)/*{{{*/
   816 {
   817 	// If ROMLMAP is set, force system to access ROM
   818 	if (!state.romlmap)
   819 		address |= 0x800000;
   821 	// Check access permissions
   822 	ACCESS_CHECK_WR(address, 16);
   824 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   825 		// ROM access
   826 	} else if (address <= 0x3FFFFF) {
   827 		// RAM access
   828 		uint32_t newAddr = mapAddr(address, true);
   829 		if (newAddr <= 0x1fffff)
   830 			WR16(state.base_ram, newAddr, state.base_ram_size - 1, value);
   831 		else
   832 			WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
   833 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   834 		// I/O register space, zone A
   835 		switch (address & 0x0F0000) {
   836 			case 0x000000:				// Map RAM access
   837 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   838 				WR16(state.map, address, 0x7FF, value);
   839 				break;
   840 			case 0x020000:				// Video RAM
   841 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   842 				WR16(state.vram, address, 0x7FFF, value);
   843 				break;
   844 			default:
   845 				IoWrite(address, value, 16);
   846 		}
   847 	} else {
   848 		IoWrite(address, value, 16);
   849 	}
   850 }/*}}}*/
   852 /**
   853  * @brief Write M68K memory, 8-bit
   854  */
   855 void m68k_write_memory_8(uint32_t address, uint32_t value)/*{{{*/
   856 {
   857 	// If ROMLMAP is set, force system to access ROM
   858 	if (!state.romlmap)
   859 		address |= 0x800000;
   861 	// Check access permissions
   862 	ACCESS_CHECK_WR(address, 8);
   864 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   865 		// ROM access (read only!)
   866 	} else if (address <= 0x3FFFFF) {
   867 		// RAM access
   868 		uint32_t newAddr = mapAddr(address, true);
   869 		if (newAddr <= 0x1fffff)
   870 			WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
   871 		else
   872 			WR8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
   873 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   874 		// I/O register space, zone A
   875 		switch (address & 0x0F0000) {
   876 			case 0x000000:				// Map RAM access
   877 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   878 				WR8(state.map, address, 0x7FF, value);
   879 				break;
   880 			case 0x020000:				// Video RAM
   881 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   882 				WR8(state.vram, address, 0x7FFF, value);
   883 				break;
   884 			default:
   885 				IoWrite(address, value, 8);
   886 		}
   887 	} else {
   888 		IoWrite(address, value, 8);
   889 	}
   890 }/*}}}*/
   893 // for the disassembler
   894 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
   895 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
   896 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }