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