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