Fri, 18 Apr 2014 01:26:01 -0600
treat all DMA reads/writes as kernel mode (previously it would depend on whether the processor happens to be in user mode or kernel mode when the DMA completes, which is totally incorrect); handle 32-bit accesses that straddle page boundaries properly (all 32-bit accesses are now split into two 16-bit accesses); allow reads to the entire zero page, rather than just address 0
src/memory.c | file | annotate | diff | revisions | |
src/memory.h | file | annotate | diff | revisions |
1.1 diff -r 1124f0f5409d -r c19afa2c81db src/memory.c 1.2 --- a/src/memory.c Thu Apr 17 01:58:05 2014 -0600 1.3 +++ b/src/memory.c Fri Apr 18 01:26:01 2014 -0600 1.4 @@ -20,6 +20,15 @@ 1.5 1.6 #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1])) 1.7 1.8 +static uint32_t map_address_debug(uint32_t addr) 1.9 +{ 1.10 + uint16_t page = (addr >> 12) & 0x3FF; 1.11 + 1.12 + // Look it up in the map RAM and get the physical page address 1.13 + uint32_t new_page_addr = MAPRAM(page) & 0x3FF; 1.14 + return (new_page_addr << 12) + (addr & 0xFFF); 1.15 +} 1.16 + 1.17 uint32_t mapAddr(uint32_t addr, bool writing)/*{{{*/ 1.18 { 1.19 if (addr < 0x400000) { 1.20 @@ -70,7 +79,7 @@ 1.21 } 1.22 }/*}}}*/ 1.23 1.24 -MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)/*{{{*/ 1.25 +MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing, bool dma)/*{{{*/ 1.26 { 1.27 // Get the page bits for this page. 1.28 uint16_t page = (addr >> 12) & 0x3FF; 1.29 @@ -83,7 +92,7 @@ 1.30 } 1.31 1.32 // Are we in Supervisor mode? 1.33 - if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000) 1.34 + if (dma || (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)) 1.35 // Yes. We can do anything we like. 1.36 return MEM_ALLOWED; 1.37 1.38 @@ -96,7 +105,7 @@ 1.39 1.40 // User attempt to access the kernel 1.41 // A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode 1.42 - if (((addr >> 19) & 0x0F) == 0) { 1.43 + if (((addr >> 19) & 0x0F) == 0 && !(!writing && addr <= 0x1000)) { 1.44 LOGS("Attempt by user code to access kernel space"); 1.45 return MEM_KERNEL; 1.46 } 1.47 @@ -107,32 +116,13 @@ 1.48 addr, page, MAPRAM(page), state.map[page*2], state.map[(page*2)+1], pagebits); 1.49 return MEM_PAGE_NO_WE; 1.50 } 1.51 - 1.52 // Page access allowed. 1.53 return MEM_ALLOWED; 1.54 }/*}}}*/ 1.55 1.56 - 1.57 - 1.58 -/******************************************************** 1.59 - * m68k memory read/write support functions for Musashi 1.60 - ********************************************************/ 1.61 - 1.62 -/** 1.63 - * @brief Check memory access permissions for a write operation. 1.64 - * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but 1.65 - * gcc throws warnings when you have a return-with-value in a void 1.66 - * function, even if the return-with-value is completely unreachable. 1.67 - * Similarly it doesn't like it if you have a return without a value 1.68 - * in a non-void function, even if it's impossible to ever reach the 1.69 - * return-with-no-value. UGH! 1.70 - */ 1.71 -/*{{{ macro: ACCESS_CHECK_WR(address, bits)*/ 1.72 -#define ACCESS_CHECK_WR(address, bits) \ 1.73 +#define _ACCESS_CHECK_WR_BYTE(address) \ 1.74 do { \ 1.75 - bool fault = false; \ 1.76 - MEM_STATUS st; \ 1.77 - switch (st = checkMemoryAccess(address, true)) { \ 1.78 + switch (st = checkMemoryAccess(address, true, false)) { \ 1.79 case MEM_ALLOWED: \ 1.80 /* Access allowed */ \ 1.81 break; \ 1.82 @@ -154,7 +144,33 @@ 1.83 fault = true; \ 1.84 break; \ 1.85 } \ 1.86 - \ 1.87 + }while (0) 1.88 + 1.89 + 1.90 + 1.91 +/******************************************************** 1.92 + * m68k memory read/write support functions for Musashi 1.93 + ********************************************************/ 1.94 + 1.95 +/** 1.96 + * @brief Check memory access permissions for a write operation. 1.97 + * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but 1.98 + * gcc throws warnings when you have a return-with-value in a void 1.99 + * function, even if the return-with-value is completely unreachable. 1.100 + * Similarly it doesn't like it if you have a return without a value 1.101 + * in a non-void function, even if it's impossible to ever reach the 1.102 + * return-with-no-value. UGH! 1.103 + */ 1.104 +/*{{{ macro: ACCESS_CHECK_WR(address, bits)*/ 1.105 +#define ACCESS_CHECK_WR(address, bits) \ 1.106 + do { \ 1.107 + bool fault = false; \ 1.108 + MEM_STATUS st; \ 1.109 + _ACCESS_CHECK_WR_BYTE(address); \ 1.110 + if (!fault && bits == 32 \ 1.111 + && ((address + 3) & ~0xfff) != ((address & ~0xfff))){ \ 1.112 + _ACCESS_CHECK_WR_BYTE(address + 3); \ 1.113 + } \ 1.114 if (fault) { \ 1.115 if (bits >= 16) \ 1.116 state.bsr0 = 0x7C00; \ 1.117 @@ -169,21 +185,9 @@ 1.118 } while (0) 1.119 /*}}}*/ 1.120 1.121 -/** 1.122 - * @brief Check memory access permissions for a read operation. 1.123 - * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but 1.124 - * gcc throws warnings when you have a return-with-value in a void 1.125 - * function, even if the return-with-value is completely unreachable. 1.126 - * Similarly it doesn't like it if you have a return without a value 1.127 - * in a non-void function, even if it's impossible to ever reach the 1.128 - * return-with-no-value. UGH! 1.129 - */ 1.130 -/*{{{ macro: ACCESS_CHECK_RD(address, bits)*/ 1.131 -#define ACCESS_CHECK_RD(address, bits) \ 1.132 +#define _ACCESS_CHECK_RD_BYTE(address) \ 1.133 do { \ 1.134 - bool fault = false; \ 1.135 - MEM_STATUS st; \ 1.136 - switch (st = checkMemoryAccess(address, false)) { \ 1.137 + switch (st = checkMemoryAccess(address, false, false)) { \ 1.138 case MEM_ALLOWED: \ 1.139 /* Access allowed */ \ 1.140 break; \ 1.141 @@ -205,15 +209,38 @@ 1.142 fault = true; \ 1.143 break; \ 1.144 } \ 1.145 + } while (0) 1.146 + 1.147 +/** 1.148 + * @brief Check memory access permissions for a read operation. 1.149 + * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but 1.150 + * gcc throws warnings when you have a return-with-value in a void 1.151 + * function, even if the return-with-value is completely unreachable. 1.152 + * Similarly it doesn't like it if you have a return without a value 1.153 + * in a non-void function, even if it's impossible to ever reach the 1.154 + * return-with-no-value. UGH! 1.155 + */ 1.156 +/*{{{ macro: ACCESS_CHECK_RD(address, bits)*/ 1.157 +#define ACCESS_CHECK_RD(address, bits) \ 1.158 + do { \ 1.159 + bool fault = false; \ 1.160 + uint32_t faultAddr = address; \ 1.161 + MEM_STATUS st; \ 1.162 + _ACCESS_CHECK_RD_BYTE(address); \ 1.163 + if (!fault && bits == 32 \ 1.164 + && ((address + 2) & ~0xfff) != (address & ~0xfff)){ \ 1.165 + _ACCESS_CHECK_RD_BYTE(address + 2); \ 1.166 + if (fault) faultAddr = address + 2; \ 1.167 + } \ 1.168 \ 1.169 if (fault) { \ 1.170 if (bits >= 16) \ 1.171 state.bsr0 = 0x7C00; \ 1.172 else \ 1.173 - state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \ 1.174 - state.bsr0 |= (address >> 16); \ 1.175 - state.bsr1 = address & 0xffff; \ 1.176 - LOG("Bus Error while reading, addr %08X, statcode %d", address, st); \ 1.177 + state.bsr0 = (faultAddr & 1) ? 0x7E00 : 0x7D00; \ 1.178 + state.bsr0 |= (faultAddr >> 16); \ 1.179 + state.bsr1 = faultAddr & 0xffff; \ 1.180 + LOG("Bus Error while reading, addr %08X, statcode %d", faultAddr, st); \ 1.181 if (state.ee) m68k_pulse_bus_error(); \ 1.182 if (bits >= 32) \ 1.183 return EMPTY & 0xFFFFFFFF; \ 1.184 @@ -227,7 +254,7 @@ 1.185 { 1.186 // Check memory access permissions 1.187 bool access_ok = false; 1.188 - switch (checkMemoryAccess(state.dma_address, !reading)) { 1.189 + switch (checkMemoryAccess(state.dma_address, !reading, true)) { 1.190 case MEM_PAGEFAULT: 1.191 // Page fault 1.192 state.genstat = 0xABFF 1.193 @@ -717,6 +744,20 @@ 1.194 * m68k memory read/write support functions for Musashi 1.195 ********************************************************/ 1.196 1.197 + 1.198 +static uint16_t ram_read_16(uint32_t address) 1.199 +{ 1.200 + if (address <= 0x1fffff) { 1.201 + // Base memory wraps around 1.202 + return RD16(state.base_ram, address, state.base_ram_size - 1); 1.203 + } else { 1.204 + if ((address <= (state.exp_ram_size + 0x200000 - 1)) && (address >= 0x200000)){ 1.205 + return RD16(state.exp_ram, address - 0x200000, state.exp_ram_size - 1); 1.206 + }else 1.207 + return EMPTY & 0xffff; 1.208 + } 1.209 +} 1.210 + 1.211 /** 1.212 * @brief Read M68K memory, 32-bit 1.213 */ 1.214 @@ -737,15 +778,11 @@ 1.215 } else if (address <= 0x3fffff) { 1.216 // RAM access 1.217 uint32_t newAddr = mapAddr(address, false); 1.218 - if (newAddr <= 0x1fffff) { 1.219 - // Base memory wraps around 1.220 - return RD32(state.base_ram, newAddr, state.base_ram_size - 1); 1.221 - } else { 1.222 - if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000)) 1.223 - return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1); 1.224 - else 1.225 - return EMPTY & 0xffffffff; 1.226 - } 1.227 + // Base memory wraps around 1.228 + data = ((ram_read_16(newAddr) << 16) | 1.229 + ram_read_16(mapAddr(address + 2, false))); 1.230 + 1.231 + return (data); 1.232 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { 1.233 // I/O register space, zone A 1.234 switch (address & 0x0F0000) { 1.235 @@ -867,6 +904,20 @@ 1.236 return data; 1.237 }/*}}}*/ 1.238 1.239 + 1.240 +static void ram_write_16(uint32_t address, uint32_t value)/*{{{*/ 1.241 +{ 1.242 + if (address <= 0x1fffff) { 1.243 + if (address < state.base_ram_size) { 1.244 + WR16(state.base_ram, address, state.base_ram_size - 1, value); 1.245 + } 1.246 + } else { 1.247 + if ((address - 0x200000) < state.exp_ram_size) { 1.248 + WR16(state.exp_ram, address - 0x200000, state.exp_ram_size - 1, value); 1.249 + } 1.250 + } 1.251 +} 1.252 + 1.253 /** 1.254 * @brief Write M68K memory, 32-bit 1.255 */ 1.256 @@ -878,21 +929,13 @@ 1.257 1.258 // Check access permissions 1.259 ACCESS_CHECK_WR(address, 32); 1.260 - 1.261 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.262 // ROM access 1.263 } else if (address <= 0x3FFFFF) { 1.264 // RAM access 1.265 uint32_t newAddr = mapAddr(address, true); 1.266 - if (newAddr <= 0x1fffff) { 1.267 - if (newAddr < state.base_ram_size) { 1.268 - WR32(state.base_ram, newAddr, state.base_ram_size - 1, value); 1.269 - } 1.270 - } else { 1.271 - if ((newAddr - 0x200000) < state.exp_ram_size) { 1.272 - WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value); 1.273 - } 1.274 - } 1.275 + ram_write_16(newAddr, (value & 0xffff0000) >> 16); 1.276 + ram_write_16(mapAddr(address + 2, true), (value & 0xffff)); 1.277 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { 1.278 // I/O register space, zone A 1.279 switch (address & 0x0F0000) { 1.280 @@ -1008,20 +1051,12 @@ 1.281 uint32_t m68k_read_disassembler_32(uint32_t addr) 1.282 { 1.283 if (addr < 0x400000) { 1.284 - uint16_t page = (addr >> 12) & 0x3FF; 1.285 - uint32_t new_page_addr = MAPRAM(page) & 0x3FF; 1.286 - uint32_t newAddr = (new_page_addr << 12) + (addr & 0xFFF); 1.287 - if (newAddr <= 0x1fffff) { 1.288 - if (newAddr >= state.base_ram_size) 1.289 - return EMPTY; 1.290 - else 1.291 - return RD32(state.base_ram, newAddr, state.base_ram_size - 1); 1.292 - } else { 1.293 - if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000)) 1.294 - return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1); 1.295 - else 1.296 - return EMPTY; 1.297 - } 1.298 + uint32_t newAddrHigh, newAddrLow; 1.299 + newAddrHigh = map_address_debug(addr); 1.300 + newAddrLow = map_address_debug(addr + 2); 1.301 + return ((ram_read_16(newAddrHigh) << 16) | 1.302 + ram_read_16(newAddrLow)); 1.303 + 1.304 } else { 1.305 printf(">>> WARNING Disassembler RD32 out of range 0x%08X\n", addr); 1.306 return EMPTY;
2.1 diff -r 1124f0f5409d -r c19afa2c81db src/memory.h 2.2 --- a/src/memory.h Thu Apr 17 01:58:05 2014 -0600 2.3 +++ b/src/memory.h Fri Apr 18 01:26:01 2014 -0600 2.4 @@ -60,7 +60,7 @@ 2.5 * @return One of the MEM_STATUS constants, specifying whether the access is 2.6 * permitted, or what error occurred. 2.7 */ 2.8 -MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing); 2.9 +MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing, bool dma); 2.10 2.11 /** 2.12 * @brief Map a CPU memory address into physical memory space.