experimental memory mapper, not quite working experimental_memory_mapper_v2

Fri, 18 Jan 2013 17:03:48 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Fri, 18 Jan 2013 17:03:48 +0000
branch
experimental_memory_mapper_v2
changeset 128
3246b74d96bc
parent 127
4c03f6433d0d
child 132
8a7dc9b5b1db

experimental memory mapper, not quite working

Makefile file | annotate | diff | revisions
src/main.c file | annotate | diff | revisions
src/memory.c file | annotate | diff | revisions
src/memory.h file | annotate | diff | revisions
src/musashi/m68kcpu.h file | annotate | diff | revisions
src/wd2010.c file | annotate | diff | revisions
     1.1 --- a/Makefile	Wed Jan 16 00:41:51 2013 +0000
     1.2 +++ b/Makefile	Fri Jan 18 17:03:48 2013 +0000
     1.3 @@ -167,7 +167,7 @@
     1.4  MAKE	=	make
     1.5  CC		=	gcc
     1.6  CXX		=	g++
     1.7 -CFLAGS	=	-Wall -pedantic -std=gnu99 $(EXT_CFLAGS)
     1.8 +CFLAGS	=	-Wall -pedantic -std=gnu99 $(EXT_CFLAGS) -DWD2010_SEEK_DELAY=1 -DSHOW_LEDS -DDEBUG_MAP
     1.9  CXXFLAGS=	-Wall -pedantic -std=gnu++0x $(EXT_CXXFLAGS)
    1.10  LDFLAGS	=	$(EXT_LDFLAGS)
    1.11  RM		=	rm
     2.1 --- a/src/main.c	Wed Jan 16 00:41:51 2013 +0000
     2.2 +++ b/src/main.c	Fri Jan 18 17:03:48 2013 +0000
     2.3 @@ -291,49 +291,50 @@
     2.4  				}else{
     2.5  					printf("ERROR: DMA attempt with no drive selected!\n");
     2.6  				}
     2.7 -				if (!access_check_dma(state.dma_reading)) {
     2.8 -					break;
     2.9 -				}
    2.10 -				uint32_t newAddr;
    2.11 -				// Map logical address to a physical RAM address
    2.12 -				newAddr = mapAddr(state.dma_address, !state.dma_reading);
    2.13 +
    2.14 +				if (access_check_dma()) {
    2.15 +
    2.16 +					uint32_t newAddr;
    2.17 +					// Map logical address to a physical RAM address
    2.18 +					newAddr = MAP_ADDR(state.dma_address);
    2.19  
    2.20 -				if (!state.dma_reading) {
    2.21 -					// Data available. Get it from the FDC or HDC.
    2.22 -					if (state.fd_selected) {
    2.23 -						d = wd2797_read_reg(&state.fdc_ctx, WD2797_REG_DATA);
    2.24 -						d <<= 8;
    2.25 -						d += wd2797_read_reg(&state.fdc_ctx, WD2797_REG_DATA);
    2.26 -					}else if (state.hd_selected) {
    2.27 -						d = wd2010_read_data(&state.hdc_ctx);
    2.28 -						d <<= 8;
    2.29 -						d += wd2010_read_data(&state.hdc_ctx);
    2.30 -					}
    2.31 -					if (newAddr <= 0x1FFFFF) {
    2.32 -						WR16(state.base_ram, newAddr, state.base_ram_size - 1, d);
    2.33 -					} else if (newAddr >= 0x200000) {
    2.34 -						WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, d);
    2.35 -					}
    2.36 -				} else {
    2.37 -					// Data write to FDC or HDC.
    2.38 +					if (!state.dma_reading) {
    2.39 +						// Data available. Get it from the FDC or HDC.
    2.40 +						if (state.fd_selected) {
    2.41 +							d = wd2797_read_reg(&state.fdc_ctx, WD2797_REG_DATA);
    2.42 +							d <<= 8;
    2.43 +							d += wd2797_read_reg(&state.fdc_ctx, WD2797_REG_DATA);
    2.44 +						}else if (state.hd_selected) {
    2.45 +							d = wd2010_read_data(&state.hdc_ctx);
    2.46 +							d <<= 8;
    2.47 +							d += wd2010_read_data(&state.hdc_ctx);
    2.48 +						}
    2.49 +						if (newAddr <= 0x1FFFFF) {
    2.50 +							WR16(state.base_ram, newAddr, state.base_ram_size - 1, d);
    2.51 +						} else if (newAddr >= 0x200000) {
    2.52 +							WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, d);
    2.53 +						}
    2.54 +					} else {
    2.55 +						// Data write to FDC or HDC.
    2.56  
    2.57 -					// Get the data from RAM
    2.58 -					if (newAddr <= 0x1fffff) {
    2.59 -						d = RD16(state.base_ram, newAddr, state.base_ram_size - 1);
    2.60 -					} else {
    2.61 -						if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
    2.62 -							d = RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
    2.63 -						else
    2.64 -							d = 0xffff;
    2.65 -					}
    2.66 +						// Get the data from RAM
    2.67 +						if (newAddr <= 0x1fffff) {
    2.68 +							d = RD16(state.base_ram, newAddr, state.base_ram_size - 1);
    2.69 +						} else {
    2.70 +							if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
    2.71 +								d = RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
    2.72 +							else
    2.73 +								d = 0xffff;
    2.74 +						}
    2.75  
    2.76 -					// Send the data to the FDD or HDD
    2.77 -					if (state.fd_selected){
    2.78 -						wd2797_write_reg(&state.fdc_ctx, WD2797_REG_DATA, (d >> 8));
    2.79 -						wd2797_write_reg(&state.fdc_ctx, WD2797_REG_DATA, (d & 0xff));
    2.80 -					}else if (state.hd_selected){
    2.81 -						wd2010_write_data(&state.hdc_ctx, (d >> 8));
    2.82 -						wd2010_write_data(&state.hdc_ctx, (d & 0xff));
    2.83 +						// Send the data to the FDD or HDD
    2.84 +						if (state.fd_selected){
    2.85 +							wd2797_write_reg(&state.fdc_ctx, WD2797_REG_DATA, (d >> 8));
    2.86 +							wd2797_write_reg(&state.fdc_ctx, WD2797_REG_DATA, (d & 0xff));
    2.87 +						}else if (state.hd_selected){
    2.88 +							wd2010_write_data(&state.hdc_ctx, (d >> 8));
    2.89 +							wd2010_write_data(&state.hdc_ctx, (d & 0xff));
    2.90 +						}
    2.91  					}
    2.92  				}
    2.93  
     3.1 --- a/src/memory.c	Wed Jan 16 00:41:51 2013 +0000
     3.2 +++ b/src/memory.c	Fri Jan 18 17:03:48 2013 +0000
     3.3 @@ -17,100 +17,10 @@
     3.4   * Memory mapping
     3.5   ******************/
     3.6  
     3.7 -#define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
     3.8 -
     3.9 -uint32_t mapAddr(uint32_t addr, bool writing)/*{{{*/
    3.10 -{
    3.11 -	if (addr < 0x400000) {
    3.12 -		// RAM access. Check against the Map RAM
    3.13 -		// Start by getting the original page address
    3.14 -		uint16_t page = (addr >> 12) & 0x3FF;
    3.15 -
    3.16 -		// Look it up in the map RAM and get the physical page address
    3.17 -		uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
    3.18 -
    3.19 -		// Update the Page Status bits
    3.20 -		uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
    3.21 -		// Pagebits --
    3.22 -		//   0 = not present
    3.23 -		//   1 = present but not accessed
    3.24 -		//   2 = present, accessed (read from)
    3.25 -		//   3 = present, dirty (written to)
    3.26 -		switch (pagebits) {
    3.27 -			case 0:
    3.28 -				// Page not present
    3.29 -				// This should cause a page fault
    3.30 -				LOGS("Whoa! Pagebit update, when the page is not present!");
    3.31 -				break;
    3.32 -
    3.33 -			case 1:
    3.34 -				// Page present -- first access
    3.35 -				state.map[page*2] &= 0x9F;	// turn off "present" bit (but not write enable!)
    3.36 -				if (writing)
    3.37 -					state.map[page*2] |= 0x60;		// Page written to (dirty)
    3.38 -				else
    3.39 -					state.map[page*2] |= 0x40;		// Page accessed but not written
    3.40 -				break;
    3.41 -
    3.42 -			case 2:
    3.43 -			case 3:
    3.44 -				// Page present, 2nd or later access
    3.45 -				if (writing)
    3.46 -					state.map[page*2] |= 0x60;		// Page written to (dirty)
    3.47 -				break;
    3.48 -		}
    3.49 -
    3.50 -		// Return the address with the new physical page spliced in
    3.51 -		return (new_page_addr << 12) + (addr & 0xFFF);
    3.52 -	} else {
    3.53 -		// I/O, VRAM or MapRAM space; no mapping is performed or required
    3.54 -		// TODO: assert here?
    3.55 -		return addr;
    3.56 -	}
    3.57 -}/*}}}*/
    3.58 -
    3.59 -MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)/*{{{*/
    3.60 -{
    3.61 -	// Get the page bits for this page.
    3.62 -	uint16_t page = (addr >> 12) & 0x3FF;
    3.63 -	uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07;
    3.64 -
    3.65 -	// Check page is present (but only for RAM zone)
    3.66 -	if ((addr < 0x400000) && ((pagebits & 0x03) == 0)) {
    3.67 -		LOG("Page not mapped in: addr %08X, page %04X, mapbits %04X", addr, page, MAPRAM(page));
    3.68 -		return MEM_PAGEFAULT;
    3.69 -	}
    3.70 -
    3.71 -	// Are we in Supervisor mode?
    3.72 -	if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
    3.73 -		// Yes. We can do anything we like.
    3.74 -		return MEM_ALLOWED;
    3.75 -
    3.76 -	// If we're here, then we must be in User mode.
    3.77 -	// Check that the user didn't access memory outside of the RAM area
    3.78 -	if (addr >= 0x400000) {
    3.79 -		LOGS("User accessed privileged memory");
    3.80 -		return MEM_UIE;
    3.81 -	}
    3.82 -
    3.83 -	// User attempt to access the kernel
    3.84 -	// A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
    3.85 -	if (((addr >> 19) & 0x0F) == 0) {
    3.86 -		LOGS("Attempt by user code to access kernel space");
    3.87 -		return MEM_KERNEL;
    3.88 -	}
    3.89 -
    3.90 -	// Check page is write enabled
    3.91 -	if (writing && ((pagebits & 0x04) == 0)) {
    3.92 -		LOG("Page not write enabled: inaddr %08X, page %04X, mapram %04X [%02X %02X], pagebits %d",
    3.93 -				addr, page, MAPRAM(page), state.map[page*2], state.map[(page*2)+1], pagebits);
    3.94 -		return MEM_PAGE_NO_WE;
    3.95 -	}
    3.96 -
    3.97 -	// Page access allowed.
    3.98 -	return MEM_ALLOWED;
    3.99 -}/*}}}*/
   3.100 -
   3.101 +/// Set a page bit
   3.102 +#define MAP_SET_PAGEBIT(addr, bit) state.map[(((addr) >> 12) & 0x3FF)*2] |=  (bit << 2)
   3.103 +/// Clear a page bit
   3.104 +#define MAP_CLR_PAGEBIT(addr, bit) state.map[(((addr) >> 12) & 0x3FF)*2] &= ~(bit << 2)
   3.105  
   3.106  
   3.107  /********************************************************
   3.108 @@ -129,40 +39,7 @@
   3.109  /*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
   3.110  #define ACCESS_CHECK_WR(address, bits)								\
   3.111  	do {															\
   3.112 -		bool fault = false;											\
   3.113 -		MEM_STATUS st;												\
   3.114 -		switch (st = checkMemoryAccess(address, true)) {			\
   3.115 -			case MEM_ALLOWED:										\
   3.116 -				/* Access allowed */								\
   3.117 -				break;												\
   3.118 -			case MEM_PAGEFAULT:										\
   3.119 -				/* Page fault */									\
   3.120 -				state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0);	\
   3.121 -				fault = true;										\
   3.122 -				break;												\
   3.123 -			case MEM_UIE:											\
   3.124 -				/* User access to memory above 4MB */				\
   3.125 -				state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0);	\
   3.126 -				fault = true;										\
   3.127 -				break;												\
   3.128 -			case MEM_KERNEL:										\
   3.129 -			case MEM_PAGE_NO_WE:									\
   3.130 -				/* kernel access or page not write enabled */		\
   3.131 -				/* XXX: is this the correct value? */				\
   3.132 -				state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0);	\
   3.133 -				fault = true;										\
   3.134 -				break;												\
   3.135 -		}															\
   3.136 -																	\
   3.137 -		if (fault) {												\
   3.138 -			if (bits >= 16)											\
   3.139 -				state.bsr0 = 0x7C00;								\
   3.140 -			else													\
   3.141 -				state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00;		\
   3.142 -			state.bsr0 |= (address >> 16);							\
   3.143 -			state.bsr1 = address & 0xffff;							\
   3.144 -			LOG("Bus Error while writing, addr %08X, statcode %d", address, st);		\
   3.145 -			if (state.ee) m68k_pulse_bus_error();					\
   3.146 +		if (access_check_cpu(address, bits, true)) {				\
   3.147  			return;													\
   3.148  		}															\
   3.149  	} while (0)
   3.150 @@ -180,100 +57,220 @@
   3.151  /*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
   3.152  #define ACCESS_CHECK_RD(address, bits)								\
   3.153  	do {															\
   3.154 -		bool fault = false;											\
   3.155 -		MEM_STATUS st;												\
   3.156 -		switch (st = checkMemoryAccess(address, false)) {			\
   3.157 -			case MEM_ALLOWED:										\
   3.158 -				/* Access allowed */								\
   3.159 -				break;												\
   3.160 -			case MEM_PAGEFAULT:										\
   3.161 -				/* Page fault */									\
   3.162 -				state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0);	\
   3.163 -				fault = true;										\
   3.164 -				break;												\
   3.165 -			case MEM_UIE:											\
   3.166 -				/* User access to memory above 4MB */				\
   3.167 -				state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0);	\
   3.168 -				fault = true;										\
   3.169 -				break;												\
   3.170 -			case MEM_KERNEL:										\
   3.171 -			case MEM_PAGE_NO_WE:									\
   3.172 -				/* kernel access or page not write enabled */		\
   3.173 -				/* XXX: is this the correct value? */				\
   3.174 -				state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0);	\
   3.175 -				fault = true;										\
   3.176 -				break;												\
   3.177 -		}															\
   3.178 -																	\
   3.179 -		if (fault) {												\
   3.180 -			if (bits >= 16)											\
   3.181 -				state.bsr0 = 0x7C00;								\
   3.182 +		if (access_check_cpu(address, bits, false)) {				\
   3.183 +			if (bits == 32)											\
   3.184 +				return EMPTY & 0xFFFFFFFF;							\
   3.185  			else													\
   3.186 -				state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00;		\
   3.187 -			state.bsr0 |= (address >> 16);							\
   3.188 -			state.bsr1 = address & 0xffff;							\
   3.189 -			LOG("Bus Error while reading, addr %08X, statcode %d", address, st);		\
   3.190 -			if (state.ee) m68k_pulse_bus_error();					\
   3.191 -			if (bits == 32)											\
   3.192 -				return EMPTY & 0xFFFFFFFF;									\
   3.193 -			else													\
   3.194 -				return EMPTY & ((1UL << bits)-1);								\
   3.195 +				return EMPTY & ((1UL << bits)-1);					\
   3.196  		}															\
   3.197  	} while (0)
   3.198  /*}}}*/
   3.199  
   3.200 -bool access_check_dma(int reading)
   3.201 +
   3.202 +/**
   3.203 + * Update the page bits for a given memory address
   3.204 + *
   3.205 + * @param	addr	Memory address being accessed
   3.206 + * @param	l7intr	Set to <i>true</i> if a level-seven interrupt has been
   3.207 + * 					signalled (even if <b>ENABLE ERROR</b> isn't set).
   3.208 + * @param	write	Set to <i>true</i> if the address is being written to.
   3.209 + */
   3.210 +static void update_page_bits(uint32_t addr, bool l7intr, bool write)
   3.211  {
   3.212 -	// Check memory access permissions
   3.213 -	bool access_ok;
   3.214 -	switch (checkMemoryAccess(state.dma_address, !reading)) {
   3.215 -		case MEM_PAGEFAULT:
   3.216 -			// Page fault
   3.217 -			state.genstat = 0xABFF
   3.218 -				| (reading ? 0x4000 : 0)
   3.219 -				| (state.pie ? 0x0400 : 0);
   3.220 -			access_ok = false;
   3.221 -			break;
   3.222 +	bool ps0_state = false;
   3.223 +
   3.224 +	// Don't try and update pagebits for non-RAM addresses
   3.225 +	if (addr > 0x3FFFFF)
   3.226 +		return;
   3.227 +
   3.228 +	if (l7intr) {
   3.229 +//		if (!(MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) {
   3.230 +			// FIXME FUCKUP The ruddy TRM is wrong AGAIN! If above line is uncommented, Really Bad Things Happen.
   3.231 +		if ((MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) {
   3.232 +			// Level 7 interrupt, PS0 clear, PS1 don't-care. Set PS0.
   3.233 +			ps0_state = true;
   3.234 +		}
   3.235 +	} else {
   3.236 +		// No L7 interrupt
   3.237 +		if ((write && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS1) &&  (MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) ||
   3.238 +			(write &&  (MAP_PAGEBITS(addr) & PAGE_BIT_PS1) && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS0)))
   3.239 +		{
   3.240 +			// No L7 interrupt, PS[1:0] = 0b01, write
   3.241 +			// No L7 interrupt, PS[1:0] = 0b10, write
   3.242 +			ps0_state = true;
   3.243 +		}
   3.244 +	}
   3.245  
   3.246 -		case MEM_UIE:
   3.247 -			// User access to memory above 4MB
   3.248 -			// FIXME? Shouldn't be possible with DMA... assert this?
   3.249 -			state.genstat = 0xBAFF
   3.250 -				| (reading ? 0x4000 : 0)
   3.251 -				| (state.pie ? 0x0400 : 0);
   3.252 -			access_ok = false;
   3.253 -			break;
   3.254 +#ifdef MAPRAM_BIT_TEST
   3.255 +	LOG("Starting Mapram Bit Test");
   3.256 +	state.map[0] = state.map[1] = 0;
   3.257 +	LOG("Start   = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.258 +	MAP_SET_PAGEBIT(0, PAGE_BIT_WE);
   3.259 +	LOG("Set WE  = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.260 +	MAP_SET_PAGEBIT(0, PAGE_BIT_PS1);
   3.261 +	LOG("Set PS1 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.262 +	MAP_SET_PAGEBIT(0, PAGE_BIT_PS0);
   3.263 +	LOG("Set PS0 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.264 +	
   3.265 +	MAP_CLR_PAGEBIT(0, PAGE_BIT_WE);
   3.266 +	LOG("Clr WE  = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.267 +	MAP_CLR_PAGEBIT(0, PAGE_BIT_PS1);
   3.268 +	LOG("Clr PS1 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.269 +	MAP_CLR_PAGEBIT(0, PAGE_BIT_PS0);
   3.270 +	LOG("Clr PS0 = %04X %02X", MAPRAM_ADDR(0), MAP_PAGEBITS(0));
   3.271 +	exit(-1);
   3.272 +#endif
   3.273 +
   3.274 +	uint16_t old_pagebits = MAP_PAGEBITS(addr);
   3.275  
   3.276 -		case MEM_KERNEL:
   3.277 -		case MEM_PAGE_NO_WE:
   3.278 -			// Kernel access or page not write enabled
   3.279 -			/* XXX: is this correct? */
   3.280 -			state.genstat = 0xBBFF
   3.281 -				| (reading ? 0x4000 : 0)
   3.282 -				| (state.pie ? 0x0400 : 0);
   3.283 -			access_ok = false;
   3.284 -			break;
   3.285 +	// PS1 is always set on access
   3.286 +	MAP_SET_PAGEBIT(addr, PAGE_BIT_PS1);
   3.287 +
   3.288 +	uint16_t new_pagebit1 = MAP_PAGEBITS(addr);
   3.289 +
   3.290 +	// Update PS0
   3.291 +	if (ps0_state) {
   3.292 +		MAP_SET_PAGEBIT(addr, PAGE_BIT_PS0);
   3.293 +	} else {
   3.294 +		MAP_CLR_PAGEBIT(addr, PAGE_BIT_PS0);
   3.295 +	}
   3.296  
   3.297 -		case MEM_ALLOWED:
   3.298 -			access_ok = true;
   3.299 +	uint16_t new_pagebit2 = MAP_PAGEBITS(addr);
   3.300 +	switch (addr) {
   3.301 +		case 0x000000:
   3.302 +		case 0x001000:
   3.303 +		case 0x002000:
   3.304 +		case 0x003000:
   3.305 +		case 0x004000:
   3.306 +		case 0x033000:
   3.307 +		case 0x034000:
   3.308 +		case 0x035000:
   3.309 +			LOG("Addr %08X MapNew %04X Pagebit update -- ps0 %d, %02X => %02X => %02X", addr, MAPRAM_ADDR(addr), ps0_state, old_pagebits, new_pagebit1, new_pagebit2);
   3.310 +		default:
   3.311  			break;
   3.312  	}
   3.313 -	if (!access_ok) {
   3.314 +}
   3.315 +
   3.316 +bool access_check_dma(void)
   3.317 +{
   3.318 +	// TODO FIXME BUGBUG Sanity check - Make sure DMAC is only accessing RAM addresses
   3.319 +
   3.320 +	// DMA access check -- make sure the page is mapped in
   3.321 +	if (!(MAP_PAGEBITS(state.dma_address) & PAGE_BIT_PS0) && !(MAP_PAGEBITS(state.dma_address) & PAGE_BIT_PS1)) {
   3.322 +		// DMA access to page which is not mapped in.
   3.323 +		// Level 7 interrupt, page fault, DMA invoked
   3.324 +		state.genstat = 0xABFF
   3.325 +			| (state.dma_reading ? 0x4000 : 0)
   3.326 +			| (state.pie ? 0x0400 : 0);
   3.327 +
   3.328 +		// XXX: Check all this stuff.
   3.329  		state.bsr0 = 0x3C00;
   3.330  		state.bsr0 |= (state.dma_address >> 16);
   3.331  		state.bsr1 = state.dma_address & 0xffff;
   3.332 -		if (state.ee) m68k_set_irq(7);
   3.333 -		printf("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
   3.334 +
   3.335 +		// Update page bits for this transfer
   3.336 +		update_page_bits(state.dma_address, true, !state.dma_reading);
   3.337 +
   3.338 +		// XXX: is this right?
   3.339 +		// Fire a Level 7 interrupt
   3.340 +		/*if (state.ee)*/ m68k_set_irq(7);
   3.341 +
   3.342 +		LOG("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
   3.343 +		return false;
   3.344 +	} else {
   3.345 +		// No errors. Just update the page bits.
   3.346 +		update_page_bits(state.dma_address, false, !state.dma_reading);
   3.347 +		return true;
   3.348  	}
   3.349 -	return (access_ok);
   3.350 +}
   3.351 +
   3.352 +/**
   3.353 + * Check memory access permissions for a CPU memory access.
   3.354 + *
   3.355 + * @param	addr	Virtual memory address being accessed (from CPU address bus).
   3.356 + * @param	bits	Word size of this transfer (8, 16 or 32 bits).
   3.357 + * @param	write	<i>true</i> if this is a write operation, <i>false</i> if it is a read operation.
   3.358 + * @return	<i>true</i> if the access was denied and a level-7 interrupt and/or bus error raised.
   3.359 + * 			<i>false</i> if the access was allowed.
   3.360 + */
   3.361 +bool access_check_cpu(uint32_t addr, int bits, bool write)
   3.362 +{
   3.363 +	bool supervisor = (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000);
   3.364 +	bool fault = false;
   3.365 +
   3.366 +	// TODO FIXME BUGBUG? Do we need to check for supervisor access here?
   3.367 +	if ((addr >= 0x000000) && (addr <= 0x3FFFFF) && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS1) && !(MAP_PAGEBITS(addr) & PAGE_BIT_PS0)) {
   3.368 +		// (A) Page Fault -- user access to page which is not mapped in
   3.369 +		// Level 7 Interrupt, Bus Error, regs=PAGEFAULT
   3.370 +		if (write) {
   3.371 +			state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0);
   3.372 +		} else {
   3.373 +			state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0);
   3.374 +		}
   3.375 +		fault = true;
   3.376 +	} else if (!supervisor && (addr >= 0x000000) && (addr <= 0x07FFFF)) {
   3.377 +		// (B) User attempted to access the kernel
   3.378 +		// Level 7 Interrupt, Bus Error, regs=KERNEL
   3.379 +		if (write) {
   3.380 +			// XXX: BUGBUG? Is this correct?
   3.381 +			state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0);
   3.382 +		} else {
   3.383 +			state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0);
   3.384 +		}
   3.385 +		fault = true;
   3.386 +	} else if (!supervisor && write && (addr >= 0x000000) && (addr <= 0x3FFFFF) && !(MAP_PAGEBITS(addr) & PAGE_BIT_WE)) {
   3.387 +		// (C) User attempted to write to a page which is not write enabled
   3.388 +		// Level 7 Interrupt, Bus Error, regs=WRITE_EN
   3.389 +		if (write) {
   3.390 +			// XXX: BUGBUG? Is this correct?
   3.391 +			state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0);
   3.392 +		} else {
   3.393 +			state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0);
   3.394 +		}
   3.395 +		fault = true;
   3.396 +	} else if (!supervisor && (addr >= 0x400000) && (addr <= 0xFFFFFF)) {
   3.397 +		// (D) UIE - user I/O exception
   3.398 +		// Bus Error only, regs=UIE
   3.399 +		if (write) {
   3.400 +			state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0);
   3.401 +		} else {
   3.402 +			state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0);
   3.403 +		}
   3.404 +		fault = true;
   3.405 +	}
   3.406 +
   3.407 +	// Update the page bits first
   3.408 +	update_page_bits(addr, fault, write);
   3.409 +
   3.410 +	if (fault) {
   3.411 +		if (bits >= 16)
   3.412 +			state.bsr0 = 0x7C00;
   3.413 +		else
   3.414 +			state.bsr0 = (addr & 1) ? 0x7E00 : 0x7D00;
   3.415 +		// FIXME? Physical or virtual address here?
   3.416 +		state.bsr0 |= (addr >> 16);
   3.417 +		state.bsr1 = addr & 0xffff;
   3.418 +
   3.419 +		LOG("CPU Bus Error or L7Intr while %s, vaddr %08X, map %08X, pagebits 0x%02X bsr0=%04X bsr1=%04X genstat=%04X", 
   3.420 +				write ? "writing" : "reading", addr,
   3.421 +				MAPRAM_ADDR(addr & 0x3fffff),
   3.422 +				MAP_PAGEBITS(addr & 0x3fffff),
   3.423 +				state.bsr0, state.bsr1, state.genstat);
   3.424 +
   3.425 +		// FIXME? BUGBUG? Does EE disable one or both of these?
   3.426 +		// /*if (state.ee)*/ m68k_set_irq(7);
   3.427 +		/*if (state.ee)*/ m68k_pulse_bus_error();
   3.428 +	}
   3.429 +
   3.430 +	return fault;
   3.431  }
   3.432  
   3.433  // Logging macros
   3.434  #define LOG_NOT_HANDLED_R(bits)															\
   3.435 -	if (!handled) printf("unhandled read%02d, addr=0x%08X\n", bits, address);
   3.436 +	if (!handled) fprintf(stderr, "unhandled read%02d, addr=0x%08X\n", bits, address);
   3.437  
   3.438  #define LOG_NOT_HANDLED_W(bits)															\
   3.439 -	if (!handled) printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
   3.440 +	if (!handled) fprintf(stderr, "unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
   3.441  
   3.442  /********************************************************
   3.443   * I/O read/write functions
   3.444 @@ -286,7 +283,7 @@
   3.445  {
   3.446  	assert((bits == 8) || (bits == 16) || (bits == 32));
   3.447  	if ((bits & allowed) == 0) {
   3.448 -		printf("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
   3.449 +		LOG("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
   3.450  	}
   3.451  }
   3.452  
   3.453 @@ -349,6 +346,7 @@
   3.454  			case 0x070000:				// Line Printer Status Register
   3.455  				break;
   3.456  			case 0x080000:				// Real Time Clock
   3.457 +				LOGS("REAL TIME CLOCK WRITE");
   3.458  				break;
   3.459  			case 0x090000:				// Phone registers
   3.460  				switch (address & 0x0FF000) {
   3.461 @@ -483,6 +481,7 @@
   3.462  						handled = true;
   3.463  						break;
   3.464  					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   3.465 +						LOGS("REAL TIME CLOCK DATA WRITE");
   3.466  						break;
   3.467  					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   3.468  						switch (address & 0x077000) {
   3.469 @@ -529,11 +528,15 @@
   3.470  						// TODO: figure out which sizes are valid (probably just 8 and 16)
   3.471  						// ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
   3.472  						if (bits == 8) {
   3.473 -							printf("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
   3.474 +#ifdef LOG_KEYBOARD_WRITES
   3.475 +							LOG("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
   3.476 +#endif
   3.477  							keyboard_write(&state.kbd, (address >> 1) & 3, data);
   3.478  							handled = true;
   3.479  						} else if (bits == 16) {
   3.480 -							printf("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
   3.481 +#ifdef LOG_KEYBOARD_WRITES
   3.482 +							LOG("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
   3.483 +#endif
   3.484  							keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
   3.485  							handled = true;
   3.486  						}
   3.487 @@ -587,7 +590,7 @@
   3.488  				return data;
   3.489  				break;
   3.490  			case 0x080000:				// Real Time Clock
   3.491 -				printf("READ NOTIMP: Realtime Clock\n");
   3.492 +				LOGS("REAL TIME CLOCK READ");
   3.493  				break;
   3.494  			case 0x090000:				// Phone registers
   3.495  				switch (address & 0x0FF000) {
   3.496 @@ -665,6 +668,7 @@
   3.497  					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   3.498  						break;
   3.499  					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   3.500 +						LOGS("REAL TIME CLOCK DATA READ");
   3.501  						break;
   3.502  					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   3.503  						switch (address & 0x077000) {
   3.504 @@ -735,7 +739,8 @@
   3.505  		return RD32(state.rom, address, ROM_SIZE - 1);
   3.506  	} else if (address <= 0x3fffff) {
   3.507  		// RAM access
   3.508 -		uint32_t newAddr = mapAddr(address, false);
   3.509 +		uint32_t newAddr = MAP_ADDR(address);
   3.510 +
   3.511  		if (newAddr <= 0x1fffff) {
   3.512  			if (newAddr >= state.base_ram_size)
   3.513  				return EMPTY & 0xffffffff;
   3.514 @@ -787,7 +792,8 @@
   3.515  		data = RD16(state.rom, address, ROM_SIZE - 1);
   3.516  	} else if (address <= 0x3fffff) {
   3.517  		// RAM access
   3.518 -		uint32_t newAddr = mapAddr(address, false);
   3.519 +		uint32_t newAddr = MAP_ADDR(address);
   3.520 +
   3.521  		if (newAddr <= 0x1fffff) {
   3.522  			if (newAddr >= state.base_ram_size)
   3.523  				return EMPTY & 0xffff;
   3.524 @@ -839,7 +845,8 @@
   3.525  		data = RD8(state.rom, address, ROM_SIZE - 1);
   3.526  	} else if (address <= 0x3fffff) {
   3.527  		// RAM access
   3.528 -		uint32_t newAddr = mapAddr(address, false);
   3.529 +		uint32_t newAddr = MAP_ADDR(address);
   3.530 +
   3.531  		if (newAddr <= 0x1fffff) {
   3.532  			if (newAddr >= state.base_ram_size)
   3.533  				return EMPTY & 0xff;
   3.534 @@ -888,7 +895,8 @@
   3.535  		// ROM access
   3.536  	} else if (address <= 0x3FFFFF) {
   3.537  		// RAM access
   3.538 -		uint32_t newAddr = mapAddr(address, true);
   3.539 +		uint32_t newAddr = MAP_ADDR(address);
   3.540 +
   3.541  		if (newAddr <= 0x1fffff) {
   3.542  			if (newAddr < state.base_ram_size) {
   3.543  				WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
   3.544 @@ -933,7 +941,7 @@
   3.545  		// ROM access
   3.546  	} else if (address <= 0x3FFFFF) {
   3.547  		// RAM access
   3.548 -		uint32_t newAddr = mapAddr(address, true);
   3.549 +		uint32_t newAddr = MAP_ADDR(address);
   3.550  
   3.551  		if (newAddr <= 0x1fffff) {
   3.552  			if (newAddr < state.base_ram_size) {
   3.553 @@ -979,7 +987,8 @@
   3.554  		// ROM access (read only!)
   3.555  	} else if (address <= 0x3FFFFF) {
   3.556  		// RAM access
   3.557 -		uint32_t newAddr = mapAddr(address, true);
   3.558 +		uint32_t newAddr = MAP_ADDR(address);
   3.559 +
   3.560  		if (newAddr <= 0x1fffff) {
   3.561  			if (newAddr < state.base_ram_size) {
   3.562  				WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
   3.563 @@ -1013,6 +1022,7 @@
   3.564  uint32_t m68k_read_disassembler_32(uint32_t addr)
   3.565  {
   3.566  	if (addr < 0x400000) {
   3.567 +		// XXX FIXME BUGBUG update this to use the new mapper macros!
   3.568  		uint16_t page = (addr >> 12) & 0x3FF;
   3.569  		uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
   3.570  		uint32_t newAddr = (new_page_addr << 12) + (addr & 0xFFF);
   3.571 @@ -1028,7 +1038,7 @@
   3.572  				return EMPTY;
   3.573  		}
   3.574  	} else {
   3.575 -		printf(">>> WARNING Disassembler RD32 out of range 0x%08X\n", addr);
   3.576 +		LOG("WARNING: Disassembler RD32 out of range 0x%08X\n", addr);
   3.577  		return EMPTY;
   3.578  	}
   3.579  }
   3.580 @@ -1051,7 +1061,7 @@
   3.581  				return EMPTY & 0xffff;
   3.582  		}
   3.583  	} else {
   3.584 -		printf(">>> WARNING Disassembler RD16 out of range 0x%08X\n", addr);
   3.585 +		LOG("WARNING: Disassembler RD16 out of range 0x%08X\n", addr);
   3.586  		return EMPTY & 0xffff;
   3.587  	}
   3.588  }
   3.589 @@ -1074,7 +1084,7 @@
   3.590  				return EMPTY & 0xff;
   3.591  		}
   3.592  	} else {
   3.593 -		printf(">>> WARNING Disassembler RD8 out of range 0x%08X\n", addr);
   3.594 +		LOG("WARNING: Disassembler RD8 out of range 0x%08X\n", addr);
   3.595  		return EMPTY & 0xff;
   3.596  	}
   3.597  }
     4.1 --- a/src/memory.h	Wed Jan 16 00:41:51 2013 +0000
     4.2 +++ b/src/memory.h	Fri Jan 18 17:03:48 2013 +0000
     4.3 @@ -45,14 +45,57 @@
     4.4   * Memory mapping
     4.5   ******************/
     4.6  
     4.7 -typedef enum {
     4.8 -	MEM_ALLOWED = 0,
     4.9 -	MEM_PAGEFAULT,		// Page fault -- page not present
    4.10 -	MEM_PAGE_NO_WE,		// Page not write enabled
    4.11 -	MEM_KERNEL,			// User attempted to access kernel memory
    4.12 -	MEM_UIE				// User Nonmemory Location Access
    4.13 -} MEM_STATUS;
    4.14 +/***
    4.15 + * An entry in MAP RAM looks like this:
    4.16 + *
    4.17 + *    15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    4.18 + *   +-----------------------------------------------+
    4.19 + *   |  |  |  |  |  |  |   MA[21..12] ADDRESS BITS   |
    4.20 + *   +-----------------------------------------------+
    4.21 + *
    4.22 + *   Bits 0 thru 9: High 10 address bits (mapping)
    4.23 + *   Bits 10 thru 15: Page bits
    4.24 + *     B10: PS4
    4.25 + *     B11: PS3
    4.26 + *     B12: PS2
    4.27 + *     B13: PS0
    4.28 + *     B14: PS1
    4.29 + *     B15: WE+
    4.30 + *
    4.31 + * Page bit meanings:
    4.32 + *    PS4, 3 and 2 are unused.
    4.33 + *    PS1:PS0:
    4.34 + *      PS1  PS0   Meaning
    4.35 + *      ---  ---   -------
    4.36 + *       0    0    Page not present
    4.37 + *       0    1    Page present but has not been accessed
    4.38 + *       1    0    Page has been accessed but not written
    4.39 + *       1    1    Page has been accessed and written to (is dirty)
    4.40 + *
    4.41 + *    WE+: Write Enable. Set to 1 if the page is writable.
    4.42 + *
    4.43 + * Each RAM page is 4096 bytes.
    4.44 + */
    4.45  
    4.46 +/// Known page bits and their values
    4.47 +enum {
    4.48 +	PAGE_BIT_PS0 = 0x08,	///< PS0 page status bit
    4.49 +	PAGE_BIT_PS1 = 0x10,	///< PS1 (page accessed) page bit
    4.50 +	PAGE_BIT_WE  = 0x20		///< WE (write enable) page bit
    4.51 +};
    4.52 +
    4.53 +/// Get the Map RAM entry for the specified page
    4.54 +#define MAPRAM(page) (((uint16_t)state.map[page*2] << 8) + ((uint16_t)state.map[(page*2)+1]))
    4.55 +/// Get the page number for a given address
    4.56 +#define MAP_ADDR_TO_PAGE(addr) (((addr) >> 12) & 0x3FF)
    4.57 +/// Get the Map RAM entry for the specified virtual address
    4.58 +#define MAPRAM_ADDR(addr) (MAPRAM(MAP_ADDR_TO_PAGE(addr)))
    4.59 +/// Map an address from CPU address space to physical memory
    4.60 +#define MAP_ADDR(addr) (((MAPRAM_ADDR(addr) & 0x3FF) << 12) | (addr & 0xFFF))
    4.61 +/// Get the page bits associated with the mapping for a given physical memory address
    4.62 +#define MAP_PAGEBITS(addr) ((MAPRAM_ADDR(addr) >> 10) & 0x3F)
    4.63 +
    4.64 +#if 0
    4.65  /**
    4.66   * @brief 	Check memory access permissions for a given address.
    4.67   * @param	addr		Address.
    4.68 @@ -63,19 +106,18 @@
    4.69  MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing);
    4.70  
    4.71  /**
    4.72 - * @brief	Map a CPU memory address into physical memory space.
    4.73 - * @param	addr		Address.
    4.74 - * @param	writing		true if writing to memory, false if reading.
    4.75 - * @return	Address, remapped into physical memory.
    4.76 - */
    4.77 -uint32_t mapAddr(uint32_t addr, bool writing);
    4.78 -
    4.79 -/**
    4.80   * @brief   Check access flags for a DMA transfer and trigger an exception if
    4.81   *          the access is not permitted
    4.82   * @param   reading     true if reading from memory, false if writing
    4.83 - * @return  true if the access is permitted, false if not
    4.84   */
    4.85  bool access_check_dma(int reading);
    4.86 +#endif
    4.87 +
    4.88 +
    4.89 +/**
    4.90 + * Check memory access permissions for a DMA operation.
    4.91 + * @return  true if the access is permitted, false if not
    4.92 + */
    4.93 +bool access_check_dma(void);
    4.94  
    4.95  #endif
     5.1 --- a/src/musashi/m68kcpu.h	Wed Jan 16 00:41:51 2013 +0000
     5.2 +++ b/src/musashi/m68kcpu.h	Fri Jan 18 17:03:48 2013 +0000
     5.3 @@ -1,4 +1,5 @@
     5.4  #include <stdio.h>
     5.5 +#include <ctype.h>
     5.6  /* ======================================================================== */
     5.7  /* ========================= LICENSING & COPYRIGHT ======================== */
     5.8  /* ======================================================================== */
     5.9 @@ -1652,6 +1653,41 @@
    5.10  INLINE void m68ki_exception_trapN(uint vector)
    5.11  {
    5.12  	uint sr = m68ki_init_exception();
    5.13 +
    5.14 +#ifdef MC68K_TRAP_SYSCALLS
    5.15 +	if (vector == 32) {
    5.16 +		printf(">>> TRAP #0 = SYSCALL #%d%s\n", REG_D[0] & 63, REG_D[0] > 63 ? "!!!" : "");
    5.17 +		// d0 = syscall number
    5.18 +		printf("\t d0:%08X    d1:%08X    d2:%08X    d3:%08X\n", REG_D[0], REG_D[1], REG_D[2], REG_D[3]);
    5.19 +		printf("\t d4:%08X    d5:%08X    d6:%08X    d7:%08X\n", REG_D[4], REG_D[5], REG_D[6], REG_D[7]);
    5.20 +		printf("\t a0:%08X    a1:%08X    a2:%08X    a3:%08X\n", REG_A[0], REG_A[1], REG_A[2], REG_A[3]);
    5.21 +		printf("\t a4:%08X    a5:%08X    a6:%08X    sp:%08X\n", REG_A[4], REG_A[5], REG_A[6], REG_USP);
    5.22 +		printf("\t pc:%08X    sr:%08X\n", REG_PC, sr);
    5.23 +
    5.24 +		/*
    5.25 +		// dump stack -- but syscalls use registers to pass parameters
    5.26 +		for (int i=-128; i<128; i+=4) {
    5.27 +			printf("  sp%s%02d: %08X\n", i<0?"":"+", i, m68k_read_disassembler_32(REG_SP+i));
    5.28 +		}
    5.29 +		*/
    5.30 +		for (int r=0; r<2; r++) {
    5.31 +			printf("  *a%d: [", r);
    5.32 +			if (REG_A[r] == 0x00) {
    5.33 +				printf("NullPointer]\n");
    5.34 +				continue;
    5.35 +			}
    5.36 +			for (int i=0; i<32; i++) {
    5.37 +				unsigned char c = m68k_read_disassembler_8(REG_A[r]+i);
    5.38 +				if (isprint(c))
    5.39 +					putchar(c);
    5.40 +				else
    5.41 +					putchar('.');
    5.42 +			}
    5.43 +			printf("]\n");
    5.44 +		}
    5.45 +	}
    5.46 +#endif // MC68K_TRAP_SYSCALLS
    5.47 +
    5.48  	m68ki_stack_frame_0000(REG_PC, sr, vector);
    5.49  	m68ki_jump_vector(vector);
    5.50  
     6.1 --- a/src/wd2010.c	Wed Jan 16 00:41:51 2013 +0000
     6.2 +++ b/src/wd2010.c	Fri Jan 18 17:03:48 2013 +0000
     6.3 @@ -263,6 +263,7 @@
     6.4  	size_t lba;
     6.5  	int new_track;
     6.6  	int sector_count;
     6.7 +	unsigned int ssz;
     6.8  
     6.9  	m68k_end_timeslice();
    6.10  
    6.11 @@ -296,7 +297,7 @@
    6.12  			break;
    6.13  		case WD2010_REG_SDH:
    6.14  			/*XXX: remove this once the DMA page fault test passes (unless this is actually the correct behavior here)*/
    6.15 -			ctx->data_pos = ctx->data_len = 0;
    6.16 +			//ctx->data_pos = ctx->data_len = 0;
    6.17  			ctx->sdh = val;
    6.18  			break;
    6.19  		case WD2010_REG_COMMAND:	// Command register
    6.20 @@ -343,13 +344,23 @@
    6.21  							break;
    6.22  						case CMD_READ_SECTOR:
    6.23  							/*XXX: does a separate function to set the head have to be added?*/
    6.24 -							LOG("WD2010: READ SECTOR cmd=%02X chs=%d:%d:%d nsectors=%d", cmd, ctx->track, ctx->head, ctx->sector, ctx->sector_count);
    6.25 +							LOG("WD2010: READ SECTOR cmd=%02X sdh=0x%02X drive=%d ddrive1=%d chs=%d:%d:%d nsectors=%d", cmd, ctx->sdh, (ctx->sdh >> 3) & 3, ctx->mcr2_ddrive1, ctx->track, ctx->head, ctx->sector, val&CMD_MULTI_SECTOR ? ctx->sector_count : 1);
    6.26 +
    6.27 +							switch ((ctx->sdh >> 5) & 0x03) {
    6.28 +								case 0: ssz = 256; break;
    6.29 +								case 1: ssz = 512; break;
    6.30 +								case 2: ssz = 1024; break;
    6.31 +								case 3: ssz = 128; break;
    6.32 +							}
    6.33 +							if (ssz != ctx->geom_secsz)
    6.34 +								LOG("WARNING: Geometry mismatch. WD2010 Write Sector with secsz %d != phys_secsz %d.", ssz, ctx->geom_secsz);
    6.35  
    6.36  							// Read Sector
    6.37  
    6.38  							// Check to see if the cyl, hd and sec are valid
    6.39 -							if ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1)) {
    6.40 -								LOG("*** WD2010 ALERT: CHS parameter limit exceeded! CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
    6.41 +							if ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1) || (ssz != ctx->geom_secsz)) {
    6.42 +								LOG("*** WD2010 ALERT: CHS parameter limit exceeded! dDrive1=%d CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
    6.43 +										ctx->mcr2_ddrive1,
    6.44  										ctx->track, ctx->head, ctx->sector,
    6.45  										ctx->sector_count,
    6.46  										ctx->sector + ctx->sector_count - 1,
    6.47 @@ -395,12 +406,22 @@
    6.48  						case CMD_WRITE_FORMAT:
    6.49  							ctx->sector = 0;
    6.50  						case CMD_WRITE_SECTOR:
    6.51 -							LOG("WD2010: WRITE SECTOR cmd=%02X chs=%d:%d:%d nsectors=%d", cmd, ctx->track, ctx->head, ctx->sector, ctx->sector_count);
    6.52 +							LOG("WD2010: WRITE SECTOR cmd=%02X sdh=0x%02X drive=%d ddrive1=%d chs=%d:%d:%d nsectors=%d", cmd, ctx->sdh, (ctx->sdh >> 3) & 3, ctx->mcr2_ddrive1, ctx->track, ctx->head, ctx->sector, val&CMD_MULTI_SECTOR ? ctx->sector_count : 1);
    6.53  							// Write Sector
    6.54  
    6.55 +							switch ((ctx->sdh >> 5) & 0x03) {
    6.56 +								case 0: ssz = 256; break;
    6.57 +								case 1: ssz = 512; break;
    6.58 +								case 2: ssz = 1024; break;
    6.59 +								case 3: ssz = 128; break;
    6.60 +							}
    6.61 +							if (ssz != ctx->geom_secsz)
    6.62 +								LOG("WARNING: Geometry mismatch. WD2010 Write Sector with secsz %d != phys_secsz %d.", ssz, ctx->geom_secsz);
    6.63 +
    6.64  							// Check to see if the cyl, hd and sec are valid
    6.65 -							if ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1)) {
    6.66 -								LOG("*** WD2010 ALERT: CHS parameter limit exceeded! CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
    6.67 +							if ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1) || (ssz != ctx->geom_secsz)) {
    6.68 +								LOG("*** WD2010 ALERT: CHS parameter limit exceeded! dDrive1=%d CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
    6.69 +										ctx->mcr2_ddrive1,
    6.70  										ctx->track, ctx->head, ctx->sector,
    6.71  										ctx->sector_count,
    6.72  										ctx->sector + ctx->sector_count - 1,