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