src/memory.c

Fri, 12 Apr 2013 16:26:25 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Fri, 12 Apr 2013 16:26:25 +0100
branch
experimental_memory_mapper_v2
changeset 144
609707511166
parent 141
8460d432606f
permissions
-rw-r--r--

Don't set PS1 if there is a level-7 interrupt or bus error

PS1 should only be set if the page was originally present (PS1 or PS0 set). If
PS0 and PS1 are clear (page not present) then do NOT set PS1.

Once again the TRM is blatantly and spectacularly wrong...

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