src/memory.c

Tue, 15 Jan 2013 17:02:56 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 15 Jan 2013 17:02:56 +0000
changeset 121
15ae2788e848
parent 119
101fe02456ce
child 128
3246b74d96bc
child 129
8b24770dea79
permissions
-rw-r--r--

Implement m68k_read_disassembler_* properly

The previous implementations of m68k_read_disassembler are unsuitable due to
interactions with the memory mapper. A read from memory by the DASM should not
mutate system state.

So we modify the m68k_read_disassembler_{8,16,32} functions to do the memory
mapping themselves without causing page faults (bus error exception) or
updating the page flag bits (which could really upset the kernel).

Now all we need is a debugger/disassembler...

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