src/memory.c

Mon, 06 Dec 2010 01:43:04 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 06 Dec 2010 01:43:04 +0000
changeset 54
57c6ef81ae81
parent 53
e1693c4b8a0c
child 55
ba6b8e570062
child 76
2ef98ea1e944
permissions
-rw-r--r--

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