svp compiler: ops completed? last ver. with interpreter built in
[picodrive.git] / Pico / carthw / svp / compiler.c
1
2 #include "../../PicoInt.h"
3 #include "compiler.h"
4
5 static unsigned int *block_table[0x5090/2];
6 static unsigned int *block_table_iram[15][0x800/2];
7 static unsigned int *tcache_ptr = NULL;
8
9 static int nblocks = 0;
10 static int iram_context = 0;
11
12 #ifndef ARM
13 #define DUMP_BLOCK 0x0c9a
14 unsigned int tcache[512*1024];
15 void regfile_load(void){}
16 void regfile_store(void){}
17 #endif
18
19 #define EMBED_INTERPRETER
20 #define ssp1601_reset ssp1601_reset_local
21 #define ssp1601_run ssp1601_run_local
22
23 #define GET_PC() rPC
24 #define GET_PPC_OFFS() (GET_PC()*2 - 2)
25 #define SET_PC(d) { rPC = d; }          /* must return to dispatcher after this */
26 //#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
27 //#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
28 //#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
29
30 #include "ssp16.c"
31 #include "gen_arm.c"
32
33 // -----------------------------------------------------
34
35 // ld d, s
36 static void op00(unsigned int op, unsigned int imm)
37 {
38         unsigned int tmpv;
39         PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
40         if (op == 0) return; // nop
41         if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
42                 // not sure. MAME claims that only hi word is transfered.
43                 read_P(); // update P
44                 rA32 = rP.v;
45         }
46         else
47         {
48                 tmpv = REG_READ(op & 0x0f);
49                 REG_WRITE((op & 0xf0) >> 4, tmpv);
50         }
51 }
52
53 // ld d, (ri)
54 static void op01(unsigned int op, unsigned int imm)
55 {
56         unsigned int tmpv;
57         tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
58 }
59
60 // ld (ri), s
61 static void op02(unsigned int op, unsigned int imm)
62 {
63         unsigned int tmpv;
64         tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
65 }
66
67 // ldi d, imm
68 static void op04(unsigned int op, unsigned int imm)
69 {
70         REG_WRITE((op & 0xf0) >> 4, imm);
71 }
72
73 // ld d, ((ri))
74 static void op05(unsigned int op, unsigned int imm)
75 {
76         unsigned int tmpv;
77         tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
78 }
79
80 // ldi (ri), imm
81 static void op06(unsigned int op, unsigned int imm)
82 {
83         ptr1_write(op, imm);
84 }
85
86 // ld adr, a
87 static void op07(unsigned int op, unsigned int imm)
88 {
89         ssp->RAM[op & 0x1ff] = rA;
90 }
91
92 // ld d, ri
93 static void op09(unsigned int op, unsigned int imm)
94 {
95         unsigned int tmpv;
96         tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
97 }
98
99 // ld ri, s
100 static void op0a(unsigned int op, unsigned int imm)
101 {
102         rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
103 }
104
105 // ldi ri, simm (also op0d op0e op0f)
106 static void op0c(unsigned int op, unsigned int imm)
107 {
108         rIJ[(op>>8)&7] = op;
109 }
110
111 // call cond, addr
112 static void op24(unsigned int op, unsigned int imm)
113 {
114         int cond = 0;
115         do {
116                 COND_CHECK
117                 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
118         }
119         while (0);
120 }
121
122 // ld d, (a)
123 static void op25(unsigned int op, unsigned int imm)
124 {
125         unsigned int tmpv;
126         tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
127 }
128
129 // bra cond, addr
130 static void op26(unsigned int op, unsigned int imm)
131 {
132         do
133         {
134                 int cond = 0;
135                 COND_CHECK
136                 if (cond) SET_PC(imm);
137         }
138         while (0);
139 }
140
141 // mod cond, op
142 static void op48(unsigned int op, unsigned int imm)
143 {
144         do
145         {
146                 int cond = 0;
147                 COND_CHECK
148                 if (cond) {
149                         switch (op & 7) {
150                                 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
151                                 case 3: rA32 <<= 1; break; // shl
152                                 case 6: rA32 = -(signed int)rA32; break; // neg
153                                 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
154                                 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
155                                                          op&7, GET_PPC_OFFS());
156                         }
157                         UPD_ACC_ZN // ?
158                 }
159         }
160         while(0);
161 }
162
163 // mpys?
164 static void op1b(unsigned int op, unsigned int imm)
165 {
166         read_P(); // update P
167         rA32 -= rP.v;                   // maybe only upper word?
168         UPD_ACC_ZN                      // there checking flags after this
169         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
170         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
171 }
172
173 // mpya (rj), (ri), b
174 static void op4b(unsigned int op, unsigned int imm)
175 {
176         read_P(); // update P
177         rA32 += rP.v; // confirmed to be 32bit
178         UPD_ACC_ZN // ?
179         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
180         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
181 }
182
183 // mld (rj), (ri), b
184 static void op5b(unsigned int op, unsigned int imm)
185 {
186         rA32 = 0;
187         rST &= 0x0fff; // ?
188         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
189         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
190 }
191
192 // OP a, s
193 static void op10(unsigned int op, unsigned int imm)
194 {
195         do
196         {
197                 unsigned int tmpv;
198                 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
199         }
200         while(0);
201 }
202
203 static void op30(unsigned int op, unsigned int imm)
204 {
205         do
206         {
207                 unsigned int tmpv;
208                 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
209         }
210         while(0);
211 }
212
213 static void op40(unsigned int op, unsigned int imm)
214 {
215         do
216         {
217                 unsigned int tmpv;
218                 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
219         }
220         while(0);
221 }
222
223 static void op50(unsigned int op, unsigned int imm)
224 {
225         do
226         {
227                 unsigned int tmpv;
228                 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
229         }
230         while(0);
231 }
232
233 static void op60(unsigned int op, unsigned int imm)
234 {
235         do
236         {
237                 unsigned int tmpv;
238                 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
239         }
240         while(0);
241 }
242
243 static void op70(unsigned int op, unsigned int imm)
244 {
245         do
246         {
247                 unsigned int tmpv;
248                 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
249         }
250         while(0);
251 }
252
253 // OP a, (ri)
254 static void op11(unsigned int op, unsigned int imm)
255 {
256         unsigned int tmpv;
257         tmpv = ptr1_read(op); OP_SUBA(tmpv);
258 }
259
260 static void op31(unsigned int op, unsigned int imm)
261 {
262         unsigned int tmpv;
263         tmpv = ptr1_read(op); OP_CMPA(tmpv);
264 }
265
266 static void op41(unsigned int op, unsigned int imm)
267 {
268         unsigned int tmpv;
269         tmpv = ptr1_read(op); OP_ADDA(tmpv);
270 }
271
272 static void op51(unsigned int op, unsigned int imm)
273 {
274         unsigned int tmpv;
275         tmpv = ptr1_read(op); OP_ANDA(tmpv);
276 }
277
278 static void op61(unsigned int op, unsigned int imm)
279 {
280         unsigned int tmpv;
281         tmpv = ptr1_read(op); OP_ORA (tmpv);
282 }
283
284 static void op71(unsigned int op, unsigned int imm)
285 {
286         unsigned int tmpv;
287         tmpv = ptr1_read(op); OP_EORA(tmpv);
288 }
289
290 // OP a, adr
291 static void op03(unsigned int op, unsigned int imm)
292 {
293         unsigned int tmpv;
294         tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
295 }
296
297 static void op13(unsigned int op, unsigned int imm)
298 {
299         unsigned int tmpv;
300         tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
301 }
302
303 static void op33(unsigned int op, unsigned int imm)
304 {
305         unsigned int tmpv;
306         tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
307 }
308
309 static void op43(unsigned int op, unsigned int imm)
310 {
311         unsigned int tmpv;
312         tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
313 }
314
315 static void op53(unsigned int op, unsigned int imm)
316 {
317         unsigned int tmpv;
318         tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
319 }
320
321 static void op63(unsigned int op, unsigned int imm)
322 {
323         unsigned int tmpv;
324         tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
325 }
326
327 static void op73(unsigned int op, unsigned int imm)
328 {
329         unsigned int tmpv;
330         tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
331 }
332
333 // OP a, imm
334 static void op14(unsigned int op, unsigned int imm)
335 {
336         OP_SUBA(imm);
337 }
338
339 static void op34(unsigned int op, unsigned int imm)
340 {
341         OP_CMPA(imm);
342 }
343
344 static void op44(unsigned int op, unsigned int imm)
345 {
346         OP_ADDA(imm);
347 }
348
349 static void op54(unsigned int op, unsigned int imm)
350 {
351         OP_ANDA(imm);
352 }
353
354 static void op64(unsigned int op, unsigned int imm)
355 {
356         OP_ORA (imm);
357 }
358
359 static void op74(unsigned int op, unsigned int imm)
360 {
361         OP_EORA(imm);
362 }
363
364 // OP a, ((ri))
365 static void op15(unsigned int op, unsigned int imm)
366 {
367         unsigned int tmpv;
368         tmpv = ptr2_read(op); OP_SUBA(tmpv);
369 }
370
371 static void op35(unsigned int op, unsigned int imm)
372 {
373         unsigned int tmpv;
374         tmpv = ptr2_read(op); OP_CMPA(tmpv);
375 }
376
377 static void op45(unsigned int op, unsigned int imm)
378 {
379         unsigned int tmpv;
380         tmpv = ptr2_read(op); OP_ADDA(tmpv);
381 }
382
383 static void op55(unsigned int op, unsigned int imm)
384 {
385         unsigned int tmpv;
386         tmpv = ptr2_read(op); OP_ANDA(tmpv);
387 }
388
389 static void op65(unsigned int op, unsigned int imm)
390 {
391         unsigned int tmpv;
392         tmpv = ptr2_read(op); OP_ORA (tmpv);
393 }
394
395 static void op75(unsigned int op, unsigned int imm)
396 {
397         unsigned int tmpv;
398         tmpv = ptr2_read(op); OP_EORA(tmpv);
399 }
400
401 // OP a, ri
402 static void op19(unsigned int op, unsigned int imm)
403 {
404         unsigned int tmpv;
405         tmpv = rIJ[IJind]; OP_SUBA(tmpv);
406 }
407
408 static void op39(unsigned int op, unsigned int imm)
409 {
410         unsigned int tmpv;
411         tmpv = rIJ[IJind]; OP_CMPA(tmpv);
412 }
413
414 static void op49(unsigned int op, unsigned int imm)
415 {
416         unsigned int tmpv;
417         tmpv = rIJ[IJind]; OP_ADDA(tmpv);
418 }
419
420 static void op59(unsigned int op, unsigned int imm)
421 {
422         unsigned int tmpv;
423         tmpv = rIJ[IJind]; OP_ANDA(tmpv);
424 }
425
426 static void op69(unsigned int op, unsigned int imm)
427 {
428         unsigned int tmpv;
429         tmpv = rIJ[IJind]; OP_ORA (tmpv);
430 }
431
432 static void op79(unsigned int op, unsigned int imm)
433 {
434         unsigned int tmpv;
435         tmpv = rIJ[IJind]; OP_EORA(tmpv);
436 }
437
438 // OP simm
439 static void op1c(unsigned int op, unsigned int imm)
440 {
441         OP_SUBA(op & 0xff);
442 }
443
444 static void op3c(unsigned int op, unsigned int imm)
445 {
446         OP_CMPA(op & 0xff);
447 }
448
449 static void op4c(unsigned int op, unsigned int imm)
450 {
451         OP_ADDA(op & 0xff);
452 }
453
454 static void op5c(unsigned int op, unsigned int imm)
455 {
456         OP_ANDA(op & 0xff);
457 }
458
459 static void op6c(unsigned int op, unsigned int imm)
460 {
461         OP_ORA (op & 0xff);
462 }
463
464 static void op7c(unsigned int op, unsigned int imm)
465 {
466         OP_EORA(op & 0xff);
467 }
468
469 typedef void (in_func)(unsigned int op, unsigned int imm);
470
471 static in_func *in_funcs[0x80] =
472 {
473         op00, op01, op02, op03, op04, op05, op06, op07,
474         NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
475         op10, op11, NULL, op13, op14, op15, NULL, NULL,
476         NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
477         NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
478         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
479         op30, op31, NULL, op33, op34, op35, NULL, NULL,
480         NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
481         op40, op41, NULL, op43, op44, op45, NULL, NULL,
482         op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
483         op50, op51, NULL, op53, op54, op55, NULL, NULL,
484         NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
485         op60, op61, NULL, op63, op64, op65, NULL, NULL,
486         NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
487         op70, op71, NULL, op73, op74, op75, NULL, NULL,
488         NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
489 };
490
491
492 static u32 ssp_pm_read(int reg)
493 {
494         u32 d = 0, mode;
495
496         if (ssp->emu_status & SSP_PMC_SET)
497         {
498                 ssp->pmac_read[reg] = rPMC.v;
499                 ssp->emu_status &= ~SSP_PMC_SET;
500                 return 0;
501         }
502
503         // just in case
504         ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
505
506         mode = ssp->pmac_read[reg]>>16;
507         if      ((mode & 0xfff0) == 0x0800) // ROM
508         {
509                 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
510                 ssp->pmac_read[reg] += 1;
511         }
512         else if ((mode & 0x47ff) == 0x0018) // DRAM
513         {
514                 unsigned short *dram = (unsigned short *)svp->dram;
515                 int inc = get_inc(mode);
516                 d = dram[ssp->pmac_read[reg]&0xffff];
517                 ssp->pmac_read[reg] += inc;
518         }
519
520         // PMC value corresponds to last PMR accessed
521         rPMC.v = ssp->pmac_read[reg];
522
523         return d;
524 }
525
526 static void ssp_pm_write(u32 d, int reg)
527 {
528         unsigned short *dram;
529         int mode, addr;
530
531         if (ssp->emu_status & SSP_PMC_SET)
532         {
533                 ssp->pmac_write[reg] = rPMC.v;
534                 ssp->emu_status &= ~SSP_PMC_SET;
535                 return;
536         }
537
538         // just in case
539         ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
540
541         dram = (unsigned short *)svp->dram;
542         mode = ssp->pmac_write[reg]>>16;
543         addr = ssp->pmac_write[reg]&0xffff;
544         if      ((mode & 0x43ff) == 0x0018) // DRAM
545         {
546                 int inc = get_inc(mode);
547                 if (mode & 0x0400) {
548                        overwrite_write(dram[addr], d);
549                 } else dram[addr] = d;
550                 ssp->pmac_write[reg] += inc;
551         }
552         else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
553         {
554                 if (mode & 0x0400) {
555                        overwrite_write(dram[addr], d);
556                 } else dram[addr] = d;
557                 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
558         }
559         else if ((mode & 0x47ff) == 0x001c) // IRAM
560         {
561                 int inc = get_inc(mode);
562                 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
563                 ssp->pmac_write[reg] += inc;
564                 ssp->drc.iram_dirty = 1;
565         }
566
567         rPMC.v = ssp->pmac_write[reg];
568 }
569
570
571 // -----------------------------------------------------
572
573 // 14 IRAM blocks
574 static unsigned char iram_context_map[] =
575 {
576          0, 0, 0, 0, 1, 0, 0, 0, // 04
577          0, 0, 0, 0, 0, 0, 2, 0, // 0e
578          0, 0, 0, 0, 0, 3, 0, 4, // 15 17
579          5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
580          8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
581          0, 0, 0, 0, 0, 0, 0, 0,
582          0, 0,11, 0, 0,12, 0, 0, // 32 35
583         13,14, 0, 0, 0, 0, 0, 0  // 38 39
584 };
585
586 static int get_iram_context(void)
587 {
588         unsigned char *ir = (unsigned char *)svp->iram_rom;
589         int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
590         val1 = iram_context_map[(val>>1)&0x3f];
591
592         if (val1 == 0) {
593                 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
594                 //debug_dump2file(name, svp->iram_rom, 0x800);
595                 exit(1);
596         }
597 //      elprintf(EL_ANOMALY, "iram_context: %02i", val1);
598         return val1;
599 }
600
601 // -----------------------------------------------------
602
603 /* regs with known values */
604 static struct
605 {
606         ssp_reg_t gr[8];
607         unsigned char r[8];
608         unsigned int pmac_read[5];
609         unsigned int pmac_write[5];
610         ssp_reg_t pmc;
611         unsigned int emu_status;
612 } known_regs;
613
614 #define KRREG_X     (1 << SSP_X)
615 #define KRREG_Y     (1 << SSP_Y)
616 #define KRREG_A     (1 << SSP_A)        /* AH only */
617 #define KRREG_ST    (1 << SSP_ST)
618 #define KRREG_STACK (1 << SSP_STACK)
619 #define KRREG_PC    (1 << SSP_PC)
620 #define KRREG_P     (1 << SSP_P)
621 #define KRREG_PR0   (1 << 8)
622 #define KRREG_PR4   (1 << 12)
623 #define KRREG_AL    (1 << 16)
624 #define KRREG_PMCM  (1 << 18)           /* only mode word of PMC */
625 #define KRREG_PMC   (1 << 19)
626 #define KRREG_PM0R  (1 << 20)
627 #define KRREG_PM1R  (1 << 21)
628 #define KRREG_PM2R  (1 << 22)
629 #define KRREG_PM3R  (1 << 23)
630 #define KRREG_PM4R  (1 << 24)
631 #define KRREG_PM0W  (1 << 25)
632 #define KRREG_PM1W  (1 << 26)
633 #define KRREG_PM2W  (1 << 27)
634 #define KRREG_PM3W  (1 << 28)
635 #define KRREG_PM4W  (1 << 29)
636
637 /* bitfield of known register values */
638 static u32 known_regb = 0;
639
640 /* known vals, which need to be flushed
641  * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
642  * ST means flags are being held in ARM PSR
643  * P means that it needs to be recalculated
644  */
645 static u32 dirty_regb = 0;
646
647 /* known values of host regs.
648  * -1            - unknown
649  * 000000-00ffff - 16bit value
650  * 100000-10ffff - base reg (r7) + 16bit val
651  * 0r0000        - means reg (low) eq gr[r].h, r != AL
652  */
653 static int hostreg_r[4];
654
655 static void hostreg_clear(void)
656 {
657         int i;
658         for (i = 0; i < 4; i++)
659                 hostreg_r[i] = -1;
660 }
661
662 static void hostreg_sspreg_changed(int sspreg)
663 {
664         int i;
665         for (i = 0; i < 4; i++)
666                 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
667 }
668
669
670 #define PROGRAM(x)   ((unsigned short *)svp->iram_rom)[x]
671 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
672
673 static void tr_unhandled(void)
674 {
675         FILE *f = fopen("tcache.bin", "wb");
676         fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
677         fclose(f);
678         printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
679         exit(1);
680 }
681
682 /* update P, if needed. Trashes r0 */
683 static void tr_flush_dirty_P(void)
684 {
685         // TODO: const regs
686         if (!(dirty_regb & KRREG_P)) return;
687         EOP_MOV_REG_ASR(10, 4, 16);             // mov  r10, r4, asr #16
688         EOP_MOV_REG_LSL( 0, 4, 16);             // mov  r0,  r4, lsl #16
689         EOP_MOV_REG_ASR( 0, 0, 15);             // mov  r0,  r0, asr #15
690         EOP_MUL(10, 0, 10);                     // mul  r10, r0, r10
691         dirty_regb &= ~KRREG_P;
692         hostreg_r[0] = -1;
693 }
694
695 /* write dirty pr to host reg. Nothing is trashed */
696 static void tr_flush_dirty_pr(int r)
697 {
698         int ror = 0, reg;
699
700         if (!(dirty_regb & (1 << (r+8)))) return;
701
702         switch (r&3) {
703                 case 0: ror =    0; break;
704                 case 1: ror = 24/2; break;
705                 case 2: ror = 16/2; break;
706         }
707         reg = (r < 4) ? 8 : 9;
708         EOP_BIC_IMM(reg,reg,ror,0xff);
709         if (known_regs.r[r] != 0)
710                 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
711         dirty_regb &= ~(1 << (r+8));
712 }
713
714 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
715 static void tr_flush_dirty_prs(void)
716 {
717         int i, ror = 0, reg;
718         int dirty = dirty_regb >> 8;
719         /* r0-r7 */
720         for (i = 0; dirty && i < 8; i++, dirty >>= 1)
721         {
722                 if (!(dirty&1)) continue;
723                 switch (i&3) {
724                         case 0: ror =    0; break;
725                         case 1: ror = 24/2; break;
726                         case 2: ror = 16/2; break;
727                 }
728                 reg = (i < 4) ? 8 : 9;
729                 EOP_BIC_IMM(reg,reg,ror,0xff);
730                 if (known_regs.r[i] != 0)
731                         EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
732         }
733         dirty_regb &= ~0xff00;
734 }
735
736 /* write dirty pr and "forget" it. Nothing is trashed. */
737 static void tr_release_pr(int r)
738 {
739         tr_flush_dirty_pr(r);
740         known_regb &= ~(1 << (r+8));
741 }
742
743 /* fush ARM PSR to r6. Trashes r1 */
744 static void tr_flush_dirty_ST(void)
745 {
746         if (!(dirty_regb & KRREG_ST)) return;
747         EOP_BIC_IMM(6,6,0,0x0f);
748         EOP_MRS(1);
749         EOP_ORR_REG_LSR(6,6,1,28);
750         dirty_regb &= ~KRREG_ST;
751         hostreg_r[1] = -1;
752 }
753
754 /* inverse of above. Trashes r1 */
755 static void tr_make_dirty_ST(void)
756 {
757         if (dirty_regb & KRREG_ST) return;
758         if (known_regb & KRREG_ST) {
759                 int flags = 0;
760                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
761                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
762                 EOP_MSR_IMM(4/2, flags);
763         } else {
764                 EOP_MOV_REG_LSL(1, 6, 28);
765                 EOP_MSR_REG(1);
766                 hostreg_r[1] = -1;
767         }
768         dirty_regb |= KRREG_ST;
769 }
770
771 /* load 16bit val into host reg r0-r3. Nothing is trashed */
772 static void tr_mov16(int r, int val)
773 {
774         if (hostreg_r[r] != val) {
775                 emit_mov_const(A_COND_AL, r, val);
776                 hostreg_r[r] = val;
777         }
778 }
779
780 static void tr_mov16_cond(int cond, int r, int val)
781 {
782         emit_mov_const(cond, r, val);
783         hostreg_r[r] = -1;
784 }
785
786 /* trashes r0 */
787 static void tr_flush_dirty_pmcrs(void)
788 {
789         u32 i, val = (u32)-1;
790         if (!(dirty_regb & 0x3ff80000)) return;
791
792         if (dirty_regb & KRREG_PMC) {
793                 val = known_regs.pmc.v;
794                 emit_mov_const(A_COND_AL, 1, val);
795                 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
796
797                 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
798                         printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
799                         tr_unhandled();
800                 }
801         }
802         for (i = 0; i < 5; i++)
803         {
804                 if (dirty_regb & (1 << (20+i))) {
805                         if (val != known_regs.pmac_read[i]) {
806                                 val = known_regs.pmac_read[i];
807                                 emit_mov_const(A_COND_AL, 1, val);
808                         }
809                         EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
810                 }
811                 if (dirty_regb & (1 << (25+i))) {
812                         if (val != known_regs.pmac_write[i]) {
813                                 val = known_regs.pmac_write[i];
814                                 emit_mov_const(A_COND_AL, 1, val);
815                         }
816                         EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
817                 }
818         }
819         dirty_regb &= ~0x3ff80000;
820         hostreg_r[1] = -1;
821 }
822
823 /* read bank word to r0 (upper bits zero). Thrashes r1. */
824 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
825 {
826         int breg = 7;
827         if (addr > 0x7f) {
828                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
829                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
830                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
831                 }
832                 breg = 1;
833         }
834         EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1);    // ldrh r0, [r1, (op&0x7f)<<1]
835         hostreg_r[0] = -1;
836 }
837
838 /* write r0 to bank. Trashes r1. */
839 static void tr_bank_write(int addr)
840 {
841         int breg = 7;
842         if (addr > 0x7f) {
843                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
844                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
845                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
846                 }
847                 breg = 1;
848         }
849         EOP_STRH_IMM(0,breg,(addr&0x7f)<<1);            // strh r0, [r1, (op&0x7f)<<1]
850 }
851
852 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
853 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
854 {
855         int modulo_shift = -1;  /* unknown */
856
857         if (mod == 0) return;
858
859         if (!need_modulo || mod == 1) // +!
860                 modulo_shift = 8;
861         else if (need_modulo && (known_regb & KRREG_ST)) {
862                 modulo_shift = known_regs.gr[SSP_ST].h & 7;
863                 if (modulo_shift == 0) modulo_shift = 8;
864         }
865
866         if (modulo_shift == -1)
867         {
868                 int reg = (r < 4) ? 8 : 9;
869                 tr_release_pr(r);
870                 if (dirty_regb & KRREG_ST) {
871                         // avoid flushing ARM flags
872                         EOP_AND_IMM(1, 6, 0, 0x70);
873                         EOP_SUB_IMM(1, 1, 0, 0x10);
874                         EOP_AND_IMM(1, 1, 0, 0x70);
875                         EOP_ADD_IMM(1, 1, 0, 0x10);
876                 } else {
877                         EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands  r1, r6, #0x70
878                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
879                 }
880                 EOP_MOV_REG_LSR(1, 1, 4);               // mov r1, r1, lsr #4
881                 EOP_RSB_IMM(2, 1, 0, 8);                // rsb r1, r1, #8
882                 EOP_MOV_IMM(3, 8/2, count);             // mov r3, #0x01000000
883                 if (r&3)
884                         EOP_ADD_IMM(1, 1, 0, (r&3)*8);  // add r1, r1, #(r&3)*8
885                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
886                 if (mod == 2)
887                      EOP_SUB_REG2_LSL(reg,reg,3,2);     // sub reg, reg, #0x01000000 << r2
888                 else EOP_ADD_REG2_LSL(reg,reg,3,2);
889                 EOP_RSB_IMM(1, 1, 0, 32);               // rsb r1, r1, #32
890                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
891                 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
892         }
893         else if (known_regb & (1 << (r + 8)))
894         {
895                 int modulo = (1 << modulo_shift) - 1;
896                 if (mod == 2)
897                      known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
898                 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
899         }
900         else
901         {
902                 int reg = (r < 4) ? 8 : 9;
903                 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
904                 EOP_MOV_REG_ROR(reg,reg,ror);
905                 // {add|sub} reg, reg, #1<<shift
906                 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
907                 EOP_MOV_REG_ROR(reg,reg,32-ror);
908         }
909 }
910
911 /* handle writes r0 to (rX). Trashes r1.
912  * fortunately we can ignore modulo increment modes for writes. */
913 static void tr_rX_write(int op)
914 {
915         if ((op&3) == 3)
916         {
917                 int mod = (op>>2) & 3; // direct addressing
918                 tr_bank_write((op & 0x100) + mod);
919         }
920         else
921         {
922                 int r = (op&3) | ((op>>6)&4);
923                 if (known_regb & (1 << (r + 8))) {
924                         tr_bank_write((op&0x100) | known_regs.r[r]);
925                 } else {
926                         int reg = (r < 4) ? 8 : 9;
927                         int ror = ((4 - (r&3))*8) & 0x1f;
928                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
929                         if (r >= 4)
930                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
931                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
932                         else     EOP_ADD_REG_LSL(1,7,1,1);
933                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
934                         hostreg_r[1] = -1;
935                 }
936                 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
937         }
938 }
939
940 /* read (rX) to r0. Trashes r1-r3. */
941 static void tr_rX_read(int r, int mod)
942 {
943         if ((r&3) == 3)
944         {
945                 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
946         }
947         else
948         {
949                 if (known_regb & (1 << (r + 8))) {
950                         tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
951                 } else {
952                         int reg = (r < 4) ? 8 : 9;
953                         int ror = ((4 - (r&3))*8) & 0x1f;
954                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
955                         if (r >= 4)
956                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
957                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
958                         else     EOP_ADD_REG_LSL(1,7,1,1);
959                         EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
960                         hostreg_r[0] = hostreg_r[1] = -1;
961                 }
962                 tr_ptrr_mod(r, mod, 1, 1);
963         }
964 }
965
966 /* read ((rX)) to r0. Trashes r1,r2. */
967 static void tr_rX_read2(int op)
968 {
969         int r = (op&3) | ((op>>6)&4); // src
970
971         if ((r&3) == 3) {
972                 tr_bank_read((op&0x100) | ((op>>2)&3));
973         } else if (known_regb & (1 << (r+8))) {
974                 tr_bank_read((op&0x100) | known_regs.r[r]);
975         } else {
976                 int reg = (r < 4) ? 8 : 9;
977                 int ror = ((4 - (r&3))*8) & 0x1f;
978                 EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
979                 if (r >= 4)
980                         EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
981                 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
982                 else     EOP_ADD_REG_LSL(1,7,1,1);
983                 EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
984         }
985         EOP_LDR_IMM(2,7,0x48c);                                 // ptr_iram_rom
986         EOP_ADD_REG_LSL(2,2,0,1);                               // add  r2, r2, r0, lsl #1
987         EOP_ADD_IMM(0,0,0,1);                                   // add  r0, r0, #1
988         if ((r&3) == 3) {
989                 tr_bank_write((op&0x100) | ((op>>2)&3));
990         } else if (known_regb & (1 << (r+8))) {
991                 tr_bank_write((op&0x100) | known_regs.r[r]);
992         } else {
993                 EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
994                 hostreg_r[1] = -1;
995         }
996         EOP_LDRH_SIMPLE(0,2);                                   // ldrh r0, [r2]
997         hostreg_r[0] = hostreg_r[2] = -1;
998 }
999
1000 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1001 static int tr_cond_check(int op)
1002 {
1003         int f = (op & 0x100) >> 8;
1004         switch (op&0xf0) {
1005                 case 0x00: return A_COND_AL;    /* always true */
1006                 case 0x50:                      /* Z matches f(?) bit */
1007                         if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1008                         EOP_TST_IMM(6, 0, 4);
1009                         return f ? A_COND_NE : A_COND_EQ;
1010                 case 0x70:                      /* N matches f(?) bit */
1011                         if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1012                         EOP_TST_IMM(6, 0, 8);
1013                         return f ? A_COND_NE : A_COND_EQ;
1014                 default:
1015                         printf("unimplemented cond?\n");
1016                         tr_unhandled();
1017                         return 0;
1018         }
1019 }
1020
1021 static int tr_neg_cond(int cond)
1022 {
1023         switch (cond) {
1024                 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1025                 case A_COND_EQ: return A_COND_NE;
1026                 case A_COND_NE: return A_COND_EQ;
1027                 case A_COND_MI: return A_COND_PL;
1028                 case A_COND_PL: return A_COND_MI;
1029                 default:        printf("bad cond for neg\n"); exit(1);
1030         }
1031         return 0;
1032 }
1033
1034 static int tr_aop_ssp2arm(int op)
1035 {
1036         switch (op) {
1037                 case 1: return A_OP_SUB;
1038                 case 3: return A_OP_CMP;
1039                 case 4: return A_OP_ADD;
1040                 case 5: return A_OP_AND;
1041                 case 6: return A_OP_ORR;
1042                 case 7: return A_OP_EOR;
1043         }
1044
1045         tr_unhandled();
1046         return 0;
1047 }
1048
1049 // -----------------------------------------------------
1050
1051 //@ r4:  XXYY
1052 //@ r5:  A
1053 //@ r6:  STACK and emu flags
1054 //@ r7:  SSP context
1055 //@ r10: P
1056
1057 // read general reg to r0. Trashes r1
1058 static void tr_GR0_to_r0(int op)
1059 {
1060         tr_mov16(0, 0xffff);
1061 }
1062
1063 static void tr_X_to_r0(int op)
1064 {
1065         if (hostreg_r[0] != (SSP_X<<16)) {
1066                 EOP_MOV_REG_LSR(0, 4, 16);      // mov  r0, r4, lsr #16
1067                 hostreg_r[0] = SSP_X<<16;
1068         }
1069 }
1070
1071 static void tr_Y_to_r0(int op)
1072 {
1073         if (hostreg_r[0] != (SSP_Y<<16)) {
1074                 EOP_MOV_REG_SIMPLE(0, 4);       // mov  r0, r4
1075                 hostreg_r[0] = SSP_Y<<16;
1076         }
1077 }
1078
1079 static void tr_A_to_r0(int op)
1080 {
1081         if (hostreg_r[0] != (SSP_A<<16)) {
1082                 EOP_MOV_REG_LSR(0, 5, 16);      // mov  r0, r5, lsr #16  @ AH
1083                 hostreg_r[0] = SSP_A<<16;
1084         }
1085 }
1086
1087 static void tr_ST_to_r0(int op)
1088 {
1089         // VR doesn't need much accuracy here..
1090         EOP_MOV_REG_LSR(0, 6, 4);               // mov  r0, r6, lsr #4
1091         EOP_AND_IMM(0, 0, 0, 0x67);             // and  r0, r0, #0x67
1092         hostreg_r[0] = -1;
1093 }
1094
1095 static void tr_STACK_to_r0(int op)
1096 {
1097         // 448
1098         EOP_SUB_IMM(6, 6,  8/2, 0x20);          // sub  r6, r6, #1<<29
1099         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
1100         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
1101         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
1102         EOP_LDRH_SIMPLE(0, 1);                  // ldrh r0, [r1]
1103         hostreg_r[0] = hostreg_r[1] = -1;
1104 }
1105
1106 static void tr_PC_to_r0(int op)
1107 {
1108         tr_mov16(0, known_regs.gr[SSP_PC].h);
1109 }
1110
1111 static void tr_P_to_r0(int op)
1112 {
1113         tr_flush_dirty_P();
1114         EOP_MOV_REG_LSR(0, 10, 16);             // mov  r0, r10, lsr #16
1115         hostreg_r[0] = -1;
1116 }
1117
1118 static void tr_AL_to_r0(int op)
1119 {
1120         if (op == 0x000f) {
1121                 if (known_regb & KRREG_PMC) {
1122                         known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1123                 } else {
1124                         EOP_LDR_IMM(0,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1125                         EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1126                         EOP_STR_IMM(0,7,0x484);
1127                 }
1128         }
1129
1130         if (hostreg_r[0] != (SSP_AL<<16)) {
1131                 EOP_MOV_REG_SIMPLE(0, 5);       // mov  r0, r5
1132                 hostreg_r[0] = SSP_AL<<16;
1133         }
1134 }
1135
1136 static void tr_PMX_to_r0(int reg)
1137 {
1138         if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1139         {
1140                 known_regs.pmac_read[reg] = known_regs.pmc.v;
1141                 known_regs.emu_status &= ~SSP_PMC_SET;
1142                 known_regb |= 1 << (20+reg);
1143                 dirty_regb |= 1 << (20+reg);
1144                 return;
1145         }
1146
1147         if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1148         {
1149                 u32 pmcv = known_regs.pmac_read[reg];
1150                 int mode = pmcv>>16;
1151                 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1152
1153                 if      ((mode & 0xfff0) == 0x0800)
1154                 {
1155                         EOP_LDR_IMM(1,7,0x488);         // rom_ptr
1156                         emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1157                         EOP_LDRH_REG(0,1,0);            // ldrh r0, [r1, r0]
1158                         known_regs.pmac_read[reg] += 1;
1159                 }
1160                 else if ((mode & 0x47ff) == 0x0018) // DRAM
1161                 {
1162                         int inc = get_inc(mode);
1163                         EOP_LDR_IMM(1,7,0x490);         // dram_ptr
1164                         emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1165                         EOP_LDRH_REG(0,1,0);            // ldrh r0, [r1, r0]
1166                         if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
1167                         {
1168                                 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1169                                 tr_flush_dirty_ST();
1170                                 EOP_LDR_IMM(1,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1171                                 EOP_TST_REG_SIMPLE(0,0);
1172                                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1);       // addeq r11, r11, #1024
1173                                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
1174                                 EOP_STR_IMM(1,7,0x484);                 // str r1, [r7, #0x484] // emu_status
1175                         }
1176                         known_regs.pmac_read[reg] += inc;
1177                 }
1178                 else
1179                 {
1180                         tr_unhandled();
1181                 }
1182                 known_regs.pmc.v = known_regs.pmac_read[reg];
1183                 //known_regb |= KRREG_PMC;
1184                 dirty_regb |= KRREG_PMC;
1185                 dirty_regb |= 1 << (20+reg);
1186                 hostreg_r[0] = hostreg_r[1] = -1;
1187                 return;
1188         }
1189
1190         known_regb &= ~KRREG_PMC;
1191         dirty_regb &= ~KRREG_PMC;
1192         known_regb &= ~(1 << (20+reg));
1193         dirty_regb &= ~(1 << (20+reg));
1194
1195         // call the C code to handle this
1196         tr_flush_dirty_ST();
1197         //tr_flush_dirty_pmcrs();
1198         tr_mov16(0, reg);
1199         emit_call(ssp_pm_read);
1200         hostreg_clear();
1201 }
1202
1203 static void tr_PM0_to_r0(int op)
1204 {
1205         tr_PMX_to_r0(0);
1206 }
1207
1208 static void tr_PM1_to_r0(int op)
1209 {
1210         tr_PMX_to_r0(1);
1211 }
1212
1213 static void tr_PM2_to_r0(int op)
1214 {
1215         tr_PMX_to_r0(2);
1216 }
1217
1218 static void tr_XST_to_r0(int op)
1219 {
1220         EOP_ADD_IMM(0, 7, 24/2, 4);     // add r0, r7, #0x400
1221         EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1222 }
1223
1224 static void tr_PM4_to_r0(int op)
1225 {
1226         tr_PMX_to_r0(4);
1227 }
1228
1229 static void tr_PMC_to_r0(int op)
1230 {
1231         if (known_regb & KRREG_PMC)
1232         {
1233                 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1234                         known_regs.emu_status |= SSP_PMC_SET;
1235                         known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1236                         // do nothing - this is handled elsewhere
1237                 } else {
1238                         tr_mov16(0, known_regs.pmc.l);
1239                         known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1240                 }
1241         }
1242         else
1243         {
1244                 EOP_LDR_IMM(1,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1245                 tr_flush_dirty_ST();
1246                 if (op != 0x000e)
1247                         EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1248                 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1249                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1250                 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1251                 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET);       // orrne r1, r1, #..
1252                 EOP_STR_IMM(1,7,0x484);
1253                 hostreg_r[0] = hostreg_r[1] = -1;
1254         }
1255 }
1256
1257
1258 typedef void (tr_read_func)(int op);
1259
1260 static tr_read_func *tr_read_funcs[16] =
1261 {
1262         tr_GR0_to_r0,
1263         tr_X_to_r0,
1264         tr_Y_to_r0,
1265         tr_A_to_r0,
1266         tr_ST_to_r0,
1267         tr_STACK_to_r0,
1268         tr_PC_to_r0,
1269         tr_P_to_r0,
1270         tr_PM0_to_r0,
1271         tr_PM1_to_r0,
1272         tr_PM2_to_r0,
1273         tr_XST_to_r0,
1274         tr_PM4_to_r0,
1275         (tr_read_func *)tr_unhandled,
1276         tr_PMC_to_r0,
1277         tr_AL_to_r0
1278 };
1279
1280
1281 // write r0 to general reg handlers. Trashes r1
1282 #define TR_WRITE_R0_TO_REG(reg) \
1283 { \
1284         hostreg_sspreg_changed(reg); \
1285         hostreg_r[0] = (reg)<<16; \
1286         if (const_val != -1) { \
1287                 known_regs.gr[reg].h = const_val; \
1288                 known_regb |= 1 << (reg); \
1289         } else { \
1290                 known_regb &= ~(1 << (reg)); \
1291         } \
1292 }
1293
1294 static void tr_r0_to_GR0(int const_val)
1295 {
1296         // do nothing
1297 }
1298
1299 static void tr_r0_to_X(int const_val)
1300 {
1301         EOP_MOV_REG_LSL(4, 4, 16);              // mov  r4, r4, lsl #16
1302         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
1303         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
1304         dirty_regb |= KRREG_P;                  // touching X or Y makes P dirty.
1305         TR_WRITE_R0_TO_REG(SSP_X);
1306 }
1307
1308 static void tr_r0_to_Y(int const_val)
1309 {
1310         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
1311         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
1312         EOP_MOV_REG_ROR(4, 4, 16);              // mov  r4, r4, ror #16
1313         dirty_regb |= KRREG_P;
1314         TR_WRITE_R0_TO_REG(SSP_Y);
1315 }
1316
1317 static void tr_r0_to_A(int const_val)
1318 {
1319         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
1320         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16  @ AL
1321         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
1322         TR_WRITE_R0_TO_REG(SSP_A);
1323 }
1324
1325 static void tr_r0_to_ST(int const_val)
1326 {
1327         // VR doesn't need much accuracy here..
1328         EOP_AND_IMM(1, 0,   0, 0x67);           // and   r1, r0, #0x67
1329         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
1330         EOP_ORR_REG_LSL(6, 6, 1, 4);            // orr   r6, r6, r1, lsl #4
1331         TR_WRITE_R0_TO_REG(SSP_ST);
1332         hostreg_r[1] = -1;
1333         dirty_regb &= ~KRREG_ST;
1334 }
1335
1336 static void tr_r0_to_STACK(int const_val)
1337 {
1338         // 448
1339         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
1340         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
1341         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
1342         EOP_STRH_SIMPLE(0, 1);                  // strh r0, [r1]
1343         EOP_ADD_IMM(6, 6,  8/2, 0x20);          // add  r6, r6, #1<<29
1344         hostreg_r[1] = -1;
1345 }
1346
1347 static void tr_r0_to_PC(int const_val)
1348 {
1349         EOP_MOV_REG_LSL(1, 0, 16);              // mov  r1, r0, lsl #16
1350         EOP_STR_IMM(1,7,0x400+6*4);             // str  r1, [r7, #(0x400+6*8)]
1351         hostreg_r[1] = -1;
1352 }
1353
1354 static void tr_r0_to_AL(int const_val)
1355 {
1356         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16
1357         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
1358         EOP_MOV_REG_ROR(5, 5, 16);              // mov  r5, r5, ror #16
1359         hostreg_sspreg_changed(SSP_AL);
1360         if (const_val != -1) {
1361                 known_regs.gr[SSP_A].l = const_val;
1362                 known_regb |= 1 << SSP_AL;
1363         } else
1364                 known_regb &= ~(1 << SSP_AL);
1365 }
1366
1367 static void tr_r0_to_PMX(int reg)
1368 {
1369         if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1370         {
1371                 known_regs.pmac_write[reg] = known_regs.pmc.v;
1372                 known_regs.emu_status &= ~SSP_PMC_SET;
1373                 known_regb |= 1 << (25+reg);
1374                 dirty_regb |= 1 << (25+reg);
1375                 return;
1376         }
1377
1378         if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1379         {
1380                 int mode, addr;
1381
1382                 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1383
1384                 mode = known_regs.pmac_write[reg]>>16;
1385                 addr = known_regs.pmac_write[reg]&0xffff;
1386                 if      ((mode & 0x43ff) == 0x0018) // DRAM
1387                 {
1388                         int inc = get_inc(mode);
1389                         if (mode & 0x0400) tr_unhandled();
1390                         EOP_LDR_IMM(1,7,0x490);         // dram_ptr
1391                         emit_mov_const(A_COND_AL, 2, addr<<1);
1392                         EOP_STRH_REG(0,1,2);            // strh r0, [r1, r2]
1393                         known_regs.pmac_write[reg] += inc;
1394                 }
1395                 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1396                 {
1397                         if (mode & 0x0400) tr_unhandled();
1398                         EOP_LDR_IMM(1,7,0x490);         // dram_ptr
1399                         emit_mov_const(A_COND_AL, 2, addr<<1);
1400                         EOP_STRH_REG(0,1,2);            // strh r0, [r1, r2]
1401                         known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1402                 }
1403                 else if ((mode & 0x47ff) == 0x001c) // IRAM
1404                 {
1405                         int inc = get_inc(mode);
1406                         EOP_LDR_IMM(1,7,0x48c);         // iram_ptr
1407                         emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1408                         EOP_STRH_REG(0,1,2);            // strh r0, [r1, r2]
1409                         EOP_MOV_IMM(1,0,1);
1410                         EOP_STR_IMM(1,7,0x494);         // iram_dirty
1411                         known_regs.pmac_write[reg] += inc;
1412                 }
1413                 else
1414                         tr_unhandled();
1415
1416                 known_regs.pmc.v = known_regs.pmac_write[reg];
1417                 //known_regb |= KRREG_PMC;
1418                 dirty_regb |= KRREG_PMC;
1419                 dirty_regb |= 1 << (25+reg);
1420                 hostreg_r[1] = hostreg_r[2] = -1;
1421                 return;
1422         }
1423
1424         known_regb &= ~KRREG_PMC;
1425         dirty_regb &= ~KRREG_PMC;
1426         known_regb &= ~(1 << (25+reg));
1427         dirty_regb &= ~(1 << (25+reg));
1428
1429         // call the C code to handle this
1430         tr_flush_dirty_ST();
1431         //tr_flush_dirty_pmcrs();
1432         tr_mov16(1, reg);
1433         emit_call(ssp_pm_write);
1434         hostreg_clear();
1435 }
1436
1437 static void tr_r0_to_PM0(int const_val)
1438 {
1439         tr_r0_to_PMX(0);
1440 }
1441
1442 static void tr_r0_to_PM1(int const_val)
1443 {
1444         tr_r0_to_PMX(1);
1445 }
1446
1447 static void tr_r0_to_PM2(int const_val)
1448 {
1449         tr_r0_to_PMX(2);
1450 }
1451
1452 static void tr_r0_to_PM4(int const_val)
1453 {
1454         tr_r0_to_PMX(4);
1455 }
1456
1457 static void tr_r0_to_PMC(int const_val)
1458 {
1459         if ((known_regb & KRREG_PMC) && const_val != -1)
1460         {
1461                 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1462                         known_regs.emu_status |= SSP_PMC_SET;
1463                         known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1464                         known_regs.pmc.h = const_val;
1465                 } else {
1466                         known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1467                         known_regs.pmc.l = const_val;
1468                 }
1469         }
1470         else
1471         {
1472                 tr_flush_dirty_ST();
1473                 if (known_regb & KRREG_PMC) {
1474                         emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1475                         EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1476                         known_regb &= ~KRREG_PMC;
1477                         dirty_regb &= ~KRREG_PMC;
1478                 }
1479                 EOP_LDR_IMM(1,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1480                 EOP_ADD_IMM(2,7,24/2,4);                // add r2, r7, #0x400
1481                 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1482                 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4);         // strxx r0, [r2, #SSP_PMC]
1483                 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1484                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1485                 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1486                 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET);       // orrne r1, r1, #..
1487                 EOP_STR_IMM(1,7,0x484);
1488                 hostreg_r[1] = hostreg_r[2] = -1;
1489         }
1490 }
1491
1492 typedef void (tr_write_func)(int const_val);
1493
1494 static tr_write_func *tr_write_funcs[16] =
1495 {
1496         tr_r0_to_GR0,
1497         tr_r0_to_X,
1498         tr_r0_to_Y,
1499         tr_r0_to_A,
1500         tr_r0_to_ST,
1501         tr_r0_to_STACK,
1502         tr_r0_to_PC,
1503         (tr_write_func *)tr_unhandled,
1504         tr_r0_to_PM0,
1505         tr_r0_to_PM1,
1506         tr_r0_to_PM2,
1507         (tr_write_func *)tr_unhandled,
1508         tr_r0_to_PM4,
1509         (tr_write_func *)tr_unhandled,
1510         tr_r0_to_PMC,
1511         tr_r0_to_AL
1512 };
1513
1514 static void tr_mac_load_XY(int op)
1515 {
1516         tr_rX_read(op&3, (op>>2)&3); // X
1517         EOP_MOV_REG_LSL(4, 0, 16);
1518         tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1519         EOP_ORR_REG_SIMPLE(4, 0);
1520         dirty_regb |= KRREG_P;
1521         hostreg_sspreg_changed(SSP_X);
1522         hostreg_sspreg_changed(SSP_Y);
1523         known_regb &= ~KRREG_X;
1524         known_regb &= ~KRREG_Y;
1525 }
1526
1527 // -----------------------------------------------------
1528
1529 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1530 {
1531         u32 pmcv, tmpv;
1532         if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1533
1534         // programming PMC:
1535         // ldi PMC, imm1
1536         // ldi PMC, imm2
1537         (*pc)++;
1538         pmcv = imm | (PROGRAM((*pc)++) << 16);
1539         known_regs.pmc.v = pmcv;
1540         known_regb |= KRREG_PMC;
1541         dirty_regb |= KRREG_PMC;
1542         known_regs.emu_status |= SSP_PMC_SET;
1543
1544         // check for possible reg programming
1545         tmpv = PROGRAM(*pc);
1546         if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1547         {
1548                 int is_write = (tmpv & 0xff8f) == 0x80;
1549                 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1550                 if (reg > 4) tr_unhandled();
1551                 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1552                 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1553                 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1554                 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1555                 known_regs.emu_status &= ~SSP_PMC_SET;
1556                 (*pc)++;
1557                 return 5;
1558         }
1559
1560         tr_unhandled();
1561         return 4;
1562 }
1563
1564 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1565
1566 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1567 {
1568         // ldi ST, 0
1569         // ldi PM0, 0
1570         // ldi PM0, 0
1571         // ldi ST, 60h
1572         unsigned short *pp;
1573         if (op != 0x0840 || imm != 0) return 0;
1574         pp = PROGRAM_P(*pc);
1575         if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1576
1577         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
1578         EOP_ORR_IMM(6, 6, 24/2, 6);             // orr   r6, r6, 0x600
1579         hostreg_sspreg_changed(SSP_ST);
1580         known_regs.gr[SSP_ST].h = 0x60;
1581         known_regb |= 1 << SSP_ST;
1582         dirty_regb &= ~KRREG_ST;
1583         (*pc) += 3*2;
1584         return 4*2;
1585 }
1586
1587 static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1588 {
1589         // @ 3DA2 and 426A
1590         // ld PMC, (r3|00)
1591         // ld (r3|00), PMC
1592         // ld -, AL
1593         if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1594
1595         tr_bank_read(0);
1596         EOP_MOV_REG_LSL(0, 0, 4);
1597         EOP_ORR_REG_LSR(0, 0, 0, 16);
1598         tr_bank_write(0);
1599         (*pc) += 2;
1600         return 3;
1601 }
1602
1603 // -----------------------------------------------------
1604
1605 static int translate_op(unsigned int op, int *pc, int imm)
1606 {
1607         u32 tmpv, tmpv2, tmpv3;
1608         int ret = 0;
1609         known_regs.gr[SSP_PC].h = *pc;
1610
1611         switch (op >> 9)
1612         {
1613                 // ld d, s
1614                 case 0x00:
1615                         if (op == 0) { ret++; break; } // nop
1616                         tmpv  = op & 0xf; // src
1617                         tmpv2 = (op >> 4) & 0xf; // dst
1618                         if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1619                                 tr_flush_dirty_P();
1620                                 EOP_MOV_REG_SIMPLE(5, 10);
1621                                 hostreg_sspreg_changed(SSP_A);
1622                                 known_regb &= ~(KRREG_A|KRREG_AL);
1623                                 ret++; break;
1624                         }
1625                         tr_read_funcs[tmpv](op);
1626                         tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1627                         if (tmpv2 == SSP_PC) ret |= 0x10000;
1628                         ret++; break;
1629
1630                 // ld d, (ri)
1631                 case 0x01: {
1632                         int r = (op&3) | ((op>>6)&4);
1633                         int mod = (op>>2)&3;
1634                         tmpv = (op >> 4) & 0xf; // dst
1635                         ret = tr_detect_rotate(op, pc, imm);
1636                         if (ret > 0) break;
1637                         if (tmpv != 0)
1638                              tr_rX_read(r, mod);
1639                         else tr_ptrr_mod(r, mod, 1, 1);
1640                         tr_write_funcs[tmpv](-1);
1641                         if (tmpv == SSP_PC) ret |= 0x10000;
1642                         ret++; break;
1643                 }
1644
1645                 // ld (ri), s
1646                 case 0x02:
1647                         tmpv = (op >> 4) & 0xf; // src
1648                         tr_read_funcs[tmpv](op);
1649                         tr_rX_write(op);
1650                         ret++; break;
1651
1652                 // ld a, adr
1653                 case 0x03:
1654                         tr_bank_read(op&0x1ff);
1655                         tr_r0_to_A(-1);
1656                         ret++; break;
1657
1658                 // ldi d, imm
1659                 case 0x04:
1660                         tmpv = (op & 0xf0) >> 4; // dst
1661                         ret = tr_detect_pm0_block(op, pc, imm);
1662                         if (ret > 0) break;
1663                         ret = tr_detect_set_pm(op, pc, imm);
1664                         if (ret > 0) break;
1665                         tr_mov16(0, imm);
1666                         tr_write_funcs[tmpv](imm);
1667                         if (tmpv == SSP_PC) ret |= 0x10000;
1668                         ret += 2; break;
1669
1670                 // ld d, ((ri))
1671                 case 0x05:
1672                         tmpv2 = (op >> 4) & 0xf;  // dst
1673                         tr_rX_read2(op);
1674                         tr_write_funcs[tmpv2](-1);
1675                         if (tmpv2 == SSP_PC) ret |= 0x10000;
1676                         ret += 3; break;
1677
1678                 // ldi (ri), imm
1679                 case 0x06:
1680                         tr_mov16(0, imm);
1681                         tr_rX_write(op);
1682                         ret += 2; break;
1683
1684                 // ld adr, a
1685                 case 0x07:
1686                         tr_A_to_r0(op);
1687                         tr_bank_write(op&0x1ff);
1688                         ret++; break;
1689
1690                 // ld d, ri
1691                 case 0x09: {
1692                         int r;
1693                         r = (op&3) | ((op>>6)&4); // src
1694                         tmpv2 = (op >> 4) & 0xf;  // dst
1695                         if ((r&3) == 3) tr_unhandled();
1696
1697                         if (known_regb & (1 << (r+8))) {
1698                                 tr_mov16(0, known_regs.r[r]);
1699                                 tr_write_funcs[tmpv2](known_regs.r[r]);
1700                         } else {
1701                                 int reg = (r < 4) ? 8 : 9;
1702                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1703                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1704                                 hostreg_r[0] = -1;
1705                                 tr_write_funcs[tmpv2](-1);
1706                         }
1707                         ret++; break;
1708                 }
1709
1710                 // ld ri, s
1711                 case 0x0a: {
1712                         int r;
1713                         r = (op&3) | ((op>>6)&4); // dst
1714                         tmpv = (op >> 4) & 0xf;   // src
1715                         if ((r&3) == 3) tr_unhandled();
1716
1717                         if (known_regb & (1 << tmpv)) {
1718                                 known_regs.r[r] = known_regs.gr[tmpv].h;
1719                                 known_regb |= 1 << (r + 8);
1720                                 dirty_regb |= 1 << (r + 8);
1721                         } else {
1722                                 int reg = (r < 4) ? 8 : 9;
1723                                 int ror = ((4 - (r&3))*8) & 0x1f;
1724                                 tr_read_funcs[tmpv](op);
1725                                 EOP_BIC_IMM(reg, reg, ror/2, 0xff);             // bic r{7,8}, r{7,8}, <mask>
1726                                 EOP_AND_IMM(0, 0, 0, 0xff);                     // and r0, r0, 0xff
1727                                 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8);          // orr r{7,8}, r{7,8}, r0, lsl #lsl
1728                                 hostreg_r[0] = -1;
1729                                 known_regb &= ~(1 << (r+8));
1730                                 dirty_regb &= ~(1 << (r+8));
1731                         }
1732                         ret++; break;
1733                 }
1734
1735                 // ldi ri, simm
1736                 case 0x0c ... 0x0f:
1737                         tmpv = (op>>8)&7;
1738                         known_regs.r[tmpv] = op;
1739                         known_regb |= 1 << (tmpv + 8);
1740                         dirty_regb |= 1 << (tmpv + 8);
1741                         ret++; break;
1742
1743                 // call cond, addr
1744                 case 0x24: {
1745                         u32 *jump_op = NULL;
1746                         tmpv = tr_cond_check(op);
1747                         if (tmpv != A_COND_AL) {
1748                                 jump_op = tcache_ptr;
1749                                 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1750                         }
1751                         tr_mov16(0, *pc);
1752                         tr_r0_to_STACK(*pc);
1753                         if (tmpv != A_COND_AL) {
1754                                 u32 *real_ptr = tcache_ptr;
1755                                 tcache_ptr = jump_op;
1756                                 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1757                                 tcache_ptr = real_ptr;
1758                         }
1759                         tr_mov16_cond(tmpv, 0, imm);
1760                         if (tmpv != A_COND_AL) {
1761                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1762                         }
1763                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1764                         ret |= 0x10000;
1765                         ret += 2; break;
1766                 }
1767
1768                 // ld d, (a)
1769                 case 0x25:
1770                         tmpv2 = (op >> 4) & 0xf;  // dst
1771                         tr_A_to_r0(op);
1772                         EOP_LDR_IMM(1,7,0x48c);                                 // ptr_iram_rom
1773                         EOP_ADD_REG_LSL(0,1,0,1);                               // add  r0, r1, r0, lsl #1
1774                         EOP_LDRH_SIMPLE(0,0);                                   // ldrh r0, [r0]
1775                         hostreg_r[0] = hostreg_r[1] = -1;
1776                         tr_write_funcs[tmpv2](-1);
1777                         if (tmpv2 == SSP_PC) ret |= 0x10000;
1778                         ret += 3; break;
1779
1780                 // bra cond, addr
1781                 case 0x26:
1782                         tmpv = tr_cond_check(op);
1783                         tr_mov16_cond(tmpv, 0, imm);
1784                         if (tmpv != A_COND_AL) {
1785                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1786                         }
1787                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1788                         ret |= 0x10000;
1789                         ret += 2; break;
1790
1791                 // mod cond, op
1792                 case 0x48: {
1793                         // check for repeats of this op
1794                         tmpv = 1; // count
1795                         while (PROGRAM(*pc) == op && (op & 7) != 6) {
1796                                 (*pc)++; tmpv++;
1797                         }
1798                         if ((op&0xf0) != 0) // !always
1799                                 tr_make_dirty_ST();
1800
1801                         tmpv2 = tr_cond_check(op);
1802                         switch (op & 7) {
1803                                 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1804                                 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1805                                 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1806                                 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
1807                                         EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1808                                         hostreg_r[1] = -1; break; // abs
1809                                 default: tr_unhandled();
1810                         }
1811
1812                         hostreg_sspreg_changed(SSP_A);
1813                         dirty_regb |=  KRREG_ST;
1814                         known_regb &= ~KRREG_ST;
1815                         known_regb &= ~(KRREG_A|KRREG_AL);
1816                         ret += tmpv; break;
1817                 }
1818
1819                 // mpys?
1820                 case 0x1b:
1821                         tr_flush_dirty_P();
1822                         tr_mac_load_XY(op);
1823                         tr_make_dirty_ST();
1824                         EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1825                         hostreg_sspreg_changed(SSP_A);
1826                         known_regb &= ~(KRREG_A|KRREG_AL);
1827                         dirty_regb |= KRREG_ST;
1828                         ret++; break;
1829
1830                 // mpya (rj), (ri), b
1831                 case 0x4b:
1832                         tr_flush_dirty_P();
1833                         tr_mac_load_XY(op);
1834                         tr_make_dirty_ST();
1835                         EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1836                         hostreg_sspreg_changed(SSP_A);
1837                         known_regb &= ~(KRREG_A|KRREG_AL);
1838                         dirty_regb |= KRREG_ST;
1839                         ret++; break;
1840
1841                 // mld (rj), (ri), b
1842                 case 0x5b:
1843                         EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1844                         hostreg_sspreg_changed(SSP_A);
1845                         known_regs.gr[SSP_A].v = 0;
1846                         known_regb |= (KRREG_A|KRREG_AL);
1847                         dirty_regb |= KRREG_ST;
1848                         tr_mac_load_XY(op);
1849                         ret++; break;
1850
1851                 // OP a, s
1852                 case 0x10:
1853                 case 0x30:
1854                 case 0x40:
1855                 case 0x50:
1856                 case 0x60:
1857                 case 0x70:
1858                         tmpv = op & 0xf; // src
1859                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1860                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1861                         if (tmpv == SSP_P) {
1862                                 tr_flush_dirty_P();
1863                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1864                         } else if (tmpv == SSP_A) {
1865                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1866                         } else {
1867                                 tr_read_funcs[tmpv](op);
1868                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1869                         }
1870                         hostreg_sspreg_changed(SSP_A);
1871                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1872                         dirty_regb |= KRREG_ST;
1873                         ret++; break;
1874
1875                 // OP a, (ri)
1876                 case 0x11:
1877                 case 0x31:
1878                 case 0x41:
1879                 case 0x51:
1880                 case 0x61:
1881                 case 0x71:
1882                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1883                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1884                         tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1885                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1886                         hostreg_sspreg_changed(SSP_A);
1887                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1888                         dirty_regb |= KRREG_ST;
1889                         ret++; break;
1890
1891                 // OP a, adr
1892                 case 0x13:
1893                 case 0x33:
1894                 case 0x43:
1895                 case 0x53:
1896                 case 0x63:
1897                 case 0x73:
1898                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1899                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1900                         tr_bank_read(op&0x1ff);
1901                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1902                         hostreg_sspreg_changed(SSP_A);
1903                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1904                         dirty_regb |= KRREG_ST;
1905                         ret++; break;
1906
1907                 // OP a, imm
1908                 case 0x14:
1909                 case 0x34:
1910                 case 0x44:
1911                 case 0x54:
1912                 case 0x64:
1913                 case 0x74:
1914                         tmpv = (op & 0xf0) >> 4;
1915                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1916                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1917                         tr_mov16(0, imm);
1918                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1919                         hostreg_sspreg_changed(SSP_A);
1920                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1921                         dirty_regb |= KRREG_ST;
1922                         ret += 2; break;
1923
1924                 // OP a, ((ri))
1925                 case 0x15:
1926                 case 0x35:
1927                 case 0x45:
1928                 case 0x55:
1929                 case 0x65:
1930                 case 0x75:
1931                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1932                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1933                         tr_rX_read2(op);
1934                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1935                         hostreg_sspreg_changed(SSP_A);
1936                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1937                         dirty_regb |= KRREG_ST;
1938                         ret += 3; break;
1939
1940                 // OP a, ri
1941                 case 0x19:
1942                 case 0x39:
1943                 case 0x49:
1944                 case 0x59:
1945                 case 0x69:
1946                 case 0x79: {
1947                         int r;
1948                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1949                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1950                         r = (op&3) | ((op>>6)&4); // src
1951                         if ((r&3) == 3) tr_unhandled();
1952
1953                         if (known_regb & (1 << (r+8))) {
1954                                 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]);  // OPs r5, r5, #val<<16
1955                         } else {
1956                                 int reg = (r < 4) ? 8 : 9;
1957                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1958                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1959                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1960                                 hostreg_r[0] = -1;
1961                         }
1962                         hostreg_sspreg_changed(SSP_A);
1963                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1964                         dirty_regb |= KRREG_ST;
1965                         ret++; break;
1966                 }
1967
1968                 // OP simm
1969                 case 0x1c:
1970                 case 0x3c:
1971                 case 0x4c:
1972                 case 0x5c:
1973                 case 0x6c:
1974                 case 0x7c:
1975                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1976                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1977                         EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff);        // OPs r5, r5, #val<<16
1978                         hostreg_sspreg_changed(SSP_A);
1979                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1980                         dirty_regb |= KRREG_ST;
1981                         ret++; break;
1982         }
1983
1984         return ret;
1985 }
1986
1987 static void *translate_block(int pc)
1988 {
1989         unsigned int op, op1, imm, ccount = 0;
1990         unsigned int *block_start;
1991         int ret, ret_prev = -1, tpc;
1992
1993         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1994         block_start = tcache_ptr;
1995         known_regb = 0;
1996         dirty_regb = KRREG_P;
1997         known_regs.emu_status = 0;
1998         hostreg_clear();
1999
2000         emit_block_prologue();
2001
2002         for (; ccount < 100;)
2003         {
2004                 op = PROGRAM(pc++);
2005                 op1 = op >> 9;
2006                 imm = (u32)-1;
2007
2008                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2009                         imm = PROGRAM(pc++); // immediate
2010                 tpc = pc;
2011
2012                 ret = translate_op(op, &pc, imm);
2013                 if (ret <= 0)
2014                 {
2015                         tr_flush_dirty_prs();
2016                         tr_flush_dirty_ST();
2017                         tr_flush_dirty_pmcrs();
2018                         known_regs.emu_status = 0;
2019
2020                         emit_mov_const(A_COND_AL, 0, op);
2021
2022                         // need immediate?
2023                         if (imm != (u32)-1)
2024                                 emit_mov_const(A_COND_AL, 1, imm);
2025
2026                         // dump PC
2027                         emit_pc_dump(pc);
2028
2029                         if (ret_prev > 0) emit_call(regfile_store);
2030                         emit_call(in_funcs[op1]);
2031                         emit_call(regfile_load);
2032
2033                         if (in_funcs[op1] == NULL) {
2034                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
2035                                 exit(1);
2036                         }
2037                         ccount++;
2038                         hostreg_clear();
2039                         dirty_regb |= KRREG_P;
2040                         known_regb = 0;
2041                 }
2042                 else
2043                 {
2044                         ccount += ret & 0xffff;
2045                         if (ret & 0x10000) break;
2046                 }
2047
2048                 ret_prev = ret;
2049         }
2050
2051         if (ccount >= 100)
2052                 emit_pc_dump(pc);
2053
2054         tr_flush_dirty_prs();
2055         tr_flush_dirty_ST();
2056         tr_flush_dirty_pmcrs();
2057         emit_block_epilogue(ccount + 1);
2058         *tcache_ptr++ = 0xffffffff; // end of block
2059
2060         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2061                 printf("tcache overflow!\n");
2062                 fflush(stdout);
2063                 exit(1);
2064         }
2065
2066         // stats
2067         nblocks++;
2068         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2069
2070 #ifdef DUMP_BLOCK
2071         {
2072                 FILE *f = fopen("tcache.bin", "wb");
2073                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2074                 fclose(f);
2075         }
2076         exit(0);
2077 #endif
2078
2079         handle_caches();
2080
2081         return block_start;
2082 }
2083
2084
2085
2086 // -----------------------------------------------------
2087
2088 int ssp1601_dyn_startup(void)
2089 {
2090         memset(tcache, 0, TCACHE_SIZE);
2091         memset(block_table, 0, sizeof(block_table));
2092         memset(block_table_iram, 0, sizeof(block_table_iram));
2093         tcache_ptr = tcache;
2094         *tcache_ptr++ = 0xffffffff;
2095
2096 #ifdef ARM
2097         // hle'd blocks
2098         block_table[0x400] = (void *) ssp_hle_800;
2099 #endif
2100
2101 // TODO: rm
2102 {
2103 static unsigned short dummy = 0;
2104 PC = &dummy;
2105 }
2106         return 0;
2107 }
2108
2109
2110 void ssp1601_dyn_reset(ssp1601_t *ssp)
2111 {
2112         ssp1601_reset_local(ssp);
2113         ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2114         ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2115         ssp->drc.ptr_dram = (unsigned int) svp->dram;
2116         ssp->drc.iram_dirty = 0;
2117 }
2118
2119 void ssp1601_dyn_run(int cycles)
2120 {
2121         if (ssp->emu_status & SSP_WAIT_MASK) return;
2122
2123 #ifdef DUMP_BLOCK
2124         rPC = DUMP_BLOCK >> 1;
2125 #endif
2126         while (cycles > 0)
2127         {
2128                 int (*trans_entry)(void);
2129                 if (rPC < 0x800/2)
2130                 {
2131                         if (ssp->drc.iram_dirty) {
2132                                 iram_context = get_iram_context();
2133                                 ssp->drc.iram_dirty--;
2134                         }
2135                         if (block_table_iram[iram_context][rPC] == NULL)
2136                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
2137                         trans_entry = (void *) block_table_iram[iram_context][rPC];
2138                 }
2139                 else
2140                 {
2141                         if (block_table[rPC] == NULL)
2142                                 block_table[rPC] = translate_block(rPC);
2143                         trans_entry = (void *) block_table[rPC];
2144                 }
2145
2146                 cycles -= trans_entry();
2147         }
2148 }
2149