|
|
1.1 root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
2:
3: #include "generator.h"
4: #include "registers.h"
5:
6: #include <stdio.h>
7: #include <string.h>
8: #include <stdlib.h>
9: #include <setjmp.h>
10:
11: #include "reg68k.h"
12: #include "mem68k.h"
13: #include "cpu68k.h"
14: #include "cpuz80.h"
15: #include "vdp.h"
16: #include "ui.h"
17: #include "compile.h"
18: #include "gensound.h"
19:
20: /*** externed variables ***/
21:
22: #if (!(defined(PROCESSOR_ARM) || defined(PROCESSOR_SPARC) \
23: || defined(PROCESSOR_INTEL)))
24: uint32 reg68k_pc;
25: uint32 *reg68k_regs;
26: t_sr reg68k_sr;
27: #endif
28:
29: /*** forward references ***/
30:
31:
32: /*** reg68k_external_step - execute one instruction ***/
33:
34: unsigned int reg68k_external_step(void)
35: {
36: static t_ipc ipc;
37: static t_iib *piib;
38: jmp_buf jb;
39: static unsigned int clks;
40:
41: /* !!! entering global register usage area !!! */
42:
43: if (!setjmp(jb)) {
44: /* move PC and register block into global processor register variables */
45: reg68k_pc = regs.pc;
46: reg68k_regs = regs.regs;
47: reg68k_sr = regs.sr;
48:
49: if (regs.pending && ((reg68k_sr.sr_int >> 8) & 7) < regs.pending)
50: reg68k_internal_autovector(regs.pending);
51:
52: if (!(piib = cpu68k_iibtable[fetchword(reg68k_pc)]))
53: ui_err("Invalid instruction @ %08X\n", reg68k_pc);
54:
55: cpu68k_ipc(reg68k_pc,
56: mem68k_memptr[(reg68k_pc>>12) & 0xfff](reg68k_pc & 0xFFFFFF),
57: piib, &ipc);
58: cpu68k_functable[fetchword(reg68k_pc)*2+1](&ipc);
59: clks = piib->clocks;
60: /* restore global registers back to permanent storage */
61: regs.pc = reg68k_pc;
62: regs.sr = reg68k_sr;
63: longjmp(jb, 1);
64: }
65: cpu68k_clocks+= clks;
66: return clks; /* number of clocks done */
67: }
68:
69: /*** reg68k_external_execute - execute at least given number of clocks,
70: and return number of clocks executed too much ***/
71:
72: unsigned int reg68k_external_execute(unsigned int clocks)
73: {
74: unsigned int index, i;
75: t_ipclist *list;
76: t_ipc *ipc;
77: uint32 pc24;
78: jmp_buf jb;
79: static t_ipc step_ipc;
80: static t_iib *step_piib;
81: static int clks;
82:
83: clks = clocks;
84:
85: if (!setjmp(jb)) {
86: /* move PC and register block into global variables */
87: reg68k_pc = regs.pc;
88: reg68k_regs = regs.regs;
89: reg68k_sr = regs.sr;
90:
91: if (regs.pending && ((reg68k_sr.sr_int >> 8) & 7) < regs.pending)
92: reg68k_internal_autovector(regs.pending);
93:
94: do {
95: pc24 = reg68k_pc & 0xffffff;
96: if ((pc24 & 0xff0000) == 0xff0000) {
97: /* executing code from RAM, do not use compiled information */
98: do {
99: step_piib = cpu68k_iibtable[fetchword(reg68k_pc)];
100: if (!step_piib)
101: ui_err("Invalid instruction (iib assert) @ %08X\n", reg68k_pc);
102: cpu68k_ipc(reg68k_pc,
103: mem68k_memptr[(reg68k_pc>>12) &
104: 0xfff](reg68k_pc & 0xFFFFFF),
105: step_piib, &step_ipc);
106: cpu68k_functable[fetchword(reg68k_pc)*2+1](&step_ipc);
107: clks-= step_piib->clocks;
108: cpu68k_clocks+= step_piib->clocks;
109: } while (!step_piib->flags.endblk);
110: list = NULL; /* stop compiler warning ;( */
111: } else {
112: index = (pc24>>1) & (LEN_IPCLISTTABLE-1);
113: list = ipclist[index];
114: while(list && (list->pc != pc24)) {
115: list = list->next;
116: }
117: #ifdef PROCESSOR_ARM
118: if (!list) {
119: list = cpu68k_makeipclist(pc24);
120: list->next = ipclist[index];
121: ipclist[index] = list;
122: list->compiled = compile_make(list);
123: }
124: list->compiled((t_ipc *)(list+1));
125: #else
126: if (!list) {
127: /* LOG_USER(("Making IPC list @ %08x", pc24)); */
128: list = cpu68k_makeipclist(pc24);
129: list->next = ipclist[index];
130: ipclist[index] = list;
131: }
132: ipc = (t_ipc *)(list+1);
133: do {
134: ipc->function(ipc);
135: ipc++;
136: } while (*(int *)ipc);
137: #endif
138: clks-= list->clocks;
139: cpu68k_clocks+= list->clocks;
140: }
141: } while (clks > 0);
142: /* restore global registers back to permanent storage */
143: regs.pc = reg68k_pc;
144: regs.sr = reg68k_sr;
145: longjmp(jb, 1);
146: }
147: return -clks; /* i.e. number of clocks done too much */
148: }
149:
150: /*** reg68k_external_autovector - for external use ***/
151:
152: void reg68k_external_autovector(int avno)
153: {
154: jmp_buf jb;
155:
156: if (!setjmp(jb)) {
157: /* move PC and register block into global processor register variables */
158: reg68k_pc = regs.pc;
159: reg68k_regs = regs.regs;
160: reg68k_sr = regs.sr;
161:
162: reg68k_internal_autovector(avno);
163:
164: /* restore global registers back to permanent storage */
165: regs.pc = reg68k_pc;
166: regs.sr = reg68k_sr;
167: longjmp(jb, 1);
168: }
169: }
170:
171: /*** reg68k_internal_autovector - go to autovector - this call assumes global
172: registers are already setup ***/
173:
174: /* interrupts must not occur during cpu68k_frozen, as this flag indicates
175: that we are catching up events due to a dma transfer. Since the dma
176: transfer is triggered by a memory write at which stage the current value
177: of the PC is not written anywhere (due to being in the middle of a 68k
178: block and it's in a local register), we MUST NOT use regs.pc - this
179: routine uses reg68k_pc but this is loaded by reg68k_external_autovector,
180: which is called by event_nextevent() and therefore will be a *WRONG*
181: reg68k_pc! */
182:
183: void reg68k_internal_autovector(int avno)
184: {
185: int curlevel = (reg68k_sr.sr_int>>8) & 7;
186: uint32 tmpaddr;
187:
188: if ((curlevel < avno || avno == 7) && !cpu68k_frozen) {
189: if (regs.stop) {
190: LOG_DEBUG1(("stop finished"));
191: /* autovector whilst in a STOP instruction */
192: reg68k_pc+= 4;
193: regs.stop = 0;
194: }
195: if (!reg68k_sr.sr_struct.s) {
196: regs.regs[15]^= regs.sp; /* swap A7 and SP */
197: regs.sp^= regs.regs[15];
198: regs.regs[15]^= regs.sp;
199: reg68k_sr.sr_struct.s = 1;
200: }
201: regs.regs[15]-=4;
202: storelong(regs.regs[15], reg68k_pc);
203: regs.regs[15]-=2;
204: storeword(regs.regs[15], reg68k_sr.sr_int);
205: reg68k_sr.sr_struct.t = 0;
206: reg68k_sr.sr_int&= ~0x0700;
207: reg68k_sr.sr_int|= avno << 8;
208: tmpaddr = reg68k_pc;
209: reg68k_pc = fetchlong((V_AUTO+avno-1)*4);
210: /* LOG_USER(("AUTOVECTOR %d: %X -> %X", avno, tmpaddr, reg68k_pc)); */
211: regs.pending = 0;
212: } else {
213: /* LOG_USER(("%08X autovector %d pending", reg68k_pc, avno)); */
214: regs.pending = avno;
215: }
216: }
217:
218: /*** reg68k_internal_vector - go to vector - this call assumes global
219: registers are already setup ***/
220:
221: void reg68k_internal_vector(int vno, uint32 oldpc)
222: {
223: if (!reg68k_sr.sr_struct.s) {
224: reg68k_regs[15]^= regs.sp; /* swap A7 and SP */
225: regs.sp^= reg68k_regs[15];
226: reg68k_regs[15]^= regs.sp;
227: reg68k_sr.sr_struct.s = 1;
228: }
229: reg68k_regs[15]-=4;
230: storelong(reg68k_regs[15], oldpc);
231: reg68k_regs[15]-=2;
232: storeword(reg68k_regs[15], reg68k_sr.sr_int);
233: reg68k_pc = fetchlong(vno*4);
234: /* LOG_USER(("VECTOR %d: %X -> %X\n", vno, oldpc, reg68k_pc)); */
235: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.