Thu, 02 Dec 2010 17:01:34 +0000
Implement memory mapping and access checking
src/main.c | file | annotate | diff | revisions | |
src/state.h | file | annotate | diff | revisions |
1.1 diff -r 4fea89e86c5e -r a44afcf2354c src/main.c 1.2 --- a/src/main.c Thu Dec 02 16:37:55 2010 +0000 1.3 +++ b/src/main.c Thu Dec 02 17:01:34 2010 +0000 1.4 @@ -77,9 +77,9 @@ 1.5 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03; 1.6 if (pagebits != 0) { 1.7 if (writing) 1.8 - state.map[addr*2] |= 0x60; // Page written to (dirty) 1.9 + state.map[page*2] |= 0x60; // Page written to (dirty) 1.10 else 1.11 - state.map[addr*2] |= 0x40; // Page accessed but not written 1.12 + state.map[page*2] |= 0x40; // Page accessed but not written 1.13 } 1.14 1.15 // Return the address with the new physical page spliced in 1.16 @@ -139,7 +139,77 @@ 1.17 * m68k memory read/write support functions for Musashi 1.18 ********************************************************/ 1.19 1.20 -// read m68k memory 1.21 +/** 1.22 + * @brief Check memory access permissions for a write operation. 1.23 + * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but 1.24 + * gcc throws warnings when you have a return-with-value in a void 1.25 + * function, even if the return-with-value is completely unreachable. 1.26 + * Similarly it doesn't like it if you have a return without a value 1.27 + * in a non-void function, even if it's impossible to ever reach the 1.28 + * return-with-no-value. UGH! 1.29 + */ 1.30 +#define ACCESS_CHECK_WR() do { \ 1.31 + /* MEM_STATUS st; */ \ 1.32 + switch (checkMemoryAccess(address, true)) { \ 1.33 + case MEM_ALLOWED: \ 1.34 + /* Access allowed */ \ 1.35 + break; \ 1.36 + case MEM_PAGEFAULT: \ 1.37 + /* Page fault */ \ 1.38 + state.genstat = 0x8FFF; \ 1.39 + m68k_pulse_bus_error(); \ 1.40 + return; \ 1.41 + case MEM_UIE: \ 1.42 + /* User access to memory above 4MB */ \ 1.43 + state.genstat = 0x9EFF; \ 1.44 + m68k_pulse_bus_error(); \ 1.45 + return; \ 1.46 + case MEM_KERNEL: \ 1.47 + case MEM_PAGE_NO_WE: \ 1.48 + /* kernel access or page not write enabled */ \ 1.49 + /* TODO: which regs need setting? */ \ 1.50 + m68k_pulse_bus_error(); \ 1.51 + return; \ 1.52 + } \ 1.53 + } while (false) 1.54 + 1.55 +/** 1.56 + * @brief Check memory access permissions for a read operation. 1.57 + * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but 1.58 + * gcc throws warnings when you have a return-with-value in a void 1.59 + * function, even if the return-with-value is completely unreachable. 1.60 + * Similarly it doesn't like it if you have a return without a value 1.61 + * in a non-void function, even if it's impossible to ever reach the 1.62 + * return-with-no-value. UGH! 1.63 + */ 1.64 +#define ACCESS_CHECK_RD() do { \ 1.65 + /* MEM_STATUS st; */ \ 1.66 + switch (checkMemoryAccess(address, false)) { \ 1.67 + case MEM_ALLOWED: \ 1.68 + /* Access allowed */ \ 1.69 + break; \ 1.70 + case MEM_PAGEFAULT: \ 1.71 + /* Page fault */ \ 1.72 + state.genstat = 0xCFFF; \ 1.73 + m68k_pulse_bus_error(); \ 1.74 + return 0xFFFFFFFF; \ 1.75 + case MEM_UIE: \ 1.76 + /* User access to memory above 4MB */ \ 1.77 + state.genstat = 0xDEFF; \ 1.78 + m68k_pulse_bus_error(); \ 1.79 + return 0xFFFFFFFF; \ 1.80 + case MEM_KERNEL: \ 1.81 + case MEM_PAGE_NO_WE: \ 1.82 + /* kernel access or page not write enabled */ \ 1.83 + /* TODO: which regs need setting? */ \ 1.84 + m68k_pulse_bus_error(); \ 1.85 + return 0xFFFFFFFF; \ 1.86 + } \ 1.87 + } while (false) 1.88 + 1.89 +/** 1.90 + * @brief Read M68K memory, 32-bit 1.91 + */ 1.92 uint32_t m68k_read_memory_32(uint32_t address) 1.93 { 1.94 uint32_t data = 0xFFFFFFFF; 1.95 @@ -148,12 +218,15 @@ 1.96 if (!state.romlmap) 1.97 address |= 0x800000; 1.98 1.99 + // Check access permissions 1.100 + ACCESS_CHECK_RD(); 1.101 + 1.102 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.103 // ROM access 1.104 data = RD32(state.rom, address, ROM_SIZE - 1); 1.105 } else if (address <= (state.ram_size - 1)) { 1.106 - // RAM access -- TODO: mapping 1.107 - data = RD32(state.ram, address, state.ram_size - 1); 1.108 + // RAM access 1.109 + data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1); 1.110 } else if ((address >= 0x420000) && (address <= 0x427FFF)) { 1.111 // VRAM access 1.112 data = RD32(state.vram, address, 0x7FFF); 1.113 @@ -167,6 +240,9 @@ 1.114 return data; 1.115 } 1.116 1.117 +/** 1.118 + * @brief Read M68K memory, 16-bit 1.119 + */ 1.120 uint32_t m68k_read_memory_16(uint32_t address) 1.121 { 1.122 uint16_t data = 0xFFFF; 1.123 @@ -175,12 +251,15 @@ 1.124 if (!state.romlmap) 1.125 address |= 0x800000; 1.126 1.127 + // Check access permissions 1.128 + ACCESS_CHECK_RD(); 1.129 + 1.130 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.131 // ROM access 1.132 data = RD16(state.rom, address, ROM_SIZE - 1); 1.133 } else if (address <= (state.ram_size - 1)) { 1.134 - // RAM access -- TODO: mapping 1.135 - data = RD16(state.ram, address, state.ram_size - 1); 1.136 + // RAM access 1.137 + data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1); 1.138 } else if ((address >= 0x420000) && (address <= 0x427FFF)) { 1.139 // VRAM access 1.140 data = RD16(state.vram, address, 0x7FFF); 1.141 @@ -195,6 +274,9 @@ 1.142 return data; 1.143 } 1.144 1.145 +/** 1.146 + * @brief Read M68K memory, 8-bit 1.147 + */ 1.148 uint32_t m68k_read_memory_8(uint32_t address) 1.149 { 1.150 uint8_t data = 0xFF; 1.151 @@ -203,12 +285,15 @@ 1.152 if (!state.romlmap) 1.153 address |= 0x800000; 1.154 1.155 + // Check access permissions 1.156 + ACCESS_CHECK_RD(); 1.157 + 1.158 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.159 // ROM access 1.160 data = RD8(state.rom, address, ROM_SIZE - 1); 1.161 } else if (address <= (state.ram_size - 1)) { 1.162 - // RAM access -- TODO: mapping 1.163 - data = RD8(state.ram, address, state.ram_size - 1); 1.164 + // RAM access 1.165 + data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1); 1.166 } else if ((address >= 0x420000) && (address <= 0x427FFF)) { 1.167 // VRAM access 1.168 data = RD8(state.vram, address, 0x7FFF); 1.169 @@ -223,19 +308,25 @@ 1.170 return data; 1.171 } 1.172 1.173 -// write m68k memory 1.174 +/** 1.175 + * @brief Write M68K memory, 32-bit 1.176 + */ 1.177 void m68k_write_memory_32(uint32_t address, uint32_t value) 1.178 { 1.179 // If ROMLMAP is set, force system to access ROM 1.180 if (!state.romlmap) 1.181 address |= 0x800000; 1.182 1.183 + // Check access permissions 1.184 + ACCESS_CHECK_WR(); 1.185 + 1.186 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.187 // ROM access 1.188 - // TODO: bus error here? can't write to rom! 1.189 + // According to HwNote15 (John B. Milton), there is no write protection 1.190 + // here. You can write to ROM, but nothing happens. 1.191 } else if (address <= (state.ram_size - 1)) { 1.192 - // RAM -- TODO: mapping 1.193 - WR32(state.ram, address, state.ram_size - 1, value); 1.194 + // RAM access 1.195 + WR32(state.ram, mapAddr(address, true), state.ram_size - 1, value); 1.196 } else if ((address >= 0x420000) && (address <= 0x427FFF)) { 1.197 // VRAM access 1.198 WR32(state.vram, address, 0x7fff, value); 1.199 @@ -250,18 +341,25 @@ 1.200 } 1.201 } 1.202 1.203 +/** 1.204 + * @brief Write M68K memory, 16-bit 1.205 + */ 1.206 void m68k_write_memory_16(uint32_t address, uint32_t value) 1.207 { 1.208 // If ROMLMAP is set, force system to access ROM 1.209 if (!state.romlmap) 1.210 address |= 0x800000; 1.211 1.212 + // Check access permissions 1.213 + ACCESS_CHECK_WR(); 1.214 + 1.215 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.216 // ROM access 1.217 - // TODO: bus error here? can't write to rom! 1.218 + // According to HwNote15 (John B. Milton), there is no write protection 1.219 + // here. You can write to ROM, but nothing happens. 1.220 } else if (address <= (state.ram_size - 1)) { 1.221 - // RAM access -- TODO: mapping 1.222 - WR16(state.ram, address, state.ram_size - 1, value); 1.223 + // RAM access 1.224 + WR16(state.ram, mapAddr(address, true), state.ram_size - 1, value); 1.225 } else if ((address >= 0x420000) && (address <= 0x427FFF)) { 1.226 // VRAM access 1.227 WR16(state.vram, address, 0x7fff, value); 1.228 @@ -284,18 +382,25 @@ 1.229 } 1.230 } 1.231 1.232 +/** 1.233 + * @brief Write M68K memory, 8-bit 1.234 + */ 1.235 void m68k_write_memory_8(uint32_t address, uint32_t value) 1.236 { 1.237 // If ROMLMAP is set, force system to access ROM 1.238 if (!state.romlmap) 1.239 address |= 0x800000; 1.240 1.241 + // Check access permissions 1.242 + ACCESS_CHECK_WR(); 1.243 + 1.244 if ((address >= 0x800000) && (address <= 0xBFFFFF)) { 1.245 // ROM access 1.246 - // TODO: bus error here? can't write to rom! 1.247 + // According to HwNote15 (John B. Milton), there is no write protection 1.248 + // here. You can write to ROM, but nothing happens. 1.249 } else if (address <= (state.ram_size - 1)) { 1.250 - // RAM access -- TODO: mapping 1.251 - WR8(state.ram, address, state.ram_size - 1, value); 1.252 + // RAM access 1.253 + WR8(state.ram, mapAddr(address, true), state.ram_size - 1, value); 1.254 } else if ((address >= 0x420000) && (address <= 0x427FFF)) { 1.255 // VRAM access 1.256 WR8(state.vram, address, 0x7fff, value); 1.257 @@ -354,7 +459,7 @@ 1.258 printf("Could not find a suitable video mode: %s.\n", SDL_GetError()); 1.259 exit(EXIT_FAILURE); 1.260 } 1.261 - printf("Set %dx%d at %d bits-per-pixel mode\n", screen->w, screen->h, screen->format->BitsPerPixel); 1.262 + printf("Set %dx%d at %d bits-per-pixel mode\n\n", screen->w, screen->h, screen->format->BitsPerPixel); 1.263 SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee"); 1.264 1.265 /***
2.1 diff -r 4fea89e86c5e -r a44afcf2354c src/state.h 2.2 --- a/src/state.h Thu Dec 02 16:37:55 2010 +0000 2.3 +++ b/src/state.h Thu Dec 02 17:01:34 2010 +0000 2.4 @@ -27,6 +27,9 @@ 2.5 // Map RAM 2.6 uint8_t map[0x800]; ///< Map RAM 2.7 2.8 + // General Status Register 2.9 + uint16_t genstat; 2.10 + 2.11 // GENERAL CONTROL REGISTER 2.12 /// GENCON.ROMLMAP -- false ORs the address with 0x800000, forcing the 2.13 /// 68010 to access ROM instead of RAM when booting. TRM page 2-36.