451ab91e |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus - gregimm.c * |
3 | * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * |
4 | * Copyright (C) 2007 Richard Goedeken (Richard42) * |
5 | * Copyright (C) 2002 Hacktarux * |
6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * |
9 | * the Free Software Foundation; either version 2 of the License, or * |
10 | * (at your option) any later version. * |
11 | * * |
12 | * This program is distributed in the hope that it will be useful, * |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
15 | * GNU General Public License for more details. * |
16 | * * |
17 | * You should have received a copy of the GNU General Public License * |
18 | * along with this program; if not, write to the * |
19 | * Free Software Foundation, Inc., * |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
22 | |
23 | #include <stdio.h> |
24 | |
25 | #include "assemble.h" |
26 | #include "interpret.h" |
27 | |
28 | #include "r4300/recomph.h" |
29 | #include "r4300/recomp.h" |
30 | #include "r4300/r4300.h" |
31 | #include "r4300/ops.h" |
32 | #include "r4300/macros.h" |
33 | |
34 | #include "memory/memory.h" |
35 | |
36 | static void genbltz_test(void) |
37 | { |
38 | int rs_64bit = is64((unsigned int *)dst->f.i.rs); |
39 | |
40 | if (rs_64bit == 0) |
41 | { |
42 | int rs = allocate_register_32((unsigned int *)dst->f.i.rs); |
43 | |
44 | cmp_reg32_imm32(rs, 0); |
45 | setl_m8rel((unsigned char *) &branch_taken); |
46 | } |
47 | else if (rs_64bit == -1) |
48 | { |
49 | cmp_m32rel_imm32(((unsigned int *)dst->f.i.rs)+1, 0); |
50 | setl_m8rel((unsigned char *) &branch_taken); |
51 | } |
52 | else |
53 | { |
54 | int rs = allocate_register_64((unsigned long long *)dst->f.i.rs); |
55 | |
56 | cmp_reg64_imm8(rs, 0); |
57 | setl_m8rel((unsigned char *) &branch_taken); |
58 | } |
59 | } |
60 | |
61 | void genbltz(void) |
62 | { |
63 | #if defined(COUNT_INSTR) |
64 | inc_m32rel(&instr_count[47]); |
65 | #endif |
66 | #ifdef INTERPRET_BLTZ |
67 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZ, 1); |
68 | #else |
69 | if (((dst->addr & 0xFFF) == 0xFFC && |
70 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
71 | { |
72 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZ, 1); |
73 | return; |
74 | } |
75 | |
76 | genbltz_test(); |
77 | gendelayslot(); |
78 | gentest(); |
79 | #endif |
80 | } |
81 | |
82 | void genbltz_out(void) |
83 | { |
84 | #if defined(COUNT_INSTR) |
85 | inc_m32rel(&instr_count[47]); |
86 | #endif |
87 | #ifdef INTERPRET_BLTZ_OUT |
88 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZ_OUT, 1); |
89 | #else |
90 | if (((dst->addr & 0xFFF) == 0xFFC && |
91 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
92 | { |
93 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZ_OUT, 1); |
94 | return; |
95 | } |
96 | |
97 | genbltz_test(); |
98 | gendelayslot(); |
99 | gentest_out(); |
100 | #endif |
101 | } |
102 | |
103 | void genbltz_idle(void) |
104 | { |
105 | #ifdef INTERPRET_BLTZ_IDLE |
106 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZ_IDLE, 1); |
107 | #else |
108 | if (((dst->addr & 0xFFF) == 0xFFC && |
109 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
110 | { |
111 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZ_IDLE, 1); |
112 | return; |
113 | } |
114 | |
115 | genbltz_test(); |
116 | gentest_idle(); |
117 | genbltz(); |
118 | #endif |
119 | } |
120 | |
121 | static void genbgez_test(void) |
122 | { |
123 | int rs_64bit = is64((unsigned int *)dst->f.i.rs); |
124 | |
125 | if (rs_64bit == 0) |
126 | { |
127 | int rs = allocate_register_32((unsigned int *)dst->f.i.rs); |
128 | cmp_reg32_imm32(rs, 0); |
129 | setge_m8rel((unsigned char *) &branch_taken); |
130 | } |
131 | else if (rs_64bit == -1) |
132 | { |
133 | cmp_m32rel_imm32(((unsigned int *)dst->f.i.rs)+1, 0); |
134 | setge_m8rel((unsigned char *) &branch_taken); |
135 | } |
136 | else |
137 | { |
138 | int rs = allocate_register_64((unsigned long long *)dst->f.i.rs); |
139 | cmp_reg64_imm8(rs, 0); |
140 | setge_m8rel((unsigned char *) &branch_taken); |
141 | } |
142 | } |
143 | |
144 | void genbgez(void) |
145 | { |
146 | #if defined(COUNT_INSTR) |
147 | inc_m32rel(&instr_count[48]); |
148 | #endif |
149 | #ifdef INTERPRET_BGEZ |
150 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZ, 1); |
151 | #else |
152 | if (((dst->addr & 0xFFF) == 0xFFC && |
153 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
154 | { |
155 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZ, 1); |
156 | return; |
157 | } |
158 | |
159 | genbgez_test(); |
160 | gendelayslot(); |
161 | gentest(); |
162 | #endif |
163 | } |
164 | |
165 | void genbgez_out(void) |
166 | { |
167 | #if defined(COUNT_INSTR) |
168 | inc_m32rel(&instr_count[48]); |
169 | #endif |
170 | #ifdef INTERPRET_BGEZ_OUT |
171 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZ_OUT, 1); |
172 | #else |
173 | if (((dst->addr & 0xFFF) == 0xFFC && |
174 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
175 | { |
176 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZ_OUT, 1); |
177 | return; |
178 | } |
179 | |
180 | genbgez_test(); |
181 | gendelayslot(); |
182 | gentest_out(); |
183 | #endif |
184 | } |
185 | |
186 | void genbgez_idle(void) |
187 | { |
188 | #ifdef INTERPRET_BGEZ_IDLE |
189 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZ_IDLE, 1); |
190 | #else |
191 | if (((dst->addr & 0xFFF) == 0xFFC && |
192 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
193 | { |
194 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZ_IDLE, 1); |
195 | return; |
196 | } |
197 | |
198 | genbgez_test(); |
199 | gentest_idle(); |
200 | genbgez(); |
201 | #endif |
202 | } |
203 | |
204 | void genbltzl(void) |
205 | { |
206 | #if defined(COUNT_INSTR) |
207 | inc_m32rel(&instr_count[49]); |
208 | #endif |
209 | #ifdef INTERPRET_BLTZL |
210 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZL, 1); |
211 | #else |
212 | if (((dst->addr & 0xFFF) == 0xFFC && |
213 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
214 | { |
215 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZL, 1); |
216 | return; |
217 | } |
218 | |
219 | genbltz_test(); |
220 | free_all_registers(); |
221 | gentestl(); |
222 | #endif |
223 | } |
224 | |
225 | void genbltzl_out(void) |
226 | { |
227 | #if defined(COUNT_INSTR) |
228 | inc_m32rel(&instr_count[49]); |
229 | #endif |
230 | #ifdef INTERPRET_BLTZL_OUT |
231 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZL_OUT, 1); |
232 | #else |
233 | if (((dst->addr & 0xFFF) == 0xFFC && |
234 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
235 | { |
236 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZL_OUT, 1); |
237 | return; |
238 | } |
239 | |
240 | genbltz_test(); |
241 | free_all_registers(); |
242 | gentestl_out(); |
243 | #endif |
244 | } |
245 | |
246 | void genbltzl_idle(void) |
247 | { |
248 | #ifdef INTERPRET_BLTZL_IDLE |
249 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZL_IDLE, 1); |
250 | #else |
251 | if (((dst->addr & 0xFFF) == 0xFFC && |
252 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
253 | { |
254 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZL_IDLE, 1); |
255 | return; |
256 | } |
257 | |
258 | genbltz_test(); |
259 | gentest_idle(); |
260 | genbltzl(); |
261 | #endif |
262 | } |
263 | |
264 | void genbgezl(void) |
265 | { |
266 | #if defined(COUNT_INSTR) |
267 | inc_m32rel(&instr_count[50]); |
268 | #endif |
269 | #ifdef INTERPRET_BGEZL |
270 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZL, 1); |
271 | #else |
272 | if (((dst->addr & 0xFFF) == 0xFFC && |
273 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
274 | { |
275 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZL, 1); |
276 | return; |
277 | } |
278 | |
279 | genbgez_test(); |
280 | free_all_registers(); |
281 | gentestl(); |
282 | #endif |
283 | } |
284 | |
285 | void genbgezl_out(void) |
286 | { |
287 | #if defined(COUNT_INSTR) |
288 | inc_m32rel(&instr_count[50]); |
289 | #endif |
290 | #ifdef INTERPRET_BGEZL_OUT |
291 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZL_OUT, 1); |
292 | #else |
293 | if (((dst->addr & 0xFFF) == 0xFFC && |
294 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
295 | { |
296 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZL_OUT, 1); |
297 | return; |
298 | } |
299 | |
300 | genbgez_test(); |
301 | free_all_registers(); |
302 | gentestl_out(); |
303 | #endif |
304 | } |
305 | |
306 | void genbgezl_idle(void) |
307 | { |
308 | #ifdef INTERPRET_BGEZL_IDLE |
309 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZL_IDLE, 1); |
310 | #else |
311 | if (((dst->addr & 0xFFF) == 0xFFC && |
312 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
313 | { |
314 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZL_IDLE, 1); |
315 | return; |
316 | } |
317 | |
318 | genbgez_test(); |
319 | gentest_idle(); |
320 | genbgezl(); |
321 | #endif |
322 | } |
323 | |
324 | static void genbranchlink(void) |
325 | { |
326 | int r31_64bit = is64((unsigned int*)®[31]); |
327 | |
328 | if (r31_64bit == 0) |
329 | { |
330 | int r31 = allocate_register_32_w((unsigned int *)®[31]); |
331 | |
332 | mov_reg32_imm32(r31, dst->addr+8); |
333 | } |
334 | else if (r31_64bit == -1) |
335 | { |
336 | mov_m32rel_imm32((unsigned int *)®[31], dst->addr + 8); |
337 | if (dst->addr & 0x80000000) |
338 | mov_m32rel_imm32(((unsigned int *)®[31])+1, 0xFFFFFFFF); |
339 | else |
340 | mov_m32rel_imm32(((unsigned int *)®[31])+1, 0); |
341 | } |
342 | else |
343 | { |
344 | int r31 = allocate_register_64_w((unsigned long long *)®[31]); |
345 | |
346 | mov_reg32_imm32(r31, dst->addr+8); |
347 | movsxd_reg64_reg32(r31, r31); |
348 | } |
349 | } |
350 | |
351 | void genbltzal(void) |
352 | { |
353 | #if defined(COUNT_INSTR) |
354 | inc_m32rel(&instr_count[51]); |
355 | #endif |
356 | #ifdef INTERPRET_BLTZAL |
357 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZAL, 1); |
358 | #else |
359 | if (((dst->addr & 0xFFF) == 0xFFC && |
360 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
361 | { |
362 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZAL, 1); |
363 | return; |
364 | } |
365 | |
366 | genbltz_test(); |
367 | genbranchlink(); |
368 | gendelayslot(); |
369 | gentest(); |
370 | #endif |
371 | } |
372 | |
373 | void genbltzal_out(void) |
374 | { |
375 | #if defined(COUNT_INSTR) |
376 | inc_m32rel(&instr_count[51]); |
377 | #endif |
378 | #ifdef INTERPRET_BLTZAL_OUT |
379 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZAL_OUT, 1); |
380 | #else |
381 | if (((dst->addr & 0xFFF) == 0xFFC && |
382 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
383 | { |
384 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZAL_OUT, 1); |
385 | return; |
386 | } |
387 | |
388 | genbltz_test(); |
389 | genbranchlink(); |
390 | gendelayslot(); |
391 | gentest_out(); |
392 | #endif |
393 | } |
394 | |
395 | void genbltzal_idle(void) |
396 | { |
397 | #ifdef INTERPRET_BLTZAL_IDLE |
398 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZAL_IDLE, 1); |
399 | #else |
400 | if (((dst->addr & 0xFFF) == 0xFFC && |
401 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
402 | { |
403 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZAL_IDLE, 1); |
404 | return; |
405 | } |
406 | |
407 | genbltz_test(); |
408 | genbranchlink(); |
409 | gentest_idle(); |
410 | genbltzal(); |
411 | #endif |
412 | } |
413 | |
414 | void genbgezal(void) |
415 | { |
416 | #if defined(COUNT_INSTR) |
417 | inc_m32rel(&instr_count[52]); |
418 | #endif |
419 | #ifdef INTERPRET_BGEZAL |
420 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZAL, 1); |
421 | #else |
422 | if (((dst->addr & 0xFFF) == 0xFFC && |
423 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
424 | { |
425 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZAL, 1); |
426 | return; |
427 | } |
428 | |
429 | genbgez_test(); |
430 | genbranchlink(); |
431 | gendelayslot(); |
432 | gentest(); |
433 | #endif |
434 | } |
435 | |
436 | void genbgezal_out(void) |
437 | { |
438 | #if defined(COUNT_INSTR) |
439 | inc_m32rel(&instr_count[52]); |
440 | #endif |
441 | #ifdef INTERPRET_BGEZAL_OUT |
442 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZAL_OUT, 1); |
443 | #else |
444 | if (((dst->addr & 0xFFF) == 0xFFC && |
445 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
446 | { |
447 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZAL_OUT, 1); |
448 | return; |
449 | } |
450 | |
451 | genbgez_test(); |
452 | genbranchlink(); |
453 | gendelayslot(); |
454 | gentest_out(); |
455 | #endif |
456 | } |
457 | |
458 | void genbgezal_idle(void) |
459 | { |
460 | #ifdef INTERPRET_BGEZAL_IDLE |
461 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZAL_IDLE, 1); |
462 | #else |
463 | if (((dst->addr & 0xFFF) == 0xFFC && |
464 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
465 | { |
466 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZAL_IDLE, 1); |
467 | return; |
468 | } |
469 | |
470 | genbgez_test(); |
471 | genbranchlink(); |
472 | gentest_idle(); |
473 | genbgezal(); |
474 | #endif |
475 | } |
476 | |
477 | void genbltzall(void) |
478 | { |
479 | #if defined(COUNT_INSTR) |
480 | inc_m32rel(&instr_count[53]); |
481 | #endif |
482 | #ifdef INTERPRET_BLTZALL |
483 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZALL, 1); |
484 | #else |
485 | if (((dst->addr & 0xFFF) == 0xFFC && |
486 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
487 | { |
488 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZALL, 1); |
489 | return; |
490 | } |
491 | |
492 | genbltz_test(); |
493 | genbranchlink(); |
494 | free_all_registers(); |
495 | gentestl(); |
496 | #endif |
497 | } |
498 | |
499 | void genbltzall_out(void) |
500 | { |
501 | #if defined(COUNT_INSTR) |
502 | inc_m32rel(&instr_count[53]); |
503 | #endif |
504 | #ifdef INTERPRET_BLTZALL_OUT |
505 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZALL_OUT, 1); |
506 | #else |
507 | if (((dst->addr & 0xFFF) == 0xFFC && |
508 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
509 | { |
510 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZALL_OUT, 1); |
511 | return; |
512 | } |
513 | |
514 | genbltz_test(); |
515 | genbranchlink(); |
516 | free_all_registers(); |
517 | gentestl_out(); |
518 | #endif |
519 | } |
520 | |
521 | void genbltzall_idle(void) |
522 | { |
523 | #ifdef INTERPRET_BLTZALL_IDLE |
524 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZALL_IDLE, 1); |
525 | #else |
526 | if (((dst->addr & 0xFFF) == 0xFFC && |
527 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
528 | { |
529 | gencallinterp((unsigned long long)cached_interpreter_table.BLTZALL_IDLE, 1); |
530 | return; |
531 | } |
532 | |
533 | genbltz_test(); |
534 | genbranchlink(); |
535 | gentest_idle(); |
536 | genbltzall(); |
537 | #endif |
538 | } |
539 | |
540 | void genbgezall(void) |
541 | { |
542 | #if defined(COUNT_INSTR) |
543 | inc_m32rel(&instr_count[54]); |
544 | #endif |
545 | #ifdef INTERPRET_BGEZALL |
546 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZALL, 1); |
547 | #else |
548 | if (((dst->addr & 0xFFF) == 0xFFC && |
549 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
550 | { |
551 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZALL, 1); |
552 | return; |
553 | } |
554 | |
555 | genbgez_test(); |
556 | genbranchlink(); |
557 | free_all_registers(); |
558 | gentestl(); |
559 | #endif |
560 | } |
561 | |
562 | void genbgezall_out(void) |
563 | { |
564 | #if defined(COUNT_INSTR) |
565 | inc_m32rel(&instr_count[54]); |
566 | #endif |
567 | #ifdef INTERPRET_BGEZALL_OUT |
568 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZALL_OUT, 1); |
569 | #else |
570 | if (((dst->addr & 0xFFF) == 0xFFC && |
571 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
572 | { |
573 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZALL_OUT, 1); |
574 | return; |
575 | } |
576 | |
577 | genbgez_test(); |
578 | genbranchlink(); |
579 | free_all_registers(); |
580 | gentestl_out(); |
581 | #endif |
582 | } |
583 | |
584 | void genbgezall_idle(void) |
585 | { |
586 | #ifdef INTERPRET_BGEZALL_IDLE |
587 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZALL_IDLE, 1); |
588 | #else |
589 | if (((dst->addr & 0xFFF) == 0xFFC && |
590 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
591 | { |
592 | gencallinterp((unsigned long long)cached_interpreter_table.BGEZALL_IDLE, 1); |
593 | return; |
594 | } |
595 | |
596 | genbgez_test(); |
597 | genbranchlink(); |
598 | gentest_idle(); |
599 | genbgezall(); |
600 | #endif |
601 | } |
602 | |