451ab91e |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus - pure_interp.c * |
3 | * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * |
4 | * Copyright (C) 2002 Hacktarux * |
5 | * * |
6 | * This program is free software; you can redistribute it and/or modify * |
7 | * it under the terms of the GNU General Public License as published by * |
8 | * the Free Software Foundation; either version 2 of the License, or * |
9 | * (at your option) any later version. * |
10 | * * |
11 | * This program is distributed in the hope that it will be useful, * |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
14 | * GNU General Public License for more details. * |
15 | * * |
16 | * You should have received a copy of the GNU General Public License * |
17 | * along with this program; if not, write to the * |
18 | * Free Software Foundation, Inc., * |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
20 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
21 | |
22 | #include <stdlib.h> |
23 | #include <math.h> |
24 | |
25 | #include "api/m64p_types.h" |
26 | #include "api/callbacks.h" |
27 | #include "api/debugger.h" |
28 | #include "memory/memory.h" |
29 | #include "main/rom.h" |
30 | #include "osal/preproc.h" |
31 | |
32 | #include "r4300.h" |
33 | #include "ops.h" |
34 | #include "exception.h" |
35 | #include "macros.h" |
36 | #include "interupt.h" |
37 | |
38 | #ifdef DBG |
39 | #include "debugger/dbg_types.h" |
40 | #include "debugger/debugger.h" |
41 | #endif |
42 | |
43 | static precomp_instr interp_PC; |
44 | unsigned int op; |
45 | |
46 | static void prefetch(void); |
47 | |
48 | #define PCADDR interp_PC.addr |
49 | #define ADD_TO_PC(x) interp_PC.addr += x*4; |
50 | #define DECLARE_INSTRUCTION(name) static void name(void) |
51 | #define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \ |
52 | static void name(void) \ |
53 | { \ |
54 | const int take_jump = (condition); \ |
55 | const unsigned int jump_target = (destination); \ |
56 | long long int *link_register = (link); \ |
57 | if (cop1 && check_cop1_unusable()) return; \ |
58 | if (!likely || take_jump) \ |
59 | { \ |
60 | interp_PC.addr += 4; \ |
61 | delay_slot=1; \ |
62 | prefetch(); \ |
63 | PC->ops(); \ |
64 | update_count(); \ |
65 | delay_slot=0; \ |
66 | if (take_jump && !skip_jump) \ |
67 | { \ |
68 | if (link_register != ®[0]) \ |
69 | { \ |
70 | *link_register=interp_PC.addr; \ |
71 | sign_extended(*link_register); \ |
72 | } \ |
73 | interp_PC.addr = jump_target; \ |
74 | } \ |
75 | } \ |
76 | else \ |
77 | { \ |
78 | interp_PC.addr += 8; \ |
79 | update_count(); \ |
80 | } \ |
81 | last_addr = interp_PC.addr; \ |
82 | if (next_interupt <= Count) gen_interupt(); \ |
83 | } \ |
84 | static void name##_IDLE(void) \ |
85 | { \ |
86 | const int take_jump = (condition); \ |
87 | int skip; \ |
88 | if (cop1 && check_cop1_unusable()) return; \ |
89 | if (take_jump) \ |
90 | { \ |
91 | update_count(); \ |
92 | skip = next_interupt - Count; \ |
93 | if (skip > 3) Count += (skip & 0xFFFFFFFC); \ |
94 | else name(); \ |
95 | } \ |
96 | else name(); \ |
97 | } |
98 | #define CHECK_MEMORY() |
99 | |
451ab91e |
100 | // two functions are defined from the macros above but never used |
101 | // these prototype declarations will prevent a warning |
102 | #if defined(__GNUC__) |
7b232824 |
103 | static void JR_IDLE(void) __attribute__((used)); |
104 | static void JALR_IDLE(void) __attribute__((used)); |
451ab91e |
105 | #endif |
106 | |
7b232824 |
107 | #include "interpreter.def" |
108 | |
451ab91e |
109 | static cpu_instruction_table pure_interpreter_table = { |
110 | LB, |
111 | LBU, |
112 | LH, |
113 | LHU, |
114 | LW, |
115 | LWL, |
116 | LWR, |
117 | SB, |
118 | SH, |
119 | SW, |
120 | SWL, |
121 | SWR, |
122 | |
123 | LD, |
124 | LDL, |
125 | LDR, |
126 | LL, |
127 | LWU, |
128 | SC, |
129 | SD, |
130 | SDL, |
131 | SDR, |
132 | SYNC, |
133 | |
134 | ADDI, |
135 | ADDIU, |
136 | SLTI, |
137 | SLTIU, |
138 | ANDI, |
139 | ORI, |
140 | XORI, |
141 | LUI, |
142 | |
143 | DADDI, |
144 | DADDIU, |
145 | |
146 | ADD, |
147 | ADDU, |
148 | SUB, |
149 | SUBU, |
150 | SLT, |
151 | SLTU, |
152 | AND, |
153 | OR, |
154 | XOR, |
155 | NOR, |
156 | |
157 | DADD, |
158 | DADDU, |
159 | DSUB, |
160 | DSUBU, |
161 | |
162 | MULT, |
163 | MULTU, |
164 | DIV, |
165 | DIVU, |
166 | MFHI, |
167 | MTHI, |
168 | MFLO, |
169 | MTLO, |
170 | |
171 | DMULT, |
172 | DMULTU, |
173 | DDIV, |
174 | DDIVU, |
175 | |
176 | J, |
177 | J, // _OUT (unused) |
178 | J_IDLE, |
179 | JAL, |
180 | JAL, // _OUT (unused) |
181 | JAL_IDLE, |
182 | JR, |
183 | JALR, |
184 | BEQ, |
185 | BEQ, // _OUT (unused) |
186 | BEQ_IDLE, |
187 | BNE, |
188 | BNE, // _OUT (unused) |
189 | BNE_IDLE, |
190 | BLEZ, |
191 | BLEZ, // _OUT (unused) |
192 | BLEZ_IDLE, |
193 | BGTZ, |
194 | BGTZ, // _OUT (unused) |
195 | BGTZ_IDLE, |
196 | BLTZ, |
197 | BLTZ, // _OUT (unused) |
198 | BLTZ_IDLE, |
199 | BGEZ, |
200 | BGEZ, // _OUT (unused) |
201 | BGEZ_IDLE, |
202 | BLTZAL, |
203 | BLTZAL, // _OUT (unused) |
204 | BLTZAL_IDLE, |
205 | BGEZAL, |
206 | BGEZAL, // _OUT (unused) |
207 | BGEZAL_IDLE, |
208 | |
209 | BEQL, |
210 | BEQL, // _OUT (unused) |
211 | BEQL_IDLE, |
212 | BNEL, |
213 | BNEL, // _OUT (unused) |
214 | BNEL_IDLE, |
215 | BLEZL, |
216 | BLEZL, // _OUT (unused) |
217 | BLEZL_IDLE, |
218 | BGTZL, |
219 | BGTZL, // _OUT (unused) |
220 | BGTZL_IDLE, |
221 | BLTZL, |
222 | BLTZL, // _OUT (unused) |
223 | BLTZL_IDLE, |
224 | BGEZL, |
225 | BGEZL, // _OUT (unused) |
226 | BGEZL_IDLE, |
227 | BLTZALL, |
228 | BLTZALL, // _OUT (unused) |
229 | BLTZALL_IDLE, |
230 | BGEZALL, |
231 | BGEZALL, // _OUT (unused) |
232 | BGEZALL_IDLE, |
233 | BC1TL, |
234 | BC1TL, // _OUT (unused) |
235 | BC1TL_IDLE, |
236 | BC1FL, |
237 | BC1FL, // _OUT (unused) |
238 | BC1FL_IDLE, |
239 | |
240 | SLL, |
241 | SRL, |
242 | SRA, |
243 | SLLV, |
244 | SRLV, |
245 | SRAV, |
246 | |
247 | DSLL, |
248 | DSRL, |
249 | DSRA, |
250 | DSLLV, |
251 | DSRLV, |
252 | DSRAV, |
253 | DSLL32, |
254 | DSRL32, |
255 | DSRA32, |
256 | |
257 | MTC0, |
258 | MFC0, |
259 | |
260 | TLBR, |
261 | TLBWI, |
262 | TLBWR, |
263 | TLBP, |
264 | CACHE, |
265 | ERET, |
266 | |
267 | LWC1, |
268 | SWC1, |
269 | MTC1, |
270 | MFC1, |
271 | CTC1, |
272 | CFC1, |
273 | BC1T, |
274 | BC1T, // _OUT (unused) |
275 | BC1T_IDLE, |
276 | BC1F, |
277 | BC1F, // _OUT (unused) |
278 | BC1F_IDLE, |
279 | |
280 | DMFC1, |
281 | DMTC1, |
282 | LDC1, |
283 | SDC1, |
284 | |
285 | CVT_S_D, |
286 | CVT_S_W, |
287 | CVT_S_L, |
288 | CVT_D_S, |
289 | CVT_D_W, |
290 | CVT_D_L, |
291 | CVT_W_S, |
292 | CVT_W_D, |
293 | CVT_L_S, |
294 | CVT_L_D, |
295 | |
296 | ROUND_W_S, |
297 | ROUND_W_D, |
298 | ROUND_L_S, |
299 | ROUND_L_D, |
300 | |
301 | TRUNC_W_S, |
302 | TRUNC_W_D, |
303 | TRUNC_L_S, |
304 | TRUNC_L_D, |
305 | |
306 | CEIL_W_S, |
307 | CEIL_W_D, |
308 | CEIL_L_S, |
309 | CEIL_L_D, |
310 | |
311 | FLOOR_W_S, |
312 | FLOOR_W_D, |
313 | FLOOR_L_S, |
314 | FLOOR_L_D, |
315 | |
316 | ADD_S, |
317 | ADD_D, |
318 | |
319 | SUB_S, |
320 | SUB_D, |
321 | |
322 | MUL_S, |
323 | MUL_D, |
324 | |
325 | DIV_S, |
326 | DIV_D, |
327 | |
328 | ABS_S, |
329 | ABS_D, |
330 | |
331 | MOV_S, |
332 | MOV_D, |
333 | |
334 | NEG_S, |
335 | NEG_D, |
336 | |
337 | SQRT_S, |
338 | SQRT_D, |
339 | |
340 | C_F_S, |
341 | C_F_D, |
342 | C_UN_S, |
343 | C_UN_D, |
344 | C_EQ_S, |
345 | C_EQ_D, |
346 | C_UEQ_S, |
347 | C_UEQ_D, |
348 | C_OLT_S, |
349 | C_OLT_D, |
350 | C_ULT_S, |
351 | C_ULT_D, |
352 | C_OLE_S, |
353 | C_OLE_D, |
354 | C_ULE_S, |
355 | C_ULE_D, |
356 | C_SF_S, |
357 | C_SF_D, |
358 | C_NGLE_S, |
359 | C_NGLE_D, |
360 | C_SEQ_S, |
361 | C_SEQ_D, |
362 | C_NGL_S, |
363 | C_NGL_D, |
364 | C_LT_S, |
365 | C_LT_D, |
366 | C_NGE_S, |
367 | C_NGE_D, |
368 | C_LE_S, |
369 | C_LE_D, |
370 | C_NGT_S, |
371 | C_NGT_D, |
372 | |
373 | SYSCALL, |
374 | |
375 | TEQ, |
376 | |
377 | NOP, |
378 | RESERVED, |
379 | NI, |
380 | |
381 | NULL, // FIN_BLOCK |
382 | NULL, // NOTCOMPILED |
383 | NULL, // NOTCOMPILED2 |
384 | }; |
385 | |
386 | static void prefetch(void) |
387 | { |
388 | unsigned int *mem = fast_mem_access(interp_PC.addr); |
389 | if (mem != NULL) |
390 | { |
391 | prefetch_opcode(mem[0], mem[1]); |
392 | } |
393 | else |
394 | { |
395 | DebugMessage(M64MSG_ERROR, "prefetch() execute address :%x", PC->addr); |
396 | stop=1; |
397 | } |
398 | } |
399 | |
400 | void pure_interpreter(void) |
401 | { |
402 | stop=0; |
403 | PC = &interp_PC; |
404 | PC->addr = last_addr = 0xa4000040; |
405 | |
406 | /*#ifdef DBG |
407 | if (g_DebuggerActive) |
408 | update_debugger(PC->addr); |
409 | #endif*/ |
410 | |
411 | current_instruction_table = pure_interpreter_table; |
412 | |
413 | while (!stop) |
414 | { |
415 | prefetch(); |
416 | #ifdef COMPARE_CORE |
417 | CoreCompareCallback(); |
418 | #endif |
419 | #ifdef DBG |
420 | if (g_DebuggerActive) update_debugger(PC->addr); |
421 | #endif |
422 | PC->ops(); |
423 | } |
424 | } |