|
|
1.1 ! root 1: /*****************************************************************************/ ! 2: /* Generator - Sega Genesis emulation - (c) James Ponder 1997-1998 */ ! 3: /*****************************************************************************/ ! 4: /* */ ! 5: /* z80.c */ ! 6: /* */ ! 7: /*****************************************************************************/ ! 8: ! 9: #include <stdlib.h> ! 10: #include <stdio.h> ! 11: #include <string.h> ! 12: ! 13: #include "generator.h" ! 14: #include "cpuz80.h" ! 15: #include "cpu68k.h" ! 16: #include "memz80.h" ! 17: #include "ui.h" ! 18: ! 19: #define BIG_ENDIAN ! 20: ! 21: #include "z80/mz80.h" ! 22: #include "z80/cmz80.h" ! 23: ! 24: UINT8 cpuz80_read_actual(UINT32 addr, struct MemoryReadByte *me); ! 25: void cpuz80_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me); ! 26: UINT16 cpuz80_ioread_actual(UINT16 addr, struct z80PortRead *me); ! 27: void cpuz80_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me); ! 28: ! 29: UINT8 cpuz80c_read_actual(UINT32 addr, struct MemoryReadByte *me); ! 30: void cpuz80c_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me); ! 31: UINT16 cpuz80c_ioread_actual(UINT16 addr, struct z80PortRead *me); ! 32: void cpuz80c_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me); ! 33: ! 34: /*** variables externed ***/ ! 35: ! 36: uint8 *cpuz80_ram = NULL; ! 37: uint32 cpuz80_bank = 0; ! 38: unsigned int cpuz80_active = 0; ! 39: ! 40: /*** global variables ***/ ! 41: ! 42: static unsigned int cpuz80_lastsync = 0; ! 43: static unsigned int cpuz80_resetting = 0; ! 44: static CONTEXTMZ80 cpuz80_z80; ! 45: static CONTEXTCMZ80 cpuz80c_z80; ! 46: ! 47: struct { ! 48: uint32 addr; ! 49: uint8 data; ! 50: } reads[256]; ! 51: ! 52: uint32 readpointer_head = 0; ! 53: uint32 readpointer_tail = 0; ! 54: ! 55: struct { ! 56: uint32 addr; ! 57: uint8 data; ! 58: } writes[256]; ! 59: ! 60: uint32 writepointer_head = 0; ! 61: uint32 writepointer_tail = 0; ! 62: ! 63: static struct MemoryReadByte cpuz80_read[] = { ! 64: { 0x0000, 0xFFFF, cpuz80_read_actual, NULL }, ! 65: { -1, -1, NULL, NULL } ! 66: }; ! 67: ! 68: static struct MemoryWriteByte cpuz80_write[] = { ! 69: { 0x0000, 0xFFFF, cpuz80_write_actual, NULL }, ! 70: { -1, -1, NULL, NULL } ! 71: }; ! 72: ! 73: static struct z80PortRead cpuz80_ioread[] = { ! 74: { 0x0000, 0x00FF, cpuz80_ioread_actual, NULL }, ! 75: { -1, -1, NULL, NULL } ! 76: }; ! 77: ! 78: static struct z80PortWrite cpuz80_iowrite[] = { ! 79: { 0x0000, 0x00FF, cpuz80_iowrite_actual, NULL }, ! 80: { -1, -1, NULL, NULL } ! 81: }; ! 82: ! 83: ! 84: ! 85: static struct MemoryReadByte cpuz80c_read[] = { ! 86: { 0x0000, 0xFFFF, cpuz80c_read_actual, NULL }, ! 87: { -1, -1, NULL, NULL } ! 88: }; ! 89: ! 90: static struct MemoryWriteByte cpuz80c_write[] = { ! 91: { 0x0000, 0xFFFF, cpuz80c_write_actual, NULL }, ! 92: { -1, -1, NULL, NULL } ! 93: }; ! 94: ! 95: static struct z80PortRead cpuz80c_ioread[] = { ! 96: { 0x0000, 0x00FF, cpuz80c_ioread_actual, NULL }, ! 97: { -1, -1, NULL, NULL } ! 98: }; ! 99: ! 100: static struct z80PortWrite cpuz80c_iowrite[] = { ! 101: { 0x0000, 0x00FF, cpuz80c_iowrite_actual, NULL }, ! 102: { -1, -1, NULL, NULL } ! 103: }; ! 104: ! 105: ! 106: UINT8 cpuz80_read_actual(UINT32 addr, struct MemoryReadByte *me) ! 107: { ! 108: uint8 data; ! 109: (void)me; ! 110: if (((readpointer_head+1)%256) == readpointer_tail) ! 111: ui_err("read overrun during REAL read to %08X (p=%d)", ! 112: addr, readpointer_head); ! 113: data = memz80_fetchbyte((uint32)addr); ! 114: LOG_CRITICAL(("REAL read to %08X = %02X (p=%d)", addr, data, ! 115: readpointer_head)); ! 116: reads[readpointer_head].addr = addr; ! 117: reads[readpointer_head].data = data; ! 118: if (++readpointer_head >= 256) ! 119: readpointer_head = 0; ! 120: return data; ! 121: } ! 122: ! 123: void cpuz80_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me) ! 124: { ! 125: (void)me; ! 126: LOG_CRITICAL(("REAL write to %08X of %02X (p=%d)", addr, data, ! 127: writepointer_head)); ! 128: if (((writepointer_head+1)%256) == writepointer_tail) ! 129: ui_err("write overrun"); ! 130: writes[writepointer_head].addr = addr; ! 131: writes[writepointer_head].data = data; ! 132: if (++writepointer_head >= 256) ! 133: writepointer_head = 0; ! 134: memz80_storebyte((uint32)addr, (uint8)data); ! 135: } ! 136: ! 137: UINT16 cpuz80_ioread_actual(UINT16 addr, struct z80PortRead *me) ! 138: { ! 139: (void)me; ! 140: return cpuz80_portread((uint16)addr); ! 141: } ! 142: ! 143: void cpuz80_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me) ! 144: { ! 145: (void)me; ! 146: cpuz80_portwrite((uint16)addr, (uint8)data); ! 147: } ! 148: ! 149: ! 150: ! 151: ! 152: UINT8 cpuz80c_read_actual(UINT32 addr, struct MemoryReadByte *me) ! 153: { ! 154: uint8 data; ! 155: (void)me; ! 156: if (readpointer_tail == readpointer_head) ! 157: ui_err("read underrun"); ! 158: if (reads[readpointer_tail].addr != addr) ! 159: ui_err("read address mismatch"); ! 160: data = reads[readpointer_tail].data; ! 161: LOG_CRITICAL(("FAKE read to %08X = %02X", addr, data)); ! 162: readpointer_tail = (readpointer_tail+1) % 256; ! 163: return data; ! 164: } ! 165: ! 166: void cpuz80c_write_actual(UINT32 addr, UINT8 data, struct MemoryWriteByte *me) ! 167: { ! 168: (void)me; ! 169: LOG_CRITICAL(("FAKE write to %08X of %02X (p=%d)", addr, data, ! 170: writepointer_tail)); ! 171: if (writepointer_tail == writepointer_head) { ! 172: LOG_CRITICAL(("write underrun")); ! 173: return; ! 174: } ! 175: if (writes[writepointer_tail].addr != addr && ! 176: writes[writepointer_tail].data != data) ! 177: ui_err("write address AND data mismatch"); ! 178: if (writes[writepointer_tail].addr != addr) ! 179: ui_err("write address mismatch"); ! 180: if (writes[writepointer_tail].data != data) ! 181: ui_err("write data mismatch"); ! 182: writepointer_tail = (writepointer_tail+1) % 256; ! 183: } ! 184: ! 185: UINT16 cpuz80c_ioread_actual(UINT16 addr, struct z80PortRead *me) ! 186: { ! 187: (void)me; ! 188: ui_err("ioread"); ! 189: return 0; ! 190: } ! 191: ! 192: void cpuz80c_iowrite_actual(UINT16 addr, UINT8 data, struct z80PortWrite *me) ! 193: { ! 194: (void)me; ! 195: ui_err("iowrite"); ! 196: } ! 197: ! 198: ! 199: ! 200: /*** cpuz80_init - initialise this sub-unit ***/ ! 201: ! 202: int cpuz80_init(void) ! 203: { ! 204: cmz80init(); ! 205: cpuz80_reset(); ! 206: return 0; ! 207: } ! 208: ! 209: /*** cpuz80_reset - reset z80 sub-unit ***/ ! 210: ! 211: void cpuz80_reset(void) ! 212: { ! 213: if (!cpuz80_ram) { ! 214: if ((cpuz80_ram = malloc(LEN_SRAM)) == NULL) { ! 215: fprintf(stderr, "Out of memory\n"); ! 216: exit(1); ! 217: } ! 218: } ! 219: memset(cpuz80_ram, 0, LEN_SRAM); ! 220: cpuz80_resetcpu(); ! 221: cpuz80_bank = 0; ! 222: cpuz80_active = 0; ! 223: cpuz80_lastsync = 0; ! 224: cpuz80_resetting = 0; ! 225: /* mz80GetContext(&cpuz80_z80); */ ! 226: memset(&cpuz80_z80, 0, sizeof(cpuz80_z80)); ! 227: cpuz80_z80.z80Base = cpuz80_ram; ! 228: cpuz80_z80.z80MemRead = cpuz80_read; ! 229: cpuz80_z80.z80MemWrite = cpuz80_write; ! 230: cpuz80_z80.z80IoRead = cpuz80_ioread; ! 231: cpuz80_z80.z80IoWrite = cpuz80_iowrite; ! 232: mz80SetContext(&cpuz80_z80); ! 233: mz80reset(); ! 234: ; ! 235: memset(&cpuz80c_z80, 0, sizeof(cpuz80c_z80)); ! 236: cpuz80c_z80.z80Base = cpuz80_ram; ! 237: cpuz80c_z80.z80MemRead = cpuz80c_read; ! 238: cpuz80c_z80.z80MemWrite = cpuz80c_write; ! 239: cpuz80c_z80.z80IoRead = cpuz80c_ioread; ! 240: cpuz80c_z80.z80IoWrite = cpuz80c_iowrite; ! 241: cmz80SetContext(&cpuz80c_z80); ! 242: cmz80reset(); ! 243: } ! 244: ! 245: /*** cpuz80_resetcpu - reset z80 cpu ***/ ! 246: ! 247: void cpuz80_resetcpu(void) ! 248: { ! 249: mz80reset(); ! 250: cmz80reset(); ! 251: cpuz80_resetting = 1; /* suspends execution */ ! 252: } ! 253: ! 254: /*** cpuz80_unresetcpu - unreset z80 cpu ***/ ! 255: ! 256: void cpuz80_unresetcpu(void) ! 257: { ! 258: cpuz80_resetting = 0; /* un-suspends execution */ ! 259: } ! 260: ! 261: /*** cpuz80_bankwrite - data is being written to latch ***/ ! 262: ! 263: void cpuz80_bankwrite(uint8 data) ! 264: { ! 265: cpuz80_bank = (((cpuz80_bank >> 1) | ((data & 1) <<23)) & 0xff8000); ! 266: /* ! 267: if (gen_debug) ! 268: printf("BANK WRITE: %d --> %08X\n", data, cpuz80_bank); ! 269: */ ! 270: } ! 271: ! 272: /*** cpuz80_stop - stop the processor ***/ ! 273: ! 274: void cpuz80_stop(void) ! 275: { ! 276: cpuz80_sync(); ! 277: cpuz80_active = 0; ! 278: } ! 279: ! 280: /*** cpuz80_start - start the processor ***/ ! 281: ! 282: void cpuz80_start(void) ! 283: { ! 284: cpuz80_sync(); ! 285: cpuz80_active = 1; ! 286: } ! 287: ! 288: /*** cpuz80_endfield - reset counters ***/ ! 289: ! 290: void cpuz80_endfield(void) ! 291: { ! 292: cpuz80_lastsync = 0; ! 293: } ! 294: ! 295: /*** cpuz80_sync - synchronise ***/ ! 296: ! 297: void cpuz80_sync(void) ! 298: { ! 299: int cpu68k_wanted = cpu68k_clocks - cpuz80_lastsync; ! 300: int wanted = (cpu68k_wanted<0?0:cpu68k_wanted)*7/16; ! 301: int achieved, achieved_c; ! 302: uint32 oldpc; ! 303: ! 304: if (cpuz80_active && !cpuz80_resetting) { ! 305: /* ui_log(LOG_USER, "executing %d z80 clocks @ %X", wanted, ! 306: cpuz80_z80.z80pc); */ ! 307: printf("context: s=%08X c=%08X\n", &cpuz80_z80, &cpuz80c_z80); ! 308: printf("pc invalid: %08X %08X\n", &cpuz80_z80.z80pc, &cpuz80c_z80.z80pc); ! 309: mz80GetContext(&cpuz80_z80); ! 310: cmz80GetContext(&cpuz80c_z80); ! 311: printf("pc start: %08X %08X\n", cpuz80_z80.z80pc, cpuz80c_z80.z80pc); ! 312: printf("opcodes: %02x(%02x) %02x(%02x)\n", cpuz80_ram[cpuz80_z80.z80pc], ! 313: cpuz80_ram[cpuz80_z80.z80pc+1], ! 314: cpuz80_ram[cpuz80c_z80.z80pc], ! 315: cpuz80_ram[cpuz80c_z80.z80pc+1]); ! 316: if (cpuz80_z80.z80pc != cpuz80c_z80.z80pc) { ! 317: ui_err("sPC = %08X / cPC = %08X mismatch on entry", ! 318: cpuz80_z80.z80pc, cpuz80c_z80.z80pc); ! 319: } ! 320: printf("Pending ints: s = %X c = %X\n", ! 321: cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending); ! 322: printf("DE on entry: s=%X c=%X\n", cpuz80_z80.z80de.de, ! 323: cpuz80c_z80.z80de.de); ! 324: oldpc = cpuz80_z80.z80pc; ! 325: printf("Attempting to execute %d clocks...\n", wanted); ! 326: mz80exec(wanted); /* wanted */ ! 327: cmz80exec(wanted); ! 328: achieved = mz80GetElapsedTicks(1); ! 329: achieved_c = cmz80GetElapsedTicks(1); ! 330: mz80GetContext(&cpuz80_z80); ! 331: cmz80GetContext(&cpuz80c_z80); ! 332: LOG_CRITICAL(("achieved s=%d c=%d", achieved, achieved_c)); ! 333: printf("pc end: %08X %08X\n", cpuz80_z80.z80pc, cpuz80c_z80.z80pc); ! 334: printf("Exit pending ints: s = %X c = %X\n", ! 335: cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending); ! 336: if (cpuz80_z80.z80af.af != cpuz80c_z80.z80af.af) ! 337: ui_err("AF differs: s=%X c=%X", cpuz80_z80.z80af.af, ! 338: cpuz80c_z80.z80af.af); ! 339: if (cpuz80_z80.z80bc.bc != cpuz80c_z80.z80bc.bc) ! 340: ui_err("BC differs: s=%X c=%X", cpuz80_z80.z80bc.bc, ! 341: cpuz80c_z80.z80bc.bc); ! 342: if (cpuz80_z80.z80de.de != cpuz80c_z80.z80de.de) ! 343: ui_err("DE differs: s=%X c=%X", cpuz80_z80.z80de.de, ! 344: cpuz80c_z80.z80de.de); ! 345: if (cpuz80_z80.z80hl.hl != cpuz80c_z80.z80hl.hl) ! 346: ui_err("HL differs: s=%X c=%X", cpuz80_z80.z80hl.hl, ! 347: cpuz80c_z80.z80hl.hl); ! 348: if (cpuz80_z80.z80ix.ix != cpuz80c_z80.z80ix.ix) ! 349: ui_err("IX differs: s=%X c=%X", cpuz80_z80.z80ix.ix, ! 350: cpuz80c_z80.z80ix.ix); ! 351: if (cpuz80_z80.z80iy.iy != cpuz80c_z80.z80iy.iy) ! 352: ui_err("IY differs: s=%X c=%X", cpuz80_z80.z80iy.iy, ! 353: cpuz80c_z80.z80iy.iy); ! 354: if (cpuz80_z80.z80pc != cpuz80c_z80.z80pc) { ! 355: ui_err("sPC = %08X / cPC = %08X mismatch on exit", ! 356: cpuz80_z80.z80pc, cpuz80c_z80.z80pc); ! 357: } ! 358: if (cpuz80_z80.z80intPending != cpuz80c_z80.z80intPending) { ! 359: /* ! 360: ui_err("sIntPending = %X / cIntPending = %X\n", ! 361: cpuz80_z80.z80intPending, cpuz80c_z80.z80intPending); ! 362: */ ! 363: } ! 364: if (achieved != achieved_c) { ! 365: LOG_CRITICAL(("oldpc=%08X newpc=%08X", oldpc, cpuz80_z80.z80pc)); ! 366: ui_err("achieved clocks mismatch: s=%d c=%d", achieved, achieved_c); ! 367: } ! 368: /* this if/else statement below, I'm not entirely sure this is a good ! 369: idea, perhaps just doing cpuz80_lastsync = cpu68k_clocks; always is ! 370: better? hmm. */ ! 371: if (achieved > wanted) { ! 372: cpuz80_lastsync = cpu68k_clocks; ! 373: } else { ! 374: cpuz80_lastsync = cpuz80_lastsync + achieved*16/7; ! 375: } ! 376: } else { ! 377: cpuz80_lastsync = cpu68k_clocks; ! 378: } ! 379: } ! 380: ! 381: /*** cpuz80_interrupt - cause an interrupt on the z80 */ ! 382: ! 383: void cpuz80_interrupt(void) ! 384: { ! 385: if (!cpuz80_resetting) { ! 386: LOG_CRITICAL(("interrupt!!!!!!!!!!!!!")); ! 387: mz80int(0); ! 388: cmz80int(0); ! 389: } ! 390: } ! 391: ! 392: /*** cpuz80_portread - port read from z80 */ ! 393: ! 394: uint8 cpuz80_portread(uint8 port) ! 395: { ! 396: LOG_VERBOSE(("[Z80] Port read to %X", port)); ! 397: return 0; ! 398: } ! 399: ! 400: /*** cpuz80_portwrite - z80 write to port */ ! 401: ! 402: void cpuz80_portwrite(uint8 port, uint8 value) ! 403: { ! 404: LOG_VERBOSE(("[Z80] Port write to %X of %X", port, value)); ! 405: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.