RSP LLE plugin. Compile and run (slowly, eat 50% CPU) on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-rsp-z64 / src / rsp_recomp.cpp
1 /*
2  * z64
3  *
4  * Copyright (C) 2007  ziggy
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 along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20 **/
21
22 #include "rsp_recomp.h"
23 #include <assert.h>
24
25 #define GENDEBUG
26
27 struct gen_t {
28     UINT32 crc;
29     int lbc;
30     rsp_bc_t * bc;
31 #ifdef GENDEBUG
32     char name[32];
33 #endif
34 };
35
36 struct opinfo_t {
37     int visit, labeled;
38     int label;
39
40     unsigned int nbgen;
41     unsigned int szgen;
42     gen_t * gentable;
43     gen_t * curgen;
44 };
45
46 struct branch_t {
47     int start, end;
48 };
49
50 static int curvisit;
51 static opinfo_t opinfo[0x1000/4];
52 static int jumps[0x1000];
53 static unsigned int nb_branches;
54 static branch_t branches[256];
55 static unsigned int nb_labels;
56 static int labels[256];
57
58 #define OPI(pc) opinfo[(pc)>>2]
59 /*inline*/ void SETLABEL(int pc) {
60     //printf("%x\n", pc);
61     //pc &= 0xfff;
62     assert(pc >= 0 && pc < 0x1000);
63     if (OPI(pc).labeled != curvisit) {
64         labels[nb_labels] = pc;
65         OPI(pc).label = nb_labels++;
66         assert(nb_labels < sizeof(labels)/sizeof(labels[0]));
67         OPI(pc).labeled = curvisit;
68     }
69 }
70
71 #define ABS(addr) (((addr) << 2) & 0xfff)
72 #define REL(offset) ((pc + ((offset) << 2)) & 0xfff)
73
74 static UINT32 prep_gen(int pc, UINT32 crc, int & len)
75 {
76     UINT32 op;
77     int br = 0;
78
79     branches[nb_branches].start = pc;
80
81     while ( !br )
82     {
83         if (OPI(pc).visit == curvisit) {
84             SETLABEL((pc)&0xfff);
85             SETLABEL((pc+4)&0xfff);
86             break;
87         }
88
89         OPI(pc).visit = curvisit;
90
91         op = ROPCODE(pc);
92         crc = ((crc<<1)|(crc>>31))^op^pc;
93         pc = (pc+4)&0xfff;
94         len++;
95
96         switch (op >> 26)
97         {
98         case 0x00:      /* SPECIAL */
99             {
100                 switch (op & 0x3f)
101                 {
102                 case 0x08:      /* JR */
103                     br = 1;
104                     break;
105                 case 0x09:      /* JALR */
106                     //br = 1;
107                     break;
108                 case 0x0d:      /* BREAK */
109                     br = 1;
110                     break;
111                 }
112                 break;
113             }
114
115         case 0x01:      /* REGIMM */
116             {
117                 switch (RTREG)
118                 {
119                 case 0x00:      /* BLTZ */
120                 case 0x01:      /* BGEZ */
121                     SETLABEL(REL(SIMM16));
122                     break;
123                 case 0x11:      /* BGEZAL */
124                     //br = 1;
125                     break;
126                 }
127                 break;
128             }
129
130         case 0x02:      /* J */
131             SETLABEL(ABS(UIMM26));
132             br = 1;
133             break;
134         case 0x04:      /* BEQ */
135         case 0x05:      /* BNE */
136         case 0x06:      /* BLEZ */
137         case 0x07:      /* BGTZ */
138             SETLABEL(REL(SIMM16));
139             break;
140         case 0x03:      /* JAL */
141             //SETLABEL(ABS(UIMM26));
142             //br = 1;
143             break;
144         }
145
146     }
147
148     branches[nb_branches++].end = pc;
149     assert(nb_branches < sizeof(branches)/sizeof(branches[0]));
150
151     return crc;
152 }
153
154 static void rsp_gen(int pc)
155 {
156     unsigned int i;
157
158     curvisit++;
159     if (!curvisit) {
160         // we looped, reset all visit counters
161         for (i=0; i<0x1000/4; i++) {
162             opinfo[i].visit = 0;
163             opinfo[i].labeled = 0;
164         }
165         curvisit++;
166     }
167
168     nb_branches = 0;
169     nb_labels = 0;
170
171     int len = 0;
172     UINT32 crc = prep_gen(pc, 0, len);
173
174     for (i=0; i<nb_labels; i++) {
175         if (OPI(labels[i]).visit != curvisit)
176             crc = prep_gen(labels[i], crc, len);
177     }
178
179     opinfo_t * opi = &OPI(pc);
180     if (opi->gentable) {
181         for (i=0; i<opi->nbgen; i++)
182             if (opi->gentable[i].crc == crc) {
183                 opi->curgen = opi->gentable + i;
184                 return;
185             }
186     }
187     if (opi->nbgen >= opi->szgen) {
188         if (opi->szgen)
189             opi->szgen *= 2;
190         else
191             opi->szgen = 4;
192         opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen));
193     }
194     gen_t * gen;
195     gen = opi->gentable + opi->nbgen++;
196     gen->crc = crc;
197     opi->curgen = gen;
198
199     // convert to bytecode
200     unsigned int lbc = 0;
201     static rsp_bc_t bc[0x1000*2+10];
202     for (i=0; i<nb_branches; i++) {
203         int pc;
204         int loopc;
205         int cont = 1;
206         rsp_opinfo_t delayed;
207         delayed.op = 0;
208         for (pc = branches[i].start; cont || delayed.op; pc = (pc+4)&0xfff) {
209             UINT32 op = ROPCODE(pc);
210
211             //       int realpc = pc;
212             //       char s[128];
213             //       rsp_dasm_one(s, realpc, op);
214             //       printf("%d %3x\t%s\n", lbc, realpc, s);
215
216             rsp_opinfo_t info;
217             rsp_get_opinfo(op, &info);
218             if ((info.flags & RSP_OPINFO_JUMP) && !cont)
219                 info.flags = 0;
220             else {
221                 int nop = 0;
222                 switch (info.op2) {
223                 case RSP_SLL:
224                 case RSP_SRL:
225                 case RSP_SRA:
226                     if (RDREG == RTREG && SHIFT == 0) 
227                         nop = 1;
228                     break;
229                 }
230                 if (cont)
231                     jumps[pc] = lbc;
232                 if (!nop) {
233                     bc[lbc].op = op;
234                     bc[lbc].op2 = info.op2;
235                     bc[lbc].flags = info.flags | (((pc&0xffc)<<5)-2) | (!cont? (1<<15):0);
236                     lbc++;
237                 }
238                 loopc = (pc+4)&0xfff;
239             }
240             if (delayed.op) {
241                 int addop = 0;
242                 const UINT32 op = delayed.op;
243                 switch (delayed.op2) {
244                 case RSP_BLTZ:
245                 case RSP_BGEZ:
246                 case RSP_BEQ:
247                 case RSP_BNE:
248                 case RSP_BLEZ:
249                 case RSP_BGTZ:
250                     addop = RSP_CONDJUMPLOCAL;
251                     bc[lbc].flags = (pc + (SIMM16<<2))&0xfff; // address to be resolved later
252                     break;
253                 case RSP_J:
254                     addop = RSP_JUMPLOCAL;
255                     bc[lbc].flags = (UIMM26<<2)&0xfff; // address to be resolved later
256                     break;
257                 case RSP_BGEZAL:
258                     addop = RSP_CONDJUMP;
259                     break;
260                 case RSP_JAL:
261                 case RSP_JR:
262                 case RSP_JALR:
263                     addop = RSP_JUMP;
264                     break;
265                 }
266                 bc[lbc].op = delayed.op;
267                 bc[lbc].op2 = addop;
268                 lbc++;
269             }
270             if (info.flags & RSP_OPINFO_JUMP) {
271                 delayed = info;
272             } else
273                 delayed.op = 0;
274             if (((pc + 4)&0xfff) == branches[i].end)
275                 cont = 0;
276         }
277         if (bc[lbc-1].op2 != RSP_JUMP &&
278             bc[lbc-1].op2 != RSP_JUMPLOCAL &&
279             bc[lbc-1].op2 != RSP_BREAK &&
280             bc[lbc-1].op2 != RSP_STOP) {
281
282                 bc[lbc].op = 0;
283                 bc[lbc].op2 = RSP_LOOP;
284                 bc[lbc].flags = loopc; // address to be resolved later
285                 lbc++;
286         }
287     }
288
289     // resolve local jumps
290     for (i=0; i<lbc; i++) {
291         //     printf("%d %x\n", i, bc[i].op2);
292         //     if (bc[i].op2 < RSP_CONTROL_OFFS) {
293         //       int realpc = (bc[i].flags>>3)&0xffc;
294         //       char s[128];
295         //       rsp_dasm_one(s, realpc, bc[i].op);
296         //       printf("%3x\t%s\n", realpc, s);
297         //     }
298         switch (bc[i].op2) {
299         case RSP_JUMPLOCAL:
300         case RSP_CONDJUMPLOCAL:
301         case RSP_LOOP:
302             {
303                 //         int pc;
304                 //         for (pc = 0; pc<lbc; pc++)
305                 //           if (bc[pc].op2 < RSP_CONTROL_OFFS &&
306                 //               !(bc[pc].flags & (1<<15)) &&
307                 //               ((bc[pc].flags>>5)<<2) == bc[i].flags)
308                 //             break;
309                 //         assert(pc < lbc);
310                 //         bc[i].flags = pc<<5;
311                 bc[i].flags = jumps[bc[i].flags]<<5;
312                 break;
313             }
314         }
315     }
316
317     gen->lbc = lbc;
318     gen->bc = (rsp_bc_t *) malloc(sizeof(rsp_bc_t)*lbc);
319     memcpy(gen->bc, bc, sizeof(rsp_bc_t)*lbc);
320 }
321
322 void rsp_invalidate(int begin, int len)
323 {
324     //printf("invalidate %x %x\n", begin, len);
325     begin = 0; len = 0x1000;
326     assert(begin+len<=0x1000);
327     while (len > 0) {
328         OPI(begin).curgen = 0;
329         begin += 4;
330         len -= 4;
331     }
332     rsp.inval_gen = 1;
333 }
334
335 inline void rsp_execute_one(RSP_REGS & rsp, const UINT32 op)
336 {
337     switch (op >> 26)
338     {
339     case 0x12:      /* COP2 */
340         {
341             handle_vector_ops(op);
342             break;
343         }
344
345     case 0x32:      /* LWC2 */              handle_lwc2(op); break;
346     case 0x3a:      /* SWC2 */              handle_swc2(op); break;
347
348     default:
349         {
350             unimplemented_opcode(op);
351             break;
352         }
353     }
354 }
355
356 static int cond;
357 static int run(RSP_REGS & rsp, gen_t * gen)
358 {
359     int pc = 0;
360
361     cond = 0;
362     for ( ; ; ) {
363         const rsp_bc_t & bc = gen->bc[pc];
364         const UINT32 op = bc.op;
365         const int op2 = bc.op2;
366
367         //     if (op2 < RSP_CONTROL_OFFS) {
368         //       int realpc = (bc.flags>>3)&0xffc;
369         //       char s[128];
370         //       rsp_dasm_one(s, realpc, op);
371         //       fprintf(stderr, "%3x\t%s\n", realpc, s);
372         //     }
373
374         pc++;
375         switch (op2) {
376         case RSP_LOOP:
377             pc = bc.flags>>5;
378             break;
379         case RSP_JUMPLOCAL:
380         case RSP_CONDJUMPLOCAL:
381             if (cond) {
382                 pc = bc.flags>>5;
383                 cond = 0;
384             }
385             break;
386         case RSP_JUMP:
387         case RSP_CONDJUMP:
388             if (cond) {
389                 return 0;
390             }
391             break;
392
393         #define _LINK(l) rsp.r[l] = ((bc.flags >>3)+8)&0xffc
394         #define _JUMP_PC(a) { cond=1; rsp.nextpc = ((a) & 0xfff); }
395         #define _JUMP_PC_L(a, l) { _LINK(l); _JUMP_PC(a); }
396         #define _JUMP_REL(a) _JUMP_PC(((bc.flags >>3)+4+(a<<2))&0xffc)
397         #define _JUMP_REL_L(a, l) _JUMP_PC_L(((bc.flags >>3)+4+(a<<2))&0xffc, l)
398
399         case RSP_SLL:             if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break;
400         case RSP_SRL:             if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break;
401         case RSP_SRA:             if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
402         case RSP_SLLV:            if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break;
403         case RSP_SRLV:            if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break;
404         case RSP_SRAV:            if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break;
405         case RSP_JR:              _JUMP_PC(RSVAL); break;
406         case RSP_JALR:            _JUMP_PC_L(RSVAL, RDREG); break;
407         case RSP_BREAK:
408             {
409                 *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE );
410                 if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
411                     *z64_rspinfo.MI_INTR_REG |= 1;
412                     z64_rspinfo.CheckInterrupts();
413                 }
414                 return 1;
415             }
416         case RSP_ADD:             if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
417         case RSP_ADDU:            if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
418         case RSP_SUB:             if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
419         case RSP_SUBU:            if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
420         case RSP_AND:             if (RDREG) RDVAL = RSVAL & RTVAL; break;
421         case RSP_OR:              if (RDREG) RDVAL = RSVAL | RTVAL; break;
422         case RSP_XOR:             if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
423         case RSP_NOR:             if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
424         case RSP_SLT:             if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
425         case RSP_SLTU:            if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
426         case RSP_BLTZ:            if ((INT32)(RSVAL) < 0) cond = 1; break;
427         case RSP_BGEZ:            if ((INT32)(RSVAL) >= 0) cond = 1; break;
428         case RSP_BGEZAL:  _LINK(31); if ((INT32)(RSVAL) >= 0) _JUMP_REL(SIMM16); break;
429         case RSP_J:                     cond = 1; break;
430         case RSP_JAL:           _JUMP_PC_L(UIMM26<<2, 31); break;
431         case RSP_BEQ:           if (RSVAL == RTVAL) cond = 1; break;
432         case RSP_BNE:           if (RSVAL != RTVAL) cond = 1; break;
433         case RSP_BLEZ:          if ((INT32)RSVAL <= 0) cond = 1; break;
434         case RSP_BGTZ:          if ((INT32)RSVAL > 0) cond = 1; break;
435         case RSP_ADDI:          if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
436         case RSP_ADDIU:         if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
437         case RSP_SLTI:          if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break;
438         case RSP_SLTIU:         if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break;
439         case RSP_ANDI:          if (RTREG) RTVAL = RSVAL & UIMM16; break;
440         case RSP_ORI:           if (RTREG) RTVAL = RSVAL | UIMM16; break;
441         case RSP_XORI:          if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
442         case RSP_LUI:           if (RTREG) RTVAL = UIMM16 << 16; break;
443
444         case RSP_COP0:
445             {
446                 switch ((op >> 21) & 0x1f)
447                 {
448                 case 0x00:      /* MFC0 */
449                     if (RTREG)
450                         RTVAL = get_cop0_reg(RDREG);
451                     break;
452                 case 0x04:      /* MTC0 */
453                     set_cop0_reg(RDREG, RTVAL);
454                     if (rsp.inval_gen) {
455                         rsp.inval_gen = 0;
456                         sp_pc = ((bc.flags >>3) + 4)&0xffc;
457                         return 2;
458                     }
459                     break;
460                 default:
461                     log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op);
462                     break;
463                 }
464                 break;
465             }
466
467         case RSP_MFC2:
468             {
469                 // 31       25      20      15      10     6         0
470                 // ---------------------------------------------------
471                 // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
472                 // ---------------------------------------------------
473                 //
474
475                 int el = (op >> 7) & 0xf;
476                 UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);
477                 UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);
478                 if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2));
479                 break;
480             }
481         case RSP_CFC2:
482             {
483                 // 31       25      20      15      10            0
484                 // ------------------------------------------------
485                 // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
486                 // ------------------------------------------------
487                 //
488
489                 // VP to sign extend or to not sign extend ?
490                 //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG];
491                 if (RTREG) RTVAL = rsp.flag[RDREG];
492                 break;
493             }
494         case RSP_MTC2:
495             {
496                 // 31       25      20      15      10     6         0
497                 // ---------------------------------------------------
498                 // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
499                 // ---------------------------------------------------
500                 //
501
502                 int el = (op >> 7) & 0xf;
503                 VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;
504                 VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;
505                 break;
506             }
507         case RSP_CTC2:
508             {
509                 // 31       25      20      15      10            0
510                 // ------------------------------------------------
511                 // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
512                 // ------------------------------------------------
513                 //
514
515                 rsp.flag[RDREG] = RTVAL & 0xffff;
516                 break;
517             }
518         case RSP_LB:            if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break;
519         case RSP_LH:            if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break;
520         case RSP_LW:            if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break;
521         case RSP_LBU:           if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break;
522         case RSP_LHU:           if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break;
523         case RSP_SB:            WRITE8(RSVAL + SIMM16, RTVAL); break;
524         case RSP_SH:            WRITE16(RSVAL + SIMM16, RTVAL); break;
525         case RSP_SW:            WRITE32(RSVAL + SIMM16, RTVAL); break;
526
527         default:
528             switch (op >> 26)
529             {
530             case 0x12:    /* COP2 */
531                 handle_vector_ops(op);
532                 break;
533             case 0x32:    /* LWC2 */
534                 handle_lwc2(op);
535                 break;
536             case 0x3a:    /* SWC2 */
537                 handle_swc2(op);
538                 break;
539             }
540         }
541     }
542 }
543
544 int rsp_gen_cache_hit;
545 int rsp_gen_cache_miss;
546 int rsp_jump(int pc)
547 {
548     pc &= 0xfff;
549     sp_pc = pc;
550     rsp.nextpc = ~0;
551     opinfo_t * opi = &OPI(pc);
552     gen_t * gen = opi->curgen;
553     rsp_gen_cache_hit++;
554     if (!gen) {
555         rsp_gen_cache_miss++;
556         rsp_gen(pc);
557     }
558     gen = opi->curgen;
559     //fprintf(stderr, "rsp_jump %x (%s)\n", pc, gen->name);
560
561     int res = run(rsp, gen);
562
563     //fprintf(stderr, "r31 %x from %x nextpc %x pc %x res %d (%s)\n", rsp.r[31], pc, rsp.nextpc, sp_pc, res, gen->name);
564     if (rsp.nextpc != ~0U)
565     {
566         sp_pc = (rsp.nextpc & 0xfff);
567         rsp.nextpc = ~0U;
568     }
569     else
570     {
571         //sp_pc = ((sp_pc+4)&0xfff);
572     }
573     return res;
574 }