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