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