svp compiler: all ops implemented, EXT regs left
[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 0x08aa
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 } known_regs;
537
538 #define KRREG_X     (1 << SSP_X)
539 #define KRREG_Y     (1 << SSP_Y)
540 #define KRREG_A     (1 << SSP_A)        /* AH only */
541 #define KRREG_ST    (1 << SSP_ST)
542 #define KRREG_STACK (1 << SSP_STACK)
543 #define KRREG_PC    (1 << SSP_PC)
544 #define KRREG_P     (1 << SSP_P)
545 #define KRREG_PR0   (1 << 8)
546 #define KRREG_PR4   (1 << 12)
547 #define KRREG_AL    (1 << 16)
548
549 /* bitfield of known register values */
550 static u32 known_regb = 0;
551
552 /* known vals, which need to be flushed
553  * (only ST, P, r0-r7)
554  * ST means flags are being held in ARM PSR
555  * P means that it needs to be recalculated
556  */
557 static u32 dirty_regb = 0;
558
559 /* known values of host regs.
560  * -1            - unknown
561  * 000000-00ffff - 16bit value
562  * 100000-10ffff - base reg (r7) + 16bit val
563  * 0r0000        - means reg (low) eq gr[r].h, r != AL
564  */
565 static int hostreg_r[4];
566
567 static void hostreg_clear(void)
568 {
569         int i;
570         for (i = 0; i < 4; i++)
571                 hostreg_r[i] = -1;
572 }
573
574 static void hostreg_sspreg_changed(int sspreg)
575 {
576         int i;
577         for (i = 0; i < 4; i++)
578                 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
579 }
580
581
582 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
583
584 static void tr_unhandled(void)
585 {
586         FILE *f = fopen("tcache.bin", "wb");
587         fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
588         fclose(f);
589         printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
590         exit(1);
591 }
592
593 /* update P, if needed. Trashes r0 */
594 static void tr_flush_dirty_P(void)
595 {
596         // TODO: const regs
597         if (!(dirty_regb & KRREG_P)) return;
598         EOP_MOV_REG_ASR(10, 4, 16);             // mov  r10, r4, asr #16
599         EOP_MOV_REG_LSL( 0, 4, 16);             // mov  r0,  r4, lsl #16
600         EOP_MOV_REG_ASR( 0, 0, 15);             // mov  r0,  r0, asr #15
601         EOP_MUL(10, 0, 10);                     // mul  r10, r0, r10
602         dirty_regb &= ~KRREG_P;
603         hostreg_r[0] = -1;
604 }
605
606 /* write dirty pr to host reg. Nothing is trashed */
607 static void tr_flush_dirty_pr(int r)
608 {
609         int ror = 0, reg;
610
611         if (!(dirty_regb & (1 << (r+8)))) return;
612
613         switch (r&3) {
614                 case 0: ror =    0; break;
615                 case 1: ror = 24/2; break;
616                 case 2: ror = 16/2; break;
617         }
618         reg = (r < 4) ? 8 : 9;
619         EOP_BIC_IMM(reg,reg,ror,0xff);
620         if (known_regs.r[r] != 0)
621                 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
622         dirty_regb &= ~(1 << (r+8));
623 }
624
625 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
626 static void tr_flush_dirty_prs(void)
627 {
628         int i, ror = 0, reg;
629         int dirty = dirty_regb >> 8;
630         /* r0-r7 */
631         for (i = 0; dirty && i < 8; i++, dirty >>= 1)
632         {
633                 if (!(dirty&1)) continue;
634                 switch (i&3) {
635                         case 0: ror =    0; break;
636                         case 1: ror = 24/2; break;
637                         case 2: ror = 16/2; break;
638                 }
639                 reg = (i < 4) ? 8 : 9;
640                 EOP_BIC_IMM(reg,reg,ror,0xff);
641                 if (known_regs.r[i] != 0)
642                         EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
643         }
644         dirty_regb &= ~0xff00;
645 }
646
647 /* write dirty pr and "forget" it. Nothing is trashed. */
648 static void tr_release_pr(int r)
649 {
650         tr_flush_dirty_pr(r);
651         known_regb &= ~(1 << (r+8));
652 }
653
654 /* fush ARM PSR to r6. Trashes r1 */
655 static void tr_flush_dirty_ST(void)
656 {
657         if (!(dirty_regb & KRREG_ST)) return;
658         EOP_BIC_IMM(6,6,0,0x0f);
659         EOP_MRS(1);
660         EOP_ORR_REG_LSR(6,6,1,28);
661         dirty_regb &= ~KRREG_ST;
662         hostreg_r[1] = -1;
663 }
664
665 /* inverse of above. Trashes r1 */
666 static void tr_make_dirty_ST(void)
667 {
668         if (dirty_regb & KRREG_ST) return;
669         if (known_regb & KRREG_ST) {
670                 int flags = 0;
671                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
672                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
673                 EOP_MSR_IMM(4/2, flags);
674         } else {
675                 EOP_MOV_REG_LSL(1, 6, 28);
676                 EOP_MSR_REG(1);
677                 hostreg_r[1] = -1;
678         }
679         dirty_regb |= KRREG_ST;
680 }
681
682 /* load 16bit val into host reg r0-r3. Nothing is trashed */
683 static void tr_mov16(int r, int val)
684 {
685         if (hostreg_r[r] != val) {
686                 emit_mov_const(A_COND_AL, r, val);
687                 hostreg_r[r] = val;
688         }
689 }
690
691 static void tr_mov16_cond(int cond, int r, int val)
692 {
693         emit_mov_const(cond, r, val);
694         hostreg_r[r] = -1;
695 }
696
697 /* read bank word to r0 (upper bits zero). Thrashes r1. */
698 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
699 {
700         int breg = 7;
701         if (addr > 0x7f) {
702                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
703                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
704                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
705                 }
706                 breg = 1;
707         }
708         EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1);    // ldrh r0, [r1, (op&0x7f)<<1]
709         hostreg_r[0] = -1;
710 }
711
712 /* write r0 to bank. Trashes r1. */
713 static void tr_bank_write(int addr)
714 {
715         int breg = 7;
716         if (addr > 0x7f) {
717                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
718                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
719                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
720                 }
721                 breg = 1;
722         }
723         EOP_STRH_IMM(0,breg,(addr&0x7f)<<1);            // strh r0, [r1, (op&0x7f)<<1]
724 }
725
726 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
727 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
728 {
729         int modulo_shift = -1;  /* unknown */
730
731         if (mod == 0) return;
732
733         if (!need_modulo || mod == 1) // +!
734                 modulo_shift = 8;
735         else if (need_modulo && (known_regb & KRREG_ST)) {
736                 modulo_shift = known_regs.gr[SSP_ST].h & 7;
737                 if (modulo_shift == 0) modulo_shift = 8;
738         }
739
740         if (modulo_shift == -1)
741         {
742                 int reg = (r < 4) ? 8 : 9;
743                 tr_release_pr(r);
744                 if (dirty_regb & KRREG_ST) {
745                         // avoid flushing ARM flags
746                         EOP_AND_IMM(1, 6, 0, 0x70);
747                         EOP_SUB_IMM(1, 1, 0, 0x10);
748                         EOP_AND_IMM(1, 1, 0, 0x70);
749                         EOP_ADD_IMM(1, 1, 0, 0x10);
750                 } else {
751                         EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands  r1, r6, #0x70
752                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
753                 }
754                 EOP_MOV_REG_LSR(1, 1, 4);               // mov r1, r1, lsr #4
755                 EOP_RSB_IMM(2, 1, 0, 8);                // rsb r1, r1, #8
756                 EOP_MOV_IMM(3, 8/2, count);             // mov r3, #0x01000000
757                 if (r&3)
758                         EOP_ADD_IMM(1, 1, 0, (r&3)*8);  // add r1, r1, #(r&3)*8
759                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
760                 if (mod == 2)
761                      EOP_SUB_REG2_LSL(reg,reg,3,2);     // sub reg, reg, #0x01000000 << r2
762                 else EOP_ADD_REG2_LSL(reg,reg,3,2);
763                 EOP_RSB_IMM(1, 1, 0, 32);               // rsb r1, r1, #32
764                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
765                 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
766         }
767         else if (known_regb & (1 << (r + 8)))
768         {
769                 int modulo = (1 << modulo_shift) - 1;
770                 if (mod == 2)
771                      known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
772                 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
773         }
774         else
775         {
776                 int reg = (r < 4) ? 8 : 9;
777                 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
778                 EOP_MOV_REG_ROR(reg,reg,ror);
779                 // {add|sub} reg, reg, #1<<shift
780                 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
781                 EOP_MOV_REG_ROR(reg,reg,32-ror);
782         }
783 }
784
785 /* handle writes r0 to (rX). Trashes r1.
786  * fortunately we can ignore modulo increment modes for writes. */
787 static void tr_rX_write(int op)
788 {
789         if ((op&3) == 3)
790         {
791                 int mod = (op>>2) & 3; // direct addressing
792                 tr_bank_write((op & 0x100) + mod);
793         }
794         else
795         {
796                 int r = (op&3) | ((op>>6)&4);
797                 if (known_regb & (1 << (r + 8))) {
798                         tr_bank_write((op&0x100) | known_regs.r[r]);
799                 } else {
800                         int reg = (r < 4) ? 8 : 9;
801                         int ror = ((4 - (r&3))*8) & 0x1f;
802                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
803                         if (r >= 4)
804                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
805                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
806                         else     EOP_ADD_REG_LSL(1,7,1,1);
807                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
808                         hostreg_r[1] = -1;
809                 }
810                 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
811         }
812 }
813
814 /* read (rX) to r0. Trashes r1-r3. */
815 static void tr_rX_read(int r, int mod)
816 {
817         if ((r&3) == 3)
818         {
819                 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
820         }
821         else
822         {
823                 if (known_regb & (1 << (r + 8))) {
824                         tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
825                 } else {
826                         int reg = (r < 4) ? 8 : 9;
827                         int ror = ((4 - (r&3))*8) & 0x1f;
828                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
829                         if (r >= 4)
830                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
831                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
832                         else     EOP_ADD_REG_LSL(1,7,1,1);
833                         EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
834                         hostreg_r[0] = hostreg_r[1] = -1;
835                 }
836                 tr_ptrr_mod(r, mod, 1, 1);
837         }
838 }
839
840 /* read ((rX)) to r0. Trashes r1,r2. */
841 static void tr_rX_read2(int op)
842 {
843         int r = (op&3) | ((op>>6)&4); // src
844
845         if ((r&3) == 3) {
846                 tr_bank_read((op&0x100) | ((op>>2)&3));
847         } else if (known_regb & (1 << (r+8))) {
848                 tr_bank_read((op&0x100) | known_regs.r[r]);
849         } else {
850                 int reg = (r < 4) ? 8 : 9;
851                 int ror = ((4 - (r&3))*8) & 0x1f;
852                 EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
853                 if (r >= 4)
854                         EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
855                 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
856                 else     EOP_ADD_REG_LSL(1,7,1,1);
857                 EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
858         }
859         EOP_LDR_IMM(2,7,0x48c);                                 // ptr_iram_rom
860         EOP_ADD_REG_LSL(2,2,0,1);                               // add  r2, r2, r0, lsl #1
861         EOP_ADD_IMM(0,0,0,1);                                   // add  r0, r0, #1
862         if ((r&3) == 3) {
863                 tr_bank_write((op&0x100) | ((op>>2)&3));
864         } else if (known_regb & (1 << (r+8))) {
865                 tr_bank_write((op&0x100) | known_regs.r[r]);
866         } else {
867                 EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
868                 hostreg_r[1] = -1;
869         }
870         EOP_LDRH_SIMPLE(0,2);                                   // ldrh r0, [r2]
871         hostreg_r[0] = hostreg_r[2] = -1;
872 }
873
874 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
875 static int tr_cond_check(int op)
876 {
877         int f = (op & 0x100) >> 8;
878         switch (op&0xf0) {
879                 case 0x00: return A_COND_AL;    /* always true */
880                 case 0x50:                      /* Z matches f(?) bit */
881                         if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
882                         EOP_TST_IMM(6, 0, 4);
883                         return f ? A_COND_NE : A_COND_EQ;
884                 case 0x70:                      /* N matches f(?) bit */
885                         if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
886                         EOP_TST_IMM(6, 0, 8);
887                         return f ? A_COND_NE : A_COND_EQ;
888                 default:
889                         printf("unimplemented cond?\n");
890                         tr_unhandled();
891                         return 0;
892         }
893 }
894
895 static int tr_neg_cond(int cond)
896 {
897         switch (cond) {
898                 case A_COND_AL: printf("neg for AL?\n"); exit(1);
899                 case A_COND_EQ: return A_COND_NE;
900                 case A_COND_NE: return A_COND_EQ;
901                 case A_COND_MI: return A_COND_PL;
902                 case A_COND_PL: return A_COND_MI;
903                 default:        printf("bad cond for neg\n"); exit(1);
904         }
905         return 0;
906 }
907
908 //      SSP_GR0, SSP_X,     SSP_Y,   SSP_A,
909 //      SSP_ST,  SSP_STACK, SSP_PC,  SSP_P,
910 //@ r4:  XXYY
911 //@ r5:  A
912 //@ r6:  STACK and emu flags
913 //@ r7:  SSP context
914 //@ r10: P
915
916 // read general reg to r0. Trashes r1
917 static void tr_GR0_to_r0(void)
918 {
919         tr_mov16(0, 0xffff);
920 }
921
922 static void tr_X_to_r0(void)
923 {
924         if (hostreg_r[0] != (SSP_X<<16)) {
925                 EOP_MOV_REG_LSR(0, 4, 16);      // mov  r0, r4, lsr #16
926                 hostreg_r[0] = SSP_X<<16;
927         }
928 }
929
930 static void tr_Y_to_r0(void)
931 {
932         // TODO..
933         if (hostreg_r[0] != (SSP_Y<<16)) {
934                 EOP_MOV_REG_SIMPLE(0, 4);       // mov  r0, r4
935                 hostreg_r[0] = SSP_Y<<16;
936         }
937 }
938
939 static void tr_A_to_r0(void)
940 {
941         if (hostreg_r[0] != (SSP_A<<16)) {
942                 EOP_MOV_REG_LSR(0, 5, 16);      // mov  r0, r5, lsr #16  @ AH
943                 hostreg_r[0] = SSP_A<<16;
944         }
945 }
946
947 static void tr_ST_to_r0(void)
948 {
949         // VR doesn't need much accuracy here..
950         EOP_MOV_REG_LSR(0, 6, 4);               // mov  r0, r6, lsr #4
951         EOP_AND_IMM(0, 0, 0, 0x67);             // and  r0, r0, #0x67
952         hostreg_r[0] = -1;
953 }
954
955 static void tr_STACK_to_r0(void)
956 {
957         // 448
958         EOP_SUB_IMM(6, 6,  8/2, 0x20);          // sub  r6, r6, #1<<29
959         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
960         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
961         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
962         EOP_LDRH_SIMPLE(0, 1);                  // ldrh r0, [r1]
963         hostreg_r[0] = hostreg_r[1] = -1;
964 }
965
966 static void tr_PC_to_r0(void)
967 {
968         tr_mov16(0, known_regs.gr[SSP_PC].h);
969 }
970
971 static void tr_P_to_r0(void)
972 {
973         tr_flush_dirty_P();
974         EOP_MOV_REG_LSR(0, 10, 16);             // mov  r0, r10, lsr #16
975         hostreg_r[0] = -1;
976 }
977
978 typedef void (tr_read_func)(void);
979
980 static tr_read_func *tr_read_funcs[8] =
981 {
982         tr_GR0_to_r0,
983         tr_X_to_r0,
984         tr_Y_to_r0,
985         tr_A_to_r0,
986         tr_ST_to_r0,
987         tr_STACK_to_r0,
988         tr_PC_to_r0,
989         tr_P_to_r0
990 };
991
992
993 // write r0 to general reg handlers. Trashes r1
994 #define TR_WRITE_R0_TO_REG(reg) \
995 { \
996         hostreg_sspreg_changed(reg); \
997         hostreg_r[0] = (reg)<<16; \
998         if (const_val != -1) { \
999                 known_regs.gr[reg].h = const_val; \
1000                 known_regb |= 1 << (reg); \
1001         } else { \
1002                 known_regb &= ~(1 << (reg)); \
1003         } \
1004 }
1005
1006 static void tr_r0_to_GR0(int const_val)
1007 {
1008         // do nothing
1009 }
1010
1011 static void tr_r0_to_X(int const_val)
1012 {
1013         EOP_MOV_REG_LSL(4, 4, 16);              // mov  r4, r4, lsl #16
1014         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
1015         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
1016         dirty_regb |= KRREG_P;                  // touching X or Y makes P dirty.
1017         TR_WRITE_R0_TO_REG(SSP_X);
1018 }
1019
1020 static void tr_r0_to_Y(int const_val)
1021 {
1022         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
1023         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
1024         EOP_MOV_REG_ROR(4, 4, 16);              // mov  r4, r4, ror #16
1025         dirty_regb |= KRREG_P;
1026         TR_WRITE_R0_TO_REG(SSP_Y);
1027 }
1028
1029 static void tr_r0_to_A(int const_val)
1030 {
1031         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
1032         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16  @ AL
1033         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
1034         TR_WRITE_R0_TO_REG(SSP_A);
1035 }
1036
1037 static void tr_r0_to_ST(int const_val)
1038 {
1039         // VR doesn't need much accuracy here..
1040         EOP_AND_IMM(1, 0,   0, 0x67);           // and   r1, r0, #0x67
1041         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
1042         EOP_ORR_REG_LSL(6, 6, 1, 4);            // orr   r6, r6, r1, lsl #4
1043         TR_WRITE_R0_TO_REG(SSP_ST);
1044         hostreg_r[1] = -1;
1045         dirty_regb &= ~KRREG_ST;
1046 }
1047
1048 static void tr_r0_to_STACK(int const_val)
1049 {
1050         // 448
1051         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
1052         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
1053         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
1054         EOP_STRH_SIMPLE(0, 1);                  // strh r0, [r1]
1055         EOP_ADD_IMM(6, 6,  8/2, 0x20);          // add  r6, r6, #1<<29
1056         hostreg_r[1] = -1;
1057 }
1058
1059 static void tr_r0_to_PC(int const_val)
1060 {
1061         EOP_MOV_REG_LSL(1, 0, 16);              // mov  r1, r0, lsl #16
1062         EOP_STR_IMM(1,7,0x400+6*4);             // str  r1, [r7, #(0x400+6*8)]
1063         hostreg_r[1] = -1;
1064 }
1065
1066 typedef void (tr_write_func)(int const_val);
1067
1068 static tr_write_func *tr_write_funcs[8] =
1069 {
1070         tr_r0_to_GR0,
1071         tr_r0_to_X,
1072         tr_r0_to_Y,
1073         tr_r0_to_A,
1074         tr_r0_to_ST,
1075         tr_r0_to_STACK,
1076         tr_r0_to_PC,
1077         (tr_write_func *)tr_unhandled
1078 };
1079
1080 static void tr_mac_load_XY(int op)
1081 {
1082         tr_rX_read(op&3, (op>>2)&3); // X
1083         EOP_MOV_REG_LSL(4, 0, 16);
1084         tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1085         EOP_ORR_REG_SIMPLE(4, 0);
1086         dirty_regb |= KRREG_P;
1087         hostreg_sspreg_changed(SSP_X);
1088         hostreg_sspreg_changed(SSP_Y);
1089         known_regb &= ~KRREG_X;
1090         known_regb &= ~KRREG_Y;
1091 }
1092
1093 static int tr_aop_ssp2arm(int op)
1094 {
1095         switch (op) {
1096                 case 1: return A_OP_SUB;
1097                 case 3: return A_OP_CMP;
1098                 case 4: return A_OP_ADD;
1099                 case 5: return A_OP_AND;
1100                 case 6: return A_OP_ORR;
1101                 case 7: return A_OP_EOR;
1102         }
1103
1104         tr_unhandled();
1105         return 0;
1106 }
1107
1108 static int translate_op(unsigned int op, int *pc, int imm)
1109 {
1110         u32 tmpv, tmpv2, tmpv3;
1111         int ret = 0;
1112         known_regs.gr[SSP_PC].h = *pc;
1113
1114         switch (op >> 9)
1115         {
1116                 // ld d, s
1117                 case 0x00:
1118                         if (op == 0) { ret++; break; } // nop
1119                         tmpv  = op & 0xf; // src
1120                         tmpv2 = (op >> 4) & 0xf; // dst
1121                         if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
1122                         if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1123                                 tr_flush_dirty_P();
1124                                 EOP_MOV_REG_SIMPLE(5, 10);
1125                                 hostreg_sspreg_changed(SSP_A); \
1126                                 known_regb &= ~(KRREG_A|KRREG_AL);
1127                                 ret++; break;
1128                         }
1129                         tr_read_funcs[tmpv]();
1130                         tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1131                         ret++; break;
1132
1133                 // ld d, (ri)
1134                 case 0x01: {
1135                         // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1136                         int r = (op&3) | ((op>>6)&4);
1137                         int mod = (op>>2)&3;
1138                         tmpv = (op >> 4) & 0xf; // dst
1139                         if (tmpv >= 8) return -1; // TODO
1140                         if (tmpv != 0)
1141                              tr_rX_read(r, mod);
1142                         else tr_ptrr_mod(r, mod, 1, 1);
1143                         tr_write_funcs[tmpv](-1);
1144                         ret++; break;
1145                 }
1146
1147                 // ld (ri), s
1148                 case 0x02:
1149                         tmpv = (op >> 4) & 0xf; // src
1150                         if (tmpv >= 8) return -1; // TODO
1151                         tr_read_funcs[tmpv]();
1152                         tr_rX_write(op);
1153                         ret++; break;
1154
1155                 // ld a, adr
1156                 case 0x03:
1157                         tr_bank_read(op&0x1ff);
1158                         tr_r0_to_A(-1);
1159                         ret++; break;
1160
1161                 // ldi d, imm
1162                 case 0x04:
1163                         tmpv = (op & 0xf0) >> 4;
1164                         if (tmpv < 8)
1165                         {
1166                                 tr_mov16(0, imm);
1167                                 tr_write_funcs[tmpv](imm);
1168                                 ret += 2; break;
1169                         }
1170                         else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1171                         {
1172                                 // programming PMC..
1173                                 (*pc)++;
1174                                 tmpv = imm | (PROGRAM((*pc)++) << 16);
1175                                 ret += 2;
1176                                 emit_mov_const(A_COND_AL, 0, tmpv);
1177                                 EOP_LDR_IMM(1,7,0x484);         // ldr r1, [r7, #0x484] // emu_status
1178                                 EOP_STR_IMM(0,7,0x400+14*4);    // PMC
1179                                 // reads on fe06, fe08; next op is ld -,
1180                                 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1181                                 {
1182                                         int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1183                                         tr_flush_dirty_ST();
1184                                         EOP_LDR_IMM(0,7,0x490); // dram_ptr
1185                                         EOP_ADD_IMM(0,0,24/2,0xfe);                             // add  r0, r0, #0xfe00
1186                                         EOP_LDRH_IMM(0,0,(tmpv == 0x187f03) ? 6 : 8);           // ldrh r0, [r0, #8]
1187                                         EOP_TST_REG_SIMPLE(0,0);
1188                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1);       // add r11, r11, #1024
1189                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1190                                 }
1191                                 EOP_ORR_IMM(1,1,0,SSP_PMC_SET);         // orr r1, r1, #SSP_PMC_SET
1192                                 EOP_STR_IMM(1,7,0x484);                 // str r1, [r7, #0x484] // emu_status
1193                                 hostreg_r[0] = hostreg_r[1] = -1;
1194                                 ret += 2; break;
1195                         }
1196                         else
1197                                 return -1;      /* TODO.. */
1198
1199                 // ld d, ((ri))
1200                 case 0x05:
1201                         tmpv2 = (op >> 4) & 0xf;  // dst
1202                         if (tmpv2 >= 8) return -1; // TODO
1203                         tr_rX_read2(op);
1204                         tr_write_funcs[tmpv2](-1);
1205                         ret += 3; break;
1206
1207                 // ldi (ri), imm
1208                 case 0x06:
1209                         tr_mov16(0, imm);
1210                         tr_rX_write(op);
1211                         ret += 2; break;
1212
1213                 // ld adr, a
1214                 case 0x07:
1215                         tr_A_to_r0();
1216                         tr_bank_write(op&0x1ff);
1217                         ret++; break;
1218
1219                 // ld d, ri
1220                 case 0x09: {
1221                         int r;
1222                         r = (op&3) | ((op>>6)&4); // src
1223                         tmpv2 = (op >> 4) & 0xf;  // dst
1224                         if (tmpv2 >= 8) tr_unhandled();
1225                         if ((r&3) == 3) tr_unhandled();
1226
1227                         if (known_regb & (1 << (r+8))) {
1228                                 tr_mov16(0, known_regs.r[r]);
1229                                 tr_write_funcs[tmpv2](known_regs.r[r]);
1230                         } else {
1231                                 int reg = (r < 4) ? 8 : 9;
1232                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1233                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1234                                 hostreg_r[0] = -1;
1235                                 tr_write_funcs[tmpv2](-1);
1236                         }
1237                         ret++; break;
1238                 }
1239
1240                 // ld ri, s
1241                 case 0x0a: {
1242                         int r;
1243                         r = (op&3) | ((op>>6)&4); // dst
1244                         tmpv = (op >> 4) & 0xf;   // src
1245                         if (tmpv >= 8)  tr_unhandled();
1246                         if ((r&3) == 3) tr_unhandled();
1247
1248                         if (known_regb & (1 << tmpv)) {
1249                                 known_regs.r[r] = known_regs.gr[tmpv].h;
1250                                 known_regb |= 1 << (r + 8);
1251                                 dirty_regb |= 1 << (r + 8);
1252                         } else {
1253                                 int reg = (r < 4) ? 8 : 9;
1254                                 int ror = ((4 - (r&3))*8) & 0x1f;
1255                                 tr_read_funcs[tmpv]();
1256                                 EOP_BIC_IMM(reg, reg, ror/2, 0xff);             // bic r{7,8}, r{7,8}, <mask>
1257                                 EOP_AND_IMM(0, 0, 0, 0xff);                     // and r0, r0, 0xff
1258                                 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8);          // orr r{7,8}, r{7,8}, r0, lsl #lsl
1259                                 hostreg_r[0] = -1;
1260                                 known_regb &= ~(1 << (r+8));
1261                                 dirty_regb &= ~(1 << (r+8));
1262                         }
1263                         ret++; break;
1264                 }
1265
1266                 // ldi ri, simm
1267                 case 0x0c ... 0x0f:
1268                         tmpv = (op>>8)&7;
1269                         known_regs.r[tmpv] = op;
1270                         known_regb |= 1 << (tmpv + 8);
1271                         dirty_regb |= 1 << (tmpv + 8);
1272                         ret++; break;
1273
1274                 // call cond, addr
1275                 case 0x24: {
1276                         u32 *jump_op = NULL;
1277                         tmpv = tr_cond_check(op);
1278                         if (tmpv != A_COND_AL) {
1279                                 jump_op = tcache_ptr;
1280                                 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1281                         }
1282                         tr_mov16(0, *pc);
1283                         tr_r0_to_STACK(*pc);
1284                         if (tmpv != A_COND_AL) {
1285                                 u32 *real_ptr = tcache_ptr;
1286                                 tcache_ptr = jump_op;
1287                                 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1288                                 tcache_ptr = real_ptr;
1289                         }
1290                         tr_mov16_cond(tmpv, 0, imm);
1291                         if (tmpv != A_COND_AL) {
1292                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1293                         }
1294                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1295                         ret += 2; break;
1296                 }
1297
1298                 // ld d, (a)
1299                 case 0x25:
1300                         tmpv2 = (op >> 4) & 0xf;  // dst
1301                         if (tmpv2 >= 8) return -1; // TODO
1302
1303                         tr_A_to_r0();
1304                         EOP_LDR_IMM(1,7,0x48c);                                 // ptr_iram_rom
1305                         EOP_ADD_REG_LSL(0,1,0,1);                               // add  r0, r1, r0, lsl #1
1306                         EOP_LDRH_SIMPLE(0,0);                                   // ldrh r0, [r0]
1307                         hostreg_r[0] = hostreg_r[1] = -1;
1308                         tr_write_funcs[tmpv2](-1);
1309                         ret += 3; break;
1310
1311                 // bra cond, addr
1312                 case 0x26:
1313                         tmpv = tr_cond_check(op);
1314                         tr_mov16_cond(tmpv, 0, imm);
1315                         if (tmpv != A_COND_AL) {
1316                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1317                         }
1318                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1319                         ret += 2; break;
1320
1321                 // mod cond, op
1322                 case 0x48: {
1323                         // check for repeats of this op
1324                         tmpv = 1; // count
1325                         while (PROGRAM(*pc) == op && (op & 7) != 6) {
1326                                 (*pc)++; tmpv++;
1327                         }
1328                         if ((op&0xf0) != 0) // !always
1329                                 tr_make_dirty_ST();
1330
1331                         tmpv2 = tr_cond_check(op);
1332                         switch (op & 7) {
1333                                 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1334                                 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1335                                 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1336                                 case 7: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_EOR,0,5,1,31,A_AM1_ASR,5); // eor  r1, r5, r5, asr #31
1337                                         EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1338                                         hostreg_r[1] = -1; break; // abs
1339                                 default: tr_unhandled();
1340                         }
1341
1342                         hostreg_sspreg_changed(SSP_A);
1343                         dirty_regb |=  KRREG_ST;
1344                         known_regb &= ~KRREG_ST;
1345                         known_regb &= ~(KRREG_A|KRREG_AL);
1346                         ret += tmpv; break;
1347                 }
1348
1349                 // mpys?
1350                 case 0x1b:
1351                         tr_flush_dirty_P();
1352                         tr_mac_load_XY(op);
1353                         tr_make_dirty_ST();
1354                         EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1355                         hostreg_sspreg_changed(SSP_A);
1356                         known_regb &= ~(KRREG_A|KRREG_AL);
1357                         dirty_regb |= KRREG_ST;
1358                         ret++; break;
1359
1360                 // mpya (rj), (ri), b
1361                 case 0x4b:
1362                         tr_flush_dirty_P();
1363                         tr_mac_load_XY(op);
1364                         tr_make_dirty_ST();
1365                         EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1366                         hostreg_sspreg_changed(SSP_A);
1367                         known_regb &= ~(KRREG_A|KRREG_AL);
1368                         dirty_regb |= KRREG_ST;
1369                         ret++; break;
1370
1371                 // mld (rj), (ri), b
1372                 case 0x5b:
1373                         EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1374                         hostreg_sspreg_changed(SSP_A);
1375                         known_regs.gr[SSP_A].v = 0;
1376                         known_regb |= (KRREG_A|KRREG_AL);
1377                         dirty_regb |= KRREG_ST;
1378                         tr_mac_load_XY(op);
1379                         ret++; break;
1380
1381                 // OP a, s
1382                 case 0x10:
1383                 case 0x30:
1384                 case 0x40:
1385                 case 0x50:
1386                 case 0x60:
1387                 case 0x70:
1388                         tmpv = op & 0xf; // src
1389                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1390                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1391                         if (tmpv >= 8) return -1; // TODO
1392                         if (tmpv == SSP_P) {
1393                                 tr_flush_dirty_P();
1394                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1395                         } else if (tmpv == SSP_A) {
1396                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1397                         } else {
1398                                 tr_read_funcs[tmpv]();
1399                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1400                         }
1401                         hostreg_sspreg_changed(SSP_A);
1402                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1403                         dirty_regb |= KRREG_ST;
1404                         ret++; break;
1405
1406                 // OP a, (ri)
1407                 case 0x11:
1408                 case 0x31:
1409                 case 0x41:
1410                 case 0x51:
1411                 case 0x61:
1412                 case 0x71:
1413                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1414                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1415                         tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1416                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1417                         hostreg_sspreg_changed(SSP_A);
1418                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1419                         dirty_regb |= KRREG_ST;
1420                         ret++; break;
1421
1422                 // OP a, adr
1423                 case 0x13:
1424                 case 0x33:
1425                 case 0x43:
1426                 case 0x53:
1427                 case 0x63:
1428                 case 0x73:
1429                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1430                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1431                         tr_bank_read(op&0x1ff);
1432                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1433                         hostreg_sspreg_changed(SSP_A);
1434                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1435                         dirty_regb |= KRREG_ST;
1436                         ret++; break;
1437
1438                 // OP a, imm
1439                 case 0x14:
1440                 case 0x34:
1441                 case 0x44:
1442                 case 0x54:
1443                 case 0x64:
1444                 case 0x74:
1445                         tmpv = (op & 0xf0) >> 4;
1446                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1447                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1448                         tr_mov16(0, imm);
1449                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1450                         hostreg_sspreg_changed(SSP_A);
1451                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1452                         dirty_regb |= KRREG_ST;
1453                         ret += 2; break;
1454
1455                 // OP a, ((ri))
1456                 case 0x15:
1457                 case 0x35:
1458                 case 0x45:
1459                 case 0x55:
1460                 case 0x65:
1461                 case 0x75:
1462                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1463                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1464                         tr_rX_read2(op);
1465                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1466                         hostreg_sspreg_changed(SSP_A);
1467                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1468                         dirty_regb |= KRREG_ST;
1469                         ret += 3; break;
1470
1471                 // OP a, ri
1472                 case 0x19:
1473                 case 0x39:
1474                 case 0x49:
1475                 case 0x59:
1476                 case 0x69:
1477                 case 0x79: {
1478                         int r;
1479                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1480                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1481                         r = (op&3) | ((op>>6)&4); // src
1482                         if ((r&3) == 3) tr_unhandled();
1483
1484                         if (known_regb & (1 << (r+8))) {
1485                                 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]);  // OPs r5, r5, #val<<16
1486                         } else {
1487                                 int reg = (r < 4) ? 8 : 9;
1488                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1489                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1490                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1491                                 hostreg_r[0] = -1;
1492                         }
1493                         hostreg_sspreg_changed(SSP_A);
1494                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1495                         dirty_regb |= KRREG_ST;
1496                         ret++; break;
1497                 }
1498
1499                 // OP simm
1500                 case 0x1c:
1501                 case 0x3c:
1502                 case 0x4c:
1503                 case 0x5c:
1504                 case 0x6c:
1505                 case 0x7c:
1506                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1507                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1508                         EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff);        // OPs r5, r5, #val<<16
1509                         hostreg_sspreg_changed(SSP_A);
1510                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1511                         dirty_regb |= KRREG_ST;
1512                         ret++; break;
1513         }
1514
1515         return ret;
1516 }
1517
1518 static void *translate_block(int pc)
1519 {
1520         unsigned int op, op1, imm, ccount = 0;
1521         unsigned int *block_start;
1522         int ret, ret_prev = -1;
1523
1524         // create .pool
1525         //*tcache_ptr++ = (u32) in_funcs;                       // -1 func pool
1526
1527         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1528         block_start = tcache_ptr;
1529         known_regb = 0;
1530         dirty_regb = KRREG_P;
1531         hostreg_clear();
1532
1533         emit_block_prologue();
1534
1535         for (; ccount < 100;)
1536         {
1537                 //printf("  insn #%i\n", icount);
1538                 op = PROGRAM(pc++);
1539                 op1 = op >> 9;
1540                 imm = (u32)-1;
1541
1542                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1543                         imm = PROGRAM(pc++); // immediate
1544
1545                 ret = translate_op(op, &pc, imm);
1546                 if (ret <= 0)
1547                 {
1548                         tr_flush_dirty_prs();
1549                         tr_flush_dirty_ST();
1550
1551                         emit_mov_const(A_COND_AL, 0, op);
1552
1553                         // need immediate?
1554                         if (imm != (u32)-1)
1555                                 emit_mov_const(A_COND_AL, 1, imm);
1556
1557                         // dump PC
1558                         emit_pc_dump(pc);
1559
1560                         if (ret_prev > 0) emit_call(regfile_store);
1561                         emit_call(in_funcs[op1]);
1562                         emit_call(regfile_load);
1563
1564                         if (in_funcs[op1] == NULL) {
1565                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
1566                                 exit(1);
1567                         }
1568                         ccount++;
1569                         hostreg_clear();
1570                         dirty_regb |= KRREG_P;
1571                         known_regb = 0;
1572                 }
1573                 else
1574                         ccount += ret;
1575
1576                 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1577                         ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1578                                 (op & 0xf0) == 0x60)) { // ld PC
1579                         break;
1580                 }
1581                 ret_prev = ret;
1582         }
1583
1584         tr_flush_dirty_prs();
1585         tr_flush_dirty_ST();
1586         emit_block_epilogue(ccount + 1);
1587         *tcache_ptr++ = 0xffffffff; // end of block
1588         //printf("  %i inst\n", icount);
1589
1590         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1591                 printf("tcache overflow!\n");
1592                 fflush(stdout);
1593                 exit(1);
1594         }
1595
1596         // stats
1597         nblocks++;
1598         //if (pc >= 0x400)
1599         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1600         //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1601
1602 #ifdef DUMP_BLOCK
1603         {
1604                 FILE *f = fopen("tcache.bin", "wb");
1605                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1606                 fclose(f);
1607         }
1608         exit(0);
1609 #endif
1610
1611         handle_caches();
1612
1613         return block_start;
1614 }
1615
1616
1617
1618 // -----------------------------------------------------
1619
1620 int ssp1601_dyn_startup(void)
1621 {
1622         memset(tcache, 0, TCACHE_SIZE);
1623         memset(block_table, 0, sizeof(block_table));
1624         memset(block_table_iram, 0, sizeof(block_table_iram));
1625         tcache_ptr = tcache;
1626         *tcache_ptr++ = 0xffffffff;
1627
1628 // TODO: rm
1629 {
1630 static unsigned short dummy = 0;
1631 PC = &dummy;
1632 }
1633         return 0;
1634 }
1635
1636
1637 void ssp1601_dyn_reset(ssp1601_t *ssp)
1638 {
1639         ssp1601_reset_local(ssp);
1640         ssp->ptr_rom = (unsigned int) Pico.rom;
1641         ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1642         ssp->ptr_dram = (unsigned int) svp->dram;
1643 }
1644
1645 void ssp1601_dyn_run(int cycles)
1646 {
1647         if (ssp->emu_status & SSP_WAIT_MASK) return;
1648         //{ printf("%i wait\n", Pico.m.frame_count); return; }
1649         //printf("%i  %04x\n", Pico.m.frame_count, rPC<<1);
1650
1651 #ifdef DUMP_BLOCK
1652         rPC = DUMP_BLOCK >> 1;
1653 #endif
1654         while (cycles > 0)
1655         {
1656                 int (*trans_entry)(void);
1657                 if (rPC < 0x800/2)
1658                 {
1659                         if (iram_dirty) {
1660                                 iram_context = get_iram_context();
1661                                 iram_dirty--;
1662                         }
1663                         if (block_table_iram[iram_context][rPC] == NULL)
1664                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
1665                         trans_entry = (void *) block_table_iram[iram_context][rPC];
1666                 }
1667                 else
1668                 {
1669                         if (block_table[rPC] == NULL)
1670                                 block_table[rPC] = translate_block(rPC);
1671                         trans_entry = (void *) block_table[rPC];
1672                 }
1673
1674                 //printf("enter %04x\n", rPC<<1);
1675                 cycles -= trans_entry();
1676                 //printf("leave %04x\n", rPC<<1);
1677         }
1678 //      debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1679 //      exit(1);
1680 }
1681