|
|
1.1 ! root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */ ! 2: ! 3: #include "generator.h" ! 4: #include "vdp.h" ! 5: #include "cpu68k.h" ! 6: #include "cpuz80.h" ! 7: #include "reg68k.h" ! 8: #include "ui.h" ! 9: #include "gensound.h" ! 10: ! 11: #include "snprintf.h" ! 12: ! 13: /* time for next event - update vdp_event - return when to call again */ ! 14: ! 15: inline void event_nextevent(void) ! 16: { ! 17: /* call this when it *is* time for the next event as dictated by vdp_event, ! 18: so we switch on it and update vdp_event at the same time */ ! 19: ! 20: switch(vdp_event++) { ! 21: case 0: ! 22: EVENT_NEWLINE: ! 23: LOG_DEBUG1(("%08X due %08X, %d A: %d (cd=%d)", ! 24: cpu68k_clocks, vdp_event_start, ! 25: vdp_line - vdp_visstartline, vdp_reg[10], ! 26: vdp_hskip_countdown)); ! 27: if (vdp_line == (vdp_visstartline-1)) { ! 28: vdp_vblank = 0; ! 29: } ! 30: if ((vdp_nextevent = vdp_event_vint - cpu68k_clocks) > 0) ! 31: break; ! 32: vdp_event++; ! 33: case 1: ! 34: LOG_DEBUG1(("%08X due %08X, %d B: %d (cd=%d)", ! 35: cpu68k_clocks, vdp_event_vint, ! 36: vdp_line - vdp_visstartline, vdp_reg[10], ! 37: vdp_hskip_countdown)); ! 38: if (vdp_line == vdp_visendline) { ! 39: vdp_vblank = 1; ! 40: vdp_vsync = 1; ! 41: if (vdp_reg[1] & 1<<5) ! 42: reg68k_external_autovector(6); /* vertical interrupt */ ! 43: } ! 44: if ((vdp_nextevent = vdp_event_hint - cpu68k_clocks) > 0) ! 45: break; ! 46: vdp_event++; ! 47: case 2: ! 48: LOG_DEBUG1(("%08X due %08X, %d C: %d (cd=%d)", ! 49: cpu68k_clocks, vdp_event_hint, ! 50: vdp_line - vdp_visstartline, vdp_reg[10], ! 51: vdp_hskip_countdown)); ! 52: if (vdp_line >= vdp_visstartline && vdp_line < vdp_visendline) ! 53: vdp_hblank = 1; ! 54: if (vdp_line == (vdp_visstartline-1) || (vdp_line > vdp_visendline)) { ! 55: vdp_hskip_countdown = vdp_reg[10]; ! 56: LOG_DEBUG1(("H counter reset to %d", vdp_hskip_countdown)); ! 57: } ! 58: if (vdp_reg[0] & 1<<4) { ! 59: LOG_DEBUG1(("pre = %d", vdp_hskip_countdown)); ! 60: if (vdp_hskip_countdown-- == 0) { ! 61: LOG_DEBUG1(("in = %d", vdp_hskip_countdown)); ! 62: /* re-initialise counter */ ! 63: vdp_hskip_countdown = vdp_reg[10]; ! 64: LOG_DEBUG1(("H counter looped to %d", vdp_hskip_countdown)); ! 65: if (vdp_line >= vdp_visstartline-1 && vdp_line < vdp_visendline-1) ! 66: reg68k_external_autovector(4); /* horizontal interrupt */ ! 67: /* since this game is obviously timing sensitive, we sacrifice ! 68: executing the right number of 68k clocks this frame in order ! 69: to accurately do the moments following H-Int */ ! 70: cpu68k_clocks = vdp_event_hint; ! 71: } ! 72: LOG_DEBUG1(("post = %d", vdp_hskip_countdown)); ! 73: } ! 74: /* the 68k should be frozen for 68k ram to vram copies, so we need ! 75: to eat CPU cyles immediately - implement this at the same time ! 76: as re-working this event loop */ ! 77: if (vdp_dmabytes) { ! 78: vdp_dmabytes-= (vdp_vblank || !(vdp_reg[1] & 1<<6)) /* blank mode ? */ ! 79: ? ((vdp_reg[12] & 1) ? 205 : 167) : ((vdp_reg[12] & 1) ? 18 : 16); ! 80: if (vdp_dmabytes <= 0) { ! 81: vdp_dmabytes = 0; ! 82: vdp_dmabusy = 0; ! 83: } ! 84: } ! 85: if ((vdp_nextevent = vdp_event_hdisplay - cpu68k_clocks) > 0) ! 86: break; ! 87: vdp_event++; ! 88: case 3: ! 89: LOG_DEBUG1(("%08X due %08X, %d D: %d (cd=%d)", ! 90: cpu68k_clocks, vdp_event_hdisplay, ! 91: vdp_line - vdp_visstartline, vdp_reg[10], ! 92: vdp_hskip_countdown)); ! 93: if (vdp_line >= vdp_visstartline-1 && vdp_line < vdp_visendline-1) ! 94: ui_line(vdp_line - vdp_visstartline + 1); ! 95: if ((vdp_nextevent = vdp_event_end - cpu68k_clocks) > 0) ! 96: break; ! 97: /* vdp_event++; - not required, we set vdp_event to 0 below */ ! 98: case 4: ! 99: /* end of line, do sound, platform stuff */ ! 100: LOG_DEBUG1(("%08X due %08X, %d E: %d (cd=%d)", ! 101: cpu68k_clocks, vdp_event_end, ! 102: vdp_line-vdp_visstartline, vdp_reg[10], ! 103: vdp_hskip_countdown)); ! 104: if (vdp_line >= vdp_visstartline && vdp_line < vdp_visendline) ! 105: vdp_hblank = 0; ! 106: cpuz80_sync(); ! 107: sound_process(); ! 108: vdp_line++; ! 109: if (vdp_line == vdp_visendline) ! 110: cpuz80_interrupt(); ! 111: if (vdp_line == vdp_totlines) { ! 112: ui_endfield(); ! 113: sound_endfield(); ! 114: vdp_endfield(); ! 115: cpuz80_endfield(); ! 116: cpu68k_endfield(); ! 117: cpu68k_frames++; ! 118: } ! 119: vdp_event_start+= vdp_clksperline_68k; ! 120: vdp_event_vint+= vdp_clksperline_68k; ! 121: vdp_event_hint+= vdp_clksperline_68k; ! 122: vdp_event_hdisplay+= vdp_clksperline_68k; ! 123: vdp_event_end+= vdp_clksperline_68k; ! 124: vdp_event = 1; ! 125: goto EVENT_NEWLINE; ! 126: } /* switch */ ! 127: } ! 128: ! 129: /*** event_doframe - execute until the end of the current frame ***/ ! 130: ! 131: void event_doframe(void) ! 132: { ! 133: unsigned int startframe = cpu68k_frames; ! 134: ! 135: do { ! 136: while (vdp_nextevent > 0) ! 137: vdp_nextevent = -reg68k_external_execute(vdp_nextevent); ! 138: event_nextevent(); ! 139: } while (startframe == cpu68k_frames); ! 140: ! 141: } ! 142: ! 143: /*** event_step - execute one instruction with no caching ***/ ! 144: ! 145: void event_dostep(void) ! 146: { ! 147: /* execute one instruction and subtract from vdp_nextevent those cycles */ ! 148: vdp_nextevent-= reg68k_external_step(); ! 149: /* if negative or 0, i.e. we have done all the cycles we need to this event, ! 150: call event_nextevent! */ ! 151: while (vdp_nextevent <= 0) ! 152: event_nextevent(); ! 153: } ! 154: ! 155: /*** event_freeze_clocks - freeze 68k for given clock cycles ***/ ! 156: ! 157: /* NB: this routine is called by event_freeze which is called by ! 158: vdp routines. This could all happen IN THE MIDDLE OF A BLOCK at which ! 159: point cpu68k_clocks will have been updated but vdp_nextevent will not! ! 160: therefore we must at this point work out what vdp_nextevent should be ! 161: at the current moment in time, add on the clocks, wind forward time and ! 162: then subtract the clocks that will be added later */ ! 163: ! 164: void event_freeze_clocks(unsigned int clocks) ! 165: { ! 166: int old_nextevent = vdp_nextevent; ! 167: int missed = 0; ! 168: ! 169: /* first - fix vdp_nextevent to be correct for right now, due to block ! 170: marking delay */ ! 171: ! 172: /* find out how many clocks vdp_nextevent has missed */ ! 173: /* modify vdp_nextevent to reflect the real state as of now */ ! 174: ! 175: switch (vdp_event) { ! 176: case 0: ! 177: missed = vdp_nextevent - (vdp_event_start - cpu68k_clocks); ! 178: vdp_nextevent-= missed; ! 179: break; ! 180: case 1: ! 181: missed = vdp_nextevent - (vdp_event_vint - cpu68k_clocks); ! 182: vdp_nextevent-= missed; ! 183: break; ! 184: case 2: ! 185: missed = vdp_nextevent - (vdp_event_hint - cpu68k_clocks); ! 186: vdp_nextevent-= missed; ! 187: break; ! 188: case 3: ! 189: missed = vdp_nextevent - (vdp_event_hdisplay - cpu68k_clocks); ! 190: vdp_nextevent-= missed; ! 191: break; ! 192: case 4: ! 193: missed = vdp_nextevent - (vdp_event_end - cpu68k_clocks); ! 194: vdp_nextevent-= missed; ! 195: break; ! 196: default: ! 197: printf("assertion failed: bad vdp_event in event_freeze_clocks: %d\n", ! 198: vdp_event); ! 199: } ! 200: ! 201: /* move cpu68k_clocks and vdp_nextevent forward in time */ ! 202: ! 203: cpu68k_clocks+= clocks; ! 204: vdp_nextevent-= clocks; ! 205: ! 206: /* now catch up events */ ! 207: ! 208: while (vdp_nextevent <= 0) ! 209: event_nextevent(); ! 210: ! 211: /* and then un-adjust vdp_nextevent, as the block marking code will update ! 212: this later */ ! 213: ! 214: vdp_nextevent+= missed; ! 215: } ! 216: ! 217: /*** event_freeze - freeze 68k for given VDP byte transfer ***/ ! 218: ! 219: void event_freeze(unsigned int bytes) ! 220: { ! 221: int wide = vdp_reg[12] & 1; ! 222: int clocks, possible; ! 223: double percent_possible; ! 224: int togo = (int)bytes; ! 225: ! 226: cpu68k_frozen = 1; /* prohibit interrupts since PC is not known in the ! 227: middle of a 68k block due to register mappings */ ! 228: ! 229: while (togo > 0) { ! 230: /* clocks will be negative if we're in the middle of a cpu block */ ! 231: clocks = vdp_event_end - cpu68k_clocks; ! 232: if (clocks < 0) ! 233: clocks = 0; ! 234: percent_possible = clocks/vdp_clksperline_68k; ! 235: if (vdp_reg[1] & 1<<6 && !vdp_vblank) { ! 236: /* vdp active */ ! 237: possible = (unsigned int)(percent_possible*(wide ? 18 : 16)); ! 238: } else { ! 239: /* vdp inactive */ ! 240: possible = (unsigned int)(percent_possible*(wide ? 205 : 167)); ! 241: } ! 242: if (togo >= possible) { ! 243: event_freeze_clocks(clocks); ! 244: togo-= possible; ! 245: } else { ! 246: event_freeze_clocks(((double)togo/possible)*clocks); ! 247: togo = 0; ! 248: } ! 249: } ! 250: cpu68k_frozen = 0; ! 251: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.