src/memory.c

Wed, 13 Mar 2013 00:43:25 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 13 Mar 2013 00:43:25 +0000
changeset 134
b826697f411a
parent 129
8b24770dea79
child 132
8a7dc9b5b1db
child 136
f7d78dfb45d0
permissions
-rw-r--r--

[wd2010,main] WD2010 disc geometry fixes

I believe I have fixed the geometry problem with FreeBee. The geometry was set
to 17 sectors per track instead of 16, which obviously throws off addressing.
I changed it to use 16 sectors per track. However, s4diag tries to format
sector 17, so I changed the WD2010 emulation to accept any address when
formatting (since the format command doesn't actually do anything, it doesn't
matter). It is now possible to format the hard disk, initialize the file
system, and mount it. However, cpio still fails to copy the system to the hard
disk.

Author: Andrew Warkentin <andreww591 gmail com>

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