svp compiler: block ref counter version
[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 block_ref[0x5090/2];
8 static unsigned int block_ref_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 0x0c9a
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 static u32 ssp_pm_read(int reg)
495 {
496         u32 d = 0, mode;
497
498         if (ssp->emu_status & SSP_PMC_SET)
499         {
500                 ssp->pmac_read[reg] = rPMC.v;
501                 ssp->emu_status &= ~SSP_PMC_SET;
502                 return 0;
503         }
504
505         // just in case
506         ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
507
508         mode = ssp->pmac_read[reg]>>16;
509         if      ((mode & 0xfff0) == 0x0800) // ROM
510         {
511                 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
512                 ssp->pmac_read[reg] += 1;
513         }
514         else if ((mode & 0x47ff) == 0x0018) // DRAM
515         {
516                 unsigned short *dram = (unsigned short *)svp->dram;
517                 int inc = get_inc(mode);
518                 d = dram[ssp->pmac_read[reg]&0xffff];
519                 ssp->pmac_read[reg] += inc;
520         }
521
522         // PMC value corresponds to last PMR accessed
523         rPMC.v = ssp->pmac_read[reg];
524
525         return d;
526 }
527
528 static void ssp_pm_write(u32 d, int reg)
529 {
530         unsigned short *dram;
531         int mode, addr;
532
533         if (ssp->emu_status & SSP_PMC_SET)
534         {
535                 ssp->pmac_write[reg] = rPMC.v;
536                 ssp->emu_status &= ~SSP_PMC_SET;
537                 return;
538         }
539
540         // just in case
541         ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
542
543         dram = (unsigned short *)svp->dram;
544         mode = ssp->pmac_write[reg]>>16;
545         addr = ssp->pmac_write[reg]&0xffff;
546         if      ((mode & 0x43ff) == 0x0018) // DRAM
547         {
548                 int inc = get_inc(mode);
549                 if (mode & 0x0400) {
550                        overwrite_write(dram[addr], d);
551                 } else dram[addr] = d;
552                 ssp->pmac_write[reg] += inc;
553         }
554         else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
555         {
556                 if (mode & 0x0400) {
557                        overwrite_write(dram[addr], d);
558                 } else dram[addr] = d;
559                 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
560         }
561         else if ((mode & 0x47ff) == 0x001c) // IRAM
562         {
563                 int inc = get_inc(mode);
564                 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
565                 ssp->pmac_write[reg] += inc;
566                 ssp->drc.iram_dirty = 1;
567         }
568
569         rPMC.v = ssp->pmac_write[reg];
570 }
571
572
573 // -----------------------------------------------------
574
575 // 14 IRAM blocks
576 static unsigned char iram_context_map[] =
577 {
578          0, 0, 0, 0, 1, 0, 0, 0, // 04
579          0, 0, 0, 0, 0, 0, 2, 0, // 0e
580          0, 0, 0, 0, 0, 3, 0, 4, // 15 17
581          5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
582          8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
583          0, 0, 0, 0, 0, 0, 0, 0,
584          0, 0,11, 0, 0,12, 0, 0, // 32 35
585         13,14, 0, 0, 0, 0, 0, 0  // 38 39
586 };
587
588 static int get_iram_context(void)
589 {
590         unsigned char *ir = (unsigned char *)svp->iram_rom;
591         int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
592         val1 = iram_context_map[(val>>1)&0x3f];
593
594         if (val1 == 0) {
595                 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
596                 //debug_dump2file(name, svp->iram_rom, 0x800);
597                 exit(1);
598         }
599 //      elprintf(EL_ANOMALY, "iram_context: %02i", val1);
600         return val1;
601 }
602
603 // -----------------------------------------------------
604
605 /* regs with known values */
606 static struct
607 {
608         ssp_reg_t gr[8];
609         unsigned char r[8];
610         unsigned int pmac_read[5];
611         unsigned int pmac_write[5];
612         ssp_reg_t pmc;
613         unsigned int emu_status;
614 } known_regs;
615
616 #define KRREG_X     (1 << SSP_X)
617 #define KRREG_Y     (1 << SSP_Y)
618 #define KRREG_A     (1 << SSP_A)        /* AH only */
619 #define KRREG_ST    (1 << SSP_ST)
620 #define KRREG_STACK (1 << SSP_STACK)
621 #define KRREG_PC    (1 << SSP_PC)
622 #define KRREG_P     (1 << SSP_P)
623 #define KRREG_PR0   (1 << 8)
624 #define KRREG_PR4   (1 << 12)
625 #define KRREG_AL    (1 << 16)
626 #define KRREG_PMCM  (1 << 18)           /* only mode word of PMC */
627 #define KRREG_PMC   (1 << 19)
628 #define KRREG_PM0R  (1 << 20)
629 #define KRREG_PM1R  (1 << 21)
630 #define KRREG_PM2R  (1 << 22)
631 #define KRREG_PM3R  (1 << 23)
632 #define KRREG_PM4R  (1 << 24)
633 #define KRREG_PM0W  (1 << 25)
634 #define KRREG_PM1W  (1 << 26)
635 #define KRREG_PM2W  (1 << 27)
636 #define KRREG_PM3W  (1 << 28)
637 #define KRREG_PM4W  (1 << 29)
638
639 /* bitfield of known register values */
640 static u32 known_regb = 0;
641
642 /* known vals, which need to be flushed
643  * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
644  * ST means flags are being held in ARM PSR
645  * P means that it needs to be recalculated
646  */
647 static u32 dirty_regb = 0;
648
649 /* known values of host regs.
650  * -1            - unknown
651  * 000000-00ffff - 16bit value
652  * 100000-10ffff - base reg (r7) + 16bit val
653  * 0r0000        - means reg (low) eq gr[r].h, r != AL
654  */
655 static int hostreg_r[4];
656
657 static void hostreg_clear(void)
658 {
659         int i;
660         for (i = 0; i < 4; i++)
661                 hostreg_r[i] = -1;
662 }
663
664 static void hostreg_sspreg_changed(int sspreg)
665 {
666         int i;
667         for (i = 0; i < 4; i++)
668                 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
669 }
670
671
672 #define PROGRAM(x)   ((unsigned short *)svp->iram_rom)[x]
673 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
674
675 static void tr_unhandled(void)
676 {
677         FILE *f = fopen("tcache.bin", "wb");
678         fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
679         fclose(f);
680         printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
681         exit(1);
682 }
683
684 /* update P, if needed. Trashes r0 */
685 static void tr_flush_dirty_P(void)
686 {
687         // TODO: const regs
688         if (!(dirty_regb & KRREG_P)) return;
689         EOP_MOV_REG_ASR(10, 4, 16);             // mov  r10, r4, asr #16
690         EOP_MOV_REG_LSL( 0, 4, 16);             // mov  r0,  r4, lsl #16
691         EOP_MOV_REG_ASR( 0, 0, 15);             // mov  r0,  r0, asr #15
692         EOP_MUL(10, 0, 10);                     // mul  r10, r0, r10
693         dirty_regb &= ~KRREG_P;
694         hostreg_r[0] = -1;
695 }
696
697 /* write dirty pr to host reg. Nothing is trashed */
698 static void tr_flush_dirty_pr(int r)
699 {
700         int ror = 0, reg;
701
702         if (!(dirty_regb & (1 << (r+8)))) return;
703
704         switch (r&3) {
705                 case 0: ror =    0; break;
706                 case 1: ror = 24/2; break;
707                 case 2: ror = 16/2; break;
708         }
709         reg = (r < 4) ? 8 : 9;
710         EOP_BIC_IMM(reg,reg,ror,0xff);
711         if (known_regs.r[r] != 0)
712                 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
713         dirty_regb &= ~(1 << (r+8));
714 }
715
716 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
717 static void tr_flush_dirty_prs(void)
718 {
719         int i, ror = 0, reg;
720         int dirty = dirty_regb >> 8;
721         /* r0-r7 */
722         for (i = 0; dirty && i < 8; i++, dirty >>= 1)
723         {
724                 if (!(dirty&1)) continue;
725                 switch (i&3) {
726                         case 0: ror =    0; break;
727                         case 1: ror = 24/2; break;
728                         case 2: ror = 16/2; break;
729                 }
730                 reg = (i < 4) ? 8 : 9;
731                 EOP_BIC_IMM(reg,reg,ror,0xff);
732                 if (known_regs.r[i] != 0)
733                         EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
734         }
735         dirty_regb &= ~0xff00;
736 }
737
738 /* write dirty pr and "forget" it. Nothing is trashed. */
739 static void tr_release_pr(int r)
740 {
741         tr_flush_dirty_pr(r);
742         known_regb &= ~(1 << (r+8));
743 }
744
745 /* fush ARM PSR to r6. Trashes r1 */
746 static void tr_flush_dirty_ST(void)
747 {
748         if (!(dirty_regb & KRREG_ST)) return;
749         EOP_BIC_IMM(6,6,0,0x0f);
750         EOP_MRS(1);
751         EOP_ORR_REG_LSR(6,6,1,28);
752         dirty_regb &= ~KRREG_ST;
753         hostreg_r[1] = -1;
754 }
755
756 /* inverse of above. Trashes r1 */
757 static void tr_make_dirty_ST(void)
758 {
759         if (dirty_regb & KRREG_ST) return;
760         if (known_regb & KRREG_ST) {
761                 int flags = 0;
762                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
763                 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
764                 EOP_MSR_IMM(4/2, flags);
765         } else {
766                 EOP_MOV_REG_LSL(1, 6, 28);
767                 EOP_MSR_REG(1);
768                 hostreg_r[1] = -1;
769         }
770         dirty_regb |= KRREG_ST;
771 }
772
773 /* load 16bit val into host reg r0-r3. Nothing is trashed */
774 static void tr_mov16(int r, int val)
775 {
776         if (hostreg_r[r] != val) {
777                 emit_mov_const(A_COND_AL, r, val);
778                 hostreg_r[r] = val;
779         }
780 }
781
782 static void tr_mov16_cond(int cond, int r, int val)
783 {
784         emit_mov_const(cond, r, val);
785         hostreg_r[r] = -1;
786 }
787
788 /* trashes r0 */
789 static void tr_flush_dirty_pmcrs(void)
790 {
791         u32 i, val = (u32)-1;
792         if (!(dirty_regb & 0x3ff80000)) return;
793
794         if (dirty_regb & KRREG_PMC) {
795                 val = known_regs.pmc.v;
796                 emit_mov_const(A_COND_AL, 1, val);
797                 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
798
799                 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
800                         printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
801                         tr_unhandled();
802                 }
803         }
804         for (i = 0; i < 5; i++)
805         {
806                 if (dirty_regb & (1 << (20+i))) {
807                         if (val != known_regs.pmac_read[i]) {
808                                 val = known_regs.pmac_read[i];
809                                 emit_mov_const(A_COND_AL, 1, val);
810                         }
811                         EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
812                 }
813                 if (dirty_regb & (1 << (25+i))) {
814                         if (val != known_regs.pmac_write[i]) {
815                                 val = known_regs.pmac_write[i];
816                                 emit_mov_const(A_COND_AL, 1, val);
817                         }
818                         EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
819                 }
820         }
821         dirty_regb &= ~0x3ff80000;
822         hostreg_r[1] = -1;
823 }
824
825 /* read bank word to r0 (upper bits zero). Thrashes r1. */
826 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
827 {
828         int breg = 7;
829         if (addr > 0x7f) {
830                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
831                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
832                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
833                 }
834                 breg = 1;
835         }
836         EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1);    // ldrh r0, [r1, (op&0x7f)<<1]
837         hostreg_r[0] = -1;
838 }
839
840 /* write r0 to bank. Trashes r1. */
841 static void tr_bank_write(int addr)
842 {
843         int breg = 7;
844         if (addr > 0x7f) {
845                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
846                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
847                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
848                 }
849                 breg = 1;
850         }
851         EOP_STRH_IMM(0,breg,(addr&0x7f)<<1);            // strh r0, [r1, (op&0x7f)<<1]
852 }
853
854 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
855 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
856 {
857         int modulo_shift = -1;  /* unknown */
858
859         if (mod == 0) return;
860
861         if (!need_modulo || mod == 1) // +!
862                 modulo_shift = 8;
863         else if (need_modulo && (known_regb & KRREG_ST)) {
864                 modulo_shift = known_regs.gr[SSP_ST].h & 7;
865                 if (modulo_shift == 0) modulo_shift = 8;
866         }
867
868         if (modulo_shift == -1)
869         {
870                 int reg = (r < 4) ? 8 : 9;
871                 tr_release_pr(r);
872                 if (dirty_regb & KRREG_ST) {
873                         // avoid flushing ARM flags
874                         EOP_AND_IMM(1, 6, 0, 0x70);
875                         EOP_SUB_IMM(1, 1, 0, 0x10);
876                         EOP_AND_IMM(1, 1, 0, 0x70);
877                         EOP_ADD_IMM(1, 1, 0, 0x10);
878                 } else {
879                         EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands  r1, r6, #0x70
880                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
881                 }
882                 EOP_MOV_REG_LSR(1, 1, 4);               // mov r1, r1, lsr #4
883                 EOP_RSB_IMM(2, 1, 0, 8);                // rsb r1, r1, #8
884                 EOP_MOV_IMM(3, 8/2, count);             // mov r3, #0x01000000
885                 if (r&3)
886                         EOP_ADD_IMM(1, 1, 0, (r&3)*8);  // add r1, r1, #(r&3)*8
887                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
888                 if (mod == 2)
889                      EOP_SUB_REG2_LSL(reg,reg,3,2);     // sub reg, reg, #0x01000000 << r2
890                 else EOP_ADD_REG2_LSL(reg,reg,3,2);
891                 EOP_RSB_IMM(1, 1, 0, 32);               // rsb r1, r1, #32
892                 EOP_MOV_REG2_ROR(reg,reg,1);            // mov reg, reg, ror r1
893                 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
894         }
895         else if (known_regb & (1 << (r + 8)))
896         {
897                 int modulo = (1 << modulo_shift) - 1;
898                 if (mod == 2)
899                      known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
900                 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
901         }
902         else
903         {
904                 int reg = (r < 4) ? 8 : 9;
905                 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
906                 EOP_MOV_REG_ROR(reg,reg,ror);
907                 // {add|sub} reg, reg, #1<<shift
908                 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
909                 EOP_MOV_REG_ROR(reg,reg,32-ror);
910         }
911 }
912
913 /* handle writes r0 to (rX). Trashes r1.
914  * fortunately we can ignore modulo increment modes for writes. */
915 static void tr_rX_write(int op)
916 {
917         if ((op&3) == 3)
918         {
919                 int mod = (op>>2) & 3; // direct addressing
920                 tr_bank_write((op & 0x100) + mod);
921         }
922         else
923         {
924                 int r = (op&3) | ((op>>6)&4);
925                 if (known_regb & (1 << (r + 8))) {
926                         tr_bank_write((op&0x100) | known_regs.r[r]);
927                 } else {
928                         int reg = (r < 4) ? 8 : 9;
929                         int ror = ((4 - (r&3))*8) & 0x1f;
930                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
931                         if (r >= 4)
932                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
933                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
934                         else     EOP_ADD_REG_LSL(1,7,1,1);
935                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
936                         hostreg_r[1] = -1;
937                 }
938                 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
939         }
940 }
941
942 /* read (rX) to r0. Trashes r1-r3. */
943 static void tr_rX_read(int r, int mod)
944 {
945         if ((r&3) == 3)
946         {
947                 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
948         }
949         else
950         {
951                 if (known_regb & (1 << (r + 8))) {
952                         tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
953                 } else {
954                         int reg = (r < 4) ? 8 : 9;
955                         int ror = ((4 - (r&3))*8) & 0x1f;
956                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
957                         if (r >= 4)
958                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
959                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
960                         else     EOP_ADD_REG_LSL(1,7,1,1);
961                         EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
962                         hostreg_r[0] = hostreg_r[1] = -1;
963                 }
964                 tr_ptrr_mod(r, mod, 1, 1);
965         }
966 }
967
968 /* read ((rX)) to r0. Trashes r1,r2. */
969 static void tr_rX_read2(int op)
970 {
971         int r = (op&3) | ((op>>6)&4); // src
972
973         if ((r&3) == 3) {
974                 tr_bank_read((op&0x100) | ((op>>2)&3));
975         } else if (known_regb & (1 << (r+8))) {
976                 tr_bank_read((op&0x100) | known_regs.r[r]);
977         } else {
978                 int reg = (r < 4) ? 8 : 9;
979                 int ror = ((4 - (r&3))*8) & 0x1f;
980                 EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
981                 if (r >= 4)
982                         EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
983                 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
984                 else     EOP_ADD_REG_LSL(1,7,1,1);
985                 EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
986         }
987         EOP_LDR_IMM(2,7,0x48c);                                 // ptr_iram_rom
988         EOP_ADD_REG_LSL(2,2,0,1);                               // add  r2, r2, r0, lsl #1
989         EOP_ADD_IMM(0,0,0,1);                                   // add  r0, r0, #1
990         if ((r&3) == 3) {
991                 tr_bank_write((op&0x100) | ((op>>2)&3));
992         } else if (known_regb & (1 << (r+8))) {
993                 tr_bank_write((op&0x100) | known_regs.r[r]);
994         } else {
995                 EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
996                 hostreg_r[1] = -1;
997         }
998         EOP_LDRH_SIMPLE(0,2);                                   // ldrh r0, [r2]
999         hostreg_r[0] = hostreg_r[2] = -1;
1000 }
1001
1002 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1003 static int tr_cond_check(int op)
1004 {
1005         int f = (op & 0x100) >> 8;
1006         switch (op&0xf0) {
1007                 case 0x00: return A_COND_AL;    /* always true */
1008                 case 0x50:                      /* Z matches f(?) bit */
1009                         if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1010                         EOP_TST_IMM(6, 0, 4);
1011                         return f ? A_COND_NE : A_COND_EQ;
1012                 case 0x70:                      /* N matches f(?) bit */
1013                         if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1014                         EOP_TST_IMM(6, 0, 8);
1015                         return f ? A_COND_NE : A_COND_EQ;
1016                 default:
1017                         printf("unimplemented cond?\n");
1018                         tr_unhandled();
1019                         return 0;
1020         }
1021 }
1022
1023 static int tr_neg_cond(int cond)
1024 {
1025         switch (cond) {
1026                 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1027                 case A_COND_EQ: return A_COND_NE;
1028                 case A_COND_NE: return A_COND_EQ;
1029                 case A_COND_MI: return A_COND_PL;
1030                 case A_COND_PL: return A_COND_MI;
1031                 default:        printf("bad cond for neg\n"); exit(1);
1032         }
1033         return 0;
1034 }
1035
1036 static int tr_aop_ssp2arm(int op)
1037 {
1038         switch (op) {
1039                 case 1: return A_OP_SUB;
1040                 case 3: return A_OP_CMP;
1041                 case 4: return A_OP_ADD;
1042                 case 5: return A_OP_AND;
1043                 case 6: return A_OP_ORR;
1044                 case 7: return A_OP_EOR;
1045         }
1046
1047         tr_unhandled();
1048         return 0;
1049 }
1050
1051 // -----------------------------------------------------
1052
1053 //@ r4:  XXYY
1054 //@ r5:  A
1055 //@ r6:  STACK and emu flags
1056 //@ r7:  SSP context
1057 //@ r10: P
1058
1059 // read general reg to r0. Trashes r1
1060 static void tr_GR0_to_r0(int op)
1061 {
1062         tr_mov16(0, 0xffff);
1063 }
1064
1065 static void tr_X_to_r0(int op)
1066 {
1067         if (hostreg_r[0] != (SSP_X<<16)) {
1068                 EOP_MOV_REG_LSR(0, 4, 16);      // mov  r0, r4, lsr #16
1069                 hostreg_r[0] = SSP_X<<16;
1070         }
1071 }
1072
1073 static void tr_Y_to_r0(int op)
1074 {
1075         if (hostreg_r[0] != (SSP_Y<<16)) {
1076                 EOP_MOV_REG_SIMPLE(0, 4);       // mov  r0, r4
1077                 hostreg_r[0] = SSP_Y<<16;
1078         }
1079 }
1080
1081 static void tr_A_to_r0(int op)
1082 {
1083         if (hostreg_r[0] != (SSP_A<<16)) {
1084                 EOP_MOV_REG_LSR(0, 5, 16);      // mov  r0, r5, lsr #16  @ AH
1085                 hostreg_r[0] = SSP_A<<16;
1086         }
1087 }
1088
1089 static void tr_ST_to_r0(int op)
1090 {
1091         // VR doesn't need much accuracy here..
1092         EOP_MOV_REG_LSR(0, 6, 4);               // mov  r0, r6, lsr #4
1093         EOP_AND_IMM(0, 0, 0, 0x67);             // and  r0, r0, #0x67
1094         hostreg_r[0] = -1;
1095 }
1096
1097 static void tr_STACK_to_r0(int op)
1098 {
1099         // 448
1100         EOP_SUB_IMM(6, 6,  8/2, 0x20);          // sub  r6, r6, #1<<29
1101         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
1102         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
1103         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
1104         EOP_LDRH_SIMPLE(0, 1);                  // ldrh r0, [r1]
1105         hostreg_r[0] = hostreg_r[1] = -1;
1106 }
1107
1108 static void tr_PC_to_r0(int op)
1109 {
1110         tr_mov16(0, known_regs.gr[SSP_PC].h);
1111 }
1112
1113 static void tr_P_to_r0(int op)
1114 {
1115         tr_flush_dirty_P();
1116         EOP_MOV_REG_LSR(0, 10, 16);             // mov  r0, r10, lsr #16
1117         hostreg_r[0] = -1;
1118 }
1119
1120 static void tr_AL_to_r0(int op)
1121 {
1122         if (op == 0x000f) {
1123                 if (known_regb & KRREG_PMC) {
1124                         known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1125                 } else {
1126                         EOP_LDR_IMM(0,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1127                         EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1128                         EOP_STR_IMM(0,7,0x484);
1129                 }
1130         }
1131
1132         if (hostreg_r[0] != (SSP_AL<<16)) {
1133                 EOP_MOV_REG_SIMPLE(0, 5);       // mov  r0, r5
1134                 hostreg_r[0] = SSP_AL<<16;
1135         }
1136 }
1137
1138 static void tr_PMX_to_r0(int reg)
1139 {
1140         if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1141         {
1142                 known_regs.pmac_read[reg] = known_regs.pmc.v;
1143                 known_regs.emu_status &= ~SSP_PMC_SET;
1144                 known_regb |= 1 << (20+reg);
1145                 dirty_regb |= 1 << (20+reg);
1146                 return;
1147         }
1148
1149         if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1150         {
1151                 u32 pmcv = known_regs.pmac_read[reg];
1152                 int mode = pmcv>>16;
1153                 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1154
1155                 if      ((mode & 0xfff0) == 0x0800)
1156                 {
1157                         EOP_LDR_IMM(1,7,0x488);         // rom_ptr
1158                         emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1159                         EOP_LDRH_REG(0,1,0);            // ldrh r0, [r1, r0]
1160                         known_regs.pmac_read[reg] += 1;
1161                 }
1162                 else if ((mode & 0x47ff) == 0x0018) // DRAM
1163                 {
1164                         int inc = get_inc(mode);
1165                         EOP_LDR_IMM(1,7,0x490);         // dram_ptr
1166                         emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1167                         EOP_LDRH_REG(0,1,0);            // ldrh r0, [r1, r0]
1168                         if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
1169                         {
1170                                 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1171                                 tr_flush_dirty_ST();
1172                                 EOP_LDR_IMM(1,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1173                                 EOP_TST_REG_SIMPLE(0,0);
1174                                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1);       // addeq r11, r11, #1024
1175                                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
1176                                 EOP_STR_IMM(1,7,0x484);                 // str r1, [r7, #0x484] // emu_status
1177                         }
1178                         known_regs.pmac_read[reg] += inc;
1179                 }
1180                 else
1181                 {
1182                         tr_unhandled();
1183                 }
1184                 known_regs.pmc.v = known_regs.pmac_read[reg];
1185                 //known_regb |= KRREG_PMC;
1186                 dirty_regb |= KRREG_PMC;
1187                 dirty_regb |= 1 << (20+reg);
1188                 hostreg_r[0] = hostreg_r[1] = -1;
1189                 return;
1190         }
1191
1192         known_regb &= ~KRREG_PMC;
1193         dirty_regb &= ~KRREG_PMC;
1194         known_regb &= ~(1 << (20+reg));
1195         dirty_regb &= ~(1 << (20+reg));
1196
1197         // call the C code to handle this
1198         tr_flush_dirty_ST();
1199         //tr_flush_dirty_pmcrs();
1200         tr_mov16(0, reg);
1201         emit_call(ssp_pm_read);
1202         hostreg_clear();
1203 }
1204
1205 static void tr_PM0_to_r0(int op)
1206 {
1207         tr_PMX_to_r0(0);
1208 }
1209
1210 static void tr_PM1_to_r0(int op)
1211 {
1212         tr_PMX_to_r0(1);
1213 }
1214
1215 static void tr_PM2_to_r0(int op)
1216 {
1217         tr_PMX_to_r0(2);
1218 }
1219
1220 static void tr_XST_to_r0(int op)
1221 {
1222         EOP_ADD_IMM(0, 7, 24/2, 4);     // add r0, r7, #0x400
1223         EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1224 }
1225
1226 static void tr_PM4_to_r0(int op)
1227 {
1228         tr_PMX_to_r0(4);
1229 }
1230
1231 static void tr_PMC_to_r0(int op)
1232 {
1233         if (known_regb & KRREG_PMC)
1234         {
1235                 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1236                         known_regs.emu_status |= SSP_PMC_SET;
1237                         known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1238                         // do nothing - this is handled elsewhere
1239                 } else {
1240                         tr_mov16(0, known_regs.pmc.l);
1241                         known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1242                 }
1243         }
1244         else
1245         {
1246                 EOP_LDR_IMM(1,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1247                 tr_flush_dirty_ST();
1248                 if (op != 0x000e)
1249                         EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1250                 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1251                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1252                 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1253                 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET);       // orrne r1, r1, #..
1254                 EOP_STR_IMM(1,7,0x484);
1255                 hostreg_r[0] = hostreg_r[1] = -1;
1256         }
1257 }
1258
1259
1260 typedef void (tr_read_func)(int op);
1261
1262 static tr_read_func *tr_read_funcs[16] =
1263 {
1264         tr_GR0_to_r0,
1265         tr_X_to_r0,
1266         tr_Y_to_r0,
1267         tr_A_to_r0,
1268         tr_ST_to_r0,
1269         tr_STACK_to_r0,
1270         tr_PC_to_r0,
1271         tr_P_to_r0,
1272         tr_PM0_to_r0,
1273         tr_PM1_to_r0,
1274         tr_PM2_to_r0,
1275         tr_XST_to_r0,
1276         tr_PM4_to_r0,
1277         (tr_read_func *)tr_unhandled,
1278         tr_PMC_to_r0,
1279         tr_AL_to_r0
1280 };
1281
1282
1283 // write r0 to general reg handlers. Trashes r1
1284 #define TR_WRITE_R0_TO_REG(reg) \
1285 { \
1286         hostreg_sspreg_changed(reg); \
1287         hostreg_r[0] = (reg)<<16; \
1288         if (const_val != -1) { \
1289                 known_regs.gr[reg].h = const_val; \
1290                 known_regb |= 1 << (reg); \
1291         } else { \
1292                 known_regb &= ~(1 << (reg)); \
1293         } \
1294 }
1295
1296 static void tr_r0_to_GR0(int const_val)
1297 {
1298         // do nothing
1299 }
1300
1301 static void tr_r0_to_X(int const_val)
1302 {
1303         EOP_MOV_REG_LSL(4, 4, 16);              // mov  r4, r4, lsl #16
1304         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
1305         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
1306         dirty_regb |= KRREG_P;                  // touching X or Y makes P dirty.
1307         TR_WRITE_R0_TO_REG(SSP_X);
1308 }
1309
1310 static void tr_r0_to_Y(int const_val)
1311 {
1312         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
1313         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
1314         EOP_MOV_REG_ROR(4, 4, 16);              // mov  r4, r4, ror #16
1315         dirty_regb |= KRREG_P;
1316         TR_WRITE_R0_TO_REG(SSP_Y);
1317 }
1318
1319 static void tr_r0_to_A(int const_val)
1320 {
1321         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
1322         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16  @ AL
1323         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
1324         TR_WRITE_R0_TO_REG(SSP_A);
1325 }
1326
1327 static void tr_r0_to_ST(int const_val)
1328 {
1329         // VR doesn't need much accuracy here..
1330         EOP_AND_IMM(1, 0,   0, 0x67);           // and   r1, r0, #0x67
1331         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
1332         EOP_ORR_REG_LSL(6, 6, 1, 4);            // orr   r6, r6, r1, lsl #4
1333         TR_WRITE_R0_TO_REG(SSP_ST);
1334         hostreg_r[1] = -1;
1335         dirty_regb &= ~KRREG_ST;
1336 }
1337
1338 static void tr_r0_to_STACK(int const_val)
1339 {
1340         // 448
1341         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
1342         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
1343         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
1344         EOP_STRH_SIMPLE(0, 1);                  // strh r0, [r1]
1345         EOP_ADD_IMM(6, 6,  8/2, 0x20);          // add  r6, r6, #1<<29
1346         hostreg_r[1] = -1;
1347 }
1348
1349 static void tr_r0_to_PC(int const_val)
1350 {
1351         EOP_MOV_REG_LSL(1, 0, 16);              // mov  r1, r0, lsl #16
1352         EOP_STR_IMM(1,7,0x400+6*4);             // str  r1, [r7, #(0x400+6*8)]
1353         hostreg_r[1] = -1;
1354 }
1355
1356 static void tr_r0_to_AL(int const_val)
1357 {
1358         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16
1359         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
1360         EOP_MOV_REG_ROR(5, 5, 16);              // mov  r5, r5, ror #16
1361         hostreg_sspreg_changed(SSP_AL);
1362         if (const_val != -1) {
1363                 known_regs.gr[SSP_A].l = const_val;
1364                 known_regb |= 1 << SSP_AL;
1365         } else
1366                 known_regb &= ~(1 << SSP_AL);
1367 }
1368
1369 static void tr_r0_to_PMX(int reg)
1370 {
1371         if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1372         {
1373                 known_regs.pmac_write[reg] = known_regs.pmc.v;
1374                 known_regs.emu_status &= ~SSP_PMC_SET;
1375                 known_regb |= 1 << (25+reg);
1376                 dirty_regb |= 1 << (25+reg);
1377                 return;
1378         }
1379
1380         if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1381         {
1382                 int mode, addr;
1383
1384                 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1385
1386                 mode = known_regs.pmac_write[reg]>>16;
1387                 addr = known_regs.pmac_write[reg]&0xffff;
1388                 if      ((mode & 0x43ff) == 0x0018) // DRAM
1389                 {
1390                         int inc = get_inc(mode);
1391                         if (mode & 0x0400) tr_unhandled();
1392                         EOP_LDR_IMM(1,7,0x490);         // dram_ptr
1393                         emit_mov_const(A_COND_AL, 2, addr<<1);
1394                         EOP_STRH_REG(0,1,2);            // strh r0, [r1, r2]
1395                         known_regs.pmac_write[reg] += inc;
1396                 }
1397                 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1398                 {
1399                         if (mode & 0x0400) tr_unhandled();
1400                         EOP_LDR_IMM(1,7,0x490);         // dram_ptr
1401                         emit_mov_const(A_COND_AL, 2, addr<<1);
1402                         EOP_STRH_REG(0,1,2);            // strh r0, [r1, r2]
1403                         known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1404                 }
1405                 else if ((mode & 0x47ff) == 0x001c) // IRAM
1406                 {
1407                         int inc = get_inc(mode);
1408                         EOP_LDR_IMM(1,7,0x48c);         // iram_ptr
1409                         emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1410                         EOP_STRH_REG(0,1,2);            // strh r0, [r1, r2]
1411                         EOP_MOV_IMM(1,0,1);
1412                         EOP_STR_IMM(1,7,0x494);         // iram_dirty
1413                         known_regs.pmac_write[reg] += inc;
1414                 }
1415                 else
1416                         tr_unhandled();
1417
1418                 known_regs.pmc.v = known_regs.pmac_write[reg];
1419                 //known_regb |= KRREG_PMC;
1420                 dirty_regb |= KRREG_PMC;
1421                 dirty_regb |= 1 << (25+reg);
1422                 hostreg_r[1] = hostreg_r[2] = -1;
1423                 return;
1424         }
1425
1426         known_regb &= ~KRREG_PMC;
1427         dirty_regb &= ~KRREG_PMC;
1428         known_regb &= ~(1 << (25+reg));
1429         dirty_regb &= ~(1 << (25+reg));
1430
1431         // call the C code to handle this
1432         tr_flush_dirty_ST();
1433         //tr_flush_dirty_pmcrs();
1434         tr_mov16(1, reg);
1435         emit_call(ssp_pm_write);
1436         hostreg_clear();
1437 }
1438
1439 static void tr_r0_to_PM0(int const_val)
1440 {
1441         tr_r0_to_PMX(0);
1442 }
1443
1444 static void tr_r0_to_PM1(int const_val)
1445 {
1446         tr_r0_to_PMX(1);
1447 }
1448
1449 static void tr_r0_to_PM2(int const_val)
1450 {
1451         tr_r0_to_PMX(2);
1452 }
1453
1454 static void tr_r0_to_PM4(int const_val)
1455 {
1456         tr_r0_to_PMX(4);
1457 }
1458
1459 static void tr_r0_to_PMC(int const_val)
1460 {
1461         if ((known_regb & KRREG_PMC) && const_val != -1)
1462         {
1463                 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1464                         known_regs.emu_status |= SSP_PMC_SET;
1465                         known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1466                         known_regs.pmc.h = const_val;
1467                 } else {
1468                         known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1469                         known_regs.pmc.l = const_val;
1470                 }
1471         }
1472         else
1473         {
1474                 tr_flush_dirty_ST();
1475                 if (known_regb & KRREG_PMC) {
1476                         emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1477                         EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1478                         known_regb &= ~KRREG_PMC;
1479                         dirty_regb &= ~KRREG_PMC;
1480                 }
1481                 EOP_LDR_IMM(1,7,0x484);                 // ldr r1, [r7, #0x484] // emu_status
1482                 EOP_ADD_IMM(2,7,24/2,4);                // add r2, r7, #0x400
1483                 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1484                 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4);         // strxx r0, [r2, #SSP_PMC]
1485                 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1486                 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1487                 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1488                 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET);       // orrne r1, r1, #..
1489                 EOP_STR_IMM(1,7,0x484);
1490                 hostreg_r[1] = hostreg_r[2] = -1;
1491         }
1492 }
1493
1494 typedef void (tr_write_func)(int const_val);
1495
1496 static tr_write_func *tr_write_funcs[16] =
1497 {
1498         tr_r0_to_GR0,
1499         tr_r0_to_X,
1500         tr_r0_to_Y,
1501         tr_r0_to_A,
1502         tr_r0_to_ST,
1503         tr_r0_to_STACK,
1504         tr_r0_to_PC,
1505         (tr_write_func *)tr_unhandled,
1506         tr_r0_to_PM0,
1507         tr_r0_to_PM1,
1508         tr_r0_to_PM2,
1509         (tr_write_func *)tr_unhandled,
1510         tr_r0_to_PM4,
1511         (tr_write_func *)tr_unhandled,
1512         tr_r0_to_PMC,
1513         tr_r0_to_AL
1514 };
1515
1516 static void tr_mac_load_XY(int op)
1517 {
1518         tr_rX_read(op&3, (op>>2)&3); // X
1519         EOP_MOV_REG_LSL(4, 0, 16);
1520         tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1521         EOP_ORR_REG_SIMPLE(4, 0);
1522         dirty_regb |= KRREG_P;
1523         hostreg_sspreg_changed(SSP_X);
1524         hostreg_sspreg_changed(SSP_Y);
1525         known_regb &= ~KRREG_X;
1526         known_regb &= ~KRREG_Y;
1527 }
1528
1529 // -----------------------------------------------------
1530
1531 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1532 {
1533         u32 pmcv, tmpv;
1534         if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1535
1536         // programming PMC:
1537         // ldi PMC, imm1
1538         // ldi PMC, imm2
1539         (*pc)++;
1540         pmcv = imm | (PROGRAM((*pc)++) << 16);
1541         known_regs.pmc.v = pmcv;
1542         known_regb |= KRREG_PMC;
1543         dirty_regb |= KRREG_PMC;
1544         known_regs.emu_status |= SSP_PMC_SET;
1545
1546         // check for possible reg programming
1547         tmpv = PROGRAM(*pc);
1548         if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1549         {
1550                 int is_write = (tmpv & 0xff8f) == 0x80;
1551                 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1552                 if (reg > 4) tr_unhandled();
1553                 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1554                 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1555                 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1556                 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1557                 known_regs.emu_status &= ~SSP_PMC_SET;
1558                 (*pc)++;
1559                 return 5;
1560         }
1561
1562         tr_unhandled();
1563         return 4;
1564 }
1565
1566 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1567
1568 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1569 {
1570         // ldi ST, 0
1571         // ldi PM0, 0
1572         // ldi PM0, 0
1573         // ldi ST, 60h
1574         unsigned short *pp;
1575         if (op != 0x0840 || imm != 0) return 0;
1576         pp = PROGRAM_P(*pc);
1577         if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1578
1579         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
1580         EOP_ORR_IMM(6, 6, 24/2, 6);             // orr   r6, r6, 0x600
1581         hostreg_sspreg_changed(SSP_ST);
1582         known_regs.gr[SSP_ST].h = 0x60;
1583         known_regb |= 1 << SSP_ST;
1584         dirty_regb &= ~KRREG_ST;
1585         (*pc) += 3*2;
1586         return 4*2;
1587 }
1588
1589 static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1590 {
1591         // @ 3DA2 and 426A
1592         // ld PMC, (r3|00)
1593         // ld (r3|00), PMC
1594         // ld -, AL
1595         if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1596
1597         tr_bank_read(0);
1598         EOP_MOV_REG_LSL(0, 0, 4);
1599         EOP_ORR_REG_LSR(0, 0, 0, 16);
1600         tr_bank_write(0);
1601         (*pc) += 2;
1602         return 3;
1603 }
1604
1605 // -----------------------------------------------------
1606
1607 static int translate_op(unsigned int op, int *pc, int imm)
1608 {
1609         u32 tmpv, tmpv2, tmpv3;
1610         int ret = 0;
1611         known_regs.gr[SSP_PC].h = *pc;
1612
1613         switch (op >> 9)
1614         {
1615                 // ld d, s
1616                 case 0x00:
1617                         if (op == 0) { ret++; break; } // nop
1618                         tmpv  = op & 0xf; // src
1619                         tmpv2 = (op >> 4) & 0xf; // dst
1620                         if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1621                                 tr_flush_dirty_P();
1622                                 EOP_MOV_REG_SIMPLE(5, 10);
1623                                 hostreg_sspreg_changed(SSP_A);
1624                                 known_regb &= ~(KRREG_A|KRREG_AL);
1625                                 ret++; break;
1626                         }
1627                         tr_read_funcs[tmpv](op);
1628                         tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1629                         if (tmpv2 == SSP_PC) ret |= 0x10000;
1630                         ret++; break;
1631
1632                 // ld d, (ri)
1633                 case 0x01: {
1634                         int r = (op&3) | ((op>>6)&4);
1635                         int mod = (op>>2)&3;
1636                         tmpv = (op >> 4) & 0xf; // dst
1637                         ret = tr_detect_rotate(op, pc, imm);
1638                         if (ret > 0) break;
1639                         if (tmpv != 0)
1640                              tr_rX_read(r, mod);
1641                         else tr_ptrr_mod(r, mod, 1, 1);
1642                         tr_write_funcs[tmpv](-1);
1643                         if (tmpv == SSP_PC) ret |= 0x10000;
1644                         ret++; break;
1645                 }
1646
1647                 // ld (ri), s
1648                 case 0x02:
1649                         tmpv = (op >> 4) & 0xf; // src
1650                         tr_read_funcs[tmpv](op);
1651                         tr_rX_write(op);
1652                         ret++; break;
1653
1654                 // ld a, adr
1655                 case 0x03:
1656                         tr_bank_read(op&0x1ff);
1657                         tr_r0_to_A(-1);
1658                         ret++; break;
1659
1660                 // ldi d, imm
1661                 case 0x04:
1662                         tmpv = (op & 0xf0) >> 4; // dst
1663                         ret = tr_detect_pm0_block(op, pc, imm);
1664                         if (ret > 0) break;
1665                         ret = tr_detect_set_pm(op, pc, imm);
1666                         if (ret > 0) break;
1667                         tr_mov16(0, imm);
1668                         tr_write_funcs[tmpv](imm);
1669                         if (tmpv == SSP_PC) ret |= 0x10000;
1670                         ret += 2; break;
1671
1672                 // ld d, ((ri))
1673                 case 0x05:
1674                         tmpv2 = (op >> 4) & 0xf;  // dst
1675                         tr_rX_read2(op);
1676                         tr_write_funcs[tmpv2](-1);
1677                         if (tmpv2 == SSP_PC) ret |= 0x10000;
1678                         ret += 3; break;
1679
1680                 // ldi (ri), imm
1681                 case 0x06:
1682                         tr_mov16(0, imm);
1683                         tr_rX_write(op);
1684                         ret += 2; break;
1685
1686                 // ld adr, a
1687                 case 0x07:
1688                         tr_A_to_r0(op);
1689                         tr_bank_write(op&0x1ff);
1690                         ret++; break;
1691
1692                 // ld d, ri
1693                 case 0x09: {
1694                         int r;
1695                         r = (op&3) | ((op>>6)&4); // src
1696                         tmpv2 = (op >> 4) & 0xf;  // dst
1697                         if ((r&3) == 3) tr_unhandled();
1698
1699                         if (known_regb & (1 << (r+8))) {
1700                                 tr_mov16(0, known_regs.r[r]);
1701                                 tr_write_funcs[tmpv2](known_regs.r[r]);
1702                         } else {
1703                                 int reg = (r < 4) ? 8 : 9;
1704                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1705                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1706                                 hostreg_r[0] = -1;
1707                                 tr_write_funcs[tmpv2](-1);
1708                         }
1709                         ret++; break;
1710                 }
1711
1712                 // ld ri, s
1713                 case 0x0a: {
1714                         int r;
1715                         r = (op&3) | ((op>>6)&4); // dst
1716                         tmpv = (op >> 4) & 0xf;   // src
1717                         if ((r&3) == 3) tr_unhandled();
1718
1719                         if (known_regb & (1 << tmpv)) {
1720                                 known_regs.r[r] = known_regs.gr[tmpv].h;
1721                                 known_regb |= 1 << (r + 8);
1722                                 dirty_regb |= 1 << (r + 8);
1723                         } else {
1724                                 int reg = (r < 4) ? 8 : 9;
1725                                 int ror = ((4 - (r&3))*8) & 0x1f;
1726                                 tr_read_funcs[tmpv](op);
1727                                 EOP_BIC_IMM(reg, reg, ror/2, 0xff);             // bic r{7,8}, r{7,8}, <mask>
1728                                 EOP_AND_IMM(0, 0, 0, 0xff);                     // and r0, r0, 0xff
1729                                 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8);          // orr r{7,8}, r{7,8}, r0, lsl #lsl
1730                                 hostreg_r[0] = -1;
1731                                 known_regb &= ~(1 << (r+8));
1732                                 dirty_regb &= ~(1 << (r+8));
1733                         }
1734                         ret++; break;
1735                 }
1736
1737                 // ldi ri, simm
1738                 case 0x0c ... 0x0f:
1739                         tmpv = (op>>8)&7;
1740                         known_regs.r[tmpv] = op;
1741                         known_regb |= 1 << (tmpv + 8);
1742                         dirty_regb |= 1 << (tmpv + 8);
1743                         ret++; break;
1744
1745                 // call cond, addr
1746                 case 0x24: {
1747                         u32 *jump_op = NULL;
1748                         tmpv = tr_cond_check(op);
1749                         if (tmpv != A_COND_AL) {
1750                                 jump_op = tcache_ptr;
1751                                 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1752                         }
1753                         tr_mov16(0, *pc);
1754                         tr_r0_to_STACK(*pc);
1755                         if (tmpv != A_COND_AL) {
1756                                 u32 *real_ptr = tcache_ptr;
1757                                 tcache_ptr = jump_op;
1758                                 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1759                                 tcache_ptr = real_ptr;
1760                         }
1761                         tr_mov16_cond(tmpv, 0, imm);
1762                         if (tmpv != A_COND_AL) {
1763                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1764                         }
1765                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1766                         ret |= 0x10000;
1767                         ret += 2; break;
1768                 }
1769
1770                 // ld d, (a)
1771                 case 0x25:
1772                         tmpv2 = (op >> 4) & 0xf;  // dst
1773                         tr_A_to_r0(op);
1774                         EOP_LDR_IMM(1,7,0x48c);                                 // ptr_iram_rom
1775                         EOP_ADD_REG_LSL(0,1,0,1);                               // add  r0, r1, r0, lsl #1
1776                         EOP_LDRH_SIMPLE(0,0);                                   // ldrh r0, [r0]
1777                         hostreg_r[0] = hostreg_r[1] = -1;
1778                         tr_write_funcs[tmpv2](-1);
1779                         if (tmpv2 == SSP_PC) ret |= 0x10000;
1780                         ret += 3; break;
1781
1782                 // bra cond, addr
1783                 case 0x26:
1784                         tmpv = tr_cond_check(op);
1785                         tr_mov16_cond(tmpv, 0, imm);
1786                         if (tmpv != A_COND_AL) {
1787                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1788                         }
1789                         tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1790                         ret |= 0x10000;
1791                         ret += 2; break;
1792
1793                 // mod cond, op
1794                 case 0x48: {
1795                         // check for repeats of this op
1796                         tmpv = 1; // count
1797                         while (PROGRAM(*pc) == op && (op & 7) != 6) {
1798                                 (*pc)++; tmpv++;
1799                         }
1800                         if ((op&0xf0) != 0) // !always
1801                                 tr_make_dirty_ST();
1802
1803                         tmpv2 = tr_cond_check(op);
1804                         switch (op & 7) {
1805                                 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1806                                 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1807                                 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1808                                 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
1809                                         EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1810                                         hostreg_r[1] = -1; break; // abs
1811                                 default: tr_unhandled();
1812                         }
1813
1814                         hostreg_sspreg_changed(SSP_A);
1815                         dirty_regb |=  KRREG_ST;
1816                         known_regb &= ~KRREG_ST;
1817                         known_regb &= ~(KRREG_A|KRREG_AL);
1818                         ret += tmpv; break;
1819                 }
1820
1821                 // mpys?
1822                 case 0x1b:
1823                         tr_flush_dirty_P();
1824                         tr_mac_load_XY(op);
1825                         tr_make_dirty_ST();
1826                         EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1827                         hostreg_sspreg_changed(SSP_A);
1828                         known_regb &= ~(KRREG_A|KRREG_AL);
1829                         dirty_regb |= KRREG_ST;
1830                         ret++; break;
1831
1832                 // mpya (rj), (ri), b
1833                 case 0x4b:
1834                         tr_flush_dirty_P();
1835                         tr_mac_load_XY(op);
1836                         tr_make_dirty_ST();
1837                         EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1838                         hostreg_sspreg_changed(SSP_A);
1839                         known_regb &= ~(KRREG_A|KRREG_AL);
1840                         dirty_regb |= KRREG_ST;
1841                         ret++; break;
1842
1843                 // mld (rj), (ri), b
1844                 case 0x5b:
1845                         EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1846                         hostreg_sspreg_changed(SSP_A);
1847                         known_regs.gr[SSP_A].v = 0;
1848                         known_regb |= (KRREG_A|KRREG_AL);
1849                         dirty_regb |= KRREG_ST;
1850                         tr_mac_load_XY(op);
1851                         ret++; break;
1852
1853                 // OP a, s
1854                 case 0x10:
1855                 case 0x30:
1856                 case 0x40:
1857                 case 0x50:
1858                 case 0x60:
1859                 case 0x70:
1860                         tmpv = op & 0xf; // src
1861                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1862                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1863                         if (tmpv == SSP_P) {
1864                                 tr_flush_dirty_P();
1865                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1866                         } else if (tmpv == SSP_A) {
1867                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1868                         } else {
1869                                 tr_read_funcs[tmpv](op);
1870                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1871                         }
1872                         hostreg_sspreg_changed(SSP_A);
1873                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1874                         dirty_regb |= KRREG_ST;
1875                         ret++; break;
1876
1877                 // OP a, (ri)
1878                 case 0x11:
1879                 case 0x31:
1880                 case 0x41:
1881                 case 0x51:
1882                 case 0x61:
1883                 case 0x71:
1884                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1885                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1886                         tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1887                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1888                         hostreg_sspreg_changed(SSP_A);
1889                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1890                         dirty_regb |= KRREG_ST;
1891                         ret++; break;
1892
1893                 // OP a, adr
1894                 case 0x13:
1895                 case 0x33:
1896                 case 0x43:
1897                 case 0x53:
1898                 case 0x63:
1899                 case 0x73:
1900                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1901                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1902                         tr_bank_read(op&0x1ff);
1903                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1904                         hostreg_sspreg_changed(SSP_A);
1905                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1906                         dirty_regb |= KRREG_ST;
1907                         ret++; break;
1908
1909                 // OP a, imm
1910                 case 0x14:
1911                 case 0x34:
1912                 case 0x44:
1913                 case 0x54:
1914                 case 0x64:
1915                 case 0x74:
1916                         tmpv = (op & 0xf0) >> 4;
1917                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1918                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1919                         tr_mov16(0, imm);
1920                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1921                         hostreg_sspreg_changed(SSP_A);
1922                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1923                         dirty_regb |= KRREG_ST;
1924                         ret += 2; break;
1925
1926                 // OP a, ((ri))
1927                 case 0x15:
1928                 case 0x35:
1929                 case 0x45:
1930                 case 0x55:
1931                 case 0x65:
1932                 case 0x75:
1933                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1934                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1935                         tr_rX_read2(op);
1936                         EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1937                         hostreg_sspreg_changed(SSP_A);
1938                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1939                         dirty_regb |= KRREG_ST;
1940                         ret += 3; break;
1941
1942                 // OP a, ri
1943                 case 0x19:
1944                 case 0x39:
1945                 case 0x49:
1946                 case 0x59:
1947                 case 0x69:
1948                 case 0x79: {
1949                         int r;
1950                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1951                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1952                         r = (op&3) | ((op>>6)&4); // src
1953                         if ((r&3) == 3) tr_unhandled();
1954
1955                         if (known_regb & (1 << (r+8))) {
1956                                 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]);  // OPs r5, r5, #val<<16
1957                         } else {
1958                                 int reg = (r < 4) ? 8 : 9;
1959                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1960                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1961                                 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0);   // OPs r5, r5, r0, lsl #16
1962                                 hostreg_r[0] = -1;
1963                         }
1964                         hostreg_sspreg_changed(SSP_A);
1965                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1966                         dirty_regb |= KRREG_ST;
1967                         ret++; break;
1968                 }
1969
1970                 // OP simm
1971                 case 0x1c:
1972                 case 0x3c:
1973                 case 0x4c:
1974                 case 0x5c:
1975                 case 0x6c:
1976                 case 0x7c:
1977                         tmpv2 = tr_aop_ssp2arm(op>>13); // op
1978                         tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1979                         EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff);        // OPs r5, r5, #val<<16
1980                         hostreg_sspreg_changed(SSP_A);
1981                         known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1982                         dirty_regb |= KRREG_ST;
1983                         ret++; break;
1984         }
1985
1986         return ret;
1987 }
1988
1989 static void *translate_block(int pc)
1990 {
1991         unsigned int op, op1, imm, ccount = 0;
1992         unsigned int *block_start;
1993         int ret, ret_prev = -1, tpc;
1994
1995         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1996         block_start = tcache_ptr;
1997         known_regb = 0;
1998         dirty_regb = KRREG_P;
1999         known_regs.emu_status = 0;
2000         hostreg_clear();
2001
2002         emit_block_prologue();
2003
2004         for (; ccount < 100;)
2005         {
2006                 op = PROGRAM(pc++);
2007                 op1 = op >> 9;
2008                 imm = (u32)-1;
2009
2010                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2011                         imm = PROGRAM(pc++); // immediate
2012                 tpc = pc;
2013
2014                 ret = translate_op(op, &pc, imm);
2015                 if (ret <= 0)
2016                 {
2017                         tr_flush_dirty_prs();
2018                         tr_flush_dirty_ST();
2019                         tr_flush_dirty_pmcrs();
2020                         known_regs.emu_status = 0;
2021
2022                         emit_mov_const(A_COND_AL, 0, op);
2023
2024                         // need immediate?
2025                         if (imm != (u32)-1)
2026                                 emit_mov_const(A_COND_AL, 1, imm);
2027
2028                         // dump PC
2029                         emit_pc_dump(pc);
2030
2031                         if (ret_prev > 0) emit_call(regfile_store);
2032                         emit_call(in_funcs[op1]);
2033                         emit_call(regfile_load);
2034
2035                         if (in_funcs[op1] == NULL) {
2036                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
2037                                 exit(1);
2038                         }
2039                         ccount++;
2040                         hostreg_clear();
2041                         dirty_regb |= KRREG_P;
2042                         known_regb = 0;
2043                 }
2044                 else
2045                 {
2046                         ccount += ret & 0xffff;
2047                         if (ret & 0x10000) break;
2048                 }
2049
2050                 ret_prev = ret;
2051         }
2052
2053         if (ccount >= 100)
2054                 emit_pc_dump(pc);
2055
2056         tr_flush_dirty_prs();
2057         tr_flush_dirty_ST();
2058         tr_flush_dirty_pmcrs();
2059         emit_block_epilogue(ccount + 1);
2060         *tcache_ptr++ = 0xffffffff; // end of block
2061
2062         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2063                 printf("tcache overflow!\n");
2064                 fflush(stdout);
2065                 exit(1);
2066         }
2067
2068         // stats
2069         nblocks++;
2070         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2071
2072 #ifdef DUMP_BLOCK
2073         {
2074                 FILE *f = fopen("tcache.bin", "wb");
2075                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2076                 fclose(f);
2077         }
2078         exit(0);
2079 #endif
2080
2081         handle_caches();
2082
2083         return block_start;
2084 }
2085
2086
2087
2088 // -----------------------------------------------------
2089
2090 int ssp1601_dyn_startup(void)
2091 {
2092         memset(tcache, 0, TCACHE_SIZE);
2093         memset(block_table, 0, sizeof(block_table));
2094         memset(block_table_iram, 0, sizeof(block_table_iram));
2095         memset(block_ref, 0, sizeof(block_ref));
2096         memset(block_ref_iram, 0, sizeof(block_ref_iram));
2097         tcache_ptr = tcache;
2098         *tcache_ptr++ = 0xffffffff;
2099
2100 #ifdef ARM
2101         // hle'd blocks
2102         block_table[0x400] = (void *) ssp_hle_800;
2103 #endif
2104
2105 // TODO: rm
2106 {
2107 static unsigned short dummy = 0;
2108 PC = &dummy;
2109 }
2110         return 0;
2111 }
2112
2113
2114 void ssp1601_dyn_reset(ssp1601_t *ssp)
2115 {
2116         int i, u, total = 0;
2117         for (i = 0; i < 0x5090/2; i++)
2118                 total += block_ref[i];
2119         for (u = 1; u < 15; u++)
2120                 for (i = 0; i < 0x800/2; i++)
2121                         total += block_ref_iram[u][i];
2122
2123         printf("total: %i\n", total);
2124         for (i = 0; i < 0x5090/2; i++)
2125                 if (block_ref[i])
2126                         printf("%07i %2.3f%% __:%04x\n", block_ref[i], (double)block_ref[i] / (double)total * 100.0, i<<1);
2127         for (u = 1; u < 15; u++)
2128                 for (i = 0; i < 0x800/2; i++)
2129                         if (block_ref_iram[u][i])
2130                                 printf("%07i %2.3f%% %02i:%04x\n", block_ref_iram[u][i],
2131                                         (double)block_ref_iram[u][i] / (double)total * 100.0, u, i<<1);
2132
2133
2134         ssp1601_reset_local(ssp);
2135         ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2136         ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2137         ssp->drc.ptr_dram = (unsigned int) svp->dram;
2138         ssp->drc.iram_dirty = 0;
2139 }
2140
2141 void ssp1601_dyn_run(int cycles)
2142 {
2143         if (ssp->emu_status & SSP_WAIT_MASK) return;
2144
2145 #ifdef DUMP_BLOCK
2146         rPC = DUMP_BLOCK >> 1;
2147 #endif
2148         while (cycles > 0)
2149         {
2150                 int (*trans_entry)(void);
2151                 if (rPC < 0x800/2)
2152                 {
2153                         if (ssp->drc.iram_dirty) {
2154                                 iram_context = get_iram_context();
2155                                 ssp->drc.iram_dirty--;
2156                         }
2157                         if (block_table_iram[iram_context][rPC] == NULL)
2158                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
2159                         trans_entry = (void *) block_table_iram[iram_context][rPC];
2160                         block_ref_iram[iram_context][rPC]++;
2161                 }
2162                 else
2163                 {
2164                         if (block_table[rPC] == NULL)
2165                                 block_table[rPC] = translate_block(rPC);
2166                         trans_entry = (void *) block_table[rPC];
2167                         block_ref[rPC]++;
2168                 }
2169
2170                 cycles -= trans_entry();
2171         }
2172 }
2173