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