src/memory.c

Sat, 17 Nov 2012 19:18:29 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sat, 17 Nov 2012 19:18:29 +0000
changeset 112
a392eb8f9806
parent 108
5f7faf5ecbf4
child 113
d3bb6a6a04b7
permissions
-rw-r--r--

add HDD support + fixes

Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-Message-ID: <50A772FC.8020009@gmail.com>

I have added floppy write support, full hard disk emulation, and proper handling of DMA page faults to FreeBee. I also fixed the floppy step commands, changed the "force interrupt" floppy command to generate a type 1 status, and changed the DMA address counter to reset to 3fff when a transfer completes (which is what Unix seems to expect - without it, the kernel says that the floppy isn't ready). The floppy, hard disk, and DMA page fault tests all pass. Initializing hard disks and floppies also works (the geometry for both is still fixed by the size of the image, though, and format commands only appear to succeed, but they don't modify the image). Unix still doesn't run, though (it hangs after reading some sectors from the floppy).

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@59 5 #include <assert.h>
philpem@40 6 #include "musashi/m68k.h"
philpem@40 7 #include "state.h"
philpem@100 8 #include "utils.h"
philpem@40 9 #include "memory.h"
philpem@40 10
philpem@40 11 /******************
philpem@40 12 * Memory mapping
philpem@40 13 ******************/
philpem@40 14
philpem@40 15 #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
philpem@40 16
philpem@59 17 uint32_t mapAddr(uint32_t addr, bool writing)/*{{{*/
philpem@40 18 {
philpem@40 19 if (addr < 0x400000) {
philpem@40 20 // RAM access. Check against the Map RAM
philpem@40 21 // Start by getting the original page address
philpem@40 22 uint16_t page = (addr >> 12) & 0x3FF;
philpem@40 23
philpem@40 24 // Look it up in the map RAM and get the physical page address
philpem@40 25 uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
philpem@40 26
philpem@40 27 // Update the Page Status bits
philpem@40 28 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
philpem@100 29 // Pagebits --
philpem@100 30 // 0 = not present
philpem@100 31 // 1 = present but not accessed
philpem@100 32 // 2 = present, accessed (read from)
philpem@100 33 // 3 = present, dirty (written to)
philpem@100 34 switch (pagebits) {
philpem@100 35 case 0:
philpem@100 36 // Page not present
philpem@100 37 // This should cause a page fault
philpem@100 38 LOGS("Whoa! Pagebit update, when the page is not present!");
philpem@100 39 break;
philpem@100 40
philpem@100 41 case 1:
philpem@100 42 // Page present -- first access
philpem@104 43 state.map[page*2] &= 0x9F; // turn off "present" bit (but not write enable!)
philpem@100 44 if (writing)
philpem@100 45 state.map[page*2] |= 0x60; // Page written to (dirty)
philpem@100 46 else
philpem@100 47 state.map[page*2] |= 0x40; // Page accessed but not written
philpem@100 48 break;
philpem@100 49
philpem@100 50 case 2:
philpem@100 51 case 3:
philpem@100 52 // Page present, 2nd or later access
philpem@100 53 if (writing)
philpem@100 54 state.map[page*2] |= 0x60; // Page written to (dirty)
philpem@100 55 break;
philpem@40 56 }
philpem@40 57
philpem@40 58 // Return the address with the new physical page spliced in
philpem@40 59 return (new_page_addr << 12) + (addr & 0xFFF);
philpem@40 60 } else {
philpem@40 61 // I/O, VRAM or MapRAM space; no mapping is performed or required
philpem@40 62 // TODO: assert here?
philpem@40 63 return addr;
philpem@40 64 }
philpem@59 65 }/*}}}*/
philpem@40 66
philpem@59 67 MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)/*{{{*/
philpem@40 68 {
philpem@104 69 // Get the page bits for this page.
philpem@104 70 uint16_t page = (addr >> 12) & 0x3FF;
philpem@104 71 uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07;
philpem@104 72
philpem@104 73 // Check page is present (but only for RAM zone)
philpem@104 74 if ((addr < 0x400000) && ((pagebits & 0x03) == 0)) {
philpem@104 75 LOG("Page not mapped in: addr %08X, page %04X, mapbits %04X", addr, page, MAPRAM(page));
philpem@104 76 return MEM_PAGEFAULT;
philpem@104 77 }
philpem@104 78
philpem@40 79 // Are we in Supervisor mode?
philpem@40 80 if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
philpem@40 81 // Yes. We can do anything we like.
philpem@40 82 return MEM_ALLOWED;
philpem@40 83
philpem@40 84 // If we're here, then we must be in User mode.
philpem@40 85 // Check that the user didn't access memory outside of the RAM area
philpem@106 86 if (addr >= 0x400000) {
philpem@106 87 LOGS("User accessed privileged memory");
philpem@40 88 return MEM_UIE;
philpem@106 89 }
philpem@40 90
philpem@40 91 // User attempt to access the kernel
philpem@40 92 // A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
philpem@106 93 if (((addr >> 19) & 0x0F) == 0) {
philpem@106 94 LOGS("Attempt by user code to access kernel space");
philpem@40 95 return MEM_KERNEL;
philpem@106 96 }
philpem@40 97
philpem@40 98 // Check page is write enabled
philpem@106 99 if (writing && ((pagebits & 0x04) == 0)) {
philpem@106 100 LOG("Page not write enabled: inaddr %08X, page %04X, mapram %04X [%02X %02X], pagebits %d",
philpem@106 101 addr, page, MAPRAM(page), state.map[page*2], state.map[(page*2)+1], pagebits);
philpem@40 102 return MEM_PAGE_NO_WE;
philpem@106 103 }
philpem@40 104
philpem@40 105 // Page access allowed.
philpem@40 106 return MEM_ALLOWED;
philpem@59 107 }/*}}}*/
philpem@40 108
philpem@40 109 #undef MAPRAM
philpem@40 110
philpem@40 111
philpem@40 112 /********************************************************
philpem@40 113 * m68k memory read/write support functions for Musashi
philpem@40 114 ********************************************************/
philpem@40 115
philpem@40 116 /**
philpem@40 117 * @brief Check memory access permissions for a write operation.
philpem@40 118 * @note This used to be a single macro (merged with ACCESS_CHECK_RD), but
philpem@40 119 * gcc throws warnings when you have a return-with-value in a void
philpem@40 120 * function, even if the return-with-value is completely unreachable.
philpem@40 121 * Similarly it doesn't like it if you have a return without a value
philpem@40 122 * in a non-void function, even if it's impossible to ever reach the
philpem@40 123 * return-with-no-value. UGH!
philpem@40 124 */
philpem@59 125 /*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
philpem@59 126 #define ACCESS_CHECK_WR(address, bits) \
philpem@59 127 do { \
philpem@40 128 bool fault = false; \
philpem@103 129 MEM_STATUS st; \
philpem@103 130 switch (st = checkMemoryAccess(address, true)) { \
philpem@40 131 case MEM_ALLOWED: \
philpem@40 132 /* Access allowed */ \
philpem@40 133 break; \
philpem@40 134 case MEM_PAGEFAULT: \
philpem@40 135 /* Page fault */ \
philpem@44 136 state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0); \
philpem@40 137 fault = true; \
philpem@40 138 break; \
philpem@40 139 case MEM_UIE: \
philpem@40 140 /* User access to memory above 4MB */ \
philpem@44 141 state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0); \
philpem@40 142 fault = true; \
philpem@40 143 break; \
philpem@40 144 case MEM_KERNEL: \
philpem@40 145 case MEM_PAGE_NO_WE: \
philpem@40 146 /* kernel access or page not write enabled */ \
philpem@112 147 /* XXX: is this the correct value? */ \
philpem@112 148 state.genstat = 0x9BFF | (state.pie ? 0x0400 : 0); \
philpem@40 149 fault = true; \
philpem@40 150 break; \
philpem@40 151 } \
philpem@40 152 \
philpem@40 153 if (fault) { \
philpem@40 154 if (bits >= 16) \
philpem@68 155 state.bsr0 = 0x7C00; \
philpem@40 156 else \
philpem@108 157 state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \
philpem@40 158 state.bsr0 |= (address >> 16); \
philpem@40 159 state.bsr1 = address & 0xffff; \
philpem@103 160 LOG("Bus Error while writing, addr %08X, statcode %d", address, st); \
philpem@103 161 if (state.ee) m68k_pulse_bus_error(); \
philpem@40 162 return; \
philpem@40 163 } \
philpem@70 164 } while (0)
philpem@59 165 /*}}}*/
philpem@40 166
philpem@40 167 /**
philpem@40 168 * @brief Check memory access permissions for a read operation.
philpem@40 169 * @note This used to be a single macro (merged with ACCESS_CHECK_WR), but
philpem@40 170 * gcc throws warnings when you have a return-with-value in a void
philpem@40 171 * function, even if the return-with-value is completely unreachable.
philpem@40 172 * Similarly it doesn't like it if you have a return without a value
philpem@40 173 * in a non-void function, even if it's impossible to ever reach the
philpem@40 174 * return-with-no-value. UGH!
philpem@40 175 */
philpem@59 176 /*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
philpem@59 177 #define ACCESS_CHECK_RD(address, bits) \
philpem@59 178 do { \
philpem@40 179 bool fault = false; \
philpem@103 180 MEM_STATUS st; \
philpem@103 181 switch (st = checkMemoryAccess(address, false)) { \
philpem@40 182 case MEM_ALLOWED: \
philpem@40 183 /* Access allowed */ \
philpem@40 184 break; \
philpem@40 185 case MEM_PAGEFAULT: \
philpem@40 186 /* Page fault */ \
philpem@44 187 state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0); \
philpem@40 188 fault = true; \
philpem@40 189 break; \
philpem@40 190 case MEM_UIE: \
philpem@40 191 /* User access to memory above 4MB */ \
philpem@44 192 state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0); \
philpem@40 193 fault = true; \
philpem@40 194 break; \
philpem@40 195 case MEM_KERNEL: \
philpem@40 196 case MEM_PAGE_NO_WE: \
philpem@40 197 /* kernel access or page not write enabled */ \
philpem@112 198 /* XXX: is this the correct value? */ \
philpem@112 199 state.genstat = 0xDBFF | (state.pie ? 0x0400 : 0); \
philpem@40 200 fault = true; \
philpem@40 201 break; \
philpem@40 202 } \
philpem@40 203 \
philpem@40 204 if (fault) { \
philpem@40 205 if (bits >= 16) \
philpem@68 206 state.bsr0 = 0x7C00; \
philpem@40 207 else \
philpem@108 208 state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00; \
philpem@40 209 state.bsr0 |= (address >> 16); \
philpem@40 210 state.bsr1 = address & 0xffff; \
philpem@103 211 LOG("Bus Error while reading, addr %08X, statcode %d", address, st); \
philpem@103 212 if (state.ee) m68k_pulse_bus_error(); \
philpem@40 213 return 0xFFFFFFFF; \
philpem@40 214 } \
philpem@70 215 } while (0)
philpem@59 216 /*}}}*/
philpem@40 217
philpem@112 218 bool access_check_dma(int reading)
philpem@112 219 {
philpem@112 220 // Check memory access permissions
philpem@112 221 bool access_ok;
philpem@112 222 switch (checkMemoryAccess(state.dma_address, !reading)) {
philpem@112 223 case MEM_PAGEFAULT:
philpem@112 224 // Page fault
philpem@112 225 state.genstat = 0xABFF
philpem@112 226 | (reading ? 0x4000 : 0)
philpem@112 227 | (state.pie ? 0x0400 : 0);
philpem@112 228 access_ok = false;
philpem@112 229 break;
philpem@112 230
philpem@112 231 case MEM_UIE:
philpem@112 232 // User access to memory above 4MB
philpem@112 233 // FIXME? Shouldn't be possible with DMA... assert this?
philpem@112 234 state.genstat = 0xBAFF
philpem@112 235 | (reading ? 0x4000 : 0)
philpem@112 236 | (state.pie ? 0x0400 : 0);
philpem@112 237 access_ok = false;
philpem@112 238 break;
philpem@112 239
philpem@112 240 case MEM_KERNEL:
philpem@112 241 case MEM_PAGE_NO_WE:
philpem@112 242 // Kernel access or page not write enabled
philpem@112 243 /* XXX: is this correct? */
philpem@112 244 state.genstat = 0xBBFF
philpem@112 245 | (reading ? 0x4000 : 0)
philpem@112 246 | (state.pie ? 0x0400 : 0);
philpem@112 247 access_ok = false;
philpem@112 248 break;
philpem@112 249
philpem@112 250 case MEM_ALLOWED:
philpem@112 251 access_ok = true;
philpem@112 252 break;
philpem@112 253 }
philpem@112 254 if (!access_ok) {
philpem@112 255 state.bsr0 = 0x3C00;
philpem@112 256 state.bsr0 |= (state.dma_address >> 16);
philpem@112 257 state.bsr1 = state.dma_address & 0xffff;
philpem@112 258 if (state.ee) m68k_set_irq(7);
philpem@112 259 printf("BUS ERROR FROM DMA: genstat=%04X, bsr0=%04X, bsr1=%04X\n", state.genstat, state.bsr0, state.bsr1);
philpem@112 260 }
philpem@112 261 return (access_ok);
philpem@112 262 }
philpem@112 263
philpem@40 264 // Logging macros
philpem@59 265 #define LOG_NOT_HANDLED_R(bits) \
philpem@64 266 if (!handled) printf("unhandled read%02d, addr=0x%08X\n", bits, address);
philpem@40 267
philpem@59 268 #define LOG_NOT_HANDLED_W(bits) \
philpem@64 269 if (!handled) printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, data);
philpem@59 270
philpem@59 271 /********************************************************
philpem@59 272 * I/O read/write functions
philpem@59 273 ********************************************************/
philpem@40 274
philpem@40 275 /**
philpem@59 276 * Issue a warning if a read operation is made with an invalid size
philpem@40 277 */
philpem@66 278 inline static void ENFORCE_SIZE(int bits, uint32_t address, bool read, int allowed, char *regname)
philpem@40 279 {
philpem@59 280 assert((bits == 8) || (bits == 16) || (bits == 32));
philpem@59 281 if ((bits & allowed) == 0) {
philpem@66 282 printf("WARNING: %s 0x%08X (%s) with invalid size %d!\n", read ? "read from" : "write to", address, regname, bits);
philpem@59 283 }
philpem@59 284 }
philpem@59 285
philpem@66 286 inline static void ENFORCE_SIZE_R(int bits, uint32_t address, int allowed, char *regname)
philpem@40 287 {
philpem@66 288 ENFORCE_SIZE(bits, address, true, allowed, regname);
philpem@66 289 }
philpem@66 290
philpem@66 291 inline static void ENFORCE_SIZE_W(int bits, uint32_t address, int allowed, char *regname)
philpem@66 292 {
philpem@66 293 ENFORCE_SIZE(bits, address, false, allowed, regname);
philpem@66 294 }
philpem@66 295
philpem@59 296 void IoWrite(uint32_t address, uint32_t data, int bits)/*{{{*/
philpem@59 297 {
philpem@40 298 bool handled = false;
philpem@40 299
philpem@59 300 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 301 // I/O register space, zone A
philpem@40 302 switch (address & 0x0F0000) {
philpem@40 303 case 0x010000: // General Status Register
philpem@59 304 if (bits == 16)
philpem@59 305 state.genstat = (data & 0xffff);
philpem@59 306 else if (bits == 8) {
philpem@59 307 if (address & 0)
philpem@59 308 state.genstat = data;
philpem@59 309 else
philpem@59 310 state.genstat = data << 8;
philpem@59 311 }
philpem@40 312 handled = true;
philpem@40 313 break;
philpem@40 314 case 0x030000: // Bus Status Register 0
philpem@40 315 break;
philpem@40 316 case 0x040000: // Bus Status Register 1
philpem@40 317 break;
philpem@40 318 case 0x050000: // Phone status
philpem@40 319 break;
philpem@40 320 case 0x060000: // DMA Count
philpem@66 321 ENFORCE_SIZE_W(bits, address, 16, "DMACOUNT");
philpem@59 322 state.dma_count = (data & 0x3FFF);
philpem@59 323 state.idmarw = ((data & 0x4000) == 0x4000);
philpem@59 324 state.dmaen = ((data & 0x8000) == 0x8000);
philpem@59 325 // This handles the "dummy DMA transfer" mentioned in the docs
philpem@112 326 // disabled because it causes the floppy test to fail
philpem@112 327 #if 0
philpem@112 328 if (!state.idmarw){
philpem@112 329 if (access_check_dma(true)){
philpem@112 330 uint32_t newAddr = mapAddr(state.dma_address, true);
philpem@112 331 // RAM access
philpem@112 332 if (newAddr <= 0x1fffff)
philpem@112 333 WR16(state.base_ram, newAddr, state.base_ram_size - 1, 0xFF);
philpem@112 334 else if (address <= 0x3FFFFF)
philpem@112 335 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, 0xFF);
philpem@112 336 }
philpem@112 337 }
philpem@112 338 #endif
philpem@59 339 state.dma_count++;
philpem@53 340 handled = true;
philpem@40 341 break;
philpem@40 342 case 0x070000: // Line Printer Status Register
philpem@40 343 break;
philpem@40 344 case 0x080000: // Real Time Clock
philpem@40 345 break;
philpem@40 346 case 0x090000: // Phone registers
philpem@40 347 switch (address & 0x0FF000) {
philpem@40 348 case 0x090000: // Handset relay
philpem@40 349 case 0x098000:
philpem@40 350 break;
philpem@40 351 case 0x091000: // Line select 2
philpem@40 352 case 0x099000:
philpem@40 353 break;
philpem@40 354 case 0x092000: // Hook relay 1
philpem@40 355 case 0x09A000:
philpem@40 356 break;
philpem@40 357 case 0x093000: // Hook relay 2
philpem@40 358 case 0x09B000:
philpem@40 359 break;
philpem@40 360 case 0x094000: // Line 1 hold
philpem@40 361 case 0x09C000:
philpem@40 362 break;
philpem@40 363 case 0x095000: // Line 2 hold
philpem@40 364 case 0x09D000:
philpem@40 365 break;
philpem@40 366 case 0x096000: // Line 1 A-lead
philpem@40 367 case 0x09E000:
philpem@40 368 break;
philpem@40 369 case 0x097000: // Line 2 A-lead
philpem@40 370 case 0x09F000:
philpem@40 371 break;
philpem@40 372 }
philpem@40 373 break;
philpem@59 374 case 0x0A0000: // Miscellaneous Control Register
philpem@66 375 ENFORCE_SIZE_W(bits, address, 16, "MISCCON");
philpem@59 376 // TODO: handle the ctrl bits properly
philpem@97 377 if (data & 0x8000){
philpem@97 378 state.timer_enabled = 1;
philpem@97 379 }else{
philpem@97 380 state.timer_enabled = 0;
philpem@97 381 state.timer_asserted = 0;
philpem@97 382 }
philpem@59 383 state.dma_reading = (data & 0x4000);
philpem@72 384 if (state.leds != ((~data & 0xF00) >> 8)) {
philpem@72 385 state.leds = (~data & 0xF00) >> 8;
philpem@72 386 printf("LEDs: %s %s %s %s\n",
philpem@72 387 (state.leds & 8) ? "R" : "-",
philpem@72 388 (state.leds & 4) ? "G" : "-",
philpem@72 389 (state.leds & 2) ? "Y" : "-",
philpem@72 390 (state.leds & 1) ? "R" : "-");
philpem@72 391 }
philpem@46 392 handled = true;
philpem@40 393 break;
philpem@40 394 case 0x0B0000: // TM/DIALWR
philpem@40 395 break;
philpem@59 396 case 0x0C0000: // Clear Status Register
philpem@59 397 state.genstat = 0xFFFF;
philpem@59 398 state.bsr0 = 0xFFFF;
philpem@59 399 state.bsr1 = 0xFFFF;
philpem@43 400 handled = true;
philpem@40 401 break;
philpem@40 402 case 0x0D0000: // DMA Address Register
philpem@59 403 if (address & 0x004000) {
philpem@59 404 // A14 high -- set most significant bits
philpem@59 405 state.dma_address = (state.dma_address & 0x1fe) | ((address & 0x3ffe) << 8);
philpem@59 406 } else {
philpem@59 407 // A14 low -- set least significant bits
philpem@59 408 state.dma_address = (state.dma_address & 0x3ffe00) | (address & 0x1fe);
philpem@59 409 }
philpem@59 410 handled = true;
philpem@40 411 break;
philpem@40 412 case 0x0E0000: // Disk Control Register
philpem@112 413 {
philpem@112 414 bool fd_selected;
philpem@112 415 bool hd_selected;
philpem@112 416 ENFORCE_SIZE_W(bits, address, 16, "DISKCON");
philpem@112 417 // B7 = FDD controller reset
philpem@112 418 if ((data & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
philpem@112 419 // B6 = drive 0 select
philpem@112 420 fd_selected = (data & 0x40) != 0;
philpem@112 421 // B5 = motor enable -- TODO
philpem@112 422 // B4 = HDD controller reset
philpem@112 423 if ((data & 0x10) == 0) wd2010_reset(&state.hdc_ctx);
philpem@112 424 // B3 = HDD0 select
philpem@112 425 hd_selected = (data & 0x08) != 0;
philpem@112 426 // B2,1,0 = HDD0 head select -- TODO?
philpem@112 427 if (hd_selected && !state.hd_selected){
philpem@112 428 state.fd_selected = false;
philpem@112 429 state.hd_selected = true;
philpem@112 430 }else if (fd_selected && !state.fd_selected){
philpem@112 431 state.hd_selected = false;
philpem@112 432 state.fd_selected = true;
philpem@112 433 }
philpem@112 434 handled = true;
philpem@112 435 break;
philpem@112 436 }
philpem@40 437 case 0x0F0000: // Line Printer Data Register
philpem@40 438 break;
philpem@40 439 }
philpem@40 440 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
philpem@40 441 // I/O register space, zone B
philpem@40 442 switch (address & 0xF00000) {
philpem@40 443 case 0xC00000: // Expansion slots
philpem@40 444 case 0xD00000:
philpem@40 445 switch (address & 0xFC0000) {
philpem@40 446 case 0xC00000: // Expansion slot 0
philpem@40 447 case 0xC40000: // Expansion slot 1
philpem@40 448 case 0xC80000: // Expansion slot 2
philpem@40 449 case 0xCC0000: // Expansion slot 3
philpem@40 450 case 0xD00000: // Expansion slot 4
philpem@40 451 case 0xD40000: // Expansion slot 5
philpem@40 452 case 0xD80000: // Expansion slot 6
philpem@40 453 case 0xDC0000: // Expansion slot 7
philpem@59 454 fprintf(stderr, "NOTE: WR%d to expansion card space, addr=0x%08X, data=0x%08X\n", bits, address, data);
philpem@59 455 handled = true;
philpem@40 456 break;
philpem@40 457 }
philpem@40 458 break;
philpem@40 459 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
philpem@40 460 case 0xF00000:
philpem@40 461 switch (address & 0x070000) {
philpem@112 462 case 0x000000: // [ef][08]xxxx ==> WD2010 hard disc controller
philpem@112 463 wd2010_write_reg(&state.hdc_ctx, (address >> 1) & 7, data);
philpem@112 464 handled = true;
philpem@40 465 break;
philpem@40 466 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
philpem@112 467 /*ENFORCE_SIZE_W(bits, address, 16, "FDC REGISTERS");*/
philpem@59 468 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, data);
philpem@52 469 handled = true;
philpem@40 470 break;
philpem@40 471 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
philpem@112 472 /*TODO: implement P5.1 second hard drive select*/
philpem@40 473 break;
philpem@40 474 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
philpem@40 475 break;
philpem@40 476 case 0x040000: // [ef][4c]xxxx ==> General Control Register
philpem@40 477 switch (address & 0x077000) {
philpem@40 478 case 0x040000: // [ef][4c][08]xxx ==> EE
philpem@102 479 // Error Enable. If =0, Level7 intrs and bus errors are masked.
philpem@102 480 ENFORCE_SIZE_W(bits, address, 16, "EE");
philpem@102 481 state.ee = ((data & 0x8000) == 0x8000);
philpem@102 482 handled = true;
philpem@59 483 break;
philpem@44 484 case 0x041000: // [ef][4c][19]xxx ==> PIE
philpem@66 485 ENFORCE_SIZE_W(bits, address, 16, "PIE");
philpem@59 486 state.pie = ((data & 0x8000) == 0x8000);
philpem@59 487 handled = true;
philpem@59 488 break;
philpem@40 489 case 0x042000: // [ef][4c][2A]xxx ==> BP
philpem@59 490 break;
philpem@40 491 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
philpem@66 492 ENFORCE_SIZE_W(bits, address, 16, "ROMLMAP");
philpem@59 493 state.romlmap = ((data & 0x8000) == 0x8000);
philpem@44 494 handled = true;
philpem@40 495 break;
philpem@59 496 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
philpem@66 497 ENFORCE_SIZE_W(bits, address, 16, "L1 MODEM");
philpem@59 498 break;
philpem@59 499 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
philpem@66 500 ENFORCE_SIZE_W(bits, address, 16, "L2 MODEM");
philpem@59 501 break;
philpem@59 502 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
philpem@66 503 ENFORCE_SIZE_W(bits, address, 16, "D/N CONNECT");
philpem@59 504 break;
philpem@59 505 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video
philpem@66 506 ENFORCE_SIZE_W(bits, address, 16, "WHOLE SCREEN REVERSE VIDEO");
philpem@40 507 break;
philpem@40 508 }
philpem@40 509 case 0x050000: // [ef][5d]xxxx ==> 8274
philpem@40 510 break;
philpem@40 511 case 0x060000: // [ef][6e]xxxx ==> Control regs
philpem@40 512 switch (address & 0x07F000) {
philpem@40 513 default:
philpem@40 514 break;
philpem@40 515 }
philpem@40 516 break;
philpem@40 517 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
philpem@84 518 // TODO: figure out which sizes are valid (probably just 8 and 16)
philpem@84 519 // ENFORCE_SIZE_W(bits, address, 16, "KEYBOARD CONTROLLER");
philpem@93 520 if (bits == 8) {
philpem@93 521 printf("KBD WR %02X => %02X\n", (address >> 1) & 3, data);
philpem@93 522 keyboard_write(&state.kbd, (address >> 1) & 3, data);
philpem@93 523 handled = true;
philpem@93 524 } else if (bits == 16) {
philpem@93 525 printf("KBD WR %02X => %04X\n", (address >> 1) & 3, data);
philpem@93 526 keyboard_write(&state.kbd, (address >> 1) & 3, data >> 8);
philpem@93 527 handled = true;
philpem@93 528 }
philpem@40 529 break;
philpem@40 530 }
philpem@40 531 }
philpem@40 532 }
philpem@40 533
philpem@64 534 LOG_NOT_HANDLED_W(bits);
philpem@59 535 }/*}}}*/
philpem@40 536
philpem@59 537 uint32_t IoRead(uint32_t address, int bits)/*{{{*/
philpem@59 538 {
philpem@59 539 bool handled = false;
philpem@59 540 uint32_t data = 0xFFFFFFFF;
philpem@40 541
philpem@59 542 if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 543 // I/O register space, zone A
philpem@40 544 switch (address & 0x0F0000) {
philpem@40 545 case 0x010000: // General Status Register
philpem@66 546 ENFORCE_SIZE_R(bits, address, 16, "GENSTAT");
philpem@59 547 return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
philpem@40 548 break;
philpem@40 549 case 0x030000: // Bus Status Register 0
philpem@66 550 ENFORCE_SIZE_R(bits, address, 16, "BSR0");
philpem@59 551 return ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
philpem@40 552 break;
philpem@40 553 case 0x040000: // Bus Status Register 1
philpem@66 554 ENFORCE_SIZE_R(bits, address, 16, "BSR1");
philpem@59 555 return ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
philpem@40 556 break;
philpem@40 557 case 0x050000: // Phone status
philpem@66 558 ENFORCE_SIZE_R(bits, address, 8 | 16, "PHONE STATUS");
philpem@40 559 break;
philpem@40 560 case 0x060000: // DMA Count
philpem@55 561 // TODO: U/OERR- is always inactive (bit set)... or should it be = DMAEN+?
philpem@55 562 // Bit 14 is always unused, so leave it set
philpem@66 563 ENFORCE_SIZE_R(bits, address, 16, "DMACOUNT");
philpem@59 564 return (state.dma_count & 0x3fff) | 0xC000;
philpem@40 565 break;
philpem@40 566 case 0x070000: // Line Printer Status Register
philpem@53 567 data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD
philpem@78 568 data |= wd2797_get_irq(&state.fdc_ctx) ? 0x00080008 : 0;
philpem@112 569 data |= wd2010_get_irq(&state.hdc_ctx) ? 0x00040004 : 0;
philpem@59 570 return data;
philpem@40 571 break;
philpem@40 572 case 0x080000: // Real Time Clock
philpem@59 573 printf("READ NOTIMP: Realtime Clock\n");
philpem@40 574 break;
philpem@40 575 case 0x090000: // Phone registers
philpem@40 576 switch (address & 0x0FF000) {
philpem@40 577 case 0x090000: // Handset relay
philpem@40 578 case 0x098000:
philpem@40 579 break;
philpem@40 580 case 0x091000: // Line select 2
philpem@40 581 case 0x099000:
philpem@40 582 break;
philpem@40 583 case 0x092000: // Hook relay 1
philpem@40 584 case 0x09A000:
philpem@40 585 break;
philpem@40 586 case 0x093000: // Hook relay 2
philpem@40 587 case 0x09B000:
philpem@40 588 break;
philpem@40 589 case 0x094000: // Line 1 hold
philpem@40 590 case 0x09C000:
philpem@40 591 break;
philpem@40 592 case 0x095000: // Line 2 hold
philpem@40 593 case 0x09D000:
philpem@40 594 break;
philpem@40 595 case 0x096000: // Line 1 A-lead
philpem@40 596 case 0x09E000:
philpem@40 597 break;
philpem@40 598 case 0x097000: // Line 2 A-lead
philpem@40 599 case 0x09F000:
philpem@40 600 break;
philpem@40 601 }
philpem@40 602 break;
philpem@46 603 case 0x0A0000: // Miscellaneous Control Register -- write only!
philpem@46 604 handled = true;
philpem@40 605 break;
philpem@40 606 case 0x0B0000: // TM/DIALWR
philpem@40 607 break;
philpem@46 608 case 0x0C0000: // Clear Status Register -- write only!
philpem@43 609 handled = true;
philpem@40 610 break;
philpem@40 611 case 0x0D0000: // DMA Address Register
philpem@40 612 break;
philpem@40 613 case 0x0E0000: // Disk Control Register
philpem@40 614 break;
philpem@40 615 case 0x0F0000: // Line Printer Data Register
philpem@40 616 break;
philpem@40 617 }
philpem@40 618 } else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
philpem@40 619 // I/O register space, zone B
philpem@40 620 switch (address & 0xF00000) {
philpem@40 621 case 0xC00000: // Expansion slots
philpem@40 622 case 0xD00000:
philpem@40 623 switch (address & 0xFC0000) {
philpem@40 624 case 0xC00000: // Expansion slot 0
philpem@40 625 case 0xC40000: // Expansion slot 1
philpem@40 626 case 0xC80000: // Expansion slot 2
philpem@40 627 case 0xCC0000: // Expansion slot 3
philpem@40 628 case 0xD00000: // Expansion slot 4
philpem@40 629 case 0xD40000: // Expansion slot 5
philpem@40 630 case 0xD80000: // Expansion slot 6
philpem@40 631 case 0xDC0000: // Expansion slot 7
philpem@65 632 fprintf(stderr, "NOTE: RD%d from expansion card space, addr=0x%08X\n", bits, address);
philpem@65 633 handled = true;
philpem@40 634 break;
philpem@40 635 }
philpem@40 636 break;
philpem@40 637 case 0xE00000: // HDC, FDC, MCR2 and RTC data bits
philpem@40 638 case 0xF00000:
philpem@40 639 switch (address & 0x070000) {
philpem@40 640 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller
philpem@112 641 return (wd2010_read_reg(&state.hdc_ctx, (address >> 1) & 7));
philpem@112 642
philpem@40 643 break;
philpem@40 644 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller
philpem@112 645 /*ENFORCE_SIZE_R(bits, address, 16, "FDC REGISTERS");*/
philpem@59 646 return wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
philpem@40 647 break;
philpem@40 648 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2
philpem@40 649 break;
philpem@40 650 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits
philpem@40 651 break;
philpem@40 652 case 0x040000: // [ef][4c]xxxx ==> General Control Register
philpem@40 653 switch (address & 0x077000) {
philpem@40 654 case 0x040000: // [ef][4c][08]xxx ==> EE
philpem@44 655 case 0x041000: // [ef][4c][19]xxx ==> PIE
philpem@40 656 case 0x042000: // [ef][4c][2A]xxx ==> BP
philpem@40 657 case 0x043000: // [ef][4c][3B]xxx ==> ROMLMAP
philpem@40 658 case 0x044000: // [ef][4c][4C]xxx ==> L1 MODEM
philpem@40 659 case 0x045000: // [ef][4c][5D]xxx ==> L2 MODEM
philpem@40 660 case 0x046000: // [ef][4c][6E]xxx ==> D/N CONNECT
philpem@44 661 // All write-only registers... TODO: bus error?
philpem@44 662 handled = true;
philpem@40 663 break;
philpem@44 664 case 0x047000: // [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
philpem@40 665 break;
philpem@40 666 }
philpem@40 667 break;
philpem@40 668 case 0x050000: // [ef][5d]xxxx ==> 8274
philpem@40 669 break;
philpem@40 670 case 0x060000: // [ef][6e]xxxx ==> Control regs
philpem@40 671 switch (address & 0x07F000) {
philpem@40 672 default:
philpem@40 673 break;
philpem@40 674 }
philpem@40 675 break;
philpem@40 676 case 0x070000: // [ef][7f]xxxx ==> 6850 Keyboard Controller
philpem@84 677 // TODO: figure out which sizes are valid (probably just 8 and 16)
philpem@84 678 //ENFORCE_SIZE_R(bits, address, 16, "KEYBOARD CONTROLLER");
philpem@84 679 {
philpem@93 680 if (bits == 8) {
philpem@93 681 return keyboard_read(&state.kbd, (address >> 1) & 3);
philpem@93 682 } else {
philpem@93 683 return keyboard_read(&state.kbd, (address >> 1) & 3) << 8;
philpem@93 684 }
philpem@84 685 return data;
philpem@84 686 }
philpem@40 687 break;
philpem@40 688 }
philpem@40 689 }
philpem@40 690 }
philpem@40 691
philpem@64 692 LOG_NOT_HANDLED_R(bits);
philpem@64 693
philpem@59 694 return data;
philpem@59 695 }/*}}}*/
philpem@40 696
philpem@59 697
philpem@59 698 /********************************************************
philpem@59 699 * m68k memory read/write support functions for Musashi
philpem@59 700 ********************************************************/
philpem@59 701
philpem@59 702 /**
philpem@59 703 * @brief Read M68K memory, 32-bit
philpem@59 704 */
philpem@59 705 uint32_t m68k_read_memory_32(uint32_t address)/*{{{*/
philpem@59 706 {
philpem@59 707 uint32_t data = 0xFFFFFFFF;
philpem@59 708
philpem@59 709 // If ROMLMAP is set, force system to access ROM
philpem@59 710 if (!state.romlmap)
philpem@59 711 address |= 0x800000;
philpem@59 712
philpem@59 713 // Check access permissions
philpem@59 714 ACCESS_CHECK_RD(address, 32);
philpem@59 715
philpem@59 716 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@59 717 // ROM access
philpem@60 718 return RD32(state.rom, address, ROM_SIZE - 1);
philpem@60 719 } else if (address <= 0x3fffff) {
philpem@59 720 // RAM access
philpem@60 721 uint32_t newAddr = mapAddr(address, false);
philpem@63 722 if (newAddr <= 0x1fffff) {
philpem@60 723 return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
philpem@63 724 } else {
philpem@63 725 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
philpem@63 726 return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
philpem@63 727 else
philpem@63 728 return 0xffffffff;
philpem@63 729 }
philpem@59 730 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@59 731 // I/O register space, zone A
philpem@59 732 switch (address & 0x0F0000) {
philpem@59 733 case 0x000000: // Map RAM access
philpem@59 734 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
philpem@60 735 return RD32(state.map, address, 0x7FF);
philpem@59 736 break;
philpem@59 737 case 0x020000: // Video RAM
philpem@59 738 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
philpem@60 739 return RD32(state.vram, address, 0x7FFF);
philpem@59 740 break;
philpem@59 741 default:
philpem@60 742 return IoRead(address, 32);
philpem@59 743 }
philpem@59 744 } else {
philpem@60 745 return IoRead(address, 32);
philpem@59 746 }
philpem@59 747
philpem@40 748 return data;
philpem@59 749 }/*}}}*/
philpem@40 750
philpem@40 751 /**
philpem@40 752 * @brief Read M68K memory, 16-bit
philpem@40 753 */
philpem@59 754 uint32_t m68k_read_memory_16(uint32_t address)/*{{{*/
philpem@40 755 {
philpem@40 756 uint16_t data = 0xFFFF;
philpem@40 757
philpem@40 758 // If ROMLMAP is set, force system to access ROM
philpem@40 759 if (!state.romlmap)
philpem@40 760 address |= 0x800000;
philpem@40 761
philpem@40 762 // Check access permissions
philpem@40 763 ACCESS_CHECK_RD(address, 16);
philpem@40 764
philpem@40 765 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@40 766 // ROM access
philpem@40 767 data = RD16(state.rom, address, ROM_SIZE - 1);
philpem@60 768 } else if (address <= 0x3fffff) {
philpem@40 769 // RAM access
philpem@60 770 uint32_t newAddr = mapAddr(address, false);
philpem@63 771 if (newAddr <= 0x1fffff) {
philpem@60 772 return RD16(state.base_ram, newAddr, state.base_ram_size - 1);
philpem@63 773 } else {
philpem@63 774 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
philpem@63 775 return RD16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
philpem@63 776 else
philpem@63 777 return 0xffff;
philpem@63 778 }
philpem@40 779 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 780 // I/O register space, zone A
philpem@40 781 switch (address & 0x0F0000) {
philpem@40 782 case 0x000000: // Map RAM access
philpem@40 783 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
philpem@40 784 data = RD16(state.map, address, 0x7FF);
philpem@40 785 break;
philpem@40 786 case 0x020000: // Video RAM
philpem@40 787 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
philpem@40 788 data = RD16(state.vram, address, 0x7FFF);
philpem@40 789 break;
philpem@59 790 default:
philpem@59 791 data = IoRead(address, 16);
philpem@40 792 }
philpem@59 793 } else {
philpem@59 794 data = IoRead(address, 16);
philpem@40 795 }
philpem@40 796
philpem@40 797 return data;
philpem@59 798 }/*}}}*/
philpem@40 799
philpem@40 800 /**
philpem@40 801 * @brief Read M68K memory, 8-bit
philpem@40 802 */
philpem@59 803 uint32_t m68k_read_memory_8(uint32_t address)/*{{{*/
philpem@40 804 {
philpem@40 805 uint8_t data = 0xFF;
philpem@40 806
philpem@40 807 // If ROMLMAP is set, force system to access ROM
philpem@40 808 if (!state.romlmap)
philpem@40 809 address |= 0x800000;
philpem@40 810
philpem@40 811 // Check access permissions
philpem@40 812 ACCESS_CHECK_RD(address, 8);
philpem@40 813
philpem@40 814 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@40 815 // ROM access
philpem@40 816 data = RD8(state.rom, address, ROM_SIZE - 1);
philpem@60 817 } else if (address <= 0x3fffff) {
philpem@40 818 // RAM access
philpem@60 819 uint32_t newAddr = mapAddr(address, false);
philpem@63 820 if (newAddr <= 0x1fffff) {
philpem@60 821 return RD8(state.base_ram, newAddr, state.base_ram_size - 1);
philpem@63 822 } else {
philpem@63 823 if (newAddr <= (state.exp_ram_size + 0x200000 - 1))
philpem@63 824 return RD8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
philpem@63 825 else
philpem@63 826 return 0xff;
philpem@63 827 }
philpem@40 828 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 829 // I/O register space, zone A
philpem@40 830 switch (address & 0x0F0000) {
philpem@40 831 case 0x000000: // Map RAM access
philpem@40 832 if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
philpem@40 833 data = RD8(state.map, address, 0x7FF);
philpem@40 834 break;
philpem@40 835 case 0x020000: // Video RAM
philpem@40 836 if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
philpem@40 837 data = RD8(state.vram, address, 0x7FFF);
philpem@40 838 break;
philpem@59 839 default:
philpem@59 840 data = IoRead(address, 8);
philpem@40 841 }
philpem@59 842 } else {
philpem@59 843 data = IoRead(address, 8);
philpem@40 844 }
philpem@40 845
philpem@40 846 return data;
philpem@59 847 }/*}}}*/
philpem@40 848
philpem@40 849 /**
philpem@40 850 * @brief Write M68K memory, 32-bit
philpem@40 851 */
philpem@59 852 void m68k_write_memory_32(uint32_t address, uint32_t value)/*{{{*/
philpem@40 853 {
philpem@40 854 // If ROMLMAP is set, force system to access ROM
philpem@40 855 if (!state.romlmap)
philpem@40 856 address |= 0x800000;
philpem@40 857
philpem@40 858 // Check access permissions
philpem@40 859 ACCESS_CHECK_WR(address, 32);
philpem@40 860
philpem@40 861 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@40 862 // ROM access
philpem@60 863 } else if (address <= 0x3FFFFF) {
philpem@40 864 // RAM access
philpem@60 865 uint32_t newAddr = mapAddr(address, true);
philpem@70 866 if (newAddr <= 0x1fffff)
philpem@60 867 WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
philpem@70 868 else
philpem@65 869 WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
philpem@40 870 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 871 // I/O register space, zone A
philpem@40 872 switch (address & 0x0F0000) {
philpem@40 873 case 0x000000: // Map RAM access
philpem@105 874 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X\n", address);
philpem@40 875 WR32(state.map, address, 0x7FF, value);
philpem@40 876 break;
philpem@40 877 case 0x020000: // Video RAM
philpem@105 878 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X\n", address);
philpem@40 879 WR32(state.vram, address, 0x7FFF, value);
philpem@40 880 break;
philpem@59 881 default:
philpem@59 882 IoWrite(address, value, 32);
philpem@40 883 }
philpem@59 884 } else {
philpem@59 885 IoWrite(address, value, 32);
philpem@40 886 }
philpem@59 887 }/*}}}*/
philpem@40 888
philpem@40 889 /**
philpem@40 890 * @brief Write M68K memory, 16-bit
philpem@40 891 */
philpem@59 892 void m68k_write_memory_16(uint32_t address, uint32_t value)/*{{{*/
philpem@40 893 {
philpem@40 894 // If ROMLMAP is set, force system to access ROM
philpem@40 895 if (!state.romlmap)
philpem@40 896 address |= 0x800000;
philpem@40 897
philpem@40 898 // Check access permissions
philpem@40 899 ACCESS_CHECK_WR(address, 16);
philpem@40 900
philpem@40 901 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@40 902 // ROM access
philpem@60 903 } else if (address <= 0x3FFFFF) {
philpem@40 904 // RAM access
philpem@60 905 uint32_t newAddr = mapAddr(address, true);
philpem@112 906
philpem@70 907 if (newAddr <= 0x1fffff)
philpem@60 908 WR16(state.base_ram, newAddr, state.base_ram_size - 1, value);
philpem@70 909 else
philpem@65 910 WR16(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
philpem@40 911 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 912 // I/O register space, zone A
philpem@40 913 switch (address & 0x0F0000) {
philpem@40 914 case 0x000000: // Map RAM access
philpem@40 915 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
philpem@40 916 WR16(state.map, address, 0x7FF, value);
philpem@40 917 break;
philpem@40 918 case 0x020000: // Video RAM
philpem@40 919 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
philpem@40 920 WR16(state.vram, address, 0x7FFF, value);
philpem@40 921 break;
philpem@59 922 default:
philpem@59 923 IoWrite(address, value, 16);
philpem@40 924 }
philpem@59 925 } else {
philpem@59 926 IoWrite(address, value, 16);
philpem@40 927 }
philpem@59 928 }/*}}}*/
philpem@40 929
philpem@40 930 /**
philpem@40 931 * @brief Write M68K memory, 8-bit
philpem@40 932 */
philpem@59 933 void m68k_write_memory_8(uint32_t address, uint32_t value)/*{{{*/
philpem@40 934 {
philpem@40 935 // If ROMLMAP is set, force system to access ROM
philpem@40 936 if (!state.romlmap)
philpem@40 937 address |= 0x800000;
philpem@40 938
philpem@40 939 // Check access permissions
philpem@40 940 ACCESS_CHECK_WR(address, 8);
philpem@40 941
philpem@40 942 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@40 943 // ROM access (read only!)
philpem@60 944 } else if (address <= 0x3FFFFF) {
philpem@40 945 // RAM access
philpem@60 946 uint32_t newAddr = mapAddr(address, true);
philpem@70 947 if (newAddr <= 0x1fffff)
philpem@60 948 WR8(state.base_ram, newAddr, state.base_ram_size - 1, value);
philpem@70 949 else
philpem@65 950 WR8(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
philpem@40 951 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@40 952 // I/O register space, zone A
philpem@40 953 switch (address & 0x0F0000) {
philpem@40 954 case 0x000000: // Map RAM access
philpem@59 955 if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
philpem@40 956 WR8(state.map, address, 0x7FF, value);
philpem@40 957 break;
philpem@40 958 case 0x020000: // Video RAM
philpem@59 959 if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
philpem@40 960 WR8(state.vram, address, 0x7FFF, value);
philpem@40 961 break;
philpem@59 962 default:
philpem@59 963 IoWrite(address, value, 8);
philpem@40 964 }
philpem@59 965 } else {
philpem@59 966 IoWrite(address, value, 8);
philpem@40 967 }
philpem@59 968 }/*}}}*/
philpem@40 969
philpem@40 970
philpem@40 971 // for the disassembler
philpem@40 972 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
philpem@40 973 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
philpem@40 974 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
philpem@40 975