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