svp compiler: few ops, bugfixes, code seems to work
[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 0x341e
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 r1 */
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( 1, 4, 16);             // mov  r1,  r4, lsl #16
600         EOP_MOV_REG_ASR( 1, 1, 15);             // mov  r1,  r1, asr #15
601         EOP_MUL(10, 1, 10);                     // mul  r10, r1, r10
602         dirty_regb &= ~KRREG_P;
603 }
604
605 /* write dirty pr to host reg. Nothing is trashed */
606 static void tr_flush_dirty_pr(int r)
607 {
608         int ror = 0, reg;
609
610         if (!(dirty_regb & (1 << (r+8)))) return;
611
612         switch (r&3) {
613                 case 0: ror =    0; break;
614                 case 1: ror = 24/2; break;
615                 case 2: ror = 16/2; break;
616         }
617         reg = (r < 4) ? 8 : 9;
618         EOP_BIC_IMM(reg,reg,ror,0xff);
619         if (known_regs.r[r] != 0)
620                 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
621         dirty_regb &= ~(1 << (r+8));
622 }
623
624 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
625 static void tr_flush_dirty_prs(void)
626 {
627         int i, ror = 0, reg;
628         int dirty = dirty_regb >> 8;
629         /* r0-r7 */
630         for (i = 0; dirty && i < 8; i++, dirty >>= 1)
631         {
632                 if (!(dirty&1)) continue;
633                 switch (i&3) {
634                         case 0: ror =    0; break;
635                         case 1: ror = 24/2; break;
636                         case 2: ror = 16/2; break;
637                 }
638                 reg = (i < 4) ? 8 : 9;
639                 EOP_BIC_IMM(reg,reg,ror,0xff);
640                 if (known_regs.r[i] != 0)
641                         EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
642         }
643         dirty_regb &= ~0xff00;
644 }
645
646 /* write dirty pr and "forget" it. Nothing is trashed. */
647 static void tr_release_pr(int r)
648 {
649         tr_flush_dirty_pr(r);
650         known_regb &= ~(1 << (r+8));
651 }
652
653 /* fush ARM PSR to r6. Trashes r1 */
654 static void tr_flush_dirty_ST(void)
655 {
656         if (!(dirty_regb & KRREG_ST)) return;
657         EOP_BIC_IMM(6,6,0,0x0f);
658         EOP_MRS(1);
659         EOP_ORR_REG_LSR(6,6,1,28);
660         dirty_regb &= ~KRREG_ST;
661         hostreg_r[1] = -1;
662 }
663
664 /* inverse of above. Trashes r1 */
665 static void tr_make_dirty_ST(void)
666 {
667         if (dirty_regb & KRREG_ST) return;
668         if (known_regb & KRREG_ST) {
669                 int flags = 0;
670                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
671                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
672                 EOP_MSR_IMM(4/2, flags);
673         } else {
674                 EOP_MOV_REG_LSL(1, 6, 28);
675                 EOP_MSR_REG(1);
676                 hostreg_r[1] = -1;
677         }
678         dirty_regb |= KRREG_ST;
679 }
680
681 /* load 16bit val into host reg r0-r3. Nothing is trashed */
682 static void tr_mov16(int r, int val)
683 {
684         if (hostreg_r[r] != val) {
685                 emit_mov_const(A_COND_AL, r, val);
686                 hostreg_r[r] = val;
687         }
688 }
689
690 static void tr_mov16_cond(int cond, int r, int val)
691 {
692         emit_mov_const(cond, r, val);
693         hostreg_r[r] = -1;
694 }
695
696 /* read bank word to r0. Thrashes r1. */
697 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
698 {
699         int breg = 7;
700         if (addr > 0x7f) {
701                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
702                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
703                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
704                 }
705                 breg = 1;
706         }
707         EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1);    // ldrh r0, [r1, (op&0x7f)<<1]
708         hostreg_r[0] = -1;
709 }
710
711 /* write r0 to bank. Trashes r1. */
712 static void tr_bank_write(int addr)
713 {
714         int breg = 7;
715         if (addr > 0x7f) {
716                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
717                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
718                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
719                 }
720                 breg = 1;
721         }
722         EOP_STRH_IMM(0,breg,(addr&0x7f)<<1);            // strh r0, [r1, (op&0x7f)<<1]
723 }
724
725 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
726 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
727 {
728         int modulo_shift = -1;  /* unknown */
729
730         if (mod == 0) return;
731
732         if (!need_modulo || mod == 1) // +!
733                 modulo_shift = 8;
734         else if (need_modulo && (known_regb & KRREG_ST)) {
735                 modulo_shift = known_regs.gr[SSP_ST].h & 7;
736                 if (modulo_shift == 0) modulo_shift = 8;
737         }
738
739         if (modulo_shift == -1)
740         {
741                 int reg = (r < 4) ? 8 : 9;
742                 tr_release_pr(r);
743                 tr_flush_dirty_ST();
744                 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands  r1, r6, #0x70
745                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
746                 EOP_MOV_REG_LSR(1, 1, 4);               // mov r1, r1, lsr #4
747                 EOP_RSB_IMM(2, 1, 0, 8);                // rsb r1, r1, #8
748                 EOP_MOV_IMM(3, 8/2, count);             // mov r3, #0x01000000
749                 if (r&3)
750                         EOP_ADD_IMM(1, 1, 0, (r&3)*8);  // add r1, r1, #(r&3)*8
751                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
752                 if (mod == 2)
753                      EOP_SUB_REG2_LSL(reg,reg,3,2);     // sub reg, reg, #0x01000000 << r2
754                 else EOP_ADD_REG2_LSL(reg,reg,3,2);
755                 EOP_RSB_IMM(1, 1, 0, 32);               // rsb r1, r1, #32
756                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
757                 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
758         }
759         else if (known_regb & (1 << (r + 8)))
760         {
761                 int modulo = (1 << modulo_shift) - 1;
762                 if (mod == 2)
763                      known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
764                 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
765         }
766         else
767         {
768                 int reg = (r < 4) ? 8 : 9;
769                 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
770                 EOP_MOV_REG_ROR(reg,reg,ror);
771                 // {add|sub} reg, reg, #1<<shift
772                 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
773                 EOP_MOV_REG_ROR(reg,reg,32-ror);
774         }
775 }
776
777 /* handle writes r0 to (rX). Trashes r1.
778  * fortunately we can ignore modulo increment modes for writes. */
779 static void tr_rX_write1(int op)
780 {
781         if ((op&3) == 3)
782         {
783                 int mod = (op>>2) & 3; // direct addressing
784                 tr_bank_write((op & 0x100) + mod);
785         }
786         else
787         {
788                 int r = (op&3) | ((op>>6)&4);
789                 if (known_regb & (1 << (r + 8))) {
790                         tr_bank_write((op&0x100) | known_regs.r[r]);
791                 } else {
792                         int reg = (r < 4) ? 8 : 9;
793                         int ror = ((4 - (r&3))*8) & 0x1f;
794                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
795                         if (r >= 4)
796                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
797                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
798                         else     EOP_ADD_REG_LSL(1,7,1,1);
799                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
800                         hostreg_r[1] = -1;
801                 }
802                 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
803         }
804 }
805
806 /* read (rX) to r0. Trashes r1-r3. */
807 static void tr_rX_read(int r, int mod)
808 {
809         if ((r&3) == 3)
810         {
811                 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
812         }
813         else
814         {
815                 if (known_regb & (1 << (r + 8))) {
816                         tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
817                 } else {
818                         int reg = (r < 4) ? 8 : 9;
819                         int ror = ((4 - (r&3))*8) & 0x1f;
820                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
821                         if (r >= 4)
822                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
823                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
824                         else     EOP_ADD_REG_LSL(1,7,1,1);
825                         EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
826                         hostreg_r[1] = -1;
827                 }
828                 tr_ptrr_mod(r, mod, 1, 1);
829         }
830 }
831
832
833 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
834 static int tr_cond_check(int op)
835 {
836         int f = (op & 0x100) >> 8;
837         switch (op&0xf0) {
838                 case 0x00: return A_COND_AL;    /* always true */
839                 case 0x50:                      /* Z matches f(?) bit */
840                         if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
841                         EOP_TST_IMM(6, 0, 4);
842                         return f ? A_COND_NE : A_COND_EQ;
843                 case 0x70:                      /* N matches f(?) bit */
844                         if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
845                         EOP_TST_IMM(6, 0, 8);
846                         return f ? A_COND_NE : A_COND_EQ;
847                 default:
848                         printf("unimplemented cond?\n");
849                         tr_unhandled();
850                         return 0;
851         }
852 }
853
854 static int tr_neg_cond(int cond)
855 {
856         switch (cond) {
857                 case A_COND_AL: printf("neg for AL?\n"); exit(1);
858                 case A_COND_EQ: return A_COND_NE;
859                 case A_COND_NE: return A_COND_EQ;
860                 case A_COND_MI: return A_COND_PL;
861                 case A_COND_PL: return A_COND_MI;
862                 default:        printf("bad cond for neg\n"); exit(1);
863         }
864         return 0;
865 }
866
867 //      SSP_GR0, SSP_X,     SSP_Y,   SSP_A,
868 //      SSP_ST,  SSP_STACK, SSP_PC,  SSP_P,
869 //@ r4:  XXYY
870 //@ r5:  A
871 //@ r6:  STACK and emu flags
872 //@ r7:  SSP context
873 //@ r10: P
874
875 // read general reg to r0. Trashes r1
876 static void tr_GR0_to_r0(void)
877 {
878         tr_mov16(0, 0xffff);
879 }
880
881 static void tr_X_to_r0(void)
882 {
883         if (hostreg_r[0] != (SSP_X<<16)) {
884                 EOP_MOV_REG_LSR(0, 4, 16);      // mov  r0, r4, lsr #16
885                 hostreg_r[0] = SSP_X<<16;
886         }
887 }
888
889 static void tr_Y_to_r0(void)
890 {
891         // TODO..
892         if (hostreg_r[0] != (SSP_Y<<16)) {
893                 EOP_MOV_REG_SIMPLE(0, 4);       // mov  r0, r4
894                 hostreg_r[0] = SSP_Y<<16;
895         }
896 }
897
898 static void tr_A_to_r0(void)
899 {
900         if (hostreg_r[0] != (SSP_A<<16)) {
901                 EOP_MOV_REG_LSR(0, 5, 16);      // mov  r0, r5, lsr #16  @ AH
902                 hostreg_r[0] = SSP_A<<16;
903         }
904 }
905
906 static void tr_ST_to_r0(void)
907 {
908         // VR doesn't need much accuracy here..
909         EOP_MOV_REG_LSR(0, 6, 4);               // mov  r0, r6, lsr #4
910         EOP_AND_IMM(0, 0, 0, 0x67);             // and  r0, r0, #0x67
911         hostreg_r[0] = -1;
912 }
913
914 static void tr_STACK_to_r0(void)
915 {
916         // 448
917         EOP_SUB_IMM(6, 6,  8/2, 0x20);          // sub  r6, r6, #1<<29
918         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
919         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
920         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
921         EOP_LDRH_SIMPLE(0, 1);                  // ldrh r0, [r1]
922         hostreg_r[0] = hostreg_r[1] = -1;
923 }
924
925 static void tr_PC_to_r0(void)
926 {
927         tr_mov16(0, known_regs.gr[SSP_PC].h);
928 }
929
930 static void tr_P_to_r0(void)
931 {
932         tr_flush_dirty_P();
933         EOP_MOV_REG_LSR(0, 10, 16);             // mov  r0, r10, lsr #16
934         hostreg_r[0] = -1;
935 }
936
937 typedef void (tr_read_func)(void);
938
939 static tr_read_func *tr_read_funcs[8] =
940 {
941         tr_GR0_to_r0,
942         tr_X_to_r0,
943         tr_Y_to_r0,
944         tr_A_to_r0,
945         tr_ST_to_r0,
946         tr_STACK_to_r0,
947         tr_PC_to_r0,
948         tr_P_to_r0
949 };
950
951
952 // write r0 to general reg handlers. Trashes r1
953 #define TR_WRITE_R0_TO_REG(reg) \
954 { \
955         hostreg_sspreg_changed(reg); \
956         hostreg_r[0] = (reg)<<16; \
957         if (const_val != -1) { \
958                 known_regs.gr[reg].h = const_val; \
959                 known_regb |= 1 << (reg); \
960         } else { \
961                 known_regb &= ~(1 << (reg)); \
962         } \
963 }
964
965 static void tr_r0_to_GR0(int const_val)
966 {
967         // do nothing
968 }
969
970 static void tr_r0_to_X(int const_val)
971 {
972         EOP_MOV_REG_LSL(4, 4, 16);              // mov  r4, r4, lsl #16
973         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
974         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
975         dirty_regb |= KRREG_P;                  // touching X or Y makes P dirty.
976         TR_WRITE_R0_TO_REG(SSP_X);
977 }
978
979 static void tr_r0_to_Y(int const_val)
980 {
981         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
982         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
983         EOP_MOV_REG_ROR(4, 4, 16);              // mov  r4, r4, ror #16
984         dirty_regb |= KRREG_P;
985         TR_WRITE_R0_TO_REG(SSP_Y);
986 }
987
988 static void tr_r0_to_A(int const_val)
989 {
990         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
991         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16  @ AL
992         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
993         TR_WRITE_R0_TO_REG(SSP_A);
994 }
995
996 static void tr_r0_to_ST(int const_val)
997 {
998         // VR doesn't need much accuracy here..
999         EOP_AND_IMM(1, 0,   0, 0x67);           // and   r1, r0, #0x67
1000         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
1001         EOP_ORR_REG_LSL(6, 6, 1, 4);            // orr   r6, r6, r1, lsl #4
1002         TR_WRITE_R0_TO_REG(SSP_ST);
1003         hostreg_r[1] = -1;
1004         dirty_regb &= ~KRREG_ST;
1005 }
1006
1007 static void tr_r0_to_STACK(int const_val)
1008 {
1009         // 448
1010         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
1011         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
1012         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
1013         EOP_STRH_SIMPLE(0, 1);                  // strh r0, [r1]
1014         EOP_ADD_IMM(6, 6,  8/2, 0x20);          // add  r6, r6, #1<<29
1015         hostreg_r[1] = -1;
1016 }
1017
1018 static void tr_r0_to_PC(int const_val)
1019 {
1020         EOP_MOV_REG_LSL(1, 0, 16);              // mov  r1, r0, lsl #16
1021         EOP_STR_IMM(1,7,0x400+6*4);             // str  r1, [r7, #(0x400+6*8)]
1022         hostreg_r[1] = -1;
1023 }
1024
1025 typedef void (tr_write_func)(int const_val);
1026
1027 static tr_write_func *tr_write_funcs[8] =
1028 {
1029         tr_r0_to_GR0,
1030         tr_r0_to_X,
1031         tr_r0_to_Y,
1032         tr_r0_to_A,
1033         tr_r0_to_ST,
1034         tr_r0_to_STACK,
1035         tr_r0_to_PC,
1036         (tr_write_func *)tr_unhandled
1037 };
1038
1039
1040 static int translate_op(unsigned int op, int *pc, int imm)
1041 {
1042         u32 tmpv, tmpv2;
1043         int ret = 0;
1044         known_regs.gr[SSP_PC].h = *pc;
1045
1046         switch (op >> 9)
1047         {
1048                 // ld d, s
1049                 case 0x00:
1050                         if (op == 0) { ret++; break; } // nop
1051                         tmpv  = op & 0xf; // src
1052                         tmpv2 = (op >> 4) & 0xf; // dst
1053                         if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
1054                         if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1055                                 tr_flush_dirty_P();
1056                                 EOP_MOV_REG_SIMPLE(5, 10);
1057                                 hostreg_sspreg_changed(SSP_A); \
1058                                 known_regb &= ~(KRREG_A|KRREG_AL);
1059                                 ret++; break;
1060                         }
1061                         tr_read_funcs[tmpv]();
1062                         tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1063                         ret++; break;
1064
1065                 // ld d, (ri)
1066                 case 0x01: {
1067                         // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1068                         int r = (op&3) | ((op>>6)&4);
1069                         int mod = (op>>2)&3;
1070                         tmpv = (op >> 4) & 0xf; // dst
1071                         if (tmpv >= 8) return -1; // TODO
1072                         if (tmpv != 0)
1073                              tr_rX_read(r, mod);
1074                         else tr_ptrr_mod(r, mod, 1, 1);
1075                         tr_write_funcs[tmpv](-1);
1076                         ret++; break;
1077                 }
1078
1079                 // ld (ri), s
1080                 case 0x02:
1081                         tmpv = (op >> 4) & 0xf; // src
1082                         if (tmpv >= 8) return -1; // TODO
1083                         tr_read_funcs[tmpv]();
1084                         tr_rX_write1(op);
1085                         ret++; break;
1086
1087                 // ld a, adr
1088                 case 0x03:
1089                         tr_bank_read(op&0x1ff);
1090                         tr_r0_to_A(-1);
1091                         ret++; break;
1092
1093                 // ldi d, imm
1094                 case 0x04:
1095                         tmpv = (op & 0xf0) >> 4;
1096                         if (tmpv < 8)
1097                         {
1098                                 tr_mov16(0, imm);
1099                                 tr_write_funcs[tmpv](imm);
1100                                 ret += 2; break;
1101                         }
1102                         else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1103                         {
1104                                 // programming PMC..
1105                                 (*pc)++;
1106                                 tmpv = imm | (PROGRAM((*pc)++) << 16);
1107                                 ret += 2;
1108                                 emit_mov_const(A_COND_AL, 0, tmpv);
1109                                 EOP_LDR_IMM(1,7,0x484);         // ldr r1, [r7, #0x484] // emu_status
1110                                 EOP_STR_IMM(0,7,0x400+14*4);    // PMC
1111                                 // reads on fe06, fe08; next op is ld -,
1112                                 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1113                                 {
1114                                         int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1115                                         tr_flush_dirty_ST();
1116                                         EOP_LDR_IMM(0,7,0x490); // dram_ptr
1117                                         EOP_ADD_IMM(0,0,24/2,0xfe);                             // add  r0, r0, #0xfe00
1118                                         EOP_LDRH_IMM(0,0,(tmpv == 0x187f03) ? 6 : 8);           // ldrh r0, [r0, #8]
1119                                         EOP_TST_REG_SIMPLE(0,0);
1120                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1);       // add r11, r11, #1024
1121                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1122                                 }
1123                                 EOP_ORR_IMM(1,1,0,SSP_PMC_SET);         // orr r1, r1, #SSP_PMC_SET
1124                                 EOP_STR_IMM(1,7,0x484);                 // str r1, [r7, #0x484] // emu_status
1125                                 hostreg_r[0] = hostreg_r[1] = -1;
1126                                 ret += 2; break;
1127                         }
1128                         else
1129                                 return -1;      /* TODO.. */
1130
1131                 // ld d, ((ri))
1132                 case 0x05: {
1133                         int r;
1134                         r = (op&3) | ((op>>6)&4); // src
1135                         tmpv2 = (op >> 4) & 0xf;  // dst
1136                         if (tmpv2 >= 8) return -1; // TODO
1137
1138                         if ((r&3) == 3) {
1139                                 tr_bank_read((op&0x100) | ((op>>2)&3));
1140                         } else if (known_regb & (1 << (r+8))) {
1141                                 tr_bank_read((op&0x100) | known_regs.r[r]);
1142                         } else {
1143                                 int reg = (r < 4) ? 8 : 9;
1144                                 int ror = ((4 - (r&3))*8) & 0x1f;
1145                                 EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
1146                                 if (r >= 4)
1147                                         EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
1148                                 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
1149                                 else     EOP_ADD_REG_LSL(1,7,1,1);
1150                                 EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
1151                         }
1152                         EOP_LDR_IMM(2,7,0x48c);                                 // ptr_iram_rom
1153                         EOP_ADD_REG_LSL(2,2,0,1);                               // add  r2, r2, r0, lsl #1
1154                         EOP_ADD_IMM(0,0,0,1);                                   // add  r0, r0, #1
1155                         if ((r&3) == 3) {
1156                                 tr_bank_write((op&0x100) | ((op>>2)&3));
1157                         } else if (known_regb & (1 << (r+8))) {
1158                                 tr_bank_write((op&0x100) | known_regs.r[r]);
1159                         } else {
1160                                 EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
1161                                 hostreg_r[1] = -1;
1162                         }
1163                         EOP_LDRH_SIMPLE(0,2);                                   // ldrh r0, [r2]
1164                         hostreg_r[0] = hostreg_r[2] = -1;
1165                         tr_write_funcs[tmpv2](-1);
1166                         ret += 3; break; /* should certainly take > 1 */
1167                 }
1168
1169                 // ldi (ri), imm
1170                 case 0x06:
1171                         tr_mov16(0, imm);
1172                         tr_rX_write1(op);
1173                         ret += 2; break;
1174
1175                 // ld adr, a
1176                 case 0x07:
1177                         tr_A_to_r0();
1178                         tr_bank_write(op&0x1ff);
1179                         ret++; break;
1180
1181                 // ld d, ri
1182                 case 0x09: {
1183                         int r;
1184                         r = (op&3) | ((op>>6)&4); // src
1185                         tmpv2 = (op >> 4) & 0xf;  // dst
1186                         if (tmpv2 >= 8) tr_unhandled();
1187                         if ((r&3) == 3) tr_unhandled();
1188
1189                         if (known_regb & (1 << (r+8))) {
1190                                 tr_mov16(0, known_regs.r[r]);
1191                                 tr_write_funcs[tmpv2](known_regs.r[r]);
1192                         } else {
1193                                 int reg = (r < 4) ? 8 : 9;
1194                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1195                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1196                                 hostreg_r[0] = -1;
1197                                 tr_write_funcs[tmpv2](-1);
1198                         }
1199                         ret++; break;
1200                 }
1201
1202                 // ld ri, s
1203                 case 0x0a: {
1204                         int r;
1205                         r = (op&3) | ((op>>6)&4); // dst
1206                         tmpv = (op >> 4) & 0xf;   // src
1207                         if (tmpv >= 8)  tr_unhandled();
1208                         if ((r&3) == 3) tr_unhandled();
1209
1210                         if (known_regb & (1 << tmpv)) {
1211                                 known_regs.r[r] = known_regs.gr[tmpv].h;
1212                                 known_regb |= 1 << (r + 8);
1213                                 dirty_regb |= 1 << (r + 8);
1214                         } else {
1215                                 int reg = (r < 4) ? 8 : 9;
1216                                 int ror = ((4 - (r&3))*8) & 0x1f;
1217                                 tr_read_funcs[tmpv]();
1218                                 EOP_BIC_IMM(reg, reg, ror/2, 0xff);             // bic r{7,8}, r{7,8}, <mask>
1219                                 EOP_AND_IMM(0, 0, 0, 0xff);                     // and r0, r0, 0xff
1220                                 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8);          // orr r{7,8}, r{7,8}, r0, lsl #lsl
1221                                 hostreg_r[0] = -1;
1222                                 known_regb &= ~(1 << (r+8));
1223                                 dirty_regb &= ~(1 << (r+8));
1224                         }
1225                         ret++; break;
1226                 }
1227
1228                 // ldi ri, simm
1229                 case 0x0c ... 0x0f:
1230                         tmpv = (op>>8)&7;
1231                         known_regs.r[tmpv] = op;
1232                         known_regb |= 1 << (tmpv + 8);
1233                         dirty_regb |= 1 << (tmpv + 8);
1234                         ret++; break;
1235
1236                 // call cond, addr
1237                 case 0x24: {
1238                         u32 *jump_op = NULL;
1239                         tmpv = tr_cond_check(op);
1240                         if (tmpv != A_COND_AL) {
1241                                 jump_op = tcache_ptr;
1242                                 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1243                         }
1244                         tr_mov16(0, *pc);
1245                         tr_r0_to_STACK(*pc);
1246                         if (tmpv != A_COND_AL) {
1247                                 u32 *real_ptr = tcache_ptr;
1248                                 tcache_ptr = jump_op;
1249                                 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1250                                 tcache_ptr = real_ptr;
1251                         }
1252                         tr_mov16_cond(tmpv, 0, imm);
1253                         if (tmpv != A_COND_AL) {
1254                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1255                         }
1256                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1257                         ret += 2; break;
1258                 }
1259
1260                 // ld d, (a)
1261                 case 0x25:
1262                         tmpv2 = (op >> 4) & 0xf;  // dst
1263                         if (tmpv2 >= 8) return -1; // TODO
1264
1265                         tr_A_to_r0();
1266                         EOP_LDR_IMM(1,7,0x48c);                                 // ptr_iram_rom
1267                         EOP_ADD_REG_LSL(0,1,0,1);                               // add  r0, r1, r0, lsl #1
1268                         EOP_LDRH_SIMPLE(0,0);                                   // ldrh r0, [r0]
1269                         hostreg_r[0] = hostreg_r[1] = -1;
1270                         tr_write_funcs[tmpv2](-1);
1271                         ret += 3; break;
1272
1273                 // bra cond, addr
1274                 case 0x26:
1275                         tmpv = tr_cond_check(op);
1276                         tr_mov16_cond(tmpv, 0, imm);
1277                         if (tmpv != A_COND_AL) {
1278                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1279                         }
1280                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1281                         ret += 2; break;
1282
1283                 // mod cond, op
1284                 case 0x48: {
1285                         // check for repeats of this op
1286                         tmpv = 1; // count
1287                         while (PROGRAM(*pc) == op && (op & 7) != 6) {
1288                                 (*pc)++; tmpv++;
1289                         }
1290                         if ((op&0xf0) != 0) // !always
1291                                 tr_make_dirty_ST();
1292
1293                         tmpv2 = tr_cond_check(op);
1294                         switch (op & 7) {
1295                                 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1296                                 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1297                                 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1298                                 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
1299                                         EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1300                                         hostreg_r[1] = -1; break; // abs
1301                                 default: tr_unhandled();
1302                         }
1303
1304                         hostreg_sspreg_changed(SSP_A);
1305                         dirty_regb |=  KRREG_ST;
1306                         known_regb &= ~KRREG_ST;
1307                         known_regb &= ~(KRREG_A|KRREG_AL);
1308                         ret += tmpv; break;
1309                 }
1310 /*
1311                 // mpys?
1312                 case 0x1b:
1313                         read_P(); // update P
1314                         rA32 -= rP.v;                   // maybe only upper word?
1315                         UPD_ACC_ZN                      // there checking flags after this
1316                         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1317                         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1318                         break;
1319
1320                 // mpya (rj), (ri), b
1321                 case 0x4b:
1322                         read_P(); // update P
1323                         rA32 += rP.v; // confirmed to be 32bit
1324                         UPD_ACC_ZN // ?
1325                         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1326                         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1327                         break;
1328
1329                 // mld (rj), (ri), b
1330                 case 0x5b:
1331                         EOP_MOV_IMM(5, 0, 0);                   // mov r5, #0
1332                         known_regs.r[SSP_A].v = 0;
1333                         known_regb |= (KRREG_A|KRREG_AL);
1334                         EOP_BIC_IMM(6, 6, 0, 0x0f);             // bic r6, r6, 0xf // flags
1335                         EOP_BIC_IMM(6, 6, 0, 0x04);             // bic r6, r6, 4 // set Z
1336                         // TODO
1337                         ret++; break;
1338 */
1339         }
1340
1341         return ret;
1342 }
1343
1344 static void *translate_block(int pc)
1345 {
1346         unsigned int op, op1, imm, ccount = 0;
1347         unsigned int *block_start;
1348         int ret, ret_prev = -1;
1349
1350         // create .pool
1351         //*tcache_ptr++ = (u32) in_funcs;                       // -1 func pool
1352
1353         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1354         block_start = tcache_ptr;
1355         known_regb = 0;
1356         dirty_regb = KRREG_P;
1357         hostreg_clear();
1358
1359         emit_block_prologue();
1360
1361         for (; ccount < 100;)
1362         {
1363                 //printf("  insn #%i\n", icount);
1364                 op = PROGRAM(pc++);
1365                 op1 = op >> 9;
1366                 imm = (u32)-1;
1367
1368                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1369                         imm = PROGRAM(pc++); // immediate
1370
1371                 ret = translate_op(op, &pc, imm);
1372                 if (ret <= 0)
1373                 {
1374                         tr_flush_dirty_prs();
1375                         tr_flush_dirty_ST();
1376
1377                         emit_mov_const(A_COND_AL, 0, op);
1378
1379                         // need immediate?
1380                         if (imm != (u32)-1)
1381                                 emit_mov_const(A_COND_AL, 1, imm);
1382
1383                         // dump PC
1384                         emit_pc_dump(pc);
1385
1386                         if (ret_prev > 0) emit_call(regfile_store);
1387                         emit_call(in_funcs[op1]);
1388                         emit_call(regfile_load);
1389
1390                         if (in_funcs[op1] == NULL) {
1391                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
1392                                 exit(1);
1393                         }
1394                         ccount++;
1395                         hostreg_clear();
1396                         dirty_regb |= KRREG_P;
1397                         known_regb = 0;
1398                 }
1399                 else
1400                         ccount += ret;
1401
1402                 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1403                         ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1404                                 (op & 0xf0) == 0x60)) { // ld PC
1405                         break;
1406                 }
1407                 ret_prev = ret;
1408         }
1409
1410         tr_flush_dirty_prs();
1411         tr_flush_dirty_ST();
1412         emit_block_epilogue(ccount + 1);
1413         *tcache_ptr++ = 0xffffffff; // end of block
1414         //printf("  %i inst\n", icount);
1415
1416         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1417                 printf("tcache overflow!\n");
1418                 fflush(stdout);
1419                 exit(1);
1420         }
1421
1422         // stats
1423         nblocks++;
1424         //if (pc >= 0x400)
1425         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1426         //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1427
1428 #ifdef DUMP_BLOCK
1429         {
1430                 FILE *f = fopen("tcache.bin", "wb");
1431                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1432                 fclose(f);
1433         }
1434         exit(0);
1435 #endif
1436
1437         handle_caches();
1438
1439         return block_start;
1440 }
1441
1442
1443
1444 // -----------------------------------------------------
1445
1446 int ssp1601_dyn_startup(void)
1447 {
1448         memset(tcache, 0, TCACHE_SIZE);
1449         memset(block_table, 0, sizeof(block_table));
1450         memset(block_table_iram, 0, sizeof(block_table_iram));
1451         tcache_ptr = tcache;
1452         *tcache_ptr++ = 0xffffffff;
1453
1454 // TODO: rm
1455 {
1456 static unsigned short dummy = 0;
1457 PC = &dummy;
1458 }
1459         return 0;
1460 }
1461
1462
1463 void ssp1601_dyn_reset(ssp1601_t *ssp)
1464 {
1465         ssp1601_reset_local(ssp);
1466         ssp->ptr_rom = (unsigned int) Pico.rom;
1467         ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1468         ssp->ptr_dram = (unsigned int) svp->dram;
1469 }
1470
1471 void ssp1601_dyn_run(int cycles)
1472 {
1473         if (ssp->emu_status & SSP_WAIT_MASK) return;
1474         //{ printf("%i wait\n", Pico.m.frame_count); return; }
1475         //printf("%i  %04x\n", Pico.m.frame_count, rPC<<1);
1476
1477 #ifdef DUMP_BLOCK
1478         rPC = DUMP_BLOCK >> 1;
1479 #endif
1480         while (cycles > 0)
1481         {
1482                 int (*trans_entry)(void);
1483                 if (rPC < 0x800/2)
1484                 {
1485                         if (iram_dirty) {
1486                                 iram_context = get_iram_context();
1487                                 iram_dirty--;
1488                         }
1489                         if (block_table_iram[iram_context][rPC] == NULL)
1490                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
1491                         trans_entry = (void *) block_table_iram[iram_context][rPC];
1492                 }
1493                 else
1494                 {
1495                         if (block_table[rPC] == NULL)
1496                                 block_table[rPC] = translate_block(rPC);
1497                         trans_entry = (void *) block_table[rPC];
1498                 }
1499
1500                 //printf("enter %04x\n", rPC<<1);
1501                 cycles -= trans_entry();
1502                 //printf("leave %04x\n", rPC<<1);
1503         }
1504 //      debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1505 //      exit(1);
1506 }
1507