svp compiler: some pointer reg handling
[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 0x40b0
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);            // str  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
673 static int translate_op(unsigned int op, int *pc, int imm)
674 {
675         u32 tmpv;
676         int ret = 0;
677
678         switch (op >> 9)
679         {
680                 // ld d, s
681                 case 0x00:
682                         if (op == 0) { ret++; break; } // nop
683                         break;
684
685                 // ld a, adr
686                 case 0x03:
687                         tr_bank_read(op&0x1ff);
688                         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
689                         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsl #16  @ AL
690                         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
691                         const_regb &= ~CRREG_A;
692                         hostreg_r[0] = 0x20000;
693                         ret++; break;
694
695                 // ldi (ri), imm
696                 case 0x06:
697                         //tmpv = *PC++; ptr1_write(op, tmpv); break;
698                         // int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
699                         tr_mov16(0, imm);
700                         if ((op&3) == 3)
701                         {
702                                 tmpv = (op>>2) & 3; // direct addressing
703                                 if (op & 0x100) {
704                                         if (hostreg_r[1] != 0x10200) {
705                                                 EOP_ADD_IMM(1,7,30/2,0x200>>2); // add  r1, r7, 0x200
706                                                 hostreg_r[1] = 0x10200;
707                                         }
708                                         EOP_STRH_IMM(0,1,tmpv<<1);      // str  r0, [r1, {0,2,4,6}]
709                                 } else {
710                                         EOP_STRH_IMM(0,7,tmpv<<1);      // str  r0, [r7, {0,2,4,6}]
711                                 }
712                         }
713                         else
714                         {
715                                 int r = (op&3) | ((op>>6)&4);
716                                 if (const_regb & (1 << (r + 8))) {
717                                         tr_bank_write(const_regs.r[r] | ((r < 4) ? 0 : 0x100));
718                                 } else {
719                                         int reg = (r < 4) ? 8 : 9;
720                                         int ror = ((4 - (r&3))*8) & 0x1f;
721                                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
722                                         if (r >= 4)
723                                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
724                                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
725                                         else     EOP_ADD_REG_LSL(1,7,1,1);
726                                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
727                                         hostreg_r[1] = -1;
728                                 }
729                                 tr_ptrr_mod(r, (op>>2) & 3, 0);
730                         }
731                         ret++; break;
732
733                 // ld adr, a
734                 case 0x07:
735                         if (hostreg_r[0] != 0x20000) {
736                                 EOP_MOV_REG_LSR(0, 5, 16);              // mov  r0, r5, lsr #16  @ A
737                                 hostreg_r[0] = 0x20000;
738                         }
739                         tr_bank_write(op&0x1ff);
740                         ret++; break;
741
742                 // ldi ri, simm
743                 case 0x0c ... 0x0f:
744                         tmpv = (op>>8)&7;
745                         const_regs.r[tmpv] = op;
746                         const_regb |= 1 << (tmpv + 8);
747                         dirty_regb |= 1 << (tmpv + 8);
748                         ret++; break;
749         }
750
751         return ret;
752 }
753
754 static void *translate_block(int pc)
755 {
756         unsigned int op, op1, imm, ccount = 0;
757         unsigned int *block_start;
758         int ret;
759
760         // create .pool
761         //*tcache_ptr++ = (u32) in_funcs;                       // -1 func pool
762
763         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
764         block_start = tcache_ptr;
765         const_regb = dirty_regb = 0;
766         hostreg_clear();
767
768         emit_block_prologue();
769
770         for (; ccount < 100;)
771         {
772                 //printf("  insn #%i\n", icount);
773                 op = PROGRAM(pc++);
774                 op1 = op >> 9;
775                 imm = (u32)-1;
776
777                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
778                         imm = PROGRAM(pc++); // immediate
779
780                 ret = translate_op(op, &pc, imm);
781                 if (ret <= 0)
782                 {
783                         tr_flush_dirty();
784
785                         emit_mov_const(0, op);
786
787                         // need immediate?
788                         if (imm != (u32)-1)
789                                 emit_mov_const(1, imm);
790
791                         // dump PC
792                         emit_pc_dump(pc);
793
794                         emit_interpreter_call(in_funcs[op1]);
795
796                         if (in_funcs[op1] == NULL) {
797                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
798                                 exit(1);
799                         }
800                         ccount++;
801                         hostreg_clear();
802                 }
803                 else
804                         ccount += ret;
805
806                 if (op1 == 0x24 || op1 == 0x26 || // call, bra
807                         ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
808                                 (op & 0xf0) == 0x60)) { // ld PC
809                         break;
810                 }
811         }
812
813         tr_flush_dirty();
814         emit_block_epilogue(ccount + 1);
815         *tcache_ptr++ = 0xffffffff; // end of block
816         //printf("  %i inst\n", icount);
817
818         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
819                 printf("tcache overflow!\n");
820                 fflush(stdout);
821                 exit(1);
822         }
823
824         // stats
825         nblocks++;
826         //if (pc >= 0x400)
827         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
828         //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
829
830 #ifdef DUMP_BLOCK
831         {
832                 FILE *f = fopen("tcache.bin", "wb");
833                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
834                 fclose(f);
835         }
836         exit(0);
837 #endif
838
839         handle_caches();
840
841         return block_start;
842 }
843
844
845
846 // -----------------------------------------------------
847
848 int ssp1601_dyn_startup(void)
849 {
850         memset(tcache, 0, TCACHE_SIZE);
851         memset(block_table, 0, sizeof(block_table));
852         memset(block_table_iram, 0, sizeof(block_table_iram));
853         tcache_ptr = tcache;
854         *tcache_ptr++ = 0xffffffff;
855
856         return 0;
857 }
858
859
860 void ssp1601_dyn_reset(ssp1601_t *ssp)
861 {
862         ssp1601_reset_local(ssp);
863 }
864
865 void ssp1601_dyn_run(int cycles)
866 {
867 #ifdef DUMP_BLOCK
868         rPC = DUMP_BLOCK >> 1;
869 #endif
870         while (cycles > 0)
871         {
872                 int (*trans_entry)(void);
873                 if (rPC < 0x800/2)
874                 {
875                         if (iram_dirty) {
876                                 iram_context = get_iram_context();
877                                 iram_dirty--;
878                         }
879                         if (block_table_iram[iram_context][rPC] == NULL)
880                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
881                         trans_entry = (void *) block_table_iram[iram_context][rPC];
882                 }
883                 else
884                 {
885                         if (block_table[rPC] == NULL)
886                                 block_table[rPC] = translate_block(rPC);
887                         trans_entry = (void *) block_table[rPC];
888                 }
889
890                 had_jump = 0;
891
892                 //printf("enter %04x\n", rPC<<1);
893                 cycles -= trans_entry();
894                 //printf("leave %04x\n", rPC<<1);
895         }
896 //      debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
897 //      exit(1);
898 }
899