|
|
1.1 ! root 1: /*****************************************************************************/ ! 2: /* Generator - Sega Genesis emulation - (c) James Ponder 1997-2000 */ ! 3: /*****************************************************************************/ ! 4: /* */ ! 5: /* reg68k.c */ ! 6: /* */ ! 7: /*****************************************************************************/ ! 8: ! 9: #include "generator.h" ! 10: #include "registers.h" ! 11: ! 12: #include <stdio.h> ! 13: #include <string.h> ! 14: #include <stdlib.h> ! 15: #include <setjmp.h> ! 16: ! 17: #include "mem68k.h" ! 18: #include "cpu68k.h" ! 19: #include "cpuz80.h" ! 20: #include "vdp.h" ! 21: #include "ui.h" ! 22: #include "compile.h" ! 23: #include "gensound.h" ! 24: ! 25: /*** externed variables ***/ ! 26: ! 27: #if (!(defined(PROCESSOR_ARM) || defined(PROCESSOR_SPARC) \ ! 28: || defined(PROCESSOR_INTEL))) ! 29: uint32 reg68k_pc; ! 30: uint32 *reg68k_regs; ! 31: t_sr reg68k_sr; ! 32: #endif ! 33: ! 34: /*** forward references ***/ ! 35: ! 36: inline void reg68k_checkevent(void); ! 37: void reg68k_autovector(int avno); ! 38: ! 39: static unsigned int reg68k_eventdelay; ! 40: ! 41: void reg68k_step(void) ! 42: { ! 43: /* PAL: 312 lines, 224 or 240 visible @ 50Hz - CPU @ 7.60Mhz */ ! 44: /* NTSC: 262 lines, 224 visible @ 60Hz - CPU @ 7.67Mhz */ ! 45: ! 46: static t_ipc ipc; ! 47: static t_iib *piib; ! 48: jmp_buf jb; ! 49: ! 50: /* !!! entering global register usage area !!! */ ! 51: ! 52: if (!setjmp(jb)) { ! 53: if (!(piib = cpu68k_iibtable[fetchword(regs.pc)])) ! 54: ui_err("Invalid instruction @ %08X\n", regs.pc); ! 55: /* move PC and register block into global variables */ ! 56: reg68k_pc = regs.pc; ! 57: reg68k_regs = regs.regs; ! 58: reg68k_sr = regs.sr; ! 59: ! 60: cpu68k_ipc(reg68k_pc, ! 61: mem68k_memptr[(reg68k_pc>>12) & 0xfff](reg68k_pc & 0xFFFFFF), ! 62: piib, &ipc); ! 63: cpu68k_functable[fetchword(reg68k_pc)*2+1](&ipc); ! 64: cpu68k_clocks+= piib->clocks; ! 65: reg68k_checkevent(); ! 66: /* restore global registers back to permanent storage */ ! 67: regs.pc = reg68k_pc; ! 68: regs.sr = reg68k_sr; ! 69: longjmp(jb, 1); ! 70: } ! 71: } ! 72: ! 73: inline void reg68k_checkevent(void) ! 74: { ! 75: switch(vdp_event) { ! 76: case 0: ! 77: if (cpu68k_clocks >= vdp_event_start) { ! 78: vdp_event_startofcurrentline = vdp_event_start; ! 79: LOG_USER(("%08X due %08X, %d A: %d (cd=%d)", ! 80: cpu68k_clocks, vdp_event_start, vdp_line, vdp_reg[10], ! 81: vdp_hskip_countdown)); ! 82: vdp_event++; ! 83: vdp_event_start+= vdp_clksperline_68k; ! 84: cpuz80_sync(); ! 85: if (vdp_line == 0) { ! 86: vdp_vblank = 0; ! 87: vdp_hskip_countdown = vdp_reg[10]; ! 88: ui_line(0); ! 89: } ! 90: if (vdp_line < vdp_vislines) ! 91: ui_line(vdp_line); ! 92: } ! 93: break; ! 94: case 1: ! 95: if (cpu68k_clocks >= vdp_event_vint) { ! 96: LOG_USER(("%08X due %08X, %d B: %d (cd=%d)", ! 97: cpu68k_clocks, vdp_event_vint, vdp_line, vdp_reg[10], ! 98: vdp_hskip_countdown)); ! 99: vdp_event++; ! 100: vdp_event_vint+= vdp_clksperline_68k; ! 101: if (vdp_line == vdp_vislines) { ! 102: vdp_vblank = 1; ! 103: vdp_vsync = 1; ! 104: if (vdp_reg[1] & 1<<5) ! 105: reg68k_autovector(6); /* vertical interrupt */ ! 106: } ! 107: } ! 108: break; ! 109: case 2: ! 110: if (cpu68k_clocks >= vdp_event_hint) { ! 111: LOG_USER(("%08X due %08X, %d C: %d (cd=%d)", ! 112: cpu68k_clocks, vdp_event_hint, vdp_line, vdp_reg[10], ! 113: vdp_hskip_countdown)); ! 114: /* delay hdisplay if hint is delayed */ ! 115: vdp_event++; ! 116: vdp_event_hint+= vdp_clksperline_68k; ! 117: cpuz80_sync(); ! 118: /* if (vdp_line < vdp_vislines) */ ! 119: vdp_hblank = 1; ! 120: if (vdp_reg[0] & 1<<4) { ! 121: if (vdp_hskip_countdown-- == 0) { ! 122: /* re-initialise counter */ ! 123: vdp_hskip_countdown = vdp_reg[10]; ! 124: if (vdp_line < vdp_vislines) ! 125: reg68k_autovector(4); /* horizontal interrupt */ ! 126: /* since this game is obviously timing sensitive, we sacrifice ! 127: executing the right number of 68k clocks this frame in order ! 128: to accurately do the moments following H-Int */ ! 129: cpu68k_clocks = vdp_event_hint - vdp_clksperline_68k; ! 130: } ! 131: } ! 132: } ! 133: break; ! 134: case 3: ! 135: if (cpu68k_clocks >= vdp_event_hdisplay) { ! 136: LOG_USER(("%08X due %08X, %d D: %d (cd=%d)", ! 137: cpu68k_clocks, vdp_event_hdisplay, vdp_line, vdp_reg[10], ! 138: vdp_hskip_countdown)); ! 139: vdp_event_hdisplay-= reg68k_eventdelay; ! 140: vdp_event++; ! 141: vdp_event_hdisplay+= vdp_clksperline_68k; ! 142: cpuz80_sync(); ! 143: /* err ! 144: if (vdp_line+1 < vdp_vislines) ! 145: ui_line(vdp_line+1); ! 146: */ ! 147: } ! 148: break; ! 149: case 4: ! 150: if (cpu68k_clocks >= vdp_event_end) { ! 151: /* end of line, do sound, platform stuff */ ! 152: LOG_USER(("%08X due %08X, %d E: %d (cd=%d)", ! 153: cpu68k_clocks, vdp_event_end, vdp_line, vdp_reg[10], ! 154: vdp_hskip_countdown)); ! 155: vdp_event = 0; ! 156: vdp_event_end+= vdp_clksperline_68k; ! 157: /* if (vdp_line < vdp_vislines) */ ! 158: vdp_hblank = 0; ! 159: cpuz80_sync(); ! 160: sound_process(); ! 161: vdp_line++; ! 162: if (vdp_line == vdp_totlines) { ! 163: ui_endfield(); ! 164: sound_endfield(); ! 165: cpuz80_interrupt(); ! 166: vdp_endfield(); ! 167: cpuz80_endfield(); ! 168: cpu68k_endfield(); ! 169: cpu68k_frames++; ! 170: } ! 171: } ! 172: break; ! 173: } /* switch */ ! 174: } ! 175: ! 176: /*** reg68k_framestep - do a frame and return ***/ ! 177: ! 178: void reg68k_framestep(void) ! 179: { ! 180: /* PAL: 312 lines, 224 or 240 visible @ 50Hz - CPU @ 7.60Mhz */ ! 181: /* NTSC: 262 lines, 224 visible @ 60Hz - CPU @ 7.67Mhz */ ! 182: ! 183: unsigned int startframe = cpu68k_frames; ! 184: unsigned int index, i; ! 185: t_ipclist *list; ! 186: t_ipc *ipc; ! 187: uint32 pc24; ! 188: jmp_buf jb; ! 189: static t_ipc step_ipc; ! 190: static t_iib *step_piib; ! 191: ! 192: if (!setjmp(jb)) { ! 193: /* move PC and register block into global variables */ ! 194: reg68k_pc = regs.pc; ! 195: reg68k_regs = regs.regs; ! 196: reg68k_sr = regs.sr; ! 197: ! 198: do { ! 199: pc24 = reg68k_pc & 0xffffff; ! 200: if ((pc24 & 0xff0000) == 0xff0000) { ! 201: /* executing code from RAM, do not use compiled information */ ! 202: do { ! 203: step_piib = cpu68k_iibtable[fetchword(reg68k_pc)]; ! 204: cpu68k_ipc(reg68k_pc, ! 205: mem68k_memptr[(reg68k_pc>>12) & ! 206: 0xfff](reg68k_pc & 0xFFFFFF), ! 207: step_piib, &step_ipc); ! 208: cpu68k_functable[fetchword(reg68k_pc)*2+1](&step_ipc); ! 209: cpu68k_clocks+= step_piib->clocks; ! 210: } while (!step_piib->flags.endblk); ! 211: list = NULL; /* stop compiler warning ;( */ ! 212: } else { ! 213: index = (pc24>>1) & (LEN_IPCLISTTABLE-1); ! 214: list = ipclist[index]; ! 215: while(list && (list->pc != pc24)) { ! 216: list = list->next; ! 217: } ! 218: #ifdef PROCESSOR_ARM ! 219: if (!list) { ! 220: list = cpu68k_makeipclist(pc24); ! 221: list->next = ipclist[index]; ! 222: ipclist[index] = list; ! 223: list->compiled = compile_make(list); ! 224: } ! 225: list->compiled((t_ipc *)(list+1)); ! 226: #else ! 227: if (!list) { ! 228: /* LOG_USER(("Making IPC list @ %08x", pc24)); */ ! 229: list = cpu68k_makeipclist(pc24); ! 230: list->next = ipclist[index]; ! 231: ipclist[index] = list; ! 232: } ! 233: ipc = (t_ipc *)(list+1); ! 234: do { ! 235: ipc->function(ipc); ! 236: ipc++; ! 237: } while (*(int *)ipc); ! 238: #endif ! 239: cpu68k_clocks+= list->clocks; ! 240: } ! 241: reg68k_checkevent(); ! 242: } while (cpu68k_frames == startframe); ! 243: /* restore global registers back to permanent storage */ ! 244: regs.pc = reg68k_pc; ! 245: regs.sr = reg68k_sr; ! 246: longjmp(jb, 1); ! 247: } ! 248: } ! 249: ! 250: void reg68k_autovector(int avno) ! 251: { ! 252: int curlevel = (reg68k_sr.sr_int>>8) & 7; ! 253: uint32 tmpaddr; ! 254: ! 255: LOG_VERBOSE(("autovector %d\n", avno)); ! 256: if (curlevel < avno || avno == 7) { ! 257: if (!reg68k_sr.sr_struct.s) { ! 258: regs.regs[15]^= regs.sp; /* swap A7 and SP */ ! 259: regs.sp^= regs.regs[15]; ! 260: regs.regs[15]^= regs.sp; ! 261: reg68k_sr.sr_struct.s = 1; ! 262: } ! 263: regs.regs[15]-=4; ! 264: storelong(regs.regs[15], reg68k_pc); ! 265: regs.regs[15]-=2; ! 266: storeword(regs.regs[15], reg68k_sr.sr_int); ! 267: reg68k_sr.sr_struct.t = 0; ! 268: reg68k_sr.sr_int&= ~0x0700; ! 269: reg68k_sr.sr_int|= avno << 8; ! 270: tmpaddr = reg68k_pc; ! 271: reg68k_pc = fetchlong((V_AUTO+avno-1)*4); ! 272: LOG_DEBUG1(("AUTOVECTOR %d: %X -> %X", avno, tmpaddr, reg68k_pc)); ! 273: } ! 274: } ! 275: ! 276: void reg68k_vector(int vno, uint32 oldpc) ! 277: { ! 278: LOG_DEBUG1(("Vector %d called from %8x!", vno, regs.pc)); ! 279: if (!reg68k_sr.sr_struct.s) { ! 280: regs.regs[15]^= regs.sp; /* swap A7 and SP */ ! 281: regs.sp^= regs.regs[15]; ! 282: regs.regs[15]^= regs.sp; ! 283: reg68k_sr.sr_struct.s = 1; ! 284: } ! 285: regs.regs[15]-=4; ! 286: storelong(regs.regs[15], oldpc); ! 287: regs.regs[15]-=2; ! 288: storeword(regs.regs[15], reg68k_sr.sr_int); ! 289: reg68k_pc = fetchlong(vno*4); ! 290: LOG_DEBUG1(("VECTOR %d: %X -> %X\n", vno, oldpc, reg68k_pc)); ! 291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.