|
|
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.