svp compiler: all ops implemented, EXT regs left
[picodrive.git] / Pico / carthw / svp / compiler.c
CommitLineData
726bbb3e 1// 187 blocks, 12072 bytes
2// 14 IRAM blocks
3
4#include "../../PicoInt.h"
e807ac75 5#include "compiler.h"
726bbb3e 6
892b1dd2 7static unsigned int *block_table[0x5090/2];
8static unsigned int *block_table_iram[15][0x800/2];
892b1dd2 9static unsigned int *tcache_ptr = NULL;
726bbb3e 10
726bbb3e 11static int nblocks = 0;
df143b36 12static int iram_context = 0;
726bbb3e 13
5d817c91 14#ifndef ARM
0e4d7ba5 15#define DUMP_BLOCK 0x08aa
5d817c91 16unsigned int tcache[512*1024];
17void regfile_load(void){}
18void regfile_store(void){}
19#endif
20
726bbb3e 21#define EMBED_INTERPRETER
22#define ssp1601_reset ssp1601_reset_local
23#define ssp1601_run ssp1601_run_local
24
5c129565 25#define GET_PC() rPC
26#define GET_PPC_OFFS() (GET_PC()*2 - 2)
d274c33b 27#define SET_PC(d) { rPC = d; } /* must return to dispatcher after this */
726bbb3e 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"
5c129565 33#include "gen_arm.c"
726bbb3e 34
35// -----------------------------------------------------
36
892b1dd2 37// ld d, s
38static void op00(unsigned int op, unsigned int imm)
39{
40 unsigned int tmpv;
259ed0ea 41 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
892b1dd2 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)
56static 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
63static 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
70static void op04(unsigned int op, unsigned int imm)
71{
72 REG_WRITE((op & 0xf0) >> 4, imm);
73}
74
75// ld d, ((ri))
76static 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
83static void op06(unsigned int op, unsigned int imm)
84{
85 ptr1_write(op, imm);
86}
87
88// ld adr, a
89static void op07(unsigned int op, unsigned int imm)
90{
91 ssp->RAM[op & 0x1ff] = rA;
92}
93
94// ld d, ri
95static 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
102static 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)
108static void op0c(unsigned int op, unsigned int imm)
109{
110 rIJ[(op>>8)&7] = op;
111}
112
113// call cond, addr
114static void op24(unsigned int op, unsigned int imm)
115{
116 int cond = 0;
117 do {
118 COND_CHECK
259ed0ea 119 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
892b1dd2 120 }
121 while (0);
122}
123
124// ld d, (a)
125static 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
132static void op26(unsigned int op, unsigned int imm)
133{
134 do
135 {
136 int cond = 0;
137 COND_CHECK
259ed0ea 138 if (cond) SET_PC(imm);
892b1dd2 139 }
259ed0ea 140 while (0);
892b1dd2 141}
142
143// mod cond, op
144static 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?
166static 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
176static 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
186static 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
195static 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
205static 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
215static 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
225static 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
235static 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
245static 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)
256static void op11(unsigned int op, unsigned int imm)
257{
258 unsigned int tmpv;
259 tmpv = ptr1_read(op); OP_SUBA(tmpv);
260}
261
262static void op31(unsigned int op, unsigned int imm)
263{
264 unsigned int tmpv;
265 tmpv = ptr1_read(op); OP_CMPA(tmpv);
266}
267
268static void op41(unsigned int op, unsigned int imm)
269{
270 unsigned int tmpv;
271 tmpv = ptr1_read(op); OP_ADDA(tmpv);
272}
273
274static void op51(unsigned int op, unsigned int imm)
275{
276 unsigned int tmpv;
277 tmpv = ptr1_read(op); OP_ANDA(tmpv);
278}
279
280static void op61(unsigned int op, unsigned int imm)
281{
282 unsigned int tmpv;
283 tmpv = ptr1_read(op); OP_ORA (tmpv);
284}
285
286static 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
293static void op03(unsigned int op, unsigned int imm)
294{
295 unsigned int tmpv;
296 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
297}
298
299static void op13(unsigned int op, unsigned int imm)
300{
301 unsigned int tmpv;
302 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
303}
304
305static void op33(unsigned int op, unsigned int imm)
306{
307 unsigned int tmpv;
308 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
309}
310
311static void op43(unsigned int op, unsigned int imm)
312{
313 unsigned int tmpv;
314 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
315}
316
317static void op53(unsigned int op, unsigned int imm)
318{
319 unsigned int tmpv;
320 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
321}
322
323static void op63(unsigned int op, unsigned int imm)
324{
325 unsigned int tmpv;
326 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
327}
328
329static 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
336static void op14(unsigned int op, unsigned int imm)
337{
338 OP_SUBA(imm);
339}
340
341static void op34(unsigned int op, unsigned int imm)
342{
343 OP_CMPA(imm);
344}
345
346static void op44(unsigned int op, unsigned int imm)
347{
348 OP_ADDA(imm);
349}
350
351static void op54(unsigned int op, unsigned int imm)
352{
353 OP_ANDA(imm);
354}
355
356static void op64(unsigned int op, unsigned int imm)
357{
358 OP_ORA (imm);
359}
360
361static void op74(unsigned int op, unsigned int imm)
362{
363 OP_EORA(imm);
364}
365
366// OP a, ((ri))
367static void op15(unsigned int op, unsigned int imm)
368{
369 unsigned int tmpv;
370 tmpv = ptr2_read(op); OP_SUBA(tmpv);
371}
372
373static void op35(unsigned int op, unsigned int imm)
374{
375 unsigned int tmpv;
376 tmpv = ptr2_read(op); OP_CMPA(tmpv);
377}
378
379static void op45(unsigned int op, unsigned int imm)
380{
381 unsigned int tmpv;
382 tmpv = ptr2_read(op); OP_ADDA(tmpv);
383}
384
385static void op55(unsigned int op, unsigned int imm)
386{
387 unsigned int tmpv;
388 tmpv = ptr2_read(op); OP_ANDA(tmpv);
389}
390
391static void op65(unsigned int op, unsigned int imm)
392{
393 unsigned int tmpv;
394 tmpv = ptr2_read(op); OP_ORA (tmpv);
395}
396
397static 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
404static void op19(unsigned int op, unsigned int imm)
405{
406 unsigned int tmpv;
407 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
408}
409
410static void op39(unsigned int op, unsigned int imm)
411{
412 unsigned int tmpv;
413 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
414}
415
416static void op49(unsigned int op, unsigned int imm)
417{
418 unsigned int tmpv;
419 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
420}
421
422static void op59(unsigned int op, unsigned int imm)
423{
424 unsigned int tmpv;
425 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
426}
427
428static void op69(unsigned int op, unsigned int imm)
429{
430 unsigned int tmpv;
431 tmpv = rIJ[IJind]; OP_ORA (tmpv);
432}
433
434static 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
441static void op1c(unsigned int op, unsigned int imm)
442{
443 OP_SUBA(op & 0xff);
444}
445
446static void op3c(unsigned int op, unsigned int imm)
447{
448 OP_CMPA(op & 0xff);
449}
450
451static void op4c(unsigned int op, unsigned int imm)
452{
453 OP_ADDA(op & 0xff);
454}
455
456static void op5c(unsigned int op, unsigned int imm)
457{
458 OP_ANDA(op & 0xff);
459}
460
461static void op6c(unsigned int op, unsigned int imm)
462{
463 OP_ORA (op & 0xff);
464}
465
466static void op7c(unsigned int op, unsigned int imm)
467{
468 OP_EORA(op & 0xff);
469}
470
471typedef void (in_func)(unsigned int op, unsigned int imm);
472
473static 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
df143b36 495static 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
df143b36 507static 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];
df143b36 511 val1 = iram_context_map[(val>>1)&0x3f];
512
5c129565 513 if (val1 == 0) {
df143b36 514 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
df143b36 515 //debug_dump2file(name, svp->iram_rom, 0x800);
516 exit(1);
517 }
5c129565 518// elprintf(EL_ANOMALY, "iram_context: %02i", val1);
df143b36 519 return val1;
520}
521
5d817c91 522// -----------------------------------------------------
523/*
524enum {
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 */
532static struct
533{
534 ssp_reg_t gr[8];
535 unsigned char r[8];
bad5731d 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 */
550static 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
89fea1e9 555 * P means that it needs to be recalculated
bad5731d 556 */
557static u32 dirty_regb = 0;
5d817c91 558
559/* known values of host regs.
d274c33b 560 * -1 - unknown
561 * 000000-00ffff - 16bit value
562 * 100000-10ffff - base reg (r7) + 16bit val
6e39239f 563 * 0r0000 - means reg (low) eq gr[r].h, r != AL
5d817c91 564 */
565static int hostreg_r[4];
566
567static void hostreg_clear(void)
568{
569 int i;
570 for (i = 0; i < 4; i++)
571 hostreg_r[i] = -1;
572}
573
6e39239f 574static void hostreg_sspreg_changed(int sspreg)
5d817c91 575{
576 int i;
577 for (i = 0; i < 4; i++)
6e39239f 578 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
5d817c91 579}
580
726bbb3e 581
5c129565 582#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
726bbb3e 583
6e39239f 584static void tr_unhandled(void)
585{
586 FILE *f = fopen("tcache.bin", "wb");
587 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
588 fclose(f);
589 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
590 exit(1);
591}
592
0e4d7ba5 593/* update P, if needed. Trashes r0 */
d274c33b 594static void tr_flush_dirty_P(void)
595{
596 // TODO: const regs
bad5731d 597 if (!(dirty_regb & KRREG_P)) return;
d274c33b 598 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
0e4d7ba5 599 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
600 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
601 EOP_MUL(10, 0, 10); // mul r10, r0, r10
bad5731d 602 dirty_regb &= ~KRREG_P;
0e4d7ba5 603 hostreg_r[0] = -1;
d274c33b 604}
605
89fea1e9 606/* write dirty pr to host reg. Nothing is trashed */
607static void tr_flush_dirty_pr(int r)
608{
609 int ror = 0, reg;
6e39239f 610
89fea1e9 611 if (!(dirty_regb & (1 << (r+8)))) return;
612
613 switch (r&3) {
614 case 0: ror = 0; break;
615 case 1: ror = 24/2; break;
616 case 2: ror = 16/2; break;
617 }
618 reg = (r < 4) ? 8 : 9;
619 EOP_BIC_IMM(reg,reg,ror,0xff);
620 if (known_regs.r[r] != 0)
621 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
622 dirty_regb &= ~(1 << (r+8));
623}
624
625/* write all dirty pr0-pr7 to host regs. Nothing is trashed */
626static void tr_flush_dirty_prs(void)
5d817c91 627{
628 int i, ror = 0, reg;
bad5731d 629 int dirty = dirty_regb >> 8;
5d817c91 630 /* r0-r7 */
bad5731d 631 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
5d817c91 632 {
bad5731d 633 if (!(dirty&1)) continue;
5d817c91 634 switch (i&3) {
635 case 0: ror = 0; break;
636 case 1: ror = 24/2; break;
637 case 2: ror = 16/2; break;
638 }
639 reg = (i < 4) ? 8 : 9;
640 EOP_BIC_IMM(reg,reg,ror,0xff);
bad5731d 641 if (known_regs.r[i] != 0)
642 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
5d817c91 643 }
bad5731d 644 dirty_regb &= ~0xff00;
645}
646
89fea1e9 647/* write dirty pr and "forget" it. Nothing is trashed. */
648static void tr_release_pr(int r)
649{
650 tr_flush_dirty_pr(r);
651 known_regb &= ~(1 << (r+8));
652}
653
6e39239f 654/* fush ARM PSR to r6. Trashes r1 */
bad5731d 655static void tr_flush_dirty_ST(void)
656{
657 if (!(dirty_regb & KRREG_ST)) return;
658 EOP_BIC_IMM(6,6,0,0x0f);
6e39239f 659 EOP_MRS(1);
660 EOP_ORR_REG_LSR(6,6,1,28);
bad5731d 661 dirty_regb &= ~KRREG_ST;
6e39239f 662 hostreg_r[1] = -1;
663}
664
665/* inverse of above. Trashes r1 */
666static void tr_make_dirty_ST(void)
667{
668 if (dirty_regb & KRREG_ST) return;
669 if (known_regb & KRREG_ST) {
670 int flags = 0;
671 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
672 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
673 EOP_MSR_IMM(4/2, flags);
674 } else {
675 EOP_MOV_REG_LSL(1, 6, 28);
676 EOP_MSR_REG(1);
677 hostreg_r[1] = -1;
678 }
679 dirty_regb |= KRREG_ST;
bad5731d 680}
681
682/* load 16bit val into host reg r0-r3. Nothing is trashed */
683static void tr_mov16(int r, int val)
684{
685 if (hostreg_r[r] != val) {
686 emit_mov_const(A_COND_AL, r, val);
687 hostreg_r[r] = val;
688 }
689}
690
691static void tr_mov16_cond(int cond, int r, int val)
692{
693 emit_mov_const(cond, r, val);
a6fb500b 694 hostreg_r[r] = -1;
5d817c91 695}
696
0e4d7ba5 697/* read bank word to r0 (upper bits zero). Thrashes r1. */
5d817c91 698static void tr_bank_read(int addr) /* word addr 0-0x1ff */
699{
bad5731d 700 int breg = 7;
701 if (addr > 0x7f) {
702 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
703 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
704 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 705 }
bad5731d 706 breg = 1;
5d817c91 707 }
bad5731d 708 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
5d817c91 709 hostreg_r[0] = -1;
710}
711
712/* write r0 to bank. Trashes r1. */
713static void tr_bank_write(int addr)
714{
715 int breg = 7;
716 if (addr > 0x7f) {
d274c33b 717 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 718 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 719 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 720 }
721 breg = 1;
722 }
b9c1d012 723 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 724}
725
89fea1e9 726/* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
727static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
5d817c91 728{
a6fb500b 729 int modulo_shift = -1; /* unknown */
5d817c91 730
731 if (mod == 0) return;
732
733 if (!need_modulo || mod == 1) // +!
734 modulo_shift = 8;
bad5731d 735 else if (need_modulo && (known_regb & KRREG_ST)) {
736 modulo_shift = known_regs.gr[SSP_ST].h & 7;
5d817c91 737 if (modulo_shift == 0) modulo_shift = 8;
738 }
739
89fea1e9 740 if (modulo_shift == -1)
741 {
a6fb500b 742 int reg = (r < 4) ? 8 : 9;
89fea1e9 743 tr_release_pr(r);
0e4d7ba5 744 if (dirty_regb & KRREG_ST) {
745 // avoid flushing ARM flags
746 EOP_AND_IMM(1, 6, 0, 0x70);
747 EOP_SUB_IMM(1, 1, 0, 0x10);
748 EOP_AND_IMM(1, 1, 0, 0x70);
749 EOP_ADD_IMM(1, 1, 0, 0x10);
750 } else {
751 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
752 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
753 }
89fea1e9 754 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
755 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
756 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
757 if (r&3)
758 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
759 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
760 if (mod == 2)
761 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
762 else EOP_ADD_REG2_LSL(reg,reg,3,2);
763 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
764 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
765 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
a6fb500b 766 }
767 else if (known_regb & (1 << (r + 8)))
768 {
769 int modulo = (1 << modulo_shift) - 1;
5d817c91 770 if (mod == 2)
89fea1e9 771 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
772 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
a6fb500b 773 }
774 else
775 {
5d817c91 776 int reg = (r < 4) ? 8 : 9;
777 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
778 EOP_MOV_REG_ROR(reg,reg,ror);
779 // {add|sub} reg, reg, #1<<shift
89fea1e9 780 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
5d817c91 781 EOP_MOV_REG_ROR(reg,reg,32-ror);
782 }
783}
784
bad5731d 785/* handle writes r0 to (rX). Trashes r1.
786 * fortunately we can ignore modulo increment modes for writes. */
0e4d7ba5 787static void tr_rX_write(int op)
bad5731d 788{
789 if ((op&3) == 3)
790 {
791 int mod = (op>>2) & 3; // direct addressing
792 tr_bank_write((op & 0x100) + mod);
793 }
794 else
795 {
796 int r = (op&3) | ((op>>6)&4);
797 if (known_regb & (1 << (r + 8))) {
798 tr_bank_write((op&0x100) | known_regs.r[r]);
799 } else {
800 int reg = (r < 4) ? 8 : 9;
801 int ror = ((4 - (r&3))*8) & 0x1f;
802 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
803 if (r >= 4)
804 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
805 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
806 else EOP_ADD_REG_LSL(1,7,1,1);
807 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
808 hostreg_r[1] = -1;
809 }
89fea1e9 810 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
811 }
812}
813
814/* read (rX) to r0. Trashes r1-r3. */
815static void tr_rX_read(int r, int mod)
816{
817 if ((r&3) == 3)
818 {
819 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
820 }
821 else
822 {
823 if (known_regb & (1 << (r + 8))) {
6e39239f 824 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
89fea1e9 825 } else {
826 int reg = (r < 4) ? 8 : 9;
827 int ror = ((4 - (r&3))*8) & 0x1f;
828 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
829 if (r >= 4)
830 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
831 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
832 else EOP_ADD_REG_LSL(1,7,1,1);
833 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
0e4d7ba5 834 hostreg_r[0] = hostreg_r[1] = -1;
89fea1e9 835 }
836 tr_ptrr_mod(r, mod, 1, 1);
bad5731d 837 }
838}
839
0e4d7ba5 840/* read ((rX)) to r0. Trashes r1,r2. */
841static void tr_rX_read2(int op)
842{
843 int r = (op&3) | ((op>>6)&4); // src
844
845 if ((r&3) == 3) {
846 tr_bank_read((op&0x100) | ((op>>2)&3));
847 } else if (known_regb & (1 << (r+8))) {
848 tr_bank_read((op&0x100) | known_regs.r[r]);
849 } else {
850 int reg = (r < 4) ? 8 : 9;
851 int ror = ((4 - (r&3))*8) & 0x1f;
852 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
853 if (r >= 4)
854 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
855 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
856 else EOP_ADD_REG_LSL(1,7,1,1);
857 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
858 }
859 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
860 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
861 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
862 if ((r&3) == 3) {
863 tr_bank_write((op&0x100) | ((op>>2)&3));
864 } else if (known_regb & (1 << (r+8))) {
865 tr_bank_write((op&0x100) | known_regs.r[r]);
866 } else {
867 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
868 hostreg_r[1] = -1;
869 }
870 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
871 hostreg_r[0] = hostreg_r[2] = -1;
872}
89fea1e9 873
bad5731d 874/* get ARM cond which would mean that SSP cond is satisfied. No trash. */
875static int tr_cond_check(int op)
876{
6e39239f 877 int f = (op & 0x100) >> 8;
bad5731d 878 switch (op&0xf0) {
879 case 0x00: return A_COND_AL; /* always true */
880 case 0x50: /* Z matches f(?) bit */
881 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
882 EOP_TST_IMM(6, 0, 4);
883 return f ? A_COND_NE : A_COND_EQ;
884 case 0x70: /* N matches f(?) bit */
885 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
886 EOP_TST_IMM(6, 0, 8);
887 return f ? A_COND_NE : A_COND_EQ;
888 default:
889 printf("unimplemented cond?\n");
6e39239f 890 tr_unhandled();
bad5731d 891 return 0;
892 }
893}
894
895static int tr_neg_cond(int cond)
896{
897 switch (cond) {
898 case A_COND_AL: printf("neg for AL?\n"); exit(1);
899 case A_COND_EQ: return A_COND_NE;
900 case A_COND_NE: return A_COND_EQ;
901 case A_COND_MI: return A_COND_PL;
902 case A_COND_PL: return A_COND_MI;
903 default: printf("bad cond for neg\n"); exit(1);
904 }
905 return 0;
906}
907
b9c1d012 908// SSP_GR0, SSP_X, SSP_Y, SSP_A,
909// SSP_ST, SSP_STACK, SSP_PC, SSP_P,
910//@ r4: XXYY
911//@ r5: A
912//@ r6: STACK and emu flags
913//@ r7: SSP context
914//@ r10: P
915
bad5731d 916// read general reg to r0. Trashes r1
d274c33b 917static void tr_GR0_to_r0(void)
918{
919 tr_mov16(0, 0xffff);
920}
921
922static void tr_X_to_r0(void)
923{
924 if (hostreg_r[0] != (SSP_X<<16)) {
925 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
926 hostreg_r[0] = SSP_X<<16;
927 }
928}
929
930static void tr_Y_to_r0(void)
931{
932 // TODO..
933 if (hostreg_r[0] != (SSP_Y<<16)) {
934 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
935 hostreg_r[0] = SSP_Y<<16;
936 }
937}
938
939static void tr_A_to_r0(void)
940{
941 if (hostreg_r[0] != (SSP_A<<16)) {
942 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
943 hostreg_r[0] = SSP_A<<16;
944 }
945}
946
947static void tr_ST_to_r0(void)
948{
949 // VR doesn't need much accuracy here..
950 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
951 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
952 hostreg_r[0] = -1;
953}
954
955static void tr_STACK_to_r0(void)
956{
957 // 448
958 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
959 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
960 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
961 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
962 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
963 hostreg_r[0] = hostreg_r[1] = -1;
964}
965
966static void tr_PC_to_r0(void)
967{
bad5731d 968 tr_mov16(0, known_regs.gr[SSP_PC].h);
d274c33b 969}
970
971static void tr_P_to_r0(void)
972{
973 tr_flush_dirty_P();
974 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
975 hostreg_r[0] = -1;
976}
977
978typedef void (tr_read_func)(void);
979
980static tr_read_func *tr_read_funcs[8] =
981{
982 tr_GR0_to_r0,
983 tr_X_to_r0,
984 tr_Y_to_r0,
985 tr_A_to_r0,
986 tr_ST_to_r0,
987 tr_STACK_to_r0,
988 tr_PC_to_r0,
989 tr_P_to_r0
990};
991
992
b9c1d012 993// write r0 to general reg handlers. Trashes r1
6e39239f 994#define TR_WRITE_R0_TO_REG(reg) \
995{ \
996 hostreg_sspreg_changed(reg); \
997 hostreg_r[0] = (reg)<<16; \
998 if (const_val != -1) { \
999 known_regs.gr[reg].h = const_val; \
1000 known_regb |= 1 << (reg); \
1001 } else { \
1002 known_regb &= ~(1 << (reg)); \
1003 } \
b9c1d012 1004}
1005
6e39239f 1006static void tr_r0_to_GR0(int const_val)
b9c1d012 1007{
1008 // do nothing
1009}
1010
6e39239f 1011static void tr_r0_to_X(int const_val)
b9c1d012 1012{
1013 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1014 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1015 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
6e39239f 1016 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1017 TR_WRITE_R0_TO_REG(SSP_X);
b9c1d012 1018}
1019
6e39239f 1020static void tr_r0_to_Y(int const_val)
b9c1d012 1021{
1022 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1023 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1024 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
bad5731d 1025 dirty_regb |= KRREG_P;
6e39239f 1026 TR_WRITE_R0_TO_REG(SSP_Y);
b9c1d012 1027}
1028
6e39239f 1029static void tr_r0_to_A(int const_val)
b9c1d012 1030{
1031 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
d274c33b 1032 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
b9c1d012 1033 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
6e39239f 1034 TR_WRITE_R0_TO_REG(SSP_A);
b9c1d012 1035}
1036
6e39239f 1037static void tr_r0_to_ST(int const_val)
b9c1d012 1038{
1039 // VR doesn't need much accuracy here..
1040 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1041 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1042 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
6e39239f 1043 TR_WRITE_R0_TO_REG(SSP_ST);
b9c1d012 1044 hostreg_r[1] = -1;
6e39239f 1045 dirty_regb &= ~KRREG_ST;
b9c1d012 1046}
1047
6e39239f 1048static void tr_r0_to_STACK(int const_val)
b9c1d012 1049{
1050 // 448
1051 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1052 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
d274c33b 1053 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
b9c1d012 1054 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
d274c33b 1055 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
b9c1d012 1056 hostreg_r[1] = -1;
1057}
1058
6e39239f 1059static void tr_r0_to_PC(int const_val)
b9c1d012 1060{
1061 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
d274c33b 1062 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
b9c1d012 1063 hostreg_r[1] = -1;
1064}
1065
6e39239f 1066typedef void (tr_write_func)(int const_val);
b9c1d012 1067
1068static tr_write_func *tr_write_funcs[8] =
1069{
1070 tr_r0_to_GR0,
1071 tr_r0_to_X,
1072 tr_r0_to_Y,
1073 tr_r0_to_A,
1074 tr_r0_to_ST,
1075 tr_r0_to_STACK,
1076 tr_r0_to_PC,
6e39239f 1077 (tr_write_func *)tr_unhandled
b9c1d012 1078};
1079
0e4d7ba5 1080static void tr_mac_load_XY(int op)
1081{
1082 tr_rX_read(op&3, (op>>2)&3); // X
1083 EOP_MOV_REG_LSL(4, 0, 16);
1084 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1085 EOP_ORR_REG_SIMPLE(4, 0);
1086 dirty_regb |= KRREG_P;
1087 hostreg_sspreg_changed(SSP_X);
1088 hostreg_sspreg_changed(SSP_Y);
1089 known_regb &= ~KRREG_X;
1090 known_regb &= ~KRREG_Y;
1091}
1092
1093static int tr_aop_ssp2arm(int op)
1094{
1095 switch (op) {
1096 case 1: return A_OP_SUB;
1097 case 3: return A_OP_CMP;
1098 case 4: return A_OP_ADD;
1099 case 5: return A_OP_AND;
1100 case 6: return A_OP_ORR;
1101 case 7: return A_OP_EOR;
1102 }
1103
1104 tr_unhandled();
1105 return 0;
1106}
5d817c91 1107
1108static int translate_op(unsigned int op, int *pc, int imm)
1109{
0e4d7ba5 1110 u32 tmpv, tmpv2, tmpv3;
5d817c91 1111 int ret = 0;
bad5731d 1112 known_regs.gr[SSP_PC].h = *pc;
5d817c91 1113
e807ac75 1114 switch (op >> 9)
1115 {
1116 // ld d, s
f48f5e3b 1117 case 0x00:
5d817c91 1118 if (op == 0) { ret++; break; } // nop
d274c33b 1119 tmpv = op & 0xf; // src
1120 tmpv2 = (op >> 4) & 0xf; // dst
1121 if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
1122 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1123 tr_flush_dirty_P();
1124 EOP_MOV_REG_SIMPLE(5, 10);
6e39239f 1125 hostreg_sspreg_changed(SSP_A); \
bad5731d 1126 known_regb &= ~(KRREG_A|KRREG_AL);
d274c33b 1127 ret++; break;
1128 }
1129 tr_read_funcs[tmpv]();
6e39239f 1130 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
bad5731d 1131 ret++; break;
1132
1133 // ld d, (ri)
89fea1e9 1134 case 0x01: {
1135 // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1136 int r = (op&3) | ((op>>6)&4);
1137 int mod = (op>>2)&3;
1138 tmpv = (op >> 4) & 0xf; // dst
1139 if (tmpv >= 8) return -1; // TODO
1140 if (tmpv != 0)
1141 tr_rX_read(r, mod);
1142 else tr_ptrr_mod(r, mod, 1, 1);
6e39239f 1143 tr_write_funcs[tmpv](-1);
89fea1e9 1144 ret++; break;
1145 }
bad5731d 1146
1147 // ld (ri), s
1148 case 0x02:
1149 tmpv = (op >> 4) & 0xf; // src
1150 if (tmpv >= 8) return -1; // TODO
1151 tr_read_funcs[tmpv]();
0e4d7ba5 1152 tr_rX_write(op);
d274c33b 1153 ret++; break;
f48f5e3b 1154
1155 // ld a, adr
1156 case 0x03:
5d817c91 1157 tr_bank_read(op&0x1ff);
6e39239f 1158 tr_r0_to_A(-1);
5d817c91 1159 ret++; break;
1160
b9c1d012 1161 // ldi d, imm
1162 case 0x04:
1163 tmpv = (op & 0xf0) >> 4;
1164 if (tmpv < 8)
1165 {
1166 tr_mov16(0, imm);
6e39239f 1167 tr_write_funcs[tmpv](imm);
a6fb500b 1168 ret += 2; break;
b9c1d012 1169 }
1170 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1171 {
1172 // programming PMC..
1173 (*pc)++;
1174 tmpv = imm | (PROGRAM((*pc)++) << 16);
a6fb500b 1175 ret += 2;
bad5731d 1176 emit_mov_const(A_COND_AL, 0, tmpv);
6e39239f 1177 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
b9c1d012 1178 EOP_STR_IMM(0,7,0x400+14*4); // PMC
d274c33b 1179 // reads on fe06, fe08; next op is ld -,
1180 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1181 {
bad5731d 1182 int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1183 tr_flush_dirty_ST();
b9c1d012 1184 EOP_LDR_IMM(0,7,0x490); // dram_ptr
6e39239f 1185 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
1186 EOP_LDRH_IMM(0,0,(tmpv == 0x187f03) ? 6 : 8); // ldrh r0, [r0, #8]
b9c1d012 1187 EOP_TST_REG_SIMPLE(0,0);
d274c33b 1188 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
1189 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
b9c1d012 1190 }
1191 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
1192 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1193 hostreg_r[0] = hostreg_r[1] = -1;
1194 ret += 2; break;
1195 }
1196 else
1197 return -1; /* TODO.. */
1198
bad5731d 1199 // ld d, ((ri))
0e4d7ba5 1200 case 0x05:
bad5731d 1201 tmpv2 = (op >> 4) & 0xf; // dst
1202 if (tmpv2 >= 8) return -1; // TODO
0e4d7ba5 1203 tr_rX_read2(op);
6e39239f 1204 tr_write_funcs[tmpv2](-1);
0e4d7ba5 1205 ret += 3; break;
b9c1d012 1206
5d817c91 1207 // ldi (ri), imm
1208 case 0x06:
5d817c91 1209 tr_mov16(0, imm);
0e4d7ba5 1210 tr_rX_write(op);
a6fb500b 1211 ret += 2; break;
f48f5e3b 1212
1213 // ld adr, a
1214 case 0x07:
6e39239f 1215 tr_A_to_r0();
5d817c91 1216 tr_bank_write(op&0x1ff);
1217 ret++; break;
1218
d274c33b 1219 // ld d, ri
1220 case 0x09: {
bad5731d 1221 int r;
d274c33b 1222 r = (op&3) | ((op>>6)&4); // src
bad5731d 1223 tmpv2 = (op >> 4) & 0xf; // dst
d274c33b 1224 if (tmpv2 >= 8) tr_unhandled();
bad5731d 1225 if ((r&3) == 3) tr_unhandled();
d274c33b 1226
bad5731d 1227 if (known_regb & (1 << (r+8))) {
1228 tr_mov16(0, known_regs.r[r]);
6e39239f 1229 tr_write_funcs[tmpv2](known_regs.r[r]);
d274c33b 1230 } else {
bad5731d 1231 int reg = (r < 4) ? 8 : 9;
d274c33b 1232 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1233 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1234 hostreg_r[0] = -1;
6e39239f 1235 tr_write_funcs[tmpv2](-1);
d274c33b 1236 }
d274c33b 1237 ret++; break;
1238 }
1239
bad5731d 1240 // ld ri, s
1241 case 0x0a: {
1242 int r;
1243 r = (op&3) | ((op>>6)&4); // dst
1244 tmpv = (op >> 4) & 0xf; // src
1245 if (tmpv >= 8) tr_unhandled();
1246 if ((r&3) == 3) tr_unhandled();
1247
1248 if (known_regb & (1 << tmpv)) {
1249 known_regs.r[r] = known_regs.gr[tmpv].h;
1250 known_regb |= 1 << (r + 8);
1251 dirty_regb |= 1 << (r + 8);
1252 } else {
1253 int reg = (r < 4) ? 8 : 9;
1254 int ror = ((4 - (r&3))*8) & 0x1f;
1255 tr_read_funcs[tmpv]();
1256 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1257 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1258 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1259 hostreg_r[0] = -1;
1260 known_regb &= ~(1 << (r+8));
1261 dirty_regb &= ~(1 << (r+8));
1262 }
1263 ret++; break;
1264 }
1265
5d817c91 1266 // ldi ri, simm
1267 case 0x0c ... 0x0f:
1268 tmpv = (op>>8)&7;
bad5731d 1269 known_regs.r[tmpv] = op;
1270 known_regb |= 1 << (tmpv + 8);
5d817c91 1271 dirty_regb |= 1 << (tmpv + 8);
1272 ret++; break;
bad5731d 1273
a6fb500b 1274 // call cond, addr
6e39239f 1275 case 0x24: {
1276 u32 *jump_op = NULL;
a6fb500b 1277 tmpv = tr_cond_check(op);
6e39239f 1278 if (tmpv != A_COND_AL) {
1279 jump_op = tcache_ptr;
1280 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1281 }
1282 tr_mov16(0, *pc);
1283 tr_r0_to_STACK(*pc);
1284 if (tmpv != A_COND_AL) {
1285 u32 *real_ptr = tcache_ptr;
1286 tcache_ptr = jump_op;
1287 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1288 tcache_ptr = real_ptr;
1289 }
a6fb500b 1290 tr_mov16_cond(tmpv, 0, imm);
1291 if (tmpv != A_COND_AL) {
1292 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1293 }
6e39239f 1294 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
a6fb500b 1295 ret += 2; break;
6e39239f 1296 }
a6fb500b 1297
bad5731d 1298 // ld d, (a)
1299 case 0x25:
bad5731d 1300 tmpv2 = (op >> 4) & 0xf; // dst
1301 if (tmpv2 >= 8) return -1; // TODO
1302
a6fb500b 1303 tr_A_to_r0();
bad5731d 1304 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1305 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1306 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1307 hostreg_r[0] = hostreg_r[1] = -1;
6e39239f 1308 tr_write_funcs[tmpv2](-1);
a6fb500b 1309 ret += 3; break;
bad5731d 1310
1311 // bra cond, addr
a6fb500b 1312 case 0x26:
bad5731d 1313 tmpv = tr_cond_check(op);
1314 tr_mov16_cond(tmpv, 0, imm);
1315 if (tmpv != A_COND_AL) {
bad5731d 1316 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1317 }
6e39239f 1318 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
a6fb500b 1319 ret += 2; break;
bad5731d 1320
89fea1e9 1321 // mod cond, op
89fea1e9 1322 case 0x48: {
1323 // check for repeats of this op
1324 tmpv = 1; // count
1325 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1326 (*pc)++; tmpv++;
1327 }
6e39239f 1328 if ((op&0xf0) != 0) // !always
1329 tr_make_dirty_ST();
1330
89fea1e9 1331 tmpv2 = tr_cond_check(op);
1332 switch (op & 7) {
1333 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1334 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1335 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
6e39239f 1336 case 7: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_EOR,0,5,1,31,A_AM1_ASR,5); // eor r1, r5, r5, asr #31
1337 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
89fea1e9 1338 hostreg_r[1] = -1; break; // abs
1339 default: tr_unhandled();
1340 }
6e39239f 1341
1342 hostreg_sspreg_changed(SSP_A);
1343 dirty_regb |= KRREG_ST;
1344 known_regb &= ~KRREG_ST;
1345 known_regb &= ~(KRREG_A|KRREG_AL);
89fea1e9 1346 ret += tmpv; break;
1347 }
0e4d7ba5 1348
bad5731d 1349 // mpys?
1350 case 0x1b:
0e4d7ba5 1351 tr_flush_dirty_P();
1352 tr_mac_load_XY(op);
1353 tr_make_dirty_ST();
1354 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1355 hostreg_sspreg_changed(SSP_A);
1356 known_regb &= ~(KRREG_A|KRREG_AL);
1357 dirty_regb |= KRREG_ST;
1358 ret++; break;
bad5731d 1359
1360 // mpya (rj), (ri), b
1361 case 0x4b:
0e4d7ba5 1362 tr_flush_dirty_P();
1363 tr_mac_load_XY(op);
1364 tr_make_dirty_ST();
1365 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1366 hostreg_sspreg_changed(SSP_A);
1367 known_regb &= ~(KRREG_A|KRREG_AL);
1368 dirty_regb |= KRREG_ST;
1369 ret++; break;
bad5731d 1370
1371 // mld (rj), (ri), b
1372 case 0x5b:
0e4d7ba5 1373 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1374 hostreg_sspreg_changed(SSP_A);
1375 known_regs.gr[SSP_A].v = 0;
bad5731d 1376 known_regb |= (KRREG_A|KRREG_AL);
0e4d7ba5 1377 dirty_regb |= KRREG_ST;
1378 tr_mac_load_XY(op);
1379 ret++; break;
1380
1381 // OP a, s
1382 case 0x10:
1383 case 0x30:
1384 case 0x40:
1385 case 0x50:
1386 case 0x60:
1387 case 0x70:
1388 tmpv = op & 0xf; // src
1389 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1390 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1391 if (tmpv >= 8) return -1; // TODO
1392 if (tmpv == SSP_P) {
1393 tr_flush_dirty_P();
1394 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1395 } else if (tmpv == SSP_A) {
1396 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1397 } else {
1398 tr_read_funcs[tmpv]();
1399 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1400 }
1401 hostreg_sspreg_changed(SSP_A);
1402 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1403 dirty_regb |= KRREG_ST;
1404 ret++; break;
1405
1406 // OP a, (ri)
1407 case 0x11:
1408 case 0x31:
1409 case 0x41:
1410 case 0x51:
1411 case 0x61:
1412 case 0x71:
1413 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1414 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1415 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1416 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1417 hostreg_sspreg_changed(SSP_A);
1418 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1419 dirty_regb |= KRREG_ST;
1420 ret++; break;
1421
1422 // OP a, adr
1423 case 0x13:
1424 case 0x33:
1425 case 0x43:
1426 case 0x53:
1427 case 0x63:
1428 case 0x73:
1429 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1430 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1431 tr_bank_read(op&0x1ff);
1432 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1433 hostreg_sspreg_changed(SSP_A);
1434 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1435 dirty_regb |= KRREG_ST;
1436 ret++; break;
1437
1438 // OP a, imm
1439 case 0x14:
1440 case 0x34:
1441 case 0x44:
1442 case 0x54:
1443 case 0x64:
1444 case 0x74:
1445 tmpv = (op & 0xf0) >> 4;
1446 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1447 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1448 tr_mov16(0, imm);
1449 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1450 hostreg_sspreg_changed(SSP_A);
1451 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1452 dirty_regb |= KRREG_ST;
1453 ret += 2; break;
1454
1455 // OP a, ((ri))
1456 case 0x15:
1457 case 0x35:
1458 case 0x45:
1459 case 0x55:
1460 case 0x65:
1461 case 0x75:
1462 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1463 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1464 tr_rX_read2(op);
1465 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1466 hostreg_sspreg_changed(SSP_A);
1467 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1468 dirty_regb |= KRREG_ST;
1469 ret += 3; break;
1470
1471 // OP a, ri
1472 case 0x19:
1473 case 0x39:
1474 case 0x49:
1475 case 0x59:
1476 case 0x69:
1477 case 0x79: {
1478 int r;
1479 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1480 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1481 r = (op&3) | ((op>>6)&4); // src
1482 if ((r&3) == 3) tr_unhandled();
1483
1484 if (known_regb & (1 << (r+8))) {
1485 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1486 } else {
1487 int reg = (r < 4) ? 8 : 9;
1488 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1489 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1490 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1491 hostreg_r[0] = -1;
1492 }
1493 hostreg_sspreg_changed(SSP_A);
1494 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1495 dirty_regb |= KRREG_ST;
1496 ret++; break;
1497 }
1498
1499 // OP simm
1500 case 0x1c:
1501 case 0x3c:
1502 case 0x4c:
1503 case 0x5c:
1504 case 0x6c:
1505 case 0x7c:
1506 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1507 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1508 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
1509 hostreg_sspreg_changed(SSP_A);
1510 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1511 dirty_regb |= KRREG_ST;
bad5731d 1512 ret++; break;
e807ac75 1513 }
1514
5d817c91 1515 return ret;
e807ac75 1516}
1517
df143b36 1518static void *translate_block(int pc)
726bbb3e 1519{
e807ac75 1520 unsigned int op, op1, imm, ccount = 0;
5c129565 1521 unsigned int *block_start;
d274c33b 1522 int ret, ret_prev = -1;
5c129565 1523
1524 // create .pool
e807ac75 1525 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
726bbb3e 1526
259ed0ea 1527 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 1528 block_start = tcache_ptr;
bad5731d 1529 known_regb = 0;
1530 dirty_regb = KRREG_P;
5d817c91 1531 hostreg_clear();
5c129565 1532
1533 emit_block_prologue();
726bbb3e 1534
e807ac75 1535 for (; ccount < 100;)
726bbb3e 1536 {
259ed0ea 1537 //printf(" insn #%i\n", icount);
726bbb3e 1538 op = PROGRAM(pc++);
1539 op1 = op >> 9;
e807ac75 1540 imm = (u32)-1;
5c129565 1541
e807ac75 1542 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1543 imm = PROGRAM(pc++); // immediate
5c129565 1544
5d817c91 1545 ret = translate_op(op, &pc, imm);
e807ac75 1546 if (ret <= 0)
1547 {
89fea1e9 1548 tr_flush_dirty_prs();
1549 tr_flush_dirty_ST();
5d817c91 1550
bad5731d 1551 emit_mov_const(A_COND_AL, 0, op);
5c129565 1552
e807ac75 1553 // need immediate?
1554 if (imm != (u32)-1)
bad5731d 1555 emit_mov_const(A_COND_AL, 1, imm);
5c129565 1556
e807ac75 1557 // dump PC
1558 emit_pc_dump(pc);
5c129565 1559
d274c33b 1560 if (ret_prev > 0) emit_call(regfile_store);
1561 emit_call(in_funcs[op1]);
1562 emit_call(regfile_load);
e807ac75 1563
1564 if (in_funcs[op1] == NULL) {
1565 printf("NULL func! op=%08x (%02x)\n", op, op1);
1566 exit(1);
1567 }
1568 ccount++;
5d817c91 1569 hostreg_clear();
bad5731d 1570 dirty_regb |= KRREG_P;
1571 known_regb = 0;
892b1dd2 1572 }
e807ac75 1573 else
1574 ccount += ret;
1575
726bbb3e 1576 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1577 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1578 (op & 0xf0) == 0x60)) { // ld PC
1579 break;
1580 }
d274c33b 1581 ret_prev = ret;
726bbb3e 1582 }
5c129565 1583
89fea1e9 1584 tr_flush_dirty_prs();
1585 tr_flush_dirty_ST();
e807ac75 1586 emit_block_epilogue(ccount + 1);
5c129565 1587 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 1588 //printf(" %i inst\n", icount);
1589
892b1dd2 1590 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 1591 printf("tcache overflow!\n");
1592 fflush(stdout);
1593 exit(1);
1594 }
1595
1596 // stats
1597 nblocks++;
df143b36 1598 //if (pc >= 0x400)
892b1dd2 1599 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
259ed0ea 1600 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
df143b36 1601
5d817c91 1602#ifdef DUMP_BLOCK
5c129565 1603 {
1604 FILE *f = fopen("tcache.bin", "wb");
1605 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1606 fclose(f);
1607 }
1608 exit(0);
1609#endif
259ed0ea 1610
1611 handle_caches();
1612
5c129565 1613 return block_start;
726bbb3e 1614}
1615
1616
1617
1618// -----------------------------------------------------
1619
e807ac75 1620int ssp1601_dyn_startup(void)
726bbb3e 1621{
e807ac75 1622 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 1623 memset(block_table, 0, sizeof(block_table));
df143b36 1624 memset(block_table_iram, 0, sizeof(block_table_iram));
e807ac75 1625 tcache_ptr = tcache;
5c129565 1626 *tcache_ptr++ = 0xffffffff;
726bbb3e 1627
6e39239f 1628// TODO: rm
1629{
1630static unsigned short dummy = 0;
1631PC = &dummy;
1632}
726bbb3e 1633 return 0;
1634}
1635
1636
1637void ssp1601_dyn_reset(ssp1601_t *ssp)
1638{
1639 ssp1601_reset_local(ssp);
bad5731d 1640 ssp->ptr_rom = (unsigned int) Pico.rom;
1641 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
d274c33b 1642 ssp->ptr_dram = (unsigned int) svp->dram;
726bbb3e 1643}
1644
726bbb3e 1645void ssp1601_dyn_run(int cycles)
1646{
b9c1d012 1647 if (ssp->emu_status & SSP_WAIT_MASK) return;
1648 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1649 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1650
5d817c91 1651#ifdef DUMP_BLOCK
1652 rPC = DUMP_BLOCK >> 1;
1653#endif
726bbb3e 1654 while (cycles > 0)
1655 {
e807ac75 1656 int (*trans_entry)(void);
df143b36 1657 if (rPC < 0x800/2)
1658 {
1659 if (iram_dirty) {
1660 iram_context = get_iram_context();
892b1dd2 1661 iram_dirty--;
df143b36 1662 }
1663 if (block_table_iram[iram_context][rPC] == NULL)
1664 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 1665 trans_entry = (void *) block_table_iram[iram_context][rPC];
df143b36 1666 }
1667 else
1668 {
1669 if (block_table[rPC] == NULL)
1670 block_table[rPC] = translate_block(rPC);
5c129565 1671 trans_entry = (void *) block_table[rPC];
df143b36 1672 }
726bbb3e 1673
e807ac75 1674 //printf("enter %04x\n", rPC<<1);
1675 cycles -= trans_entry();
1676 //printf("leave %04x\n", rPC<<1);
726bbb3e 1677 }
1678// debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1679// exit(1);
1680}
1681