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