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