src/memory.c

Mon, 14 Jan 2013 09:50:37 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Jan 2013 09:50:37 +0000
changeset 120
df40e6668a46
parent 119
101fe02456ce
child 121
15ae2788e848
permissions
-rw-r--r--

Max out system memory by default

Set the system memory to 2MiB base, 2MiB ext. This is a fully loaded 3B1
motherboard with a RAM expansion board. 512KiB base/no ext is the minimum
which can be specified (e.g. kernel memory map area only) but does not leave
any room for userspace. The kernel doesn't like that and doesn't handle it
gracefully...!

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