src/memory.c

Mon, 14 Jan 2013 09:22:12 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Jan 2013 09:22:12 +0000
changeset 118
feee84e0b3bf
parent 117
73caf968b67b
child 119
101fe02456ce
permissions
-rw-r--r--

More bus error fixes for FreeBee

I have fixed two more bus error handling bugs in FreeBee. First, the CPU core was executing the instruction regardless of whether a bus error occurs when fetching the opcode (which caused it to execute a bogus instruction in such cases). The other one was related to one of my previous fixes - the jump to the bus error vector was at the beginning of the main loop, so it wouldn't be called immediately after the bus error occurred if the timeslot expired, causing the return address to be off.

With these fixes, Unix now runs enough to get into userspace and run the install script (it is also possible to break out and get a shell prompt). However, many commands segfault semi-randomly (or more specifically, it seems that some child processes forked by the shell might be segfaulting before they can exec the command program), so installing the system isn't possible yet. I am not sure exactly what the bug is, but it seems to be related to some function in the shell returning null when the code calling it is assuming that it won't. What the function is, or why it is returning null, I'm not sure (the shell is built without the shared libc and is stripped, making identifying the function harder). I suspect that the function might be in libc, but that is hard to tell.

Author: Andrew Warkentin <andreww591 gmail com>

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