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