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