Mon, 06 Dec 2010 01:43:04 +0000
fix side-select bug in WDC FDC driver, was causing all reads to occur on side0... now the Loader boots!
Loader will boot, but immediately gives up on the floppy drive... Not sure why.
philpem@40 | 1 | #include <stdio.h> |
philpem@40 | 2 | #include <stdlib.h> |
philpem@40 | 3 | #include <stdint.h> |
philpem@40 | 4 | #include <stdbool.h> |
philpem@40 | 5 | #include "musashi/m68k.h" |
philpem@40 | 6 | #include "state.h" |
philpem@40 | 7 | #include "memory.h" |
philpem@40 | 8 | |
philpem@40 | 9 | /****************** |
philpem@40 | 10 | * Memory mapping |
philpem@40 | 11 | ******************/ |
philpem@40 | 12 | |
philpem@40 | 13 | #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1])) |
philpem@40 | 14 | |
philpem@40 | 15 | uint32_t mapAddr(uint32_t addr, bool writing) |
philpem@40 | 16 | { |
philpem@40 | 17 | if (addr < 0x400000) { |
philpem@40 | 18 | // RAM access. Check against the Map RAM |
philpem@40 | 19 | // Start by getting the original page address |
philpem@40 | 20 | uint16_t page = (addr >> 12) & 0x3FF; |
philpem@40 | 21 | |
philpem@40 | 22 | // Look it up in the map RAM and get the physical page address |
philpem@40 | 23 | uint32_t new_page_addr = MAPRAM(page) & 0x3FF; |
philpem@40 | 24 | |
philpem@40 | 25 | // Update the Page Status bits |
philpem@40 | 26 | uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03; |
philpem@40 | 27 | if (pagebits != 0) { |
philpem@40 | 28 | if (writing) |
philpem@40 | 29 | state.map[page*2] |= 0x60; // Page written to (dirty) |
philpem@40 | 30 | else |
philpem@40 | 31 | state.map[page*2] |= 0x40; // Page accessed but not written |
philpem@40 | 32 | } |
philpem@40 | 33 | |
philpem@40 | 34 | // Return the address with the new physical page spliced in |
philpem@40 | 35 | return (new_page_addr << 12) + (addr & 0xFFF); |
philpem@40 | 36 | } else { |
philpem@40 | 37 | // I/O, VRAM or MapRAM space; no mapping is performed or required |
philpem@40 | 38 | // TODO: assert here? |
philpem@40 | 39 | return addr; |
philpem@40 | 40 | } |
philpem@40 | 41 | } |
philpem@40 | 42 | |
philpem@40 | 43 | MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing) |
philpem@40 | 44 | { |
philpem@40 | 45 | // Are we in Supervisor mode? |
philpem@40 | 46 | if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000) |
philpem@40 | 47 | // Yes. We can do anything we like. |
philpem@40 | 48 | return MEM_ALLOWED; |
philpem@40 | 49 | |
philpem@40 | 50 | // If we're here, then we must be in User mode. |
philpem@40 | 51 | // Check that the user didn't access memory outside of the RAM area |
philpem@40 | 52 | if (addr >= 0x400000) |
philpem@40 | 53 | return MEM_UIE; |
philpem@40 | 54 | |
philpem@40 | 55 | // This leaves us with Page Fault checking. Get the page bits for this page. |
philpem@40 | 56 | uint16_t page = (addr >> 12) & 0x3FF; |
philpem@40 | 57 | uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07; |
philpem@40 | 58 | |
philpem@40 | 59 | // Check page is present |
philpem@40 | 60 | if ((pagebits & 0x03) == 0) |
philpem@40 | 61 | return MEM_PAGEFAULT; |
philpem@40 | 62 | |
philpem@40 | 63 | // User attempt to access the kernel |
philpem@40 | 64 | // A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode |
philpem@40 | 65 | if (((addr >> 19) & 0x0F) == 0) |
philpem@40 | 66 | return MEM_KERNEL; |
philpem@40 | 67 | |
philpem@40 | 68 | // Check page is write enabled |
philpem@40 | 69 | if ((pagebits & 0x04) == 0) |
philpem@40 | 70 | return MEM_PAGE_NO_WE; |
philpem@40 | 71 | |
philpem@40 | 72 | // Page access allowed. |
philpem@40 | 73 | return MEM_ALLOWED; |
philpem@40 | 74 | } |
philpem@40 | 75 | |
philpem@40 | 76 | #undef MAPRAM |
philpem@40 | 77 | |
philpem@40 | 78 | |
philpem@40 | 79 | /******************************************************** |
philpem@40 | 80 | * m68k memory read/write support functions for Musashi |
philpem@40 | 81 | ********************************************************/ |
philpem@40 | 82 | |
philpem@40 | 83 | /** |
philpem@40 | 84 | * @brief Check memory access permissions for a write operation. |
philpem@40 | 85 | * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but |
philpem@40 | 86 | * gcc throws warnings when you have a return-with-value in a void |
philpem@40 | 87 | * function, even if the return-with-value is completely unreachable. |
philpem@40 | 88 | * Similarly it doesn't like it if you have a return without a value |
philpem@40 | 89 | * in a non-void function, even if it's impossible to ever reach the |
philpem@40 | 90 | * return-with-no-value. UGH! |
philpem@40 | 91 | */ |
philpem@40 | 92 | #define ACCESS_CHECK_WR(address, bits) do { \ |
philpem@40 | 93 | bool fault = false; \ |
philpem@40 | 94 | /* MEM_STATUS st; */ \ |
philpem@40 | 95 | switch (checkMemoryAccess(address, true)) { \ |
philpem@40 | 96 | case MEM_ALLOWED: \ |
philpem@40 | 97 | /* Access allowed */ \ |
philpem@40 | 98 | break; \ |
philpem@40 | 99 | case MEM_PAGEFAULT: \ |
philpem@40 | 100 | /* Page fault */ \ |
philpem@44 | 101 | state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0); \ |
philpem@40 | 102 | fault = true; \ |
philpem@40 | 103 | break; \ |
philpem@40 | 104 | case MEM_UIE: \ |
philpem@40 | 105 | /* User access to memory above 4MB */ \ |
philpem@44 | 106 | state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0); \ |
philpem@40 | 107 | fault = true; \ |
philpem@40 | 108 | break; \ |
philpem@40 | 109 | case MEM_KERNEL: \ |
philpem@40 | 110 | case MEM_PAGE_NO_WE: \ |
philpem@40 | 111 | /* kernel access or page not write enabled */ \ |
philpem@40 | 112 | /* TODO: which regs need setting? */ \ |
philpem@40 | 113 | fault = true; \ |
philpem@40 | 114 | break; \ |
philpem@40 | 115 | } \ |
philpem@40 | 116 | \ |
philpem@40 | 117 | if (fault) { \ |
philpem@40 | 118 | if (bits >= 16) \ |
philpem@40 | 119 | state.bsr0 = 0x7F00; \ |
philpem@40 | 120 | else \ |
philpem@40 | 121 | state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00; \ |
philpem@40 | 122 | state.bsr0 |= (address >> 16); \ |
philpem@40 | 123 | state.bsr1 = address & 0xffff; \ |
philpem@40 | 124 | printf("ERR: BusError WR\n"); \ |
philpem@40 | 125 | m68k_pulse_bus_error(); \ |
philpem@40 | 126 | return; \ |
philpem@40 | 127 | } \ |
philpem@40 | 128 | } while (false) |
philpem@40 | 129 | |
philpem@40 | 130 | /** |
philpem@40 | 131 | * @brief Check memory access permissions for a read operation. |
philpem@40 | 132 | * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but |
philpem@40 | 133 | * gcc throws warnings when you have a return-with-value in a void |
philpem@40 | 134 | * function, even if the return-with-value is completely unreachable. |
philpem@40 | 135 | * Similarly it doesn't like it if you have a return without a value |
philpem@40 | 136 | * in a non-void function, even if it's impossible to ever reach the |
philpem@40 | 137 | * return-with-no-value. UGH! |
philpem@40 | 138 | */ |
philpem@40 | 139 | #define ACCESS_CHECK_RD(address, bits) do { \ |
philpem@40 | 140 | bool fault = false; \ |
philpem@40 | 141 | /* MEM_STATUS st; */ \ |
philpem@40 | 142 | switch (checkMemoryAccess(address, false)) { \ |
philpem@40 | 143 | case MEM_ALLOWED: \ |
philpem@40 | 144 | /* Access allowed */ \ |
philpem@40 | 145 | break; \ |
philpem@40 | 146 | case MEM_PAGEFAULT: \ |
philpem@40 | 147 | /* Page fault */ \ |
philpem@44 | 148 | state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0); \ |
philpem@40 | 149 | fault = true; \ |
philpem@40 | 150 | break; \ |
philpem@40 | 151 | case MEM_UIE: \ |
philpem@40 | 152 | /* User access to memory above 4MB */ \ |
philpem@44 | 153 | state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0); \ |
philpem@40 | 154 | fault = true; \ |
philpem@40 | 155 | break; \ |
philpem@40 | 156 | case MEM_KERNEL: \ |
philpem@40 | 157 | case MEM_PAGE_NO_WE: \ |
philpem@40 | 158 | /* kernel access or page not write enabled */ \ |
philpem@40 | 159 | /* TODO: which regs need setting? */ \ |
philpem@40 | 160 | fault = true; \ |
philpem@40 | 161 | break; \ |
philpem@40 | 162 | } \ |
philpem@40 | 163 | \ |
philpem@40 | 164 | if (fault) { \ |
philpem@40 | 165 | if (bits >= 16) \ |
philpem@40 | 166 | state.bsr0 = 0x7F00; \ |
philpem@40 | 167 | else \ |
philpem@40 | 168 | state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00; \ |
philpem@40 | 169 | state.bsr0 |= (address >> 16); \ |
philpem@40 | 170 | state.bsr1 = address & 0xffff; \ |
philpem@40 | 171 | printf("ERR: BusError RD\n"); \ |
philpem@40 | 172 | m68k_pulse_bus_error(); \ |
philpem@40 | 173 | return 0xFFFFFFFF; \ |
philpem@40 | 174 | } \ |
philpem@40 | 175 | } while (false) |
philpem@40 | 176 | |
philpem@40 | 177 | // Logging macros |
philpem@40 | 178 | #define LOG_NOT_HANDLED_R(bits) \ |
philpem@40 | 179 | do { \ |
philpem@40 | 180 | if (!handled) \ |
philpem@40 | 181 | printf("unhandled read%02d, addr=0x%08X\n", bits, address); \ |
philpem@40 | 182 | } while (0); |
philpem@40 | 183 | |
philpem@40 | 184 | #define LOG_NOT_HANDLED_W(bits) \ |
philpem@40 | 185 | do { \ |
philpem@40 | 186 | if (!handled) \ |
philpem@40 | 187 | printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, value); \ |
philpem@40 | 188 | } while (0); |
philpem@40 | 189 | |
philpem@40 | 190 | /** |
philpem@40 | 191 | * @brief Read M68K memory, 32-bit |
philpem@40 | 192 | */ |
philpem@40 | 193 | uint32_t m68k_read_memory_32(uint32_t address) |
philpem@40 | 194 | { |
philpem@40 | 195 | uint32_t data = 0xFFFFFFFF; |
philpem@40 | 196 | bool handled = false; |
philpem@40 | 197 | |
philpem@40 | 198 | // If ROMLMAP is set, force system to access ROM |
philpem@40 | 199 | if (!state.romlmap) |
philpem@40 | 200 | address |= 0x800000; |
philpem@40 | 201 | |
philpem@40 | 202 | // Check access permissions |
philpem@40 | 203 | ACCESS_CHECK_RD(address, 32); |
philpem@40 | 204 | |
philpem@40 | 205 | if ((address >= 0x800000) && (address <= 0xBFFFFF)) { |
philpem@40 | 206 | // ROM access |
philpem@40 | 207 | data = RD32(state.rom, address, ROM_SIZE - 1); |
philpem@40 | 208 | handled = true; |
philpem@40 | 209 | } else if (address <= (state.ram_size - 1)) { |
philpem@40 | 210 | // RAM access |
philpem@40 | 211 | data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1); |
philpem@40 | 212 | handled = true; |
philpem@40 | 213 | } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { |
philpem@40 | 214 | // I/O register space, zone A |
philpem@40 | 215 | switch (address & 0x0F0000) { |
philpem@40 | 216 | case 0x000000: // Map RAM access |
philpem@40 | 217 | if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address); |
philpem@40 | 218 | data = RD32(state.map, address, 0x7FF); |
philpem@40 | 219 | handled = true; |
philpem@40 | 220 | break; |
philpem@40 | 221 | case 0x010000: // General Status Register |
philpem@40 | 222 | data = ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat; |
philpem@40 | 223 | handled = true; |
philpem@40 | 224 | break; |
philpem@40 | 225 | case 0x020000: // Video RAM |
philpem@40 | 226 | if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address); |
philpem@40 | 227 | data = RD32(state.vram, address, 0x7FFF); |
philpem@40 | 228 | handled = true; |
philpem@40 | 229 | break; |
philpem@40 | 230 | case 0x030000: // Bus Status Register 0 |
philpem@40 | 231 | data = ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0; |
philpem@40 | 232 | handled = true; |
philpem@40 | 233 | break; |
philpem@40 | 234 | case 0x040000: // Bus Status Register 1 |
philpem@40 | 235 | data = ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1; |
philpem@40 | 236 | handled = true; |
philpem@40 | 237 | break; |
philpem@40 | 238 | case 0x050000: // Phone status |
philpem@40 | 239 | break; |
philpem@40 | 240 | case 0x060000: // DMA Count |
philpem@53 | 241 | // U/OERR- is always inactive (bit set) |
philpem@53 | 242 | data = (state.dma_count & 0x3fff) | 0x8000; |
philpem@53 | 243 | handled = true; |
philpem@40 | 244 | break; |
philpem@40 | 245 | case 0x070000: // Line Printer Status Register |
philpem@53 | 246 | data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD |
philpem@53 | 247 | data |= (state.fdc_ctx.irql) ? 0x00080008 : 0; // FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this |
philpem@40 | 248 | break; |
philpem@40 | 249 | case 0x080000: // Real Time Clock |
philpem@40 | 250 | break; |
philpem@40 | 251 | case 0x090000: // Phone registers |
philpem@40 | 252 | switch (address & 0x0FF000) { |
philpem@40 | 253 | case 0x090000: // Handset relay |
philpem@40 | 254 | case 0x098000: |
philpem@40 | 255 | break; |
philpem@40 | 256 | case 0x091000: // Line select 2 |
philpem@40 | 257 | case 0x099000: |
philpem@40 | 258 | break; |
philpem@40 | 259 | case 0x092000: // Hook relay 1 |
philpem@40 | 260 | case 0x09A000: |
philpem@40 | 261 | break; |
philpem@40 | 262 | case 0x093000: // Hook relay 2 |
philpem@40 | 263 | case 0x09B000: |
philpem@40 | 264 | break; |
philpem@40 | 265 | case 0x094000: // Line 1 hold |
philpem@40 | 266 | case 0x09C000: |
philpem@40 | 267 | break; |
philpem@40 | 268 | case 0x095000: // Line 2 hold |
philpem@40 | 269 | case 0x09D000: |
philpem@40 | 270 | break; |
philpem@40 | 271 | case 0x096000: // Line 1 A-lead |
philpem@40 | 272 | case 0x09E000: |
philpem@40 | 273 | break; |
philpem@40 | 274 | case 0x097000: // Line 2 A-lead |
philpem@40 | 275 | case 0x09F000: |
philpem@40 | 276 | break; |
philpem@40 | 277 | } |
philpem@40 | 278 | break; |
philpem@46 | 279 | case 0x0A0000: // Miscellaneous Control Register -- write only! |
philpem@46 | 280 | handled = true; |
philpem@40 | 281 | break; |
philpem@40 | 282 | case 0x0B0000: // TM/DIALWR |
philpem@40 | 283 | break; |
philpem@46 | 284 | case 0x0C0000: // Clear Status Register -- write only! |
philpem@43 | 285 | handled = true; |
philpem@40 | 286 | break; |
philpem@40 | 287 | case 0x0D0000: // DMA Address Register |
philpem@40 | 288 | break; |
philpem@40 | 289 | case 0x0E0000: // Disk Control Register |
philpem@40 | 290 | break; |
philpem@40 | 291 | case 0x0F0000: // Line Printer Data Register |
philpem@40 | 292 | break; |
philpem@40 | 293 | } |
philpem@40 | 294 | } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) { |
philpem@40 | 295 | // I/O register space, zone B |
philpem@40 | 296 | switch (address & 0xF00000) { |
philpem@40 | 297 | case 0xC00000: // Expansion slots |
philpem@40 | 298 | case 0xD00000: |
philpem@40 | 299 | switch (address & 0xFC0000) { |
philpem@40 | 300 | case 0xC00000: // Expansion slot 0 |
philpem@40 | 301 | case 0xC40000: // Expansion slot 1 |
philpem@40 | 302 | case 0xC80000: // Expansion slot 2 |
philpem@40 | 303 | case 0xCC0000: // Expansion slot 3 |
philpem@40 | 304 | case 0xD00000: // Expansion slot 4 |
philpem@40 | 305 | case 0xD40000: // Expansion slot 5 |
philpem@40 | 306 | case 0xD80000: // Expansion slot 6 |
philpem@40 | 307 | case 0xDC0000: // Expansion slot 7 |
philpem@40 | 308 | fprintf(stderr, "NOTE: RD32 from expansion card space, addr=0x%08X\n", address); |
philpem@40 | 309 | break; |
philpem@40 | 310 | } |
philpem@40 | 311 | break; |
philpem@40 | 312 | case 0xE00000: // HDC, FDC, MCR2 and RTC data bits |
philpem@40 | 313 | case 0xF00000: |
philpem@40 | 314 | switch (address & 0x070000) { |
philpem@40 | 315 | case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller |
philpem@40 | 316 | break; |
philpem@40 | 317 | case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller |
philpem@52 | 318 | data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3); |
philpem@53 | 319 | printf("WD279X: rd32 %02X ==> %02X\n", (address >> 1) & 3, data); |
philpem@52 | 320 | handled = true; |
philpem@40 | 321 | break; |
philpem@40 | 322 | case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 |
philpem@40 | 323 | break; |
philpem@40 | 324 | case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits |
philpem@40 | 325 | break; |
philpem@40 | 326 | case 0x040000: // [ef][4c]xxxx ==> General Control Register |
philpem@40 | 327 | switch (address & 0x077000) { |
philpem@40 | 328 | case 0x040000: // [ef][4c][08]xxx ==> EE |
philpem@44 | 329 | case 0x041000: // [ef][4c][19]xxx ==> PIE |
philpem@40 | 330 | case 0x042000: // [ef][4c][2A]xxx ==> BP |
philpem@40 | 331 | case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP |
philpem@44 | 332 | case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM |
philpem@44 | 333 | case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM |
philpem@44 | 334 | case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT |
philpem@44 | 335 | // All write-only registers... TODO: bus error? |
philpem@44 | 336 | handled = true; |
philpem@40 | 337 | break; |
philpem@44 | 338 | case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM] |
philpem@40 | 339 | break; |
philpem@40 | 340 | } |
philpem@40 | 341 | break; |
philpem@40 | 342 | case 0x050000: // [ef][5d]xxxx ==> 8274 |
philpem@40 | 343 | break; |
philpem@40 | 344 | case 0x060000: // [ef][6e]xxxx ==> Control regs |
philpem@40 | 345 | switch (address & 0x07F000) { |
philpem@40 | 346 | default: |
philpem@40 | 347 | break; |
philpem@40 | 348 | } |
philpem@40 | 349 | break; |
philpem@40 | 350 | case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller |
philpem@40 | 351 | break; |
philpem@40 | 352 | } |
philpem@40 | 353 | } |
philpem@40 | 354 | } |
philpem@40 | 355 | |
philpem@40 | 356 | LOG_NOT_HANDLED_R(32); |
philpem@40 | 357 | return data; |
philpem@40 | 358 | } |
philpem@40 | 359 | |
philpem@40 | 360 | /** |
philpem@40 | 361 | * @brief Read M68K memory, 16-bit |
philpem@40 | 362 | */ |
philpem@40 | 363 | uint32_t m68k_read_memory_16(uint32_t address) |
philpem@40 | 364 | { |
philpem@40 | 365 | uint16_t data = 0xFFFF; |
philpem@40 | 366 | bool handled = false; |
philpem@40 | 367 | |
philpem@40 | 368 | // If ROMLMAP is set, force system to access ROM |
philpem@40 | 369 | if (!state.romlmap) |
philpem@40 | 370 | address |= 0x800000; |
philpem@40 | 371 | |
philpem@40 | 372 | // Check access permissions |
philpem@40 | 373 | ACCESS_CHECK_RD(address, 16); |
philpem@40 | 374 | |
philpem@40 | 375 | if ((address >= 0x800000) && (address <= 0xBFFFFF)) { |
philpem@40 | 376 | // ROM access |
philpem@40 | 377 | data = RD16(state.rom, address, ROM_SIZE - 1); |
philpem@40 | 378 | handled = true; |
philpem@40 | 379 | } else if (address <= (state.ram_size - 1)) { |
philpem@40 | 380 | // RAM access |
philpem@40 | 381 | data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1); |
philpem@40 | 382 | handled = true; |
philpem@40 | 383 | } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { |
philpem@40 | 384 | // I/O register space, zone A |
philpem@40 | 385 | switch (address & 0x0F0000) { |
philpem@40 | 386 | case 0x000000: // Map RAM access |
philpem@40 | 387 | if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address); |
philpem@40 | 388 | data = RD16(state.map, address, 0x7FF); |
philpem@40 | 389 | handled = true; |
philpem@40 | 390 | break; |
philpem@40 | 391 | case 0x010000: // General Status Register |
philpem@40 | 392 | data = state.genstat; |
philpem@40 | 393 | handled = true; |
philpem@40 | 394 | break; |
philpem@40 | 395 | case 0x020000: // Video RAM |
philpem@40 | 396 | if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address); |
philpem@40 | 397 | data = RD16(state.vram, address, 0x7FFF); |
philpem@40 | 398 | handled = true; |
philpem@40 | 399 | break; |
philpem@40 | 400 | case 0x030000: // Bus Status Register 0 |
philpem@40 | 401 | data = state.bsr0; |
philpem@40 | 402 | handled = true; |
philpem@40 | 403 | break; |
philpem@40 | 404 | case 0x040000: // Bus Status Register 1 |
philpem@40 | 405 | data = state.bsr1; |
philpem@40 | 406 | handled = true; |
philpem@40 | 407 | break; |
philpem@40 | 408 | case 0x050000: // Phone status |
philpem@40 | 409 | break; |
philpem@40 | 410 | case 0x060000: // DMA Count |
philpem@53 | 411 | // U/OERR- is always inactive (bit set) |
philpem@53 | 412 | data = (state.dma_count & 0x3fff) | 0x8000; |
philpem@53 | 413 | handled = true; |
philpem@40 | 414 | break; |
philpem@40 | 415 | case 0x070000: // Line Printer Status Register |
philpem@53 | 416 | data = 0x0012; // no parity error, no line printer error, no irqs from FDD or HDD |
philpem@53 | 417 | data |= (state.fdc_ctx.irql) ? 0x0008 : 0; // FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this |
philpem@40 | 418 | break; |
philpem@40 | 419 | case 0x080000: // Real Time Clock |
philpem@40 | 420 | break; |
philpem@40 | 421 | case 0x090000: // Phone registers |
philpem@40 | 422 | switch (address & 0x0FF000) { |
philpem@40 | 423 | case 0x090000: // Handset relay |
philpem@40 | 424 | case 0x098000: |
philpem@40 | 425 | break; |
philpem@40 | 426 | case 0x091000: // Line select 2 |
philpem@40 | 427 | case 0x099000: |
philpem@40 | 428 | break; |
philpem@40 | 429 | case 0x092000: // Hook relay 1 |
philpem@40 | 430 | case 0x09A000: |
philpem@40 | 431 | break; |
philpem@40 | 432 | case 0x093000: // Hook relay 2 |
philpem@40 | 433 | case 0x09B000: |
philpem@40 | 434 | break; |
philpem@40 | 435 | case 0x094000: // Line 1 hold |
philpem@40 | 436 | case 0x09C000: |
philpem@40 | 437 | break; |
philpem@40 | 438 | case 0x095000: // Line 2 hold |
philpem@40 | 439 | case 0x09D000: |
philpem@40 | 440 | break; |
philpem@40 | 441 | case 0x096000: // Line 1 A-lead |
philpem@40 | 442 | case 0x09E000: |
philpem@40 | 443 | break; |
philpem@40 | 444 | case 0x097000: // Line 2 A-lead |
philpem@40 | 445 | case 0x09F000: |
philpem@40 | 446 | break; |
philpem@40 | 447 | } |
philpem@40 | 448 | break; |
philpem@46 | 449 | case 0x0A0000: // Miscellaneous Control Register -- write only! |
philpem@46 | 450 | handled = true; |
philpem@40 | 451 | break; |
philpem@40 | 452 | case 0x0B0000: // TM/DIALWR |
philpem@40 | 453 | break; |
philpem@46 | 454 | case 0x0C0000: // Clear Status Register -- write only! |
philpem@43 | 455 | handled = true; |
philpem@40 | 456 | break; |
philpem@40 | 457 | case 0x0D0000: // DMA Address Register |
philpem@40 | 458 | break; |
philpem@40 | 459 | case 0x0E0000: // Disk Control Register |
philpem@40 | 460 | break; |
philpem@40 | 461 | case 0x0F0000: // Line Printer Data Register |
philpem@40 | 462 | break; |
philpem@40 | 463 | } |
philpem@40 | 464 | } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) { |
philpem@40 | 465 | // I/O register space, zone B |
philpem@40 | 466 | switch (address & 0xF00000) { |
philpem@40 | 467 | case 0xC00000: // Expansion slots |
philpem@40 | 468 | case 0xD00000: |
philpem@40 | 469 | switch (address & 0xFC0000) { |
philpem@40 | 470 | case 0xC00000: // Expansion slot 0 |
philpem@40 | 471 | case 0xC40000: // Expansion slot 1 |
philpem@40 | 472 | case 0xC80000: // Expansion slot 2 |
philpem@40 | 473 | case 0xCC0000: // Expansion slot 3 |
philpem@40 | 474 | case 0xD00000: // Expansion slot 4 |
philpem@40 | 475 | case 0xD40000: // Expansion slot 5 |
philpem@40 | 476 | case 0xD80000: // Expansion slot 6 |
philpem@40 | 477 | case 0xDC0000: // Expansion slot 7 |
philpem@40 | 478 | fprintf(stderr, "NOTE: RD16 from expansion card space, addr=0x%08X\n", address); |
philpem@40 | 479 | break; |
philpem@40 | 480 | } |
philpem@40 | 481 | break; |
philpem@40 | 482 | case 0xE00000: // HDC, FDC, MCR2 and RTC data bits |
philpem@40 | 483 | case 0xF00000: |
philpem@40 | 484 | switch (address & 0x070000) { |
philpem@40 | 485 | case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller |
philpem@40 | 486 | break; |
philpem@40 | 487 | case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller |
philpem@52 | 488 | data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3); |
philpem@53 | 489 | printf("WD279X: rd16 %02X ==> %02X\n", (address >> 1) & 3, data); |
philpem@52 | 490 | handled = true; |
philpem@40 | 491 | break; |
philpem@40 | 492 | case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 |
philpem@40 | 493 | break; |
philpem@40 | 494 | case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits |
philpem@40 | 495 | break; |
philpem@40 | 496 | case 0x040000: // [ef][4c]xxxx ==> General Control Register |
philpem@40 | 497 | switch (address & 0x077000) { |
philpem@40 | 498 | case 0x040000: // [ef][4c][08]xxx ==> EE |
philpem@44 | 499 | case 0x041000: // [ef][4c][19]xxx ==> PIE |
philpem@40 | 500 | case 0x042000: // [ef][4c][2A]xxx ==> BP |
philpem@40 | 501 | case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP |
philpem@40 | 502 | case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM |
philpem@40 | 503 | case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM |
philpem@40 | 504 | case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT |
philpem@44 | 505 | // All write-only registers... TODO: bus error? |
philpem@44 | 506 | handled = true; |
philpem@40 | 507 | break; |
philpem@40 | 508 | case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video |
philpem@40 | 509 | break; |
philpem@40 | 510 | } |
philpem@40 | 511 | break; |
philpem@40 | 512 | case 0x050000: // [ef][5d]xxxx ==> 8274 |
philpem@40 | 513 | break; |
philpem@40 | 514 | case 0x060000: // [ef][6e]xxxx ==> Control regs |
philpem@40 | 515 | switch (address & 0x07F000) { |
philpem@40 | 516 | default: |
philpem@40 | 517 | break; |
philpem@40 | 518 | } |
philpem@40 | 519 | break; |
philpem@40 | 520 | case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller |
philpem@40 | 521 | break; |
philpem@40 | 522 | } |
philpem@40 | 523 | } |
philpem@40 | 524 | } |
philpem@40 | 525 | |
philpem@46 | 526 | LOG_NOT_HANDLED_R(16); |
philpem@40 | 527 | return data; |
philpem@40 | 528 | } |
philpem@40 | 529 | |
philpem@40 | 530 | /** |
philpem@40 | 531 | * @brief Read M68K memory, 8-bit |
philpem@40 | 532 | */ |
philpem@40 | 533 | uint32_t m68k_read_memory_8(uint32_t address) |
philpem@40 | 534 | { |
philpem@40 | 535 | uint8_t data = 0xFF; |
philpem@40 | 536 | bool handled = false; |
philpem@40 | 537 | |
philpem@40 | 538 | // If ROMLMAP is set, force system to access ROM |
philpem@40 | 539 | if (!state.romlmap) |
philpem@40 | 540 | address |= 0x800000; |
philpem@40 | 541 | |
philpem@40 | 542 | // Check access permissions |
philpem@40 | 543 | ACCESS_CHECK_RD(address, 8); |
philpem@40 | 544 | |
philpem@40 | 545 | if ((address >= 0x800000) && (address <= 0xBFFFFF)) { |
philpem@40 | 546 | // ROM access |
philpem@40 | 547 | data = RD8(state.rom, address, ROM_SIZE - 1); |
philpem@40 | 548 | handled = true; |
philpem@40 | 549 | } else if (address <= (state.ram_size - 1)) { |
philpem@40 | 550 | // RAM access |
philpem@40 | 551 | data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1); |
philpem@40 | 552 | handled = true; |
philpem@40 | 553 | } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { |
philpem@40 | 554 | // I/O register space, zone A |
philpem@40 | 555 | switch (address & 0x0F0000) { |
philpem@40 | 556 | case 0x000000: // Map RAM access |
philpem@40 | 557 | if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address); |
philpem@40 | 558 | data = RD8(state.map, address, 0x7FF); |
philpem@40 | 559 | handled = true; |
philpem@40 | 560 | break; |
philpem@40 | 561 | case 0x010000: // General Status Register |
philpem@40 | 562 | if ((address & 1) == 0) |
philpem@40 | 563 | data = (state.genstat >> 8) & 0xff; |
philpem@40 | 564 | else |
philpem@40 | 565 | data = (state.genstat) & 0xff; |
philpem@40 | 566 | handled = true; |
philpem@40 | 567 | break; |
philpem@40 | 568 | case 0x020000: // Video RAM |
philpem@40 | 569 | if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address); |
philpem@40 | 570 | data = RD8(state.vram, address, 0x7FFF); |
philpem@40 | 571 | handled = true; |
philpem@40 | 572 | break; |
philpem@40 | 573 | case 0x030000: // Bus Status Register 0 |
philpem@40 | 574 | if ((address & 1) == 0) |
philpem@40 | 575 | data = (state.bsr0 >> 8) & 0xff; |
philpem@40 | 576 | else |
philpem@40 | 577 | data = (state.bsr0) & 0xff; |
philpem@40 | 578 | handled = true; |
philpem@40 | 579 | break; |
philpem@40 | 580 | case 0x040000: // Bus Status Register 1 |
philpem@40 | 581 | if ((address & 1) == 0) |
philpem@40 | 582 | data = (state.bsr1 >> 8) & 0xff; |
philpem@40 | 583 | else |
philpem@40 | 584 | data = (state.bsr1) & 0xff; |
philpem@40 | 585 | handled = true; |
philpem@40 | 586 | break; |
philpem@40 | 587 | case 0x050000: // Phone status |
philpem@40 | 588 | break; |
philpem@40 | 589 | case 0x060000: // DMA Count |
philpem@53 | 590 | // TODO: how to handle this in 8bit mode? |
philpem@40 | 591 | break; |
philpem@40 | 592 | case 0x070000: // Line Printer Status Register |
philpem@53 | 593 | printf("\tLPSR RD8 fdc irql=%d, irqe=%d\n", state.fdc_ctx.irql, state.fdc_ctx.irqe); |
philpem@53 | 594 | if (address & 1) { |
philpem@53 | 595 | data = 0x12; // no parity error, no line printer error, no irqs from FDD or HDD |
philpem@53 | 596 | data |= (state.fdc_ctx.irql) ? 0x08 : 0; // FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this |
philpem@53 | 597 | } else { |
philpem@53 | 598 | data = 0; |
philpem@53 | 599 | } |
philpem@40 | 600 | break; |
philpem@40 | 601 | case 0x080000: // Real Time Clock |
philpem@40 | 602 | break; |
philpem@40 | 603 | case 0x090000: // Phone registers |
philpem@40 | 604 | switch (address & 0x0FF000) { |
philpem@40 | 605 | case 0x090000: // Handset relay |
philpem@40 | 606 | case 0x098000: |
philpem@40 | 607 | break; |
philpem@40 | 608 | case 0x091000: // Line select 2 |
philpem@40 | 609 | case 0x099000: |
philpem@40 | 610 | break; |
philpem@40 | 611 | case 0x092000: // Hook relay 1 |
philpem@40 | 612 | case 0x09A000: |
philpem@40 | 613 | break; |
philpem@40 | 614 | case 0x093000: // Hook relay 2 |
philpem@40 | 615 | case 0x09B000: |
philpem@40 | 616 | break; |
philpem@40 | 617 | case 0x094000: // Line 1 hold |
philpem@40 | 618 | case 0x09C000: |
philpem@40 | 619 | break; |
philpem@40 | 620 | case 0x095000: // Line 2 hold |
philpem@40 | 621 | case 0x09D000: |
philpem@40 | 622 | break; |
philpem@40 | 623 | case 0x096000: // Line 1 A-lead |
philpem@40 | 624 | case 0x09E000: |
philpem@40 | 625 | break; |
philpem@40 | 626 | case 0x097000: // Line 2 A-lead |
philpem@40 | 627 | case 0x09F000: |
philpem@40 | 628 | break; |
philpem@40 | 629 | } |
philpem@40 | 630 | break; |
philpem@46 | 631 | case 0x0A0000: // Miscellaneous Control Register -- write only! |
philpem@46 | 632 | handled = true; |
philpem@40 | 633 | break; |
philpem@40 | 634 | case 0x0B0000: // TM/DIALWR |
philpem@40 | 635 | break; |
philpem@46 | 636 | case 0x0C0000: // Clear Status Register -- write only! |
philpem@43 | 637 | handled = true; |
philpem@40 | 638 | break; |
philpem@40 | 639 | case 0x0D0000: // DMA Address Register |
philpem@40 | 640 | break; |
philpem@40 | 641 | case 0x0E0000: // Disk Control Register |
philpem@40 | 642 | break; |
philpem@40 | 643 | case 0x0F0000: // Line Printer Data Register |
philpem@40 | 644 | break; |
philpem@40 | 645 | } |
philpem@40 | 646 | } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) { |
philpem@40 | 647 | // I/O register space, zone B |
philpem@40 | 648 | switch (address & 0xF00000) { |
philpem@40 | 649 | case 0xC00000: // Expansion slots |
philpem@40 | 650 | case 0xD00000: |
philpem@40 | 651 | switch (address & 0xFC0000) { |
philpem@40 | 652 | case 0xC00000: // Expansion slot 0 |
philpem@40 | 653 | case 0xC40000: // Expansion slot 1 |
philpem@40 | 654 | case 0xC80000: // Expansion slot 2 |
philpem@40 | 655 | case 0xCC0000: // Expansion slot 3 |
philpem@40 | 656 | case 0xD00000: // Expansion slot 4 |
philpem@40 | 657 | case 0xD40000: // Expansion slot 5 |
philpem@40 | 658 | case 0xD80000: // Expansion slot 6 |
philpem@40 | 659 | case 0xDC0000: // Expansion slot 7 |
philpem@40 | 660 | fprintf(stderr, "NOTE: RD8 from expansion card space, addr=0x%08X\n", address); |
philpem@40 | 661 | break; |
philpem@40 | 662 | } |
philpem@40 | 663 | break; |
philpem@40 | 664 | case 0xE00000: // HDC, FDC, MCR2 and RTC data bits |
philpem@40 | 665 | case 0xF00000: |
philpem@40 | 666 | switch (address & 0x070000) { |
philpem@40 | 667 | case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller |
philpem@40 | 668 | break; |
philpem@40 | 669 | case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller |
philpem@52 | 670 | data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3); |
philpem@53 | 671 | printf("WD279X: rd8 %02X ==> %02X\n", (address >> 1) & 3, data); |
philpem@52 | 672 | handled = true; |
philpem@40 | 673 | break; |
philpem@40 | 674 | case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 |
philpem@40 | 675 | break; |
philpem@40 | 676 | case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits |
philpem@40 | 677 | break; |
philpem@40 | 678 | case 0x040000: // [ef][4c]xxxx ==> General Control Register |
philpem@40 | 679 | switch (address & 0x077000) { |
philpem@40 | 680 | case 0x040000: // [ef][4c][08]xxx ==> EE |
philpem@44 | 681 | case 0x041000: // [ef][4c][19]xxx ==> PIE |
philpem@40 | 682 | case 0x042000: // [ef][4c][2A]xxx ==> BP |
philpem@40 | 683 | case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP |
philpem@40 | 684 | case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM |
philpem@40 | 685 | case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM |
philpem@40 | 686 | case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT |
philpem@44 | 687 | // All write-only registers... TODO: bus error? |
philpem@44 | 688 | handled = true; |
philpem@40 | 689 | break; |
philpem@40 | 690 | case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video |
philpem@40 | 691 | break; |
philpem@40 | 692 | } |
philpem@40 | 693 | case 0x050000: // [ef][5d]xxxx ==> 8274 |
philpem@40 | 694 | break; |
philpem@40 | 695 | case 0x060000: // [ef][6e]xxxx ==> Control regs |
philpem@40 | 696 | switch (address & 0x07F000) { |
philpem@40 | 697 | default: |
philpem@40 | 698 | break; |
philpem@40 | 699 | } |
philpem@40 | 700 | break; |
philpem@40 | 701 | case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller |
philpem@40 | 702 | break; |
philpem@40 | 703 | } |
philpem@40 | 704 | } |
philpem@40 | 705 | } |
philpem@40 | 706 | |
philpem@40 | 707 | LOG_NOT_HANDLED_R(8); |
philpem@40 | 708 | |
philpem@40 | 709 | return data; |
philpem@40 | 710 | } |
philpem@40 | 711 | |
philpem@40 | 712 | /** |
philpem@40 | 713 | * @brief Write M68K memory, 32-bit |
philpem@40 | 714 | */ |
philpem@40 | 715 | void m68k_write_memory_32(uint32_t address, uint32_t value) |
philpem@40 | 716 | { |
philpem@40 | 717 | bool handled = false; |
philpem@40 | 718 | |
philpem@40 | 719 | // If ROMLMAP is set, force system to access ROM |
philpem@40 | 720 | if (!state.romlmap) |
philpem@40 | 721 | address |= 0x800000; |
philpem@40 | 722 | |
philpem@40 | 723 | // Check access permissions |
philpem@40 | 724 | ACCESS_CHECK_WR(address, 32); |
philpem@40 | 725 | |
philpem@40 | 726 | if ((address >= 0x800000) && (address <= 0xBFFFFF)) { |
philpem@40 | 727 | // ROM access |
philpem@40 | 728 | handled = true; |
philpem@40 | 729 | } else if (address <= (state.ram_size - 1)) { |
philpem@40 | 730 | // RAM access |
philpem@40 | 731 | WR32(state.ram, mapAddr(address, false), state.ram_size - 1, value); |
philpem@40 | 732 | handled = true; |
philpem@40 | 733 | } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { |
philpem@40 | 734 | // I/O register space, zone A |
philpem@40 | 735 | switch (address & 0x0F0000) { |
philpem@40 | 736 | case 0x000000: // Map RAM access |
philpem@40 | 737 | if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X, data=0x%08X\n", address, value); |
philpem@40 | 738 | WR32(state.map, address, 0x7FF, value); |
philpem@40 | 739 | handled = true; |
philpem@40 | 740 | break; |
philpem@40 | 741 | case 0x010000: // General Status Register |
philpem@40 | 742 | state.genstat = (value & 0xffff); |
philpem@40 | 743 | handled = true; |
philpem@40 | 744 | break; |
philpem@40 | 745 | case 0x020000: // Video RAM |
philpem@40 | 746 | if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X, data=0x%08X\n", address, value); |
philpem@40 | 747 | WR32(state.vram, address, 0x7FFF, value); |
philpem@40 | 748 | handled = true; |
philpem@40 | 749 | break; |
philpem@40 | 750 | case 0x030000: // Bus Status Register 0 |
philpem@40 | 751 | break; |
philpem@40 | 752 | case 0x040000: // Bus Status Register 1 |
philpem@40 | 753 | break; |
philpem@40 | 754 | case 0x050000: // Phone status |
philpem@40 | 755 | break; |
philpem@40 | 756 | case 0x060000: // DMA Count |
philpem@53 | 757 | printf("WR32 dmacount %08X\n", value); |
philpem@53 | 758 | state.dma_count = (value & 0x3FFF); |
philpem@53 | 759 | state.idmarw = ((value & 0x4000) == 0x4000); |
philpem@53 | 760 | state.dmaen = ((value & 0x8000) == 0x8000); |
philpem@53 | 761 | state.dmaenb = state.dmaen; |
philpem@53 | 762 | printf("\tcount %04X, idmarw %d, dmaen %d\n", state.dma_count, state.idmarw, state.dmaen); |
philpem@53 | 763 | handled = true; |
philpem@40 | 764 | break; |
philpem@40 | 765 | case 0x070000: // Line Printer Status Register |
philpem@40 | 766 | break; |
philpem@40 | 767 | case 0x080000: // Real Time Clock |
philpem@40 | 768 | break; |
philpem@40 | 769 | case 0x090000: // Phone registers |
philpem@40 | 770 | switch (address & 0x0FF000) { |
philpem@40 | 771 | case 0x090000: // Handset relay |
philpem@40 | 772 | case 0x098000: |
philpem@40 | 773 | break; |
philpem@40 | 774 | case 0x091000: // Line select 2 |
philpem@40 | 775 | case 0x099000: |
philpem@40 | 776 | break; |
philpem@40 | 777 | case 0x092000: // Hook relay 1 |
philpem@40 | 778 | case 0x09A000: |
philpem@40 | 779 | break; |
philpem@40 | 780 | case 0x093000: // Hook relay 2 |
philpem@40 | 781 | case 0x09B000: |
philpem@40 | 782 | break; |
philpem@40 | 783 | case 0x094000: // Line 1 hold |
philpem@40 | 784 | case 0x09C000: |
philpem@40 | 785 | break; |
philpem@40 | 786 | case 0x095000: // Line 2 hold |
philpem@40 | 787 | case 0x09D000: |
philpem@40 | 788 | break; |
philpem@40 | 789 | case 0x096000: // Line 1 A-lead |
philpem@40 | 790 | case 0x09E000: |
philpem@40 | 791 | break; |
philpem@40 | 792 | case 0x097000: // Line 2 A-lead |
philpem@40 | 793 | case 0x09F000: |
philpem@40 | 794 | break; |
philpem@40 | 795 | } |
philpem@40 | 796 | break; |
philpem@40 | 797 | case 0x0A0000: // Miscellaneous Control Register |
philpem@46 | 798 | // TODO: handle the ctrl bits properly |
philpem@52 | 799 | // TODO: &0x8000 --> dismiss 60hz intr |
philpem@52 | 800 | state.dma_reading = (value & 0x4000); |
philpem@46 | 801 | state.leds = (~value & 0xF00) >> 8; |
philpem@46 | 802 | printf("LEDs: %s %s %s %s\n", |
philpem@46 | 803 | (state.leds & 8) ? "R" : "-", |
philpem@46 | 804 | (state.leds & 4) ? "G" : "-", |
philpem@46 | 805 | (state.leds & 2) ? "Y" : "-", |
philpem@46 | 806 | (state.leds & 1) ? "R" : "-"); |
philpem@46 | 807 | handled = true; |
philpem@40 | 808 | break; |
philpem@40 | 809 | case 0x0B0000: // TM/DIALWR |
philpem@40 | 810 | break; |
philpem@43 | 811 | case 0x0C0000: // Clear Status Register |
philpem@43 | 812 | state.genstat = 0xFFFF; |
philpem@43 | 813 | state.bsr0 = 0xFFFF; |
philpem@43 | 814 | state.bsr1 = 0xFFFF; |
philpem@43 | 815 | handled = true; |
philpem@40 | 816 | break; |
philpem@40 | 817 | case 0x0D0000: // DMA Address Register |
philpem@52 | 818 | if (address & 0x004000) { |
philpem@52 | 819 | // A14 high -- set most significant bits |
philpem@52 | 820 | state.dma_address = (state.dma_address & 0xff) | ((address & 0x3fff) << 7); |
philpem@52 | 821 | } else { |
philpem@52 | 822 | // A14 low -- set least significant bits |
philpem@52 | 823 | state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff); |
philpem@52 | 824 | } |
philpem@53 | 825 | printf("WR DMA_ADDR, now %08X\n", state.dma_address); |
philpem@53 | 826 | handled = true; |
philpem@40 | 827 | break; |
philpem@40 | 828 | case 0x0E0000: // Disk Control Register |
philpem@52 | 829 | // B7 = FDD controller reset |
philpem@52 | 830 | if ((value & 0x80) == 0) wd2797_reset(&state.fdc_ctx); |
philpem@52 | 831 | // B6 = drive 0 select -- TODO |
philpem@52 | 832 | // B5 = motor enable -- TODO |
philpem@52 | 833 | // B4 = HDD controller reset -- TODO |
philpem@52 | 834 | // B3 = HDD0 select -- TODO |
philpem@52 | 835 | // B2,1,0 = HDD0 head select |
philpem@53 | 836 | handled = true; |
philpem@40 | 837 | break; |
philpem@40 | 838 | case 0x0F0000: // Line Printer Data Register |
philpem@40 | 839 | break; |
philpem@40 | 840 | } |
philpem@40 | 841 | } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) { |
philpem@40 | 842 | // I/O register space, zone B |
philpem@40 | 843 | switch (address & 0xF00000) { |
philpem@40 | 844 | case 0xC00000: // Expansion slots |
philpem@40 | 845 | case 0xD00000: |
philpem@40 | 846 | switch (address & 0xFC0000) { |
philpem@40 | 847 | case 0xC00000: // Expansion slot 0 |
philpem@40 | 848 | case 0xC40000: // Expansion slot 1 |
philpem@40 | 849 | case 0xC80000: // Expansion slot 2 |
philpem@40 | 850 | case 0xCC0000: // Expansion slot 3 |
philpem@40 | 851 | case 0xD00000: // Expansion slot 4 |
philpem@40 | 852 | case 0xD40000: // Expansion slot 5 |
philpem@40 | 853 | case 0xD80000: // Expansion slot 6 |
philpem@40 | 854 | case 0xDC0000: // Expansion slot 7 |
philpem@40 | 855 | fprintf(stderr, "NOTE: WR32 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value); |
philpem@40 | 856 | handled = true; |
philpem@40 | 857 | break; |
philpem@40 | 858 | } |
philpem@40 | 859 | break; |
philpem@40 | 860 | case 0xE00000: // HDC, FDC, MCR2 and RTC data bits |
philpem@40 | 861 | case 0xF00000: |
philpem@40 | 862 | switch (address & 0x070000) { |
philpem@40 | 863 | case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller |
philpem@40 | 864 | break; |
philpem@40 | 865 | case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller |
philpem@53 | 866 | printf("WD279X: wr32 %02X ==> %02X\n", (address >> 1) & 3, value); |
philpem@52 | 867 | wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value); |
philpem@53 | 868 | handled = true; |
philpem@40 | 869 | break; |
philpem@40 | 870 | case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 |
philpem@40 | 871 | break; |
philpem@40 | 872 | case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits |
philpem@40 | 873 | break; |
philpem@40 | 874 | case 0x040000: // [ef][4c]xxxx ==> General Control Register |
philpem@40 | 875 | switch (address & 0x077000) { |
philpem@40 | 876 | case 0x040000: // [ef][4c][08]xxx ==> EE |
philpem@40 | 877 | break; |
philpem@44 | 878 | case 0x041000: // [ef][4c][19]xxx ==> PIE |
philpem@44 | 879 | state.pie = ((value & 0x8000) == 0x8000); |
philpem@44 | 880 | handled = true; |
philpem@40 | 881 | break; |
philpem@40 | 882 | case 0x042000: // [ef][4c][2A]xxx ==> BP |
philpem@40 | 883 | break; |
philpem@40 | 884 | case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP |
philpem@40 | 885 | state.romlmap = ((value & 0x8000) == 0x8000); |
philpem@44 | 886 | handled = true; |
philpem@40 | 887 | break; |
philpem@40 | 888 | case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM |
philpem@40 | 889 | break; |
philpem@40 | 890 | case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM |
philpem@40 | 891 | break; |
philpem@40 | 892 | case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT |
philpem@40 | 893 | break; |
philpem@40 | 894 | case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video |
philpem@40 | 895 | break; |
philpem@40 | 896 | } |
philpem@40 | 897 | case 0x050000: // [ef][5d]xxxx ==> 8274 |
philpem@40 | 898 | break; |
philpem@40 | 899 | case 0x060000: // [ef][6e]xxxx ==> Control regs |
philpem@40 | 900 | switch (address & 0x07F000) { |
philpem@40 | 901 | default: |
philpem@40 | 902 | break; |
philpem@40 | 903 | } |
philpem@40 | 904 | break; |
philpem@40 | 905 | case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller |
philpem@40 | 906 | break; |
philpem@40 | 907 | } |
philpem@40 | 908 | } |
philpem@40 | 909 | } |
philpem@40 | 910 | |
philpem@40 | 911 | LOG_NOT_HANDLED_W(32); |
philpem@40 | 912 | } |
philpem@40 | 913 | |
philpem@40 | 914 | /** |
philpem@40 | 915 | * @brief Write M68K memory, 16-bit |
philpem@40 | 916 | */ |
philpem@40 | 917 | void m68k_write_memory_16(uint32_t address, uint32_t value) |
philpem@40 | 918 | { |
philpem@40 | 919 | bool handled = false; |
philpem@40 | 920 | |
philpem@40 | 921 | // If ROMLMAP is set, force system to access ROM |
philpem@40 | 922 | if (!state.romlmap) |
philpem@40 | 923 | address |= 0x800000; |
philpem@40 | 924 | |
philpem@40 | 925 | // Check access permissions |
philpem@40 | 926 | ACCESS_CHECK_WR(address, 16); |
philpem@40 | 927 | |
philpem@40 | 928 | if ((address >= 0x800000) && (address <= 0xBFFFFF)) { |
philpem@40 | 929 | // ROM access |
philpem@40 | 930 | handled = true; |
philpem@40 | 931 | } else if (address <= (state.ram_size - 1)) { |
philpem@40 | 932 | // RAM access |
philpem@40 | 933 | WR16(state.ram, mapAddr(address, false), state.ram_size - 1, value); |
philpem@40 | 934 | handled = true; |
philpem@40 | 935 | } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { |
philpem@40 | 936 | // I/O register space, zone A |
philpem@40 | 937 | switch (address & 0x0F0000) { |
philpem@40 | 938 | case 0x000000: // Map RAM access |
philpem@40 | 939 | if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value); |
philpem@40 | 940 | WR16(state.map, address, 0x7FF, value); |
philpem@40 | 941 | handled = true; |
philpem@40 | 942 | break; |
philpem@40 | 943 | case 0x010000: // General Status Register (read only) |
philpem@40 | 944 | handled = true; |
philpem@40 | 945 | break; |
philpem@40 | 946 | case 0x020000: // Video RAM |
philpem@40 | 947 | if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value); |
philpem@40 | 948 | WR16(state.vram, address, 0x7FFF, value); |
philpem@40 | 949 | handled = true; |
philpem@40 | 950 | break; |
philpem@40 | 951 | case 0x030000: // Bus Status Register 0 (read only) |
philpem@40 | 952 | handled = true; |
philpem@40 | 953 | break; |
philpem@40 | 954 | case 0x040000: // Bus Status Register 1 (read only) |
philpem@40 | 955 | handled = true; |
philpem@40 | 956 | break; |
philpem@40 | 957 | case 0x050000: // Phone status |
philpem@40 | 958 | break; |
philpem@40 | 959 | case 0x060000: // DMA Count |
philpem@53 | 960 | printf("WR16 dmacount %08X\n", value); |
philpem@53 | 961 | state.dma_count = (value & 0x3FFF); |
philpem@53 | 962 | state.idmarw = ((value & 0x4000) == 0x4000); |
philpem@53 | 963 | state.dmaen = ((value & 0x8000) == 0x8000); |
philpem@53 | 964 | state.dmaenb = state.dmaen; |
philpem@53 | 965 | printf("\tcount %04X, idmarw %d, dmaen %d\n", state.dma_count, state.idmarw, state.dmaen); |
philpem@53 | 966 | handled = true; |
philpem@40 | 967 | break; |
philpem@40 | 968 | case 0x070000: // Line Printer Status Register |
philpem@40 | 969 | break; |
philpem@40 | 970 | case 0x080000: // Real Time Clock |
philpem@40 | 971 | break; |
philpem@40 | 972 | case 0x090000: // Phone registers |
philpem@40 | 973 | switch (address & 0x0FF000) { |
philpem@40 | 974 | case 0x090000: // Handset relay |
philpem@40 | 975 | case 0x098000: |
philpem@40 | 976 | break; |
philpem@40 | 977 | case 0x091000: // Line select 2 |
philpem@40 | 978 | case 0x099000: |
philpem@40 | 979 | break; |
philpem@40 | 980 | case 0x092000: // Hook relay 1 |
philpem@40 | 981 | case 0x09A000: |
philpem@40 | 982 | break; |
philpem@40 | 983 | case 0x093000: // Hook relay 2 |
philpem@40 | 984 | case 0x09B000: |
philpem@40 | 985 | break; |
philpem@40 | 986 | case 0x094000: // Line 1 hold |
philpem@40 | 987 | case 0x09C000: |
philpem@40 | 988 | break; |
philpem@40 | 989 | case 0x095000: // Line 2 hold |
philpem@40 | 990 | case 0x09D000: |
philpem@40 | 991 | break; |
philpem@40 | 992 | case 0x096000: // Line 1 A-lead |
philpem@40 | 993 | case 0x09E000: |
philpem@40 | 994 | break; |
philpem@40 | 995 | case 0x097000: // Line 2 A-lead |
philpem@40 | 996 | case 0x09F000: |
philpem@40 | 997 | break; |
philpem@40 | 998 | } |
philpem@40 | 999 | break; |
philpem@40 | 1000 | case 0x0A0000: // Miscellaneous Control Register |
philpem@46 | 1001 | // TODO: handle the ctrl bits properly |
philpem@52 | 1002 | // TODO: &0x8000 --> dismiss 60hz intr |
philpem@52 | 1003 | state.dma_reading = (value & 0x4000); |
philpem@46 | 1004 | state.leds = (~value & 0xF00) >> 8; |
philpem@46 | 1005 | printf("LEDs: %s %s %s %s\n", |
philpem@46 | 1006 | (state.leds & 8) ? "R" : "-", |
philpem@46 | 1007 | (state.leds & 4) ? "G" : "-", |
philpem@46 | 1008 | (state.leds & 2) ? "Y" : "-", |
philpem@46 | 1009 | (state.leds & 1) ? "R" : "-"); |
philpem@46 | 1010 | handled = true; |
philpem@40 | 1011 | break; |
philpem@40 | 1012 | case 0x0B0000: // TM/DIALWR |
philpem@40 | 1013 | break; |
philpem@43 | 1014 | case 0x0C0000: // Clear Status Register |
philpem@43 | 1015 | state.genstat = 0xFFFF; |
philpem@43 | 1016 | state.bsr0 = 0xFFFF; |
philpem@43 | 1017 | state.bsr1 = 0xFFFF; |
philpem@43 | 1018 | handled = true; |
philpem@40 | 1019 | break; |
philpem@40 | 1020 | case 0x0D0000: // DMA Address Register |
philpem@52 | 1021 | if (address & 0x004000) { |
philpem@52 | 1022 | // A14 high -- set most significant bits |
philpem@52 | 1023 | state.dma_address = (state.dma_address & 0xff) | ((address & 0x3fff) << 7); |
philpem@52 | 1024 | } else { |
philpem@52 | 1025 | // A14 low -- set least significant bits |
philpem@52 | 1026 | state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff); |
philpem@52 | 1027 | } |
philpem@53 | 1028 | printf("WR DMA_ADDR, now %08X\n", state.dma_address); |
philpem@53 | 1029 | handled = true; |
philpem@40 | 1030 | break; |
philpem@40 | 1031 | case 0x0E0000: // Disk Control Register |
philpem@52 | 1032 | // B7 = FDD controller reset |
philpem@52 | 1033 | if ((value & 0x80) == 0) wd2797_reset(&state.fdc_ctx); |
philpem@52 | 1034 | // B6 = drive 0 select -- TODO |
philpem@52 | 1035 | // B5 = motor enable -- TODO |
philpem@52 | 1036 | // B4 = HDD controller reset -- TODO |
philpem@52 | 1037 | // B3 = HDD0 select -- TODO |
philpem@52 | 1038 | // B2,1,0 = HDD0 head select |
philpem@53 | 1039 | handled = true; |
philpem@40 | 1040 | break; |
philpem@40 | 1041 | case 0x0F0000: // Line Printer Data Register |
philpem@40 | 1042 | break; |
philpem@40 | 1043 | } |
philpem@40 | 1044 | } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) { |
philpem@40 | 1045 | // I/O register space, zone B |
philpem@40 | 1046 | switch (address & 0xF00000) { |
philpem@40 | 1047 | case 0xC00000: // Expansion slots |
philpem@40 | 1048 | case 0xD00000: |
philpem@40 | 1049 | switch (address & 0xFC0000) { |
philpem@40 | 1050 | case 0xC00000: // Expansion slot 0 |
philpem@40 | 1051 | case 0xC40000: // Expansion slot 1 |
philpem@40 | 1052 | case 0xC80000: // Expansion slot 2 |
philpem@40 | 1053 | case 0xCC0000: // Expansion slot 3 |
philpem@40 | 1054 | case 0xD00000: // Expansion slot 4 |
philpem@40 | 1055 | case 0xD40000: // Expansion slot 5 |
philpem@40 | 1056 | case 0xD80000: // Expansion slot 6 |
philpem@40 | 1057 | case 0xDC0000: // Expansion slot 7 |
philpem@40 | 1058 | fprintf(stderr, "NOTE: WR16 to expansion card space, addr=0x%08X, data=0x%04X\n", address, value); |
philpem@40 | 1059 | break; |
philpem@40 | 1060 | } |
philpem@40 | 1061 | break; |
philpem@40 | 1062 | case 0xE00000: // HDC, FDC, MCR2 and RTC data bits |
philpem@40 | 1063 | case 0xF00000: |
philpem@40 | 1064 | switch (address & 0x070000) { |
philpem@40 | 1065 | case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller |
philpem@40 | 1066 | break; |
philpem@40 | 1067 | case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller |
philpem@53 | 1068 | printf("WD279X: wr16 %02X ==> %02X\n", (address >> 1) & 3, value); |
philpem@52 | 1069 | wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value); |
philpem@53 | 1070 | handled = true; |
philpem@40 | 1071 | break; |
philpem@40 | 1072 | case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 |
philpem@40 | 1073 | break; |
philpem@40 | 1074 | case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits |
philpem@40 | 1075 | break; |
philpem@40 | 1076 | case 0x040000: // [ef][4c]xxxx ==> General Control Register |
philpem@40 | 1077 | switch (address & 0x077000) { |
philpem@40 | 1078 | case 0x040000: // [ef][4c][08]xxx ==> EE |
philpem@40 | 1079 | break; |
philpem@44 | 1080 | case 0x041000: // [ef][4c][19]xxx ==> PIE |
philpem@44 | 1081 | state.pie = ((value & 0x8000) == 0x8000); |
philpem@44 | 1082 | handled = true; |
philpem@40 | 1083 | break; |
philpem@40 | 1084 | case 0x042000: // [ef][4c][2A]xxx ==> BP |
philpem@40 | 1085 | break; |
philpem@40 | 1086 | case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP |
philpem@40 | 1087 | state.romlmap = ((value & 0x8000) == 0x8000); |
philpem@40 | 1088 | handled = true; |
philpem@40 | 1089 | break; |
philpem@40 | 1090 | case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM |
philpem@40 | 1091 | break; |
philpem@40 | 1092 | case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM |
philpem@40 | 1093 | break; |
philpem@40 | 1094 | case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT |
philpem@40 | 1095 | break; |
philpem@40 | 1096 | case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video |
philpem@40 | 1097 | break; |
philpem@40 | 1098 | } |
philpem@40 | 1099 | case 0x050000: // [ef][5d]xxxx ==> 8274 |
philpem@40 | 1100 | break; |
philpem@40 | 1101 | case 0x060000: // [ef][6e]xxxx ==> Control regs |
philpem@40 | 1102 | switch (address & 0x07F000) { |
philpem@40 | 1103 | default: |
philpem@40 | 1104 | break; |
philpem@40 | 1105 | } |
philpem@40 | 1106 | break; |
philpem@40 | 1107 | case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller |
philpem@40 | 1108 | break; |
philpem@40 | 1109 | } |
philpem@40 | 1110 | } |
philpem@40 | 1111 | } |
philpem@40 | 1112 | |
philpem@40 | 1113 | LOG_NOT_HANDLED_W(16); |
philpem@40 | 1114 | } |
philpem@40 | 1115 | |
philpem@40 | 1116 | /** |
philpem@40 | 1117 | * @brief Write M68K memory, 8-bit |
philpem@40 | 1118 | */ |
philpem@40 | 1119 | void m68k_write_memory_8(uint32_t address, uint32_t value) |
philpem@40 | 1120 | { |
philpem@40 | 1121 | bool handled = false; |
philpem@40 | 1122 | |
philpem@40 | 1123 | // If ROMLMAP is set, force system to access ROM |
philpem@40 | 1124 | if (!state.romlmap) |
philpem@40 | 1125 | address |= 0x800000; |
philpem@40 | 1126 | |
philpem@40 | 1127 | // Check access permissions |
philpem@40 | 1128 | ACCESS_CHECK_WR(address, 8); |
philpem@40 | 1129 | |
philpem@40 | 1130 | if ((address >= 0x800000) && (address <= 0xBFFFFF)) { |
philpem@40 | 1131 | // ROM access (read only!) |
philpem@40 | 1132 | handled = true; |
philpem@40 | 1133 | } else if (address <= (state.ram_size - 1)) { |
philpem@40 | 1134 | // RAM access |
philpem@40 | 1135 | WR8(state.ram, mapAddr(address, false), state.ram_size - 1, value); |
philpem@40 | 1136 | handled = true; |
philpem@40 | 1137 | } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) { |
philpem@40 | 1138 | // I/O register space, zone A |
philpem@40 | 1139 | switch (address & 0x0F0000) { |
philpem@40 | 1140 | case 0x000000: // Map RAM access |
philpem@40 | 1141 | if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=%08X, data=%02X\n", address, value); |
philpem@40 | 1142 | WR8(state.map, address, 0x7FF, value); |
philpem@40 | 1143 | handled = true; |
philpem@40 | 1144 | break; |
philpem@40 | 1145 | case 0x010000: // General Status Register |
philpem@40 | 1146 | handled = true; |
philpem@40 | 1147 | break; |
philpem@40 | 1148 | case 0x020000: // Video RAM |
philpem@46 | 1149 | if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=%08X, data=0x%02X\n", address, value); |
philpem@40 | 1150 | WR8(state.vram, address, 0x7FFF, value); |
philpem@40 | 1151 | handled = true; |
philpem@40 | 1152 | break; |
philpem@40 | 1153 | case 0x030000: // Bus Status Register 0 |
philpem@40 | 1154 | handled = true; |
philpem@40 | 1155 | break; |
philpem@40 | 1156 | case 0x040000: // Bus Status Register 1 |
philpem@40 | 1157 | handled = true; |
philpem@40 | 1158 | break; |
philpem@40 | 1159 | case 0x050000: // Phone status |
philpem@40 | 1160 | break; |
philpem@40 | 1161 | case 0x060000: // DMA Count |
philpem@53 | 1162 | // TODO: how to handle this in 8bit mode? |
philpem@40 | 1163 | break; |
philpem@40 | 1164 | case 0x070000: // Line Printer Status Register |
philpem@40 | 1165 | break; |
philpem@40 | 1166 | case 0x080000: // Real Time Clock |
philpem@40 | 1167 | break; |
philpem@40 | 1168 | case 0x090000: // Phone registers |
philpem@40 | 1169 | switch (address & 0x0FF000) { |
philpem@40 | 1170 | case 0x090000: // Handset relay |
philpem@40 | 1171 | case 0x098000: |
philpem@40 | 1172 | break; |
philpem@40 | 1173 | case 0x091000: // Line select 2 |
philpem@40 | 1174 | case 0x099000: |
philpem@40 | 1175 | break; |
philpem@40 | 1176 | case 0x092000: // Hook relay 1 |
philpem@40 | 1177 | case 0x09A000: |
philpem@40 | 1178 | break; |
philpem@40 | 1179 | case 0x093000: // Hook relay 2 |
philpem@40 | 1180 | case 0x09B000: |
philpem@40 | 1181 | break; |
philpem@40 | 1182 | case 0x094000: // Line 1 hold |
philpem@40 | 1183 | case 0x09C000: |
philpem@40 | 1184 | break; |
philpem@40 | 1185 | case 0x095000: // Line 2 hold |
philpem@40 | 1186 | case 0x09D000: |
philpem@40 | 1187 | break; |
philpem@40 | 1188 | case 0x096000: // Line 1 A-lead |
philpem@40 | 1189 | case 0x09E000: |
philpem@40 | 1190 | break; |
philpem@40 | 1191 | case 0x097000: // Line 2 A-lead |
philpem@40 | 1192 | case 0x09F000: |
philpem@40 | 1193 | break; |
philpem@40 | 1194 | } |
philpem@40 | 1195 | break; |
philpem@40 | 1196 | case 0x0A0000: // Miscellaneous Control Register |
philpem@53 | 1197 | // TODO: how to handle this in 8bit mode? |
philpem@53 | 1198 | /* |
philpem@46 | 1199 | // TODO: handle the ctrl bits properly |
philpem@52 | 1200 | if ((address & 1) == 0) { |
philpem@52 | 1201 | // low byte |
philpem@52 | 1202 | } else { |
philpem@52 | 1203 | // hight byte |
philpem@52 | 1204 | // TODO: &0x8000 --> dismiss 60hz intr |
philpem@52 | 1205 | state.dma_reading = (value & 0x40); |
philpem@46 | 1206 | state.leds = (~value & 0xF); |
philpem@52 | 1207 | } |
philpem@46 | 1208 | printf("LEDs: %s %s %s %s\n", |
philpem@46 | 1209 | (state.leds & 8) ? "R" : "-", |
philpem@46 | 1210 | (state.leds & 4) ? "G" : "-", |
philpem@46 | 1211 | (state.leds & 2) ? "Y" : "-", |
philpem@46 | 1212 | (state.leds & 1) ? "R" : "-"); |
philpem@46 | 1213 | handled = true; |
philpem@53 | 1214 | */ |
philpem@40 | 1215 | break; |
philpem@40 | 1216 | case 0x0B0000: // TM/DIALWR |
philpem@40 | 1217 | break; |
philpem@43 | 1218 | case 0x0C0000: // Clear Status Register |
philpem@43 | 1219 | state.genstat = 0xFFFF; |
philpem@43 | 1220 | state.bsr0 = 0xFFFF; |
philpem@43 | 1221 | state.bsr1 = 0xFFFF; |
philpem@43 | 1222 | handled = true; |
philpem@40 | 1223 | break; |
philpem@40 | 1224 | case 0x0D0000: // DMA Address Register |
philpem@52 | 1225 | if (address & 0x004000) { |
philpem@52 | 1226 | // A14 high -- set most significant bits |
philpem@52 | 1227 | state.dma_address = (state.dma_address & 0xff) | ((address & 0x3fff) << 7); |
philpem@52 | 1228 | } else { |
philpem@52 | 1229 | // A14 low -- set least significant bits |
philpem@52 | 1230 | state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff); |
philpem@52 | 1231 | } |
philpem@53 | 1232 | printf("WR DMA_ADDR, now %08X\n", state.dma_address); |
philpem@53 | 1233 | handled = true; |
philpem@40 | 1234 | break; |
philpem@40 | 1235 | case 0x0E0000: // Disk Control Register |
philpem@52 | 1236 | // B7 = FDD controller reset |
philpem@52 | 1237 | if ((value & 0x80) == 0) wd2797_reset(&state.fdc_ctx); |
philpem@52 | 1238 | // B6 = drive 0 select -- TODO |
philpem@52 | 1239 | // B5 = motor enable -- TODO |
philpem@52 | 1240 | // B4 = HDD controller reset -- TODO |
philpem@52 | 1241 | // B3 = HDD0 select -- TODO |
philpem@52 | 1242 | // B2,1,0 = HDD0 head select |
philpem@53 | 1243 | handled = true; |
philpem@40 | 1244 | break; |
philpem@40 | 1245 | case 0x0F0000: // Line Printer Data Register |
philpem@40 | 1246 | break; |
philpem@40 | 1247 | } |
philpem@40 | 1248 | } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) { |
philpem@40 | 1249 | // I/O register space, zone B |
philpem@40 | 1250 | switch (address & 0xF00000) { |
philpem@40 | 1251 | case 0xC00000: // Expansion slots |
philpem@40 | 1252 | case 0xD00000: |
philpem@40 | 1253 | switch (address & 0xFC0000) { |
philpem@40 | 1254 | case 0xC00000: // Expansion slot 0 |
philpem@40 | 1255 | case 0xC40000: // Expansion slot 1 |
philpem@40 | 1256 | case 0xC80000: // Expansion slot 2 |
philpem@40 | 1257 | case 0xCC0000: // Expansion slot 3 |
philpem@40 | 1258 | case 0xD00000: // Expansion slot 4 |
philpem@40 | 1259 | case 0xD40000: // Expansion slot 5 |
philpem@40 | 1260 | case 0xD80000: // Expansion slot 6 |
philpem@40 | 1261 | case 0xDC0000: // Expansion slot 7 |
philpem@40 | 1262 | fprintf(stderr, "NOTE: WR8 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value); |
philpem@40 | 1263 | break; |
philpem@40 | 1264 | } |
philpem@40 | 1265 | break; |
philpem@40 | 1266 | case 0xE00000: // HDC, FDC, MCR2 and RTC data bits |
philpem@40 | 1267 | case 0xF00000: |
philpem@40 | 1268 | switch (address & 0x070000) { |
philpem@40 | 1269 | case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller |
philpem@40 | 1270 | break; |
philpem@40 | 1271 | case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller |
philpem@53 | 1272 | printf("WD279X: wr8 %02X ==> %02X\n", (address >> 1) & 3, value); |
philpem@52 | 1273 | wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value); |
philpem@53 | 1274 | handled = true; |
philpem@40 | 1275 | break; |
philpem@40 | 1276 | case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 |
philpem@40 | 1277 | break; |
philpem@40 | 1278 | case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits |
philpem@40 | 1279 | break; |
philpem@40 | 1280 | case 0x040000: // [ef][4c]xxxx ==> General Control Register |
philpem@40 | 1281 | switch (address & 0x077000) { |
philpem@40 | 1282 | case 0x040000: // [ef][4c][08]xxx ==> EE |
philpem@40 | 1283 | break; |
philpem@44 | 1284 | case 0x041000: // [ef][4c][19]xxx ==> PIE |
philpem@44 | 1285 | if ((address & 1) == 0) |
philpem@44 | 1286 | state.pie = ((value & 0x80) == 0x80); |
philpem@44 | 1287 | handled = true; |
philpem@40 | 1288 | break; |
philpem@40 | 1289 | case 0x042000: // [ef][4c][2A]xxx ==> BP |
philpem@40 | 1290 | break; |
philpem@40 | 1291 | case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP |
philpem@40 | 1292 | if ((address & 1) == 0) |
philpem@40 | 1293 | state.romlmap = ((value & 0x80) == 0x80); |
philpem@40 | 1294 | handled = true; |
philpem@40 | 1295 | break; |
philpem@40 | 1296 | case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM |
philpem@40 | 1297 | break; |
philpem@40 | 1298 | case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM |
philpem@40 | 1299 | break; |
philpem@40 | 1300 | case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT |
philpem@40 | 1301 | break; |
philpem@40 | 1302 | case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video |
philpem@40 | 1303 | break; |
philpem@40 | 1304 | } |
philpem@40 | 1305 | case 0x050000: // [ef][5d]xxxx ==> 8274 |
philpem@40 | 1306 | break; |
philpem@40 | 1307 | case 0x060000: // [ef][6e]xxxx ==> Control regs |
philpem@40 | 1308 | switch (address & 0x07F000) { |
philpem@40 | 1309 | default: |
philpem@40 | 1310 | break; |
philpem@40 | 1311 | } |
philpem@40 | 1312 | break; |
philpem@40 | 1313 | case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller |
philpem@40 | 1314 | break; |
philpem@40 | 1315 | default: |
philpem@40 | 1316 | fprintf(stderr, "NOTE: WR8 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value); |
philpem@40 | 1317 | break; |
philpem@40 | 1318 | } |
philpem@40 | 1319 | } |
philpem@40 | 1320 | } |
philpem@40 | 1321 | |
philpem@40 | 1322 | LOG_NOT_HANDLED_W(8); |
philpem@40 | 1323 | } |
philpem@40 | 1324 | |
philpem@40 | 1325 | |
philpem@40 | 1326 | // for the disassembler |
philpem@40 | 1327 | uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); } |
philpem@40 | 1328 | uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); } |
philpem@40 | 1329 | uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); } |
philpem@40 | 1330 | |
philpem@40 | 1331 |