svp compiler: added more ops
[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 0x29a0
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 } known_regs;
537
538 #define KRREG_X     (1 << SSP_X)
539 #define KRREG_Y     (1 << SSP_Y)
540 #define KRREG_A     (1 << SSP_A)        /* AH only */
541 #define KRREG_ST    (1 << SSP_ST)
542 #define KRREG_STACK (1 << SSP_STACK)
543 #define KRREG_PC    (1 << SSP_PC)
544 #define KRREG_P     (1 << SSP_P)
545 #define KRREG_PR0   (1 << 8)
546 #define KRREG_PR4   (1 << 12)
547 #define KRREG_AL    (1 << 16)
548
549 /* bitfield of known register values */
550 static u32 known_regb = 0;
551
552 /* known vals, which need to be flushed
553  * (only ST, P, r0-r7)
554  * ST means flags are being held in ARM PSR
555  */
556 static u32 dirty_regb = 0;
557
558 /* known values of host regs.
559  * -1            - unknown
560  * 000000-00ffff - 16bit value
561  * 100000-10ffff - base reg (r7) + 16bit val
562  * 0r0000        - means reg (low) eq gr[r].h
563  */
564 static int hostreg_r[4];
565
566 static void hostreg_clear(void)
567 {
568         int i;
569         for (i = 0; i < 4; i++)
570                 hostreg_r[i] = -1;
571 }
572
573 // TODO
574 /*static*/ void hostreg_ah_changed(void)
575 {
576         int i;
577         for (i = 0; i < 4; i++)
578                 if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1;
579 }
580
581
582 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
583
584 /* update P, if needed. Trashes r1 */
585 static void tr_flush_dirty_P(void)
586 {
587         // TODO: const regs
588         if (!(dirty_regb & KRREG_P)) return;
589         EOP_MOV_REG_ASR(10, 4, 16);             // mov  r10, r4, asr #16
590         EOP_MOV_REG_LSL( 1, 4, 16);             // mov  r1,  r4, lsl #16
591         EOP_MOV_REG_ASR( 1, 1, 15);             // mov  r1,  r1, asr #15
592         EOP_MUL(10, 1, 10);                     // mul  r10, r1, r10
593         dirty_regb &= ~KRREG_P;
594 }
595
596 /* write dirty r0-r7 to host regs. Nothing is trashed */
597 static void tr_flush_dirty_pr(void)
598 {
599         int i, ror = 0, reg;
600         int dirty = dirty_regb >> 8;
601         /* r0-r7 */
602         for (i = 0; dirty && i < 8; i++, dirty >>= 1)
603         {
604                 if (!(dirty&1)) continue;
605                 switch (i&3) {
606                         case 0: ror =    0; break;
607                         case 1: ror = 24/2; break;
608                         case 2: ror = 16/2; break;
609                 }
610                 reg = (i < 4) ? 8 : 9;
611                 EOP_BIC_IMM(reg,reg,ror,0xff);
612                 if (known_regs.r[i] != 0)
613                         EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
614         }
615         dirty_regb &= ~0xff00;
616 }
617
618 /* fush ARM PSR to r6. Trashes r0 */
619 static void tr_flush_dirty_ST(void)
620 {
621         if (!(dirty_regb & KRREG_ST)) return;
622         EOP_BIC_IMM(6,6,0,0x0f);
623         EOP_MRS(0);
624         EOP_ORR_REG_LSR(6,6,0,28);
625         dirty_regb &= ~KRREG_ST;
626         hostreg_r[0] = -1;
627 }
628
629 /* load 16bit val into host reg r0-r3. Nothing is trashed */
630 static void tr_mov16(int r, int val)
631 {
632         if (hostreg_r[r] != val) {
633                 emit_mov_const(A_COND_AL, r, val);
634                 hostreg_r[r] = val;
635         }
636 }
637
638 static void tr_mov16_cond(int cond, int r, int val)
639 {
640         emit_mov_const(cond, r, val);
641 }
642
643 /* read bank word to r0. Thrashes r1. */
644 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
645 {
646         int breg = 7;
647         if (addr > 0x7f) {
648                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
649                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
650                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
651                 }
652                 breg = 1;
653         }
654         EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1);    // ldrh r0, [r1, (op&0x7f)<<1]
655         hostreg_r[0] = -1;
656 }
657
658 /* write r0 to bank. Trashes r1. */
659 static void tr_bank_write(int addr)
660 {
661         int breg = 7;
662         if (addr > 0x7f) {
663                 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
664                         EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1);  // add  r1, r7, ((op&0x180)<<1)
665                         hostreg_r[1] = 0x100000|((addr&0x180)<<1);
666                 }
667                 breg = 1;
668         }
669         EOP_STRH_IMM(0,breg,(addr&0x7f)<<1);            // strh r0, [r1, (op&0x7f)<<1]
670 }
671
672 /* handle RAM bank pointer modifiers. Nothing is trashed. */
673 static void tr_ptrr_mod(int r, int mod, int need_modulo)
674 {
675         int modulo = -1, modulo_shift = -1;     /* unknown */
676
677         if (mod == 0) return;
678
679         if (!need_modulo || mod == 1) // +!
680                 modulo_shift = 8;
681         else if (need_modulo && (known_regb & KRREG_ST)) {
682                 modulo_shift = known_regs.gr[SSP_ST].h & 7;
683                 if (modulo_shift == 0) modulo_shift = 8;
684         }
685
686         if (mod > 1 && modulo_shift == -1) { printf("need var modulo\n"); exit(1); }
687         modulo = (1 << modulo_shift) - 1;
688
689         if (known_regb & (1 << (r + 8))) {
690                 if (mod == 2)
691                      known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - 1) & modulo);
692                 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + 1) & modulo);
693         } else {
694                 int reg = (r < 4) ? 8 : 9;
695                 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
696                 EOP_MOV_REG_ROR(reg,reg,ror);
697                 // {add|sub} reg, reg, #1<<shift
698                 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
699                 EOP_MOV_REG_ROR(reg,reg,32-ror);
700         }
701 }
702
703 /* handle writes r0 to (rX). Trashes r1.
704  * fortunately we can ignore modulo increment modes for writes. */
705 static void tr_rX_write1(int op)
706 {
707         if ((op&3) == 3)
708         {
709                 int mod = (op>>2) & 3; // direct addressing
710                 tr_bank_write((op & 0x100) + mod);
711         }
712         else
713         {
714                 int r = (op&3) | ((op>>6)&4);
715                 if (known_regb & (1 << (r + 8))) {
716                         tr_bank_write((op&0x100) | known_regs.r[r]);
717                 } else {
718                         int reg = (r < 4) ? 8 : 9;
719                         int ror = ((4 - (r&3))*8) & 0x1f;
720                         EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
721                         if (r >= 4)
722                                 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
723                         if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
724                         else     EOP_ADD_REG_LSL(1,7,1,1);
725                         EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
726                         hostreg_r[1] = -1;
727                 }
728                 tr_ptrr_mod(r, (op>>2) & 3, 0);
729         }
730 }
731
732 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
733 static int tr_cond_check(int op)
734 {
735         int f = op & 0x100;
736         switch (op&0xf0) {
737                 case 0x00: return A_COND_AL;    /* always true */
738                 case 0x50:                      /* Z matches f(?) bit */
739                         if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
740                         EOP_TST_IMM(6, 0, 4);
741                         return f ? A_COND_NE : A_COND_EQ;
742                 case 0x70:                      /* N matches f(?) bit */
743                         if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
744                         EOP_TST_IMM(6, 0, 8);
745                         return f ? A_COND_NE : A_COND_EQ;
746                 default:
747                         printf("unimplemented cond?\n");
748                         exit(1);
749                         return 0;
750         }
751 }
752
753 static int tr_neg_cond(int cond)
754 {
755         switch (cond) {
756                 case A_COND_AL: printf("neg for AL?\n"); exit(1);
757                 case A_COND_EQ: return A_COND_NE;
758                 case A_COND_NE: return A_COND_EQ;
759                 case A_COND_MI: return A_COND_PL;
760                 case A_COND_PL: return A_COND_MI;
761                 default:        printf("bad cond for neg\n"); exit(1);
762         }
763         return 0;
764 }
765
766 //      SSP_GR0, SSP_X,     SSP_Y,   SSP_A,
767 //      SSP_ST,  SSP_STACK, SSP_PC,  SSP_P,
768 //@ r4:  XXYY
769 //@ r5:  A
770 //@ r6:  STACK and emu flags
771 //@ r7:  SSP context
772 //@ r10: P
773
774 // read general reg to r0. Trashes r1
775 static void tr_GR0_to_r0(void)
776 {
777         tr_mov16(0, 0xffff);
778 }
779
780 static void tr_X_to_r0(void)
781 {
782         if (hostreg_r[0] != (SSP_X<<16)) {
783                 EOP_MOV_REG_LSR(0, 4, 16);      // mov  r0, r4, lsr #16
784                 hostreg_r[0] = SSP_X<<16;
785         }
786 }
787
788 static void tr_Y_to_r0(void)
789 {
790         // TODO..
791         if (hostreg_r[0] != (SSP_Y<<16)) {
792                 EOP_MOV_REG_SIMPLE(0, 4);       // mov  r0, r4
793                 hostreg_r[0] = SSP_Y<<16;
794         }
795 }
796
797 static void tr_A_to_r0(void)
798 {
799         if (hostreg_r[0] != (SSP_A<<16)) {
800                 EOP_MOV_REG_LSR(0, 5, 16);      // mov  r0, r5, lsr #16  @ AH
801                 hostreg_r[0] = SSP_A<<16;
802         }
803 }
804
805 static void tr_ST_to_r0(void)
806 {
807         // VR doesn't need much accuracy here..
808         EOP_MOV_REG_LSR(0, 6, 4);               // mov  r0, r6, lsr #4
809         EOP_AND_IMM(0, 0, 0, 0x67);             // and  r0, r0, #0x67
810         hostreg_r[0] = -1;
811 }
812
813 static void tr_STACK_to_r0(void)
814 {
815         // 448
816         EOP_SUB_IMM(6, 6,  8/2, 0x20);          // sub  r6, r6, #1<<29
817         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
818         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
819         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
820         EOP_LDRH_SIMPLE(0, 1);                  // ldrh r0, [r1]
821         hostreg_r[0] = hostreg_r[1] = -1;
822 }
823
824 static void tr_PC_to_r0(void)
825 {
826         tr_mov16(0, known_regs.gr[SSP_PC].h);
827 }
828
829 static void tr_P_to_r0(void)
830 {
831         tr_flush_dirty_P();
832         EOP_MOV_REG_LSR(0, 10, 16);             // mov  r0, r10, lsr #16
833         hostreg_r[0] = -1;
834 }
835
836 typedef void (tr_read_func)(void);
837
838 static tr_read_func *tr_read_funcs[8] =
839 {
840         tr_GR0_to_r0,
841         tr_X_to_r0,
842         tr_Y_to_r0,
843         tr_A_to_r0,
844         tr_ST_to_r0,
845         tr_STACK_to_r0,
846         tr_PC_to_r0,
847         tr_P_to_r0
848 };
849
850
851 // write r0 to general reg handlers. Trashes r1
852 static void tr_unhandled(void)
853 {
854         printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
855         exit(1);
856 }
857
858 static void tr_r0_to_GR0(void)
859 {
860         // do nothing
861 }
862
863 static void tr_r0_to_X(void)
864 {
865         EOP_MOV_REG_LSL(4, 4, 16);              // mov  r4, r4, lsl #16
866         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
867         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
868         dirty_regb |= KRREG_P;  // touching X or Y makes P dirty.
869         hostreg_r[0] = SSP_X<<16;
870 }
871
872 static void tr_r0_to_Y(void)
873 {
874         EOP_MOV_REG_LSR(4, 4, 16);              // mov  r4, r4, lsr #16
875         EOP_ORR_REG_LSL(4, 4, 0, 16);           // orr  r4, r4, r0, lsl #16
876         EOP_MOV_REG_ROR(4, 4, 16);              // mov  r4, r4, ror #16
877         dirty_regb |= KRREG_P;
878         hostreg_r[0] = SSP_Y<<16;
879 }
880
881 static void tr_r0_to_A(void)
882 {
883         EOP_MOV_REG_LSL(5, 5, 16);              // mov  r5, r5, lsl #16
884         EOP_MOV_REG_LSR(5, 5, 16);              // mov  r5, r5, lsr #16  @ AL
885         EOP_ORR_REG_LSL(5, 5, 0, 16);           // orr  r5, r5, r0, lsl #16
886         hostreg_r[0] = SSP_A<<16;
887 }
888
889 static void tr_r0_to_ST(void)
890 {
891         // VR doesn't need much accuracy here..
892         EOP_AND_IMM(1, 0,   0, 0x67);           // and   r1, r0, #0x67
893         EOP_AND_IMM(6, 6, 8/2, 0xe0);           // and   r6, r6, #7<<29     @ preserve STACK
894         EOP_ORR_REG_LSL(6, 6, 1, 4);            // orr   r6, r6, r1, lsl #4
895         hostreg_r[1] = -1;
896 }
897
898 static void tr_r0_to_STACK(void)
899 {
900         // 448
901         EOP_ADD_IMM(1, 7, 24/2, 0x04);          // add  r1, r7, 0x400
902         EOP_ADD_IMM(1, 1, 0, 0x48);             // add  r1, r1, 0x048
903         EOP_ADD_REG_LSR(1, 1, 6, 28);           // add  r1, r1, r6, lsr #28
904         EOP_STRH_SIMPLE(0, 1);                  // strh r0, [r1]
905         EOP_ADD_IMM(6, 6,  8/2, 0x20);          // add  r6, r6, #1<<29
906         hostreg_r[1] = -1;
907 }
908
909 static void tr_r0_to_PC(void)
910 {
911         EOP_MOV_REG_LSL(1, 0, 16);              // mov  r1, r0, lsl #16
912         EOP_STR_IMM(1,7,0x400+6*4);             // str  r1, [r7, #(0x400+6*8)]
913         hostreg_r[1] = -1;
914 }
915
916 typedef void (tr_write_func)(void);
917
918 static tr_write_func *tr_write_funcs[8] =
919 {
920         tr_r0_to_GR0,
921         tr_r0_to_X,
922         tr_r0_to_Y,
923         tr_r0_to_A,
924         tr_r0_to_ST,
925         tr_r0_to_STACK,
926         tr_r0_to_PC,
927         tr_unhandled
928 };
929
930
931 static int translate_op(unsigned int op, int *pc, int imm)
932 {
933         u32 tmpv, tmpv2;
934         int ret = 0;
935         known_regs.gr[SSP_PC].h = *pc;
936
937         switch (op >> 9)
938         {
939                 // ld d, s
940                 case 0x00:
941                         if (op == 0) { ret++; break; } // nop
942                         tmpv  = op & 0xf; // src
943                         tmpv2 = (op >> 4) & 0xf; // dst
944                         if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
945                         if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
946                                 tr_flush_dirty_P();
947                                 EOP_MOV_REG_SIMPLE(5, 10);
948                                 known_regb &= ~(KRREG_A|KRREG_AL);
949                                 ret++; break;
950                         }
951                         tr_read_funcs[tmpv]();
952                         tr_write_funcs[tmpv2]();
953                         if (known_regb & (1 << tmpv)) {
954                                 known_regs.gr[tmpv2].h = known_regs.gr[tmpv].h;
955                                 known_regb |=   1 << tmpv2;
956                         } else
957                                 known_regb &= ~(1 << tmpv2);
958                         ret++; break;
959
960                 // ld d, (ri)
961                 //case 0x01: tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
962
963                 // ld (ri), s
964                 case 0x02:
965                         tmpv = (op >> 4) & 0xf; // src
966                         if (tmpv >= 8) return -1; // TODO
967                         tr_read_funcs[tmpv]();
968                         tr_rX_write1(op);
969                         ret++; break;
970
971                 // ld a, adr
972                 case 0x03:
973                         tr_bank_read(op&0x1ff);
974                         tr_r0_to_A();
975                         known_regb &= ~KRREG_A;
976                         hostreg_r[0] = SSP_A<<16;
977                         ret++; break;
978
979                 // ldi d, imm
980                 case 0x04:
981                         tmpv = (op & 0xf0) >> 4;
982                         if (tmpv < 8)
983                         {
984                                 tr_mov16(0, imm);
985                                 tr_write_funcs[tmpv]();
986                                 known_regs.gr[tmpv].h = imm;
987                                 known_regb |= 1 << tmpv;
988                                 ret++; break;
989                         }
990                         else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
991                         {
992                                 // programming PMC..
993                                 (*pc)++;
994                                 tmpv = imm | (PROGRAM((*pc)++) << 16);
995                                 emit_mov_const(A_COND_AL, 0, tmpv);
996                                 EOP_LDR_IMM(1,7,0x484);         // ldr r0, [r7, #0x484] // emu_status
997                                 EOP_STR_IMM(0,7,0x400+14*4);    // PMC
998                                 // reads on fe06, fe08; next op is ld -,
999                                 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1000                                 {
1001                                         int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1002                                         tr_flush_dirty_ST();
1003                                         EOP_LDR_IMM(0,7,0x490); // dram_ptr
1004                                         EOP_ADD_IMM(0,0,24/2,0xfe);     // add  r0, r0, #0xfe00
1005                                         EOP_LDRH_IMM(0,0,8);            // ldrh r0, [r0, #8]
1006                                         EOP_TST_REG_SIMPLE(0,0);
1007                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1);       // add r11, r11, #1024
1008                                         EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1009                                 }
1010                                 EOP_ORR_IMM(1,1,0,SSP_PMC_SET);         // orr r1, r1, #SSP_PMC_SET
1011                                 EOP_STR_IMM(1,7,0x484);                 // str r1, [r7, #0x484] // emu_status
1012                                 hostreg_r[0] = hostreg_r[1] = -1;
1013                                 ret += 2; break;
1014                         }
1015                         else
1016                                 return -1;      /* TODO.. */
1017
1018                 // ld d, ((ri))
1019                 case 0x05: {
1020                         int r;
1021                         r = (op&3) | ((op>>6)&4); // src
1022                         tmpv2 = (op >> 4) & 0xf;  // dst
1023                         if (tmpv2 >= 8) return -1; // TODO
1024
1025                         if ((r&3) == 3) {
1026                                 tr_bank_read((op&0x100) | ((op>>2)&3));
1027                         } else if (known_regb & (1 << (r+8))) {
1028                                 tr_bank_read((op&0x100) | known_regs.r[r]);
1029                         } else {
1030                                 int reg = (r < 4) ? 8 : 9;
1031                                 int ror = ((4 - (r&3))*8) & 0x1f;
1032                                 EOP_AND_IMM(1,reg,ror/2,0xff);                  // and r1, r{7,8}, <mask>
1033                                 if (r >= 4)
1034                                         EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1);            // orr r1, r1, 1<<shift
1035                                 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1);     // add r1, r7, r1, lsr #lsr
1036                                 else     EOP_ADD_REG_LSL(1,7,1,1);
1037                                 EOP_LDRH_SIMPLE(0,1);                           // ldrh r0, [r1]
1038                         }
1039                         EOP_LDR_IMM(2,7,0x48c);                                 // ptr_iram_rom
1040                         EOP_ADD_REG_LSL(2,2,0,1);                               // add  r2, r2, r0, lsl #1
1041                         EOP_ADD_IMM(0,0,0,1);                                   // add  r0, r0, #1
1042                         if ((r&3) == 3) {
1043                                 tr_bank_write((op&0x100) | ((op>>2)&3));
1044                         } else if (known_regb & (1 << (r+8))) {
1045                                 tr_bank_write((op&0x100) | known_regs.r[r]);
1046                         } else {
1047                                 EOP_STRH_SIMPLE(0,1);                           // strh r0, [r1]
1048                                 hostreg_r[1] = -1;
1049                         }
1050                         EOP_LDRH_SIMPLE(0,2);                                   // ldrh r0, [r0]
1051                         hostreg_r[0] = hostreg_r[2] = -1;
1052                         tr_write_funcs[tmpv2]();
1053                         ret += 2; break; /* should certainly take > 1 */
1054                 }
1055
1056                 // ldi (ri), imm
1057                 case 0x06:
1058                         tr_mov16(0, imm);
1059                         tr_rX_write1(op);
1060                         ret++; break;
1061
1062                 // ld adr, a
1063                 case 0x07:
1064                         if (hostreg_r[0] != (SSP_A<<16)) {
1065                                 EOP_MOV_REG_LSR(0, 5, 16);              // mov  r0, r5, lsr #16  @ A
1066                                 hostreg_r[0] = SSP_A<<16;
1067                         }
1068                         tr_bank_write(op&0x1ff);
1069                         ret++; break;
1070
1071                 // ld d, ri
1072                 case 0x09: {
1073                         int r;
1074                         r = (op&3) | ((op>>6)&4); // src
1075                         tmpv2 = (op >> 4) & 0xf;  // dst
1076                         if (tmpv2 >= 8) tr_unhandled();
1077                         if ((r&3) == 3) tr_unhandled();
1078
1079                         if (known_regb & (1 << (r+8))) {
1080                                 tr_mov16(0, known_regs.r[r]);
1081                                 known_regs.gr[tmpv2].h = known_regs.r[r];
1082                                 known_regb |= 1 << tmpv2;
1083                         } else {
1084                                 int reg = (r < 4) ? 8 : 9;
1085                                 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8);      // mov r0, r{7,8}, lsr #lsr
1086                                 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff);           // and r0, r{7,8}, <mask>
1087                                 hostreg_r[0] = -1;
1088                                 known_regb &= ~(1 << tmpv2);
1089                         }
1090                         tr_write_funcs[tmpv2]();
1091                         ret++; break;
1092                 }
1093
1094                 // ld ri, s
1095                 case 0x0a: {
1096                         int r;
1097                         r = (op&3) | ((op>>6)&4); // dst
1098                         tmpv = (op >> 4) & 0xf;   // src
1099                         if (tmpv >= 8)  tr_unhandled();
1100                         if ((r&3) == 3) tr_unhandled();
1101
1102                         if (known_regb & (1 << tmpv)) {
1103                                 known_regs.r[r] = known_regs.gr[tmpv].h;
1104                                 known_regb |= 1 << (r + 8);
1105                                 dirty_regb |= 1 << (r + 8);
1106                         } else {
1107                                 int reg = (r < 4) ? 8 : 9;
1108                                 int ror = ((4 - (r&3))*8) & 0x1f;
1109                                 tr_read_funcs[tmpv]();
1110                                 EOP_BIC_IMM(reg, reg, ror/2, 0xff);             // bic r{7,8}, r{7,8}, <mask>
1111                                 EOP_AND_IMM(0, 0, 0, 0xff);                     // and r0, r0, 0xff
1112                                 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8);          // orr r{7,8}, r{7,8}, r0, lsl #lsl
1113                                 hostreg_r[0] = -1;
1114                                 known_regb &= ~(1 << (r+8));
1115                                 dirty_regb &= ~(1 << (r+8));
1116                         }
1117                         ret++; break;
1118                 }
1119
1120                 // ldi ri, simm
1121                 case 0x0c ... 0x0f:
1122                         tmpv = (op>>8)&7;
1123                         known_regs.r[tmpv] = op;
1124                         known_regb |= 1 << (tmpv + 8);
1125                         dirty_regb |= 1 << (tmpv + 8);
1126                         ret++; break;
1127
1128                 // ld d, (a)
1129                 case 0x25:
1130                         // tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1131                         tmpv2 = (op >> 4) & 0xf;  // dst
1132                         if (tmpv2 >= 8) return -1; // TODO
1133
1134                         tr_read_funcs[SSP_A]();
1135                         EOP_LDR_IMM(1,7,0x48c);                                 // ptr_iram_rom
1136                         EOP_ADD_REG_LSL(0,1,0,1);                               // add  r0, r1, r0, lsl #1
1137                         EOP_LDRH_SIMPLE(0,0);                                   // ldrh r0, [r0]
1138                         hostreg_r[0] = hostreg_r[1] = -1;
1139                         tr_write_funcs[tmpv2]();
1140                         ret += 2; break; /* should certainly take > 1 */
1141
1142                 // bra cond, addr
1143                 case 0x26: {
1144                         tmpv = tr_cond_check(op);
1145                         tr_mov16_cond(tmpv, 0, imm);
1146                         if (tmpv != A_COND_AL) {
1147                                 EOP_C_DOP_IMM(tmpv, A_OP_ADD, 0, 11, 11, 0, 1); // add 1 to cycles if we jump
1148                                 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1149                         }
1150                         else
1151                                 ret++;  // always jump */
1152                         tr_write_funcs[SSP_PC]();
1153                         ret++; break;
1154                 }
1155
1156
1157 /*
1158                 // mpys?
1159                 case 0x1b:
1160                         read_P(); // update P
1161                         rA32 -= rP.v;                   // maybe only upper word?
1162                         UPD_ACC_ZN                      // there checking flags after this
1163                         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1164                         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1165                         break;
1166
1167                 // mpya (rj), (ri), b
1168                 case 0x4b:
1169                         read_P(); // update P
1170                         rA32 += rP.v; // confirmed to be 32bit
1171                         UPD_ACC_ZN // ?
1172                         rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1173                         rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1174                         break;
1175
1176                 // mld (rj), (ri), b
1177                 case 0x5b:
1178                         EOP_MOV_IMM(5, 0, 0);                   // mov r5, #0
1179                         known_regs.r[SSP_A].v = 0;
1180                         known_regb |= (KRREG_A|KRREG_AL);
1181                         EOP_BIC_IMM(6, 6, 0, 0x0f);             // bic r6, r6, 0xf // flags
1182                         // TODO
1183                         ret++; break;
1184 */
1185         }
1186
1187         return ret;
1188 }
1189
1190 static void *translate_block(int pc)
1191 {
1192         unsigned int op, op1, imm, ccount = 0;
1193         unsigned int *block_start;
1194         int ret, ret_prev = -1;
1195
1196         // create .pool
1197         //*tcache_ptr++ = (u32) in_funcs;                       // -1 func pool
1198
1199         printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1200         block_start = tcache_ptr;
1201         known_regb = 0;
1202         dirty_regb = KRREG_P;
1203         hostreg_clear();
1204
1205         emit_block_prologue();
1206
1207         for (; ccount < 100;)
1208         {
1209                 //printf("  insn #%i\n", icount);
1210                 op = PROGRAM(pc++);
1211                 op1 = op >> 9;
1212                 imm = (u32)-1;
1213
1214                 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1215                         imm = PROGRAM(pc++); // immediate
1216
1217                 ret = translate_op(op, &pc, imm);
1218                 if (ret <= 0)
1219                 {
1220                         tr_flush_dirty_pr();
1221
1222                         emit_mov_const(A_COND_AL, 0, op);
1223
1224                         // need immediate?
1225                         if (imm != (u32)-1)
1226                                 emit_mov_const(A_COND_AL, 1, imm);
1227
1228                         // dump PC
1229                         emit_pc_dump(pc);
1230
1231                         if (ret_prev > 0) emit_call(regfile_store);
1232                         emit_call(in_funcs[op1]);
1233                         emit_call(regfile_load);
1234
1235                         if (in_funcs[op1] == NULL) {
1236                                 printf("NULL func! op=%08x (%02x)\n", op, op1);
1237                                 exit(1);
1238                         }
1239                         ccount++;
1240                         hostreg_clear();
1241                         dirty_regb |= KRREG_P;
1242                         known_regb = 0;
1243                 }
1244                 else
1245                         ccount += ret;
1246
1247                 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1248                         ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1249                                 (op & 0xf0) == 0x60)) { // ld PC
1250                         break;
1251                 }
1252                 ret_prev = ret;
1253         }
1254
1255         tr_flush_dirty_pr();
1256         emit_block_epilogue(ccount + 1);
1257         *tcache_ptr++ = 0xffffffff; // end of block
1258         //printf("  %i inst\n", icount);
1259
1260         if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1261                 printf("tcache overflow!\n");
1262                 fflush(stdout);
1263                 exit(1);
1264         }
1265
1266         // stats
1267         nblocks++;
1268         //if (pc >= 0x400)
1269         printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1270         //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1271
1272 #ifdef DUMP_BLOCK
1273         {
1274                 FILE *f = fopen("tcache.bin", "wb");
1275                 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1276                 fclose(f);
1277         }
1278         exit(0);
1279 #endif
1280
1281         handle_caches();
1282
1283         return block_start;
1284 }
1285
1286
1287
1288 // -----------------------------------------------------
1289
1290 int ssp1601_dyn_startup(void)
1291 {
1292         memset(tcache, 0, TCACHE_SIZE);
1293         memset(block_table, 0, sizeof(block_table));
1294         memset(block_table_iram, 0, sizeof(block_table_iram));
1295         tcache_ptr = tcache;
1296         *tcache_ptr++ = 0xffffffff;
1297
1298         return 0;
1299 }
1300
1301
1302 void ssp1601_dyn_reset(ssp1601_t *ssp)
1303 {
1304         ssp1601_reset_local(ssp);
1305         ssp->ptr_rom = (unsigned int) Pico.rom;
1306         ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1307         ssp->ptr_dram = (unsigned int) svp->dram;
1308 }
1309
1310 void ssp1601_dyn_run(int cycles)
1311 {
1312         if (ssp->emu_status & SSP_WAIT_MASK) return;
1313         //{ printf("%i wait\n", Pico.m.frame_count); return; }
1314         //printf("%i  %04x\n", Pico.m.frame_count, rPC<<1);
1315
1316 #ifdef DUMP_BLOCK
1317         rPC = DUMP_BLOCK >> 1;
1318 #endif
1319         while (cycles > 0)
1320         {
1321                 int (*trans_entry)(void);
1322                 if (rPC < 0x800/2)
1323                 {
1324                         if (iram_dirty) {
1325                                 iram_context = get_iram_context();
1326                                 iram_dirty--;
1327                         }
1328                         if (block_table_iram[iram_context][rPC] == NULL)
1329                                 block_table_iram[iram_context][rPC] = translate_block(rPC);
1330                         trans_entry = (void *) block_table_iram[iram_context][rPC];
1331                 }
1332                 else
1333                 {
1334                         if (block_table[rPC] == NULL)
1335                                 block_table[rPC] = translate_block(rPC);
1336                         trans_entry = (void *) block_table[rPC];
1337                 }
1338
1339                 //printf("enter %04x\n", rPC<<1);
1340                 cycles -= trans_entry();
1341                 //printf("leave %04x\n", rPC<<1);
1342         }
1343 //      debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1344 //      exit(1);
1345 }
1346