svp compiler: more ops, idle detection
[picodrive.git] / Pico / carthw / svp / compiler.c
1 // 187 blocks, 12072 bytes
2 // 14 IRAM blocks
3
4 #include "../../PicoInt.h"
5 #include "compiler.h"
6
7 static unsigned int *block_table[0x5090/2];
8 static unsigned int *block_table_iram[15][0x800/2];
9 static unsigned int *tcache_ptr = NULL;
10
11 static int nblocks = 0;
12 static int iram_context = 0;
13
14 #ifndef ARM
15 #define DUMP_BLOCK 0x1d7c
16 unsigned int tcache[512*1024];
17 void regfile_load(void){}
18 void regfile_store(void){}
19 #endif
20
21 #define EMBED_INTERPRETER
22 #define ssp1601_reset ssp1601_reset_local
23 #define ssp1601_run ssp1601_run_local
24
25 #define GET_PC() rPC
26 #define GET_PPC_OFFS() (GET_PC()*2 - 2)
27 #define SET_PC(d) { rPC = d; }          /* must return to dispatcher after this */
28 //#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
29 //#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
30 //#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
31
32 #include "ssp16.c"
33 #include "gen_arm.c"
34
35 // -----------------------------------------------------
36
37 // ld d, s
38 static void op00(unsigned int op, unsigned int imm)
39 {
40         unsigned int tmpv;
41         PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
42         if (op == 0) return; // nop
43         if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
44                 // not sure. MAME claims that only hi word is transfered.
45                 read_P(); // update P
46                 rA32 = rP.v;
47         }
48         else
49         {
50                 tmpv = REG_READ(op & 0x0f);
51                 REG_WRITE((op & 0xf0) >> 4, tmpv);
52         }
53 }
54
55 // ld d, (ri)
56 static void op01(unsigned int op, unsigned int imm)
57 {
58         unsigned int tmpv;
59         tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
60 }
61
62 // ld (ri), s
63 static void op02(unsigned int op, unsigned int imm)
64 {
65         unsigned int tmpv;
66         tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
67 }
68
69 // ldi d, imm
70 static void op04(unsigned int op, unsigned int imm)
71 {
72         REG_WRITE((op & 0xf0) >> 4, imm);
73 }
74
75 // ld d, ((ri))
76 static void op05(unsigned int op, unsigned int imm)
77 {
78         unsigned int tmpv;
79         tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
80 }
81
82 // ldi (ri), imm
83 static void op06(unsigned int op, unsigned int imm)
84 {
85         ptr1_write(op, imm);
86 }
87
88 // ld adr, a
89 static void op07(unsigned int op, unsigned int imm)
90 {
91         ssp->RAM[op & 0x1ff] = rA;
92 }
93
94 // ld d, ri
95 static void op09(unsigned int op, unsigned int imm)
96 {
97         unsigned int tmpv;
98         tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
99 }
100
101 // ld ri, s
102 static void op0a(unsigned int op, unsigned int imm)
103 {
104         rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
105 }
106
107 // ldi ri, simm (also op0d op0e op0f)
108 static void op0c(unsigned int op, unsigned int imm)
109 {
110         rIJ[(op>>8)&7] = op;
111 }
112
113 // call cond, addr
114 static void op24(unsigned int op, unsigned int imm)
115 {
116         int cond = 0;
117         do {
118                 COND_CHECK
119                 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
120         }
121         while (0);
122 }
123
124 // ld d, (a)
125 static void op25(unsigned int op, unsigned int imm)
126 {
127         unsigned int tmpv;
128         tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
129 }
130
131 // bra cond, addr
132 static void op26(unsigned int op, unsigned int imm)
133 {
134         do
135         {
136                 int cond = 0;
137                 COND_CHECK
138                 if (cond) SET_PC(imm);
139         }
140         while (0);
141 }
142
143 // mod cond, op
144 static void op48(unsigned int op, unsigned int imm)
145 {
146         do
147         {
148                 int cond = 0;
149                 COND_CHECK
150                 if (cond) {
151                         switch (op & 7) {
152                                 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
153                                 case 3: rA32 <<= 1; break; // shl
154                                 case 6: rA32 = -(signed int)rA32; break; // neg
155                                 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
156                                 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
157                                                          op&7, GET_PPC_OFFS());
158                         }
159                         UPD_ACC_ZN // ?
160                 }
161         }
162         while(0);
163 }
164
165 // mpys?
166 static void op1b(unsigned int op, unsigned int imm)
167 {
168         read_P(); // update P
169         rA32 -= rP.v;                   // maybe only upper word?
170         UPD_ACC_ZN                      // there checking flags after this
171         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
172         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
173 }
174
175 // mpya (rj), (ri), b
176 static void op4b(unsigned int op, unsigned int imm)
177 {
178         read_P(); // update P
179         rA32 += rP.v; // confirmed to be 32bit
180         UPD_ACC_ZN // ?
181         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
182         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
183 }
184
185 // mld (rj), (ri), b
186 static void op5b(unsigned int op, unsigned int imm)
187 {
188         rA32 = 0;
189         rST &= 0x0fff; // ?
190         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
191         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
192 }
193
194 // OP a, s
195 static void op10(unsigned int op, unsigned int imm)
196 {
197         do
198         {
199                 unsigned int tmpv;
200                 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
201         }
202         while(0);
203 }
204
205 static void op30(unsigned int op, unsigned int imm)
206 {
207         do
208         {
209                 unsigned int tmpv;
210                 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
211         }
212         while(0);
213 }
214
215 static void op40(unsigned int op, unsigned int imm)
216 {
217         do
218         {
219                 unsigned int tmpv;
220                 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
221         }
222         while(0);
223 }
224
225 static void op50(unsigned int op, unsigned int imm)
226 {
227         do
228         {
229                 unsigned int tmpv;
230                 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
231         }
232         while(0);
233 }
234
235 static void op60(unsigned int op, unsigned int imm)
236 {
237         do
238         {
239                 unsigned int tmpv;
240                 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
241         }
242         while(0);
243 }
244
245 static void op70(unsigned int op, unsigned int imm)
246 {
247         do
248         {
249                 unsigned int tmpv;
250                 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
251         }
252         while(0);
253 }
254
255 // OP a, (ri)
256 static void op11(unsigned int op, unsigned int imm)
257 {
258         unsigned int tmpv;
259         tmpv = ptr1_read(op); OP_SUBA(tmpv);
260 }
261
262 static void op31(unsigned int op, unsigned int imm)
263 {
264         unsigned int tmpv;
265         tmpv = ptr1_read(op); OP_CMPA(tmpv);
266 }
267
268 static void op41(unsigned int op, unsigned int imm)
269 {
270         unsigned int tmpv;
271         tmpv = ptr1_read(op); OP_ADDA(tmpv);
272 }
273
274 static void op51(unsigned int op, unsigned int imm)
275 {
276         unsigned int tmpv;
277         tmpv = ptr1_read(op); OP_ANDA(tmpv);
278 }
279
280 static void op61(unsigned int op, unsigned int imm)
281 {
282         unsigned int tmpv;
283         tmpv = ptr1_read(op); OP_ORA (tmpv);
284 }
285
286 static void op71(unsigned int op, unsigned int imm)
287 {
288         unsigned int tmpv;
289         tmpv = ptr1_read(op); OP_EORA(tmpv);
290 }
291
292 // OP a, adr
293 static void op03(unsigned int op, unsigned int imm)
294 {
295         unsigned int tmpv;
296         tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
297 }
298
299 static void op13(unsigned int op, unsigned int imm)
300 {
301         unsigned int tmpv;
302         tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
303 }
304
305 static void op33(unsigned int op, unsigned int imm)
306 {
307         unsigned int tmpv;
308         tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
309 }
310
311 static void op43(unsigned int op, unsigned int imm)
312 {
313         unsigned int tmpv;
314         tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
315 }
316
317 static void op53(unsigned int op, unsigned int imm)
318 {
319         unsigned int tmpv;
320         tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
321 }
322
323 static void op63(unsigned int op, unsigned int imm)
324 {
325         unsigned int tmpv;
326         tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
327 }
328
329 static void op73(unsigned int op, unsigned int imm)
330 {
331         unsigned int tmpv;
332         tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
333 }
334
335 // OP a, imm
336 static void op14(unsigned int op, unsigned int imm)
337 {
338         OP_SUBA(imm);
339 }
340
341 static void op34(unsigned int op, unsigned int imm)
342 {
343         OP_CMPA(imm);
344 }
345
346 static void op44(unsigned int op, unsigned int imm)
347 {
348         OP_ADDA(imm);
349 }
350
351 static void op54(unsigned int op, unsigned int imm)
352 {
353         OP_ANDA(imm);
354 }
355
356 static void op64(unsigned int op, unsigned int imm)
357 {
358         OP_ORA (imm);
359 }
360
361 static void op74(unsigned int op, unsigned int imm)
362 {
363         OP_EORA(imm);
364 }
365
366 // OP a, ((ri))
367 static void op15(unsigned int op, unsigned int imm)
368 {
369         unsigned int tmpv;
370         tmpv = ptr2_read(op); OP_SUBA(tmpv);
371 }
372
373 static void op35(unsigned int op, unsigned int imm)
374 {
375         unsigned int tmpv;
376         tmpv = ptr2_read(op); OP_CMPA(tmpv);
377 }
378
379 static void op45(unsigned int op, unsigned int imm)
380 {
381         unsigned int tmpv;
382         tmpv = ptr2_read(op); OP_ADDA(tmpv);
383 }
384
385 static void op55(unsigned int op, unsigned int imm)
386 {
387         unsigned int tmpv;
388         tmpv = ptr2_read(op); OP_ANDA(tmpv);
389 }
390
391 static void op65(unsigned int op, unsigned int imm)
392 {
393         unsigned int tmpv;
394         tmpv = ptr2_read(op); OP_ORA (tmpv);
395 }
396
397 static void op75(unsigned int op, unsigned int imm)
398 {
399         unsigned int tmpv;
400         tmpv = ptr2_read(op); OP_EORA(tmpv);
401 }
402
403 // OP a, ri
404 static void op19(unsigned int op, unsigned int imm)
405 {
406         unsigned int tmpv;
407         tmpv = rIJ[IJind]; OP_SUBA(tmpv);
408 }
409
410 static void op39(unsigned int op, unsigned int imm)
411 {
412         unsigned int tmpv;
413         tmpv = rIJ[IJind]; OP_CMPA(tmpv);
414 }
415
416 static void op49(unsigned int op, unsigned int imm)
417 {
418         unsigned int tmpv;
419         tmpv = rIJ[IJind]; OP_ADDA(tmpv);
420 }
421
422 static void op59(unsigned int op, unsigned int imm)
423 {
424         unsigned int tmpv;
425         tmpv = rIJ[IJind]; OP_ANDA(tmpv);
426 }
427
428 static void op69(unsigned int op, unsigned int imm)
429 {
430         unsigned int tmpv;
431         tmpv = rIJ[IJind]; OP_ORA (tmpv);
432 }
433
434 static void op79(unsigned int op, unsigned int imm)
435 {
436         unsigned int tmpv;
437         tmpv = rIJ[IJind]; OP_EORA(tmpv);
438 }
439
440 // OP simm
441 static void op1c(unsigned int op, unsigned int imm)
442 {
443         OP_SUBA(op & 0xff);
444 }
445
446 static void op3c(unsigned int op, unsigned int imm)
447 {
448         OP_CMPA(op & 0xff);
449 }
450
451 static void op4c(unsigned int op, unsigned int imm)
452 {
453         OP_ADDA(op & 0xff);
454 }
455
456 static void op5c(unsigned int op, unsigned int imm)
457 {
458         OP_ANDA(op & 0xff);
459 }
460
461 static void op6c(unsigned int op, unsigned int imm)
462 {
463         OP_ORA (op & 0xff);
464 }
465
466 static void op7c(unsigned int op, unsigned int imm)
467 {
468         OP_EORA(op & 0xff);
469 }
470
471 typedef void (in_func)(unsigned int op, unsigned int imm);
472
473 static in_func *in_funcs[0x80] =
474 {
475         op00, op01, op02, op03, op04, op05, op06, op07,
476         NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
477         op10, op11, NULL, op13, op14, op15, NULL, NULL,
478         NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
479         NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
480         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
481         op30, op31, NULL, op33, op34, op35, NULL, NULL,
482         NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
483         op40, op41, NULL, op43, op44, op45, NULL, NULL,
484         op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
485         op50, op51, NULL, op53, op54, op55, NULL, NULL,
486         NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
487         op60, op61, NULL, op63, op64, op65, NULL, NULL,
488         NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
489         op70, op71, NULL, op73, op74, op75, NULL, NULL,
490         NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
491 };
492
493 // -----------------------------------------------------
494
495 static unsigned char iram_context_map[] =
496 {
497          0, 0, 0, 0, 1, 0, 0, 0, // 04
498          0, 0, 0, 0, 0, 0, 2, 0, // 0e
499          0, 0, 0, 0, 0, 3, 0, 4, // 15 17
500          5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
501          8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
502          0, 0, 0, 0, 0, 0, 0, 0,
503          0, 0,11, 0, 0,12, 0, 0, // 32 35
504         13,14, 0, 0, 0, 0, 0, 0  // 38 39
505 };
506
507 static int get_iram_context(void)
508 {
509         unsigned char *ir = (unsigned char *)svp->iram_rom;
510         int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
511         val1 = iram_context_map[(val>>1)&0x3f];
512
513         if (val1 == 0) {
514                 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
515                 //debug_dump2file(name, svp->iram_rom, 0x800);
516                 exit(1);
517         }
518 //      elprintf(EL_ANOMALY, "iram_context: %02i", val1);
519         return val1;
520 }
521
522 // -----------------------------------------------------
523 /*
524 enum {
525         SSP_GR0, SSP_X,     SSP_Y,   SSP_A,
526         SSP_ST,  SSP_STACK, SSP_PC,  SSP_P,
527         SSP_PM0, SSP_PM1,   SSP_PM2, SSP_XST,
528         SSP_PM4, SSP_gr13,  SSP_PMC, SSP_AL
529 };
530 */
531 /* regs with known values */
532 static struct
533 {
534         ssp_reg_t gr[8];
535         unsigned char r[8];
536 } const_regs;
537
538 #define CRREG_X     (1 << SSP_X)
539 #define CRREG_Y     (1 << SSP_Y)
540 #define CRREG_A     (1 << SSP_A)        /* AH only */
541 #define CRREG_ST    (1 << SSP_ST)
542 #define CRREG_STACK (1 << SSP_STACK)
543 #define CRREG_PC    (1 << SSP_PC)
544 #define CRREG_P     (1 << SSP_P)
545 #define CRREG_PR0   (1 << 8)
546 #define CRREG_PR4   (1 << 12)
547 #define CRREG_AL    (1 << 16)
548
549 static u32 const_regb = 0;              /* bitfield of known register values */
550 static u32 dirty_regb = 0;              /* known vals, which need to be flushed (only P, r0-r7) */
551
552 /* known values of host regs.
553  * -1            - unknown
554  * 000000-00ffff - 16bit value
555  * 100000-10ffff - base reg (r7) + 16bit val
556  * 0r0000        - means reg (low) eq gr[r].h
557  */
558 static int hostreg_r[4];
559
560 static void hostreg_clear(void)
561 {
562         int i;
563         for (i = 0; i < 4; i++)
564                 hostreg_r[i] = -1;
565 }
566
567 /*static*/ void hostreg_ah_changed(void)
568 {
569         int i;
570         for (i = 0; i < 4; i++)
571                 if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1;
572 }
573
574
575 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
576
577 /* load 16bit val into host reg r0-r3. Nothing is trashed */
578 static void tr_mov16(int r, int val)
579 {
580         if (hostreg_r[r] != val) {
581                 emit_mov_const(r, val);
582                 hostreg_r[r] = val;
583         }
584 }
585
586 /* update P, if needed. Trashes r1 */
587 static void tr_flush_dirty_P(void)
588 {
589         // TODO: const regs
590         if (!(dirty_regb & CRREG_P)) return;
591         EOP_MOV_REG_ASR(10, 4, 16);             // mov  r10, r4, asr #16
592         EOP_MOV_REG_LSL( 1, 4, 16);             // mov  r1,  r4, lsl #16
593         EOP_MOV_REG_ASR( 1, 1, 15);             // mov  r1,  r1, asr #15
594         EOP_MUL(10, 1, 10);                     // mul  r10, r1, r10
595         dirty_regb &= ~CRREG_P;
596 }
597
598 /* write dirty r0-r7 to host regs. Nothing is trashed */
599 static void tr_flush_dirty_pr(void)
600 {
601         int i, ror = 0, reg;
602         dirty_regb >>= 8;
603         /* r0-r7 */
604         for (i = 0; dirty_regb && i < 8; i++, dirty_regb >>= 1)
605         {
606                 if (!(dirty_regb&1)) continue;
607                 switch (i&3) {
608                         case 0: ror =    0; break;
609                         case 1: ror = 24/2; break;
610                         case 2: ror = 16/2; break;
611                 }
612                 reg = (i < 4) ? 8 : 9;
613                 EOP_BIC_IMM(reg,reg,ror,0xff);
614                 if (const_regs.r[i] != 0)
615                         EOP_ORR_IMM(reg,reg,ror,const_regs.r[i]);
616         }
617 }
618
619 /* read bank word to r0 (MSW may contain trash). Thrashes r1. */
620 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
621 {
622         if (addr&1) {
623                 int breg = 7;
624                 if (addr > 0x7f) {
625                         if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
626                                 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
627                                 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
628                         }
629                         breg = 1;
630                 }
631                 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1);    // ldrh r0, [r1, (op&0x7f)<<1]
632         } else {
633                 EOP_LDR_IMM(0,7,(addr&0x1ff)<<1);       // ldr  r0, [r1, (op&0x1ff)<<1]
634         }
635         hostreg_r[0] = -1;
636 }
637
638 /* write r0 to bank. Trashes r1. */
639 static void tr_bank_write(int addr)
640 {
641         int breg = 7;
642         if (addr > 0x7f) {
643                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
644                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
645                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
646                 }
647                 breg = 1;
648         }
649         EOP_STRH_IMM(0,breg,(addr&0x7f)<<1);            // strh r0, [r1, (op&0x7f)<<1]
650 }
651
652 /* handle RAM bank pointer modifiers. Nothing is trashed. */
653 static void tr_ptrr_mod(int r, int mod, int need_modulo)
654 {
655         int modulo = -1, modulo_shift = -1;     /* unknown */
656
657         if (mod == 0) return;
658
659         if (!need_modulo || mod == 1) // +!
660                 modulo_shift = 8;
661         else if (need_modulo && (const_regb & CRREG_ST)) {
662                 modulo_shift = const_regs.gr[SSP_ST].h & 7;
663                 if (modulo_shift == 0) modulo_shift = 8;
664         }
665
666         if (mod > 1 && modulo_shift == -1) { printf("need var modulo\n"); exit(1); }
667         modulo = (1 << modulo_shift) - 1;
668
669         if (const_regb & (1 << (r + 8))) {
670                 if (mod == 2)
671                      const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] - 1) & modulo);
672                 else const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] + 1) & modulo);
673         } else {
674                 int reg = (r < 4) ? 8 : 9;
675                 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
676                 EOP_MOV_REG_ROR(reg,reg,ror);
677                 // {add|sub} reg, reg, #1<<shift
678                 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
679                 EOP_MOV_REG_ROR(reg,reg,32-ror);
680         }
681 }
682
683 //      SSP_GR0, SSP_X,     SSP_Y,   SSP_A,
684 //      SSP_ST,  SSP_STACK, SSP_PC,  SSP_P,
685 //@ r4:  XXYY
686 //@ r5:  A
687 //@ r6:  STACK and emu flags
688 //@ r7:  SSP context
689 //@ r10: P
690
691 static void tr_GR0_to_r0(void)
692 {
693         tr_mov16(0, 0xffff);
694 }
695
696 static void tr_X_to_r0(void)
697 {
698         if (hostreg_r[0] != (SSP_X<<16)) {
699                 EOP_MOV_REG_LSR(0, 4, 16);      // mov  r0, r4, lsr #16
700                 hostreg_r[0] = SSP_X<<16;
701         }
702 }
703
704 static void tr_Y_to_r0(void)
705 {
706         // TODO..
707         if (hostreg_r[0] != (SSP_Y<<16)) {
708                 EOP_MOV_REG_SIMPLE(0, 4);       // mov  r0, r4
709                 hostreg_r[0] = SSP_Y<<16;
710         }
711 }
712
713 static void tr_A_to_r0(void)
714 {
715         if (hostreg_r[0] != (SSP_A<<16)) {
716                 EOP_MOV_REG_LSR(0, 5, 16);      // mov  r0, r5, lsr #16  @ AH
717                 hostreg_r[0] = SSP_A<<16;
718         }
719 }
720
721 static void tr_ST_to_r0(void)
722 {
723         // VR doesn't need much accuracy here..
724         EOP_MOV_REG_LSR(0, 6, 4);               // mov  r0, r6, lsr #4
725         EOP_AND_IMM(0, 0, 0, 0x67);             // and  r0, r0, #0x67
726         hostreg_r[0] = -1;
727 }
728
729 static void tr_STACK_to_r0(void)
730 {
731         // 448
732         EOP_SUB_IMM(6, 6,  8/2, 0x20);          // sub  r6, r6, #1<<29
733         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
734         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
735         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
736         EOP_LDRH_SIMPLE(0, 1);                  // ldrh r0, [r1]
737         hostreg_r[0] = hostreg_r[1] = -1;
738 }
739
740 static void tr_PC_to_r0(void)
741 {
742         tr_mov16(0, const_regs.gr[SSP_PC].h);
743 }
744
745 static void tr_P_to_r0(void)
746 {
747         tr_flush_dirty_P();
748         EOP_MOV_REG_LSR(0, 10, 16);             // mov  r0, r10, lsr #16
749         hostreg_r[0] = -1;
750 }
751
752 typedef void (tr_read_func)(void);
753
754 static tr_read_func *tr_read_funcs[8] =
755 {
756         tr_GR0_to_r0,
757         tr_X_to_r0,
758         tr_Y_to_r0,
759         tr_A_to_r0,
760         tr_ST_to_r0,
761         tr_STACK_to_r0,
762         tr_PC_to_r0,
763         tr_P_to_r0
764 };
765
766
767 // write r0 to general reg handlers. Trashes r1
768 static void tr_unhandled(void)
769 {
770         printf("unhandled @ %04x\n", const_regs.gr[SSP_PC].h<<1);
771         exit(1);
772 }
773
774 static void tr_r0_to_GR0(void)
775 {
776         // do nothing
777 }
778
779 static void tr_r0_to_X(void)
780 {
781         EOP_MOV_REG_LSL(4, 4, 16);              // mov  r4, r4, lsl #16
782         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
783         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
784         dirty_regb |= CRREG_P;  // touching X or Y makes P dirty.
785 }
786
787 static void tr_r0_to_Y(void)
788 {
789         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
790         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
791         EOP_MOV_REG_ROR(4, 4, 16);              // mov  r4, r4, ror #16
792         dirty_regb |= CRREG_P;
793 }
794
795 static void tr_r0_to_A(void)
796 {
797         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
798         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16  @ AL
799         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
800 }
801
802 static void tr_r0_to_ST(void)
803 {
804         // VR doesn't need much accuracy here..
805         EOP_AND_IMM(1, 0,   0, 0x67);           // and   r1, r0, #0x67
806         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
807         EOP_ORR_REG_LSL(6, 6, 1, 4);            // orr   r6, r6, r1, lsl #4
808         hostreg_r[1] = -1;
809 }
810
811 static void tr_r0_to_STACK(void)
812 {
813         // 448
814         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
815         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
816         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
817         EOP_STRH_SIMPLE(0, 1);                  // strh r0, [r1]
818         EOP_ADD_IMM(6, 6,  8/2, 0x20);          // add  r6, r6, #1<<29
819         hostreg_r[1] = -1;
820 }
821
822 static void tr_r0_to_PC(void)
823 {
824         EOP_MOV_REG_LSL(1, 0, 16);              // mov  r1, r0, lsl #16
825         EOP_STR_IMM(1,7,0x400+6*4);             // str  r1, [r7, #(0x400+6*8)]
826         hostreg_r[1] = -1;
827 }
828
829 typedef void (tr_write_func)(void);
830
831 static tr_write_func *tr_write_funcs[8] =
832 {
833         tr_r0_to_GR0,
834         tr_r0_to_X,
835         tr_r0_to_Y,
836         tr_r0_to_A,
837         tr_r0_to_ST,
838         tr_r0_to_STACK,
839         tr_r0_to_PC,
840         tr_unhandled
841 };
842
843
844 static int translate_op(unsigned int op, int *pc, int imm)
845 {
846         u32 tmpv, tmpv2;
847         int ret = 0;
848         const_regs.gr[SSP_PC].h = *pc;
849
850         switch (op >> 9)
851         {
852                 // ld d, s
853                 case 0x00:
854                         if (op == 0) { ret++; break; } // nop
855                         tmpv  = op & 0xf; // src
856                         tmpv2 = (op >> 4) & 0xf; // dst
857                         if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
858                         if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
859                                 tr_flush_dirty_P();
860                                 EOP_MOV_REG_SIMPLE(5, 10);
861                                 const_regb &= ~(CRREG_A|CRREG_AL);
862                                 ret++; break;
863                         }
864                         tr_read_funcs[tmpv]();
865                         tr_write_funcs[tmpv2]();
866                         if (const_regb & (1 << tmpv)) {
867                                 const_regs.gr[tmpv2].h = const_regs.gr[tmpv].h;
868                                 const_regb |=   1 << tmpv2;
869                         } else
870                                 const_regb &= ~(1 << tmpv2);
871                         ret++; break;
872
873                 // ld a, adr
874                 case 0x03:
875                         tr_bank_read(op&0x1ff);
876                         tr_r0_to_A();
877                         const_regb &= ~CRREG_A;
878                         hostreg_r[0] = SSP_A<<16;
879                         ret++; break;
880
881                 // ldi d, imm
882                 case 0x04:
883                         tmpv = (op & 0xf0) >> 4;
884                         if (tmpv < 8)
885                         {
886                                 tr_mov16(0, imm);
887                                 tr_write_funcs[tmpv]();
888                                 const_regs.gr[tmpv].h = imm;
889                                 const_regb |= 1 << tmpv;
890                                 ret++; break;
891                         }
892                         else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
893                         {
894                                 // programming PMC..
895                                 (*pc)++;
896                                 tmpv = imm | (PROGRAM((*pc)++) << 16);
897                                 emit_mov_const(0, tmpv);
898                                 EOP_LDR_IMM(1,7,0x484);         // ldr r0, [r7, #0x484] // emu_status
899                                 EOP_STR_IMM(0,7,0x400+14*4);    // PMC
900                                 // reads on fe06, fe08; next op is ld -,
901                                 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
902                                 {
903                                         int flag = (tmpv == 0x187f03) ? (SSP_WAIT_30FE06) : (SSP_WAIT_30FE08);
904                                         EOP_LDR_IMM(0,7,0x490); // dram_ptr
905                                         EOP_ADD_IMM(0,0,24/2,0xfe);     // add  r0, r0, #0xfe00
906                                         EOP_LDRH_IMM(0,0,8);            // ldrh r0, [r0, #8]
907                                         EOP_TST_REG_SIMPLE(0,0);
908                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1);       // add r11, r11, #1024
909                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
910                                 }
911                                 EOP_ORR_IMM(1,1,0,SSP_PMC_SET);         // orr r1, r1, #SSP_PMC_SET
912                                 EOP_STR_IMM(1,7,0x484);                 // str r1, [r7, #0x484] // emu_status
913                                 hostreg_r[0] = hostreg_r[1] = -1;
914                                 ret += 2; break;
915                         }
916                         else
917                                 return -1;      /* TODO.. */
918
919
920                 // ldi (ri), imm
921                 case 0x06:
922                         // int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
923                         tr_mov16(0, imm);
924                         if ((op&3) == 3)
925                         {
926                                 tmpv = (op>>2) & 3; // direct addressing
927                                 if (op & 0x100) {
928                                         if (hostreg_r[1] != 0x100200) {
929                                                 EOP_ADD_IMM(1,7,30/2,0x200>>2); // add  r1, r7, 0x200
930                                                 hostreg_r[1] = 0x100200;
931                                         }
932                                         EOP_STRH_IMM(0,1,tmpv<<1);      // str  r0, [r1, {0,2,4,6}]
933                                 } else {
934                                         EOP_STRH_IMM(0,7,tmpv<<1);      // str  r0, [r7, {0,2,4,6}]
935                                 }
936                         }
937                         else
938                         {
939                                 int r = (op&3) | ((op>>6)&4);
940                                 if (const_regb & (1 << (r + 8))) {
941                                         tr_bank_write(const_regs.r[r] | ((r < 4) ? 0 : 0x100));
942                                 } else {
943                                         int reg = (r < 4) ? 8 : 9;
944                                         int ror = ((4 - (r&3))*8) & 0x1f;
945                                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
946                                         if (r >= 4)
947                                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
948                                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
949                                         else     EOP_ADD_REG_LSL(1,7,1,1);
950                                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
951                                         hostreg_r[1] = -1;
952                                 }
953                                 tr_ptrr_mod(r, (op>>2) & 3, 0);
954                         }
955                         ret++; break;
956
957                 // ld adr, a
958                 case 0x07:
959                         if (hostreg_r[0] != (SSP_A<<16)) {
960                                 EOP_MOV_REG_LSR(0, 5, 16);              // mov  r0, r5, lsr #16  @ A
961                                 hostreg_r[0] = SSP_A<<16;
962                         }
963                         tr_bank_write(op&0x1ff);
964                         ret++; break;
965
966                 // ld d, ri
967                 case 0x09: {
968                         int r, reg;
969                         r = (op&3) | ((op>>6)&4); // src
970                         tmpv2 = (op >> 4) & 0xf; // dst
971                         if (tmpv2 >= 8) tr_unhandled();
972
973                         if (const_regb & (1 << (r+8))) {
974                                 tr_mov16(0, const_regs.r[r]);
975                                 const_regs.gr[tmpv2].h = const_regs.r[r];
976                                 const_regb |= 1 << tmpv2;
977                         } else {
978                                 reg = (r < 4) ? 8 : 9;
979                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
980                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
981                                 hostreg_r[0] = -1;
982                                 const_regb &= ~(1 << tmpv2);
983                         }
984                         tr_write_funcs[tmpv2]();
985                         ret++; break;
986                 }
987
988                 // ldi ri, simm
989                 case 0x0c ... 0x0f:
990                         tmpv = (op>>8)&7;
991                         const_regs.r[tmpv] = op;
992                         const_regb |= 1 << (tmpv + 8);
993                         dirty_regb |= 1 << (tmpv + 8);
994                         ret++; break;
995         }
996
997         return ret;
998 }
999
1000 static void *translate_block(int pc)
1001 {
1002         unsigned int op, op1, imm, ccount = 0;
1003         unsigned int *block_start;
1004         int ret, ret_prev = -1;
1005
1006         // create .pool
1007         //*tcache_ptr++ = (u32) in_funcs;                       // -1 func pool
1008
1009         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1010         block_start = tcache_ptr;
1011         const_regb = 0;
1012         dirty_regb = CRREG_P;
1013         hostreg_clear();
1014
1015         emit_block_prologue();
1016
1017         for (; ccount < 100;)
1018         {
1019                 //printf("  insn #%i\n", icount);
1020                 op = PROGRAM(pc++);
1021                 op1 = op >> 9;
1022                 imm = (u32)-1;
1023
1024                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1025                         imm = PROGRAM(pc++); // immediate
1026
1027                 ret = translate_op(op, &pc, imm);
1028                 if (ret <= 0)
1029                 {
1030                         tr_flush_dirty_pr();
1031
1032                         emit_mov_const(0, op);
1033
1034                         // need immediate?
1035                         if (imm != (u32)-1)
1036                                 emit_mov_const(1, imm);
1037
1038                         // dump PC
1039                         emit_pc_dump(pc);
1040
1041                         if (ret_prev > 0) emit_call(regfile_store);
1042                         emit_call(in_funcs[op1]);
1043                         emit_call(regfile_load);
1044
1045                         if (in_funcs[op1] == NULL) {
1046                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
1047                                 exit(1);
1048                         }
1049                         ccount++;
1050                         hostreg_clear();
1051                         dirty_regb |= CRREG_P;
1052                 }
1053                 else
1054                         ccount += ret;
1055
1056                 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1057                         ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1058                                 (op & 0xf0) == 0x60)) { // ld PC
1059                         break;
1060                 }
1061                 ret_prev = ret;
1062         }
1063
1064         tr_flush_dirty_pr();
1065         emit_block_epilogue(ccount + 1);
1066         *tcache_ptr++ = 0xffffffff; // end of block
1067         //printf("  %i inst\n", icount);
1068
1069         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1070                 printf("tcache overflow!\n");
1071                 fflush(stdout);
1072                 exit(1);
1073         }
1074
1075         // stats
1076         nblocks++;
1077         //if (pc >= 0x400)
1078         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1079         //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1080
1081 #ifdef DUMP_BLOCK
1082         {
1083                 FILE *f = fopen("tcache.bin", "wb");
1084                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1085                 fclose(f);
1086         }
1087         exit(0);
1088 #endif
1089
1090         handle_caches();
1091
1092         return block_start;
1093 }
1094
1095
1096
1097 // -----------------------------------------------------
1098
1099 int ssp1601_dyn_startup(void)
1100 {
1101         memset(tcache, 0, TCACHE_SIZE);
1102         memset(block_table, 0, sizeof(block_table));
1103         memset(block_table_iram, 0, sizeof(block_table_iram));
1104         tcache_ptr = tcache;
1105         *tcache_ptr++ = 0xffffffff;
1106
1107         return 0;
1108 }
1109
1110
1111 void ssp1601_dyn_reset(ssp1601_t *ssp)
1112 {
1113         ssp1601_reset_local(ssp);
1114         ssp->ptr_rom  = (unsigned int) Pico.rom;
1115         ssp->ptr_iram = (unsigned int) svp->iram_rom;
1116         ssp->ptr_dram = (unsigned int) svp->dram;
1117 }
1118
1119 void ssp1601_dyn_run(int cycles)
1120 {
1121         if (ssp->emu_status & SSP_WAIT_MASK) return;
1122         //{ printf("%i wait\n", Pico.m.frame_count); return; }
1123         //printf("%i  %04x\n", Pico.m.frame_count, rPC<<1);
1124
1125 #ifdef DUMP_BLOCK
1126         rPC = DUMP_BLOCK >> 1;
1127 #endif
1128         while (cycles > 0)
1129         {
1130                 int (*trans_entry)(void);
1131                 if (rPC < 0x800/2)
1132                 {
1133                         if (iram_dirty) {
1134                                 iram_context = get_iram_context();
1135                                 iram_dirty--;
1136                         }
1137                         if (block_table_iram[iram_context][rPC] == NULL)
1138                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
1139                         trans_entry = (void *) block_table_iram[iram_context][rPC];
1140                 }
1141                 else
1142                 {
1143                         if (block_table[rPC] == NULL)
1144                                 block_table[rPC] = translate_block(rPC);
1145                         trans_entry = (void *) block_table[rPC];
1146                 }
1147
1148                 //printf("enter %04x\n", rPC<<1);
1149                 cycles -= trans_entry();
1150                 //printf("leave %04x\n", rPC<<1);
1151         }
1152 //      debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1153 //      exit(1);
1154 }
1155