src/memory.c

Wed, 16 Apr 2014 02:20:43 -0600

author
andrew@localhost
date
Wed, 16 Apr 2014 02:20:43 -0600
changeset 147
ad888290cdff
parent 139
d91346487fe9
child 150
c19afa2c81db
permissions
-rw-r--r--

fixed bus error handling for real this time (save registers before every instruction and push the saved registers if a bus error occurs, since the instruction may have changed registers before the bus error, and also stop the instruction immediately with longjmp so it won't change memory after the bus error)

This isn't actually what a real 68k does, but it is a good enough approximation. A real 68k will jump back into the middle of the faulted instruction and resume it from the memory access that faulted as opposed to restarting from the beginning like this CPU emulation does. It would be a lot harder to do that with the way this CPU library is designed. Newer versions of MESS basically do the same thing (they use a newer version of this library).

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