12-in-1 + realtec mapper
[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
89fea1e9 15#define DUMP_BLOCK 0x3516
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
563 * 0r0000 - means reg (low) eq gr[r].h
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
bad5731d 574// TODO
5d817c91 575/*static*/ void hostreg_ah_changed(void)
576{
577 int i;
578 for (i = 0; i < 4; i++)
d274c33b 579 if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1;
5d817c91 580}
581
726bbb3e 582
5c129565 583#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
726bbb3e 584
d274c33b 585/* update P, if needed. Trashes r1 */
586static void tr_flush_dirty_P(void)
587{
588 // TODO: const regs
bad5731d 589 if (!(dirty_regb & KRREG_P)) return;
d274c33b 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
bad5731d 594 dirty_regb &= ~KRREG_P;
d274c33b 595}
596
89fea1e9 597/* write dirty pr to host reg. Nothing is trashed */
598static 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 */
617static void tr_flush_dirty_prs(void)
5d817c91 618{
619 int i, ror = 0, reg;
bad5731d 620 int dirty = dirty_regb >> 8;
5d817c91 621 /* r0-r7 */
bad5731d 622 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
5d817c91 623 {
bad5731d 624 if (!(dirty&1)) continue;
5d817c91 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);
bad5731d 632 if (known_regs.r[i] != 0)
633 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
5d817c91 634 }
bad5731d 635 dirty_regb &= ~0xff00;
636}
637
89fea1e9 638/* write dirty pr and "forget" it. Nothing is trashed. */
639static void tr_release_pr(int r)
640{
641 tr_flush_dirty_pr(r);
642 known_regb &= ~(1 << (r+8));
643}
644
bad5731d 645/* fush ARM PSR to r6. Trashes r0 */
646static 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 */
657static 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
665static void tr_mov16_cond(int cond, int r, int val)
666{
667 emit_mov_const(cond, r, val);
a6fb500b 668 hostreg_r[r] = -1;
5d817c91 669}
670
bad5731d 671/* read bank word to r0. Thrashes r1. */
5d817c91 672static void tr_bank_read(int addr) /* word addr 0-0x1ff */
673{
bad5731d 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);
5d817c91 679 }
bad5731d 680 breg = 1;
5d817c91 681 }
bad5731d 682 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
5d817c91 683 hostreg_r[0] = -1;
684}
685
686/* write r0 to bank. Trashes r1. */
687static void tr_bank_write(int addr)
688{
689 int breg = 7;
690 if (addr > 0x7f) {
d274c33b 691 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 692 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 693 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 694 }
695 breg = 1;
696 }
b9c1d012 697 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 698}
699
89fea1e9 700/* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
701static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
5d817c91 702{
a6fb500b 703 int modulo_shift = -1; /* unknown */
5d817c91 704
705 if (mod == 0) return;
706
707 if (!need_modulo || mod == 1) // +!
708 modulo_shift = 8;
bad5731d 709 else if (need_modulo && (known_regb & KRREG_ST)) {
710 modulo_shift = known_regs.gr[SSP_ST].h & 7;
5d817c91 711 if (modulo_shift == 0) modulo_shift = 8;
712 }
713
89fea1e9 714 if (modulo_shift == -1)
715 {
a6fb500b 716 int reg = (r < 4) ? 8 : 9;
89fea1e9 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;
a6fb500b 733 }
734 else if (known_regb & (1 << (r + 8)))
735 {
736 int modulo = (1 << modulo_shift) - 1;
5d817c91 737 if (mod == 2)
89fea1e9 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);
a6fb500b 740 }
741 else
742 {
5d817c91 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
89fea1e9 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));
5d817c91 748 EOP_MOV_REG_ROR(reg,reg,32-ror);
749 }
750}
751
bad5731d 752/* handle writes r0 to (rX). Trashes r1.
753 * fortunately we can ignore modulo increment modes for writes. */
754static 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 }
89fea1e9 777 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
778 }
779}
780
781/* read (rX) to r0. Trashes r1-r3. */
782static 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);
bad5731d 804 }
805}
806
89fea1e9 807
bad5731d 808/* get ARM cond which would mean that SSP cond is satisfied. No trash. */
809static 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
829static 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
b9c1d012 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
bad5731d 850// read general reg to r0. Trashes r1
d274c33b 851static void tr_GR0_to_r0(void)
852{
853 tr_mov16(0, 0xffff);
854}
855
856static 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
864static 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
873static 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
881static 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
889static 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
900static void tr_PC_to_r0(void)
901{
bad5731d 902 tr_mov16(0, known_regs.gr[SSP_PC].h);
d274c33b 903}
904
905static 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
912typedef void (tr_read_func)(void);
913
914static 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
b9c1d012 927// write r0 to general reg handlers. Trashes r1
d274c33b 928static void tr_unhandled(void)
b9c1d012 929{
bad5731d 930 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
b9c1d012 931 exit(1);
932}
933
934static void tr_r0_to_GR0(void)
935{
936 // do nothing
937}
938
939static 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
bad5731d 944 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
945 hostreg_r[0] = SSP_X<<16;
b9c1d012 946}
947
948static 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
bad5731d 953 dirty_regb |= KRREG_P;
954 hostreg_r[0] = SSP_Y<<16;
b9c1d012 955}
956
957static void tr_r0_to_A(void)
958{
959 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
d274c33b 960 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
b9c1d012 961 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
bad5731d 962 hostreg_r[0] = SSP_A<<16;
b9c1d012 963}
964
965static 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
974static 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
d274c33b 979 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
b9c1d012 980 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
d274c33b 981 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
b9c1d012 982 hostreg_r[1] = -1;
983}
984
985static void tr_r0_to_PC(void)
986{
987 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
d274c33b 988 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
b9c1d012 989 hostreg_r[1] = -1;
990}
991
992typedef void (tr_write_func)(void);
993
994static 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,
d274c33b 1003 tr_unhandled
b9c1d012 1004};
1005
5d817c91 1006
1007static int translate_op(unsigned int op, int *pc, int imm)
1008{
d274c33b 1009 u32 tmpv, tmpv2;
5d817c91 1010 int ret = 0;
bad5731d 1011 known_regs.gr[SSP_PC].h = *pc;
5d817c91 1012
e807ac75 1013 switch (op >> 9)
1014 {
1015 // ld d, s
f48f5e3b 1016 case 0x00:
5d817c91 1017 if (op == 0) { ret++; break; } // nop
d274c33b 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);
bad5731d 1024 known_regb &= ~(KRREG_A|KRREG_AL);
d274c33b 1025 ret++; break;
1026 }
1027 tr_read_funcs[tmpv]();
1028 tr_write_funcs[tmpv2]();
bad5731d 1029 if (known_regb & (1 << tmpv)) {
1030 known_regs.gr[tmpv2].h = known_regs.gr[tmpv].h;
1031 known_regb |= 1 << tmpv2;
d274c33b 1032 } else
bad5731d 1033 known_regb &= ~(1 << tmpv2);
1034 ret++; break;
1035
1036 // ld d, (ri)
89fea1e9 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 }
bad5731d 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);
d274c33b 1058 ret++; break;
f48f5e3b 1059
1060 // ld a, adr
1061 case 0x03:
5d817c91 1062 tr_bank_read(op&0x1ff);
b9c1d012 1063 tr_r0_to_A();
bad5731d 1064 known_regb &= ~KRREG_A;
d274c33b 1065 hostreg_r[0] = SSP_A<<16;
5d817c91 1066 ret++; break;
1067
b9c1d012 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]();
bad5731d 1075 known_regs.gr[tmpv].h = imm;
1076 known_regb |= 1 << tmpv;
a6fb500b 1077 ret += 2; break;
b9c1d012 1078 }
1079 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1080 {
1081 // programming PMC..
1082 (*pc)++;
1083 tmpv = imm | (PROGRAM((*pc)++) << 16);
a6fb500b 1084 ret += 2;
bad5731d 1085 emit_mov_const(A_COND_AL, 0, tmpv);
b9c1d012 1086 EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status
1087 EOP_STR_IMM(0,7,0x400+14*4); // PMC
d274c33b 1088 // reads on fe06, fe08; next op is ld -,
1089 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1090 {
bad5731d 1091 int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1092 tr_flush_dirty_ST();
b9c1d012 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);
d274c33b 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
b9c1d012 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
bad5731d 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;
a6fb500b 1142 known_regb &= ~(1 << tmpv2);
bad5731d 1143 tr_write_funcs[tmpv2]();
a6fb500b 1144 ret += 3; break; /* should certainly take > 1 */
bad5731d 1145 }
b9c1d012 1146
5d817c91 1147 // ldi (ri), imm
1148 case 0x06:
5d817c91 1149 tr_mov16(0, imm);
bad5731d 1150 tr_rX_write1(op);
a6fb500b 1151 ret += 2; break;
f48f5e3b 1152
1153 // ld adr, a
1154 case 0x07:
d274c33b 1155 if (hostreg_r[0] != (SSP_A<<16)) {
5d817c91 1156 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
d274c33b 1157 hostreg_r[0] = SSP_A<<16;
5d817c91 1158 }
1159 tr_bank_write(op&0x1ff);
1160 ret++; break;
1161
d274c33b 1162 // ld d, ri
1163 case 0x09: {
bad5731d 1164 int r;
d274c33b 1165 r = (op&3) | ((op>>6)&4); // src
bad5731d 1166 tmpv2 = (op >> 4) & 0xf; // dst
d274c33b 1167 if (tmpv2 >= 8) tr_unhandled();
bad5731d 1168 if ((r&3) == 3) tr_unhandled();
d274c33b 1169
bad5731d 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;
d274c33b 1174 } else {
bad5731d 1175 int reg = (r < 4) ? 8 : 9;
d274c33b 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;
bad5731d 1179 known_regb &= ~(1 << tmpv2);
d274c33b 1180 }
1181 tr_write_funcs[tmpv2]();
1182 ret++; break;
1183 }
1184
bad5731d 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
5d817c91 1211 // ldi ri, simm
1212 case 0x0c ... 0x0f:
1213 tmpv = (op>>8)&7;
bad5731d 1214 known_regs.r[tmpv] = op;
1215 known_regb |= 1 << (tmpv + 8);
5d817c91 1216 dirty_regb |= 1 << (tmpv + 8);
1217 ret++; break;
bad5731d 1218
a6fb500b 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
bad5731d 1231 // ld d, (a)
1232 case 0x25:
bad5731d 1233 tmpv2 = (op >> 4) & 0xf; // dst
1234 if (tmpv2 >= 8) return -1; // TODO
1235
a6fb500b 1236 tr_A_to_r0();
bad5731d 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;
a6fb500b 1241 known_regb &= ~(1 << tmpv2);
bad5731d 1242 tr_write_funcs[tmpv2]();
a6fb500b 1243 ret += 3; break;
bad5731d 1244
1245 // bra cond, addr
a6fb500b 1246 case 0x26:
bad5731d 1247 tmpv = tr_cond_check(op);
1248 tr_mov16_cond(tmpv, 0, imm);
1249 if (tmpv != A_COND_AL) {
bad5731d 1250 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1251 }
a6fb500b 1252 tr_r0_to_PC();
1253 ret += 2; break;
bad5731d 1254
89fea1e9 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
bad5731d 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
a6fb500b 1303 EOP_BIC_IMM(6, 6, 0, 0x04); // bic r6, r6, 4 // set Z
bad5731d 1304 // TODO
1305 ret++; break;
1306*/
e807ac75 1307 }
1308
5d817c91 1309 return ret;
e807ac75 1310}
1311
df143b36 1312static void *translate_block(int pc)
726bbb3e 1313{
e807ac75 1314 unsigned int op, op1, imm, ccount = 0;
5c129565 1315 unsigned int *block_start;
d274c33b 1316 int ret, ret_prev = -1;
5c129565 1317
1318 // create .pool
e807ac75 1319 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
726bbb3e 1320
259ed0ea 1321 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 1322 block_start = tcache_ptr;
bad5731d 1323 known_regb = 0;
1324 dirty_regb = KRREG_P;
5d817c91 1325 hostreg_clear();
5c129565 1326
1327 emit_block_prologue();
726bbb3e 1328
e807ac75 1329 for (; ccount < 100;)
726bbb3e 1330 {
259ed0ea 1331 //printf(" insn #%i\n", icount);
726bbb3e 1332 op = PROGRAM(pc++);
1333 op1 = op >> 9;
e807ac75 1334 imm = (u32)-1;
5c129565 1335
e807ac75 1336 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1337 imm = PROGRAM(pc++); // immediate
5c129565 1338
5d817c91 1339 ret = translate_op(op, &pc, imm);
e807ac75 1340 if (ret <= 0)
1341 {
89fea1e9 1342 tr_flush_dirty_prs();
1343 tr_flush_dirty_ST();
5d817c91 1344
bad5731d 1345 emit_mov_const(A_COND_AL, 0, op);
5c129565 1346
e807ac75 1347 // need immediate?
1348 if (imm != (u32)-1)
bad5731d 1349 emit_mov_const(A_COND_AL, 1, imm);
5c129565 1350
e807ac75 1351 // dump PC
1352 emit_pc_dump(pc);
5c129565 1353
d274c33b 1354 if (ret_prev > 0) emit_call(regfile_store);
1355 emit_call(in_funcs[op1]);
1356 emit_call(regfile_load);
e807ac75 1357
1358 if (in_funcs[op1] == NULL) {
1359 printf("NULL func! op=%08x (%02x)\n", op, op1);
1360 exit(1);
1361 }
1362 ccount++;
5d817c91 1363 hostreg_clear();
bad5731d 1364 dirty_regb |= KRREG_P;
1365 known_regb = 0;
892b1dd2 1366 }
e807ac75 1367 else
1368 ccount += ret;
1369
726bbb3e 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 }
d274c33b 1375 ret_prev = ret;
726bbb3e 1376 }
5c129565 1377
89fea1e9 1378 tr_flush_dirty_prs();
1379 tr_flush_dirty_ST();
e807ac75 1380 emit_block_epilogue(ccount + 1);
5c129565 1381 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 1382 //printf(" %i inst\n", icount);
1383
892b1dd2 1384 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 1385 printf("tcache overflow!\n");
1386 fflush(stdout);
1387 exit(1);
1388 }
1389
1390 // stats
1391 nblocks++;
df143b36 1392 //if (pc >= 0x400)
892b1dd2 1393 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
259ed0ea 1394 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
df143b36 1395
5d817c91 1396#ifdef DUMP_BLOCK
5c129565 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
259ed0ea 1404
1405 handle_caches();
1406
5c129565 1407 return block_start;
726bbb3e 1408}
1409
1410
1411
1412// -----------------------------------------------------
1413
e807ac75 1414int ssp1601_dyn_startup(void)
726bbb3e 1415{
e807ac75 1416 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 1417 memset(block_table, 0, sizeof(block_table));
df143b36 1418 memset(block_table_iram, 0, sizeof(block_table_iram));
e807ac75 1419 tcache_ptr = tcache;
5c129565 1420 *tcache_ptr++ = 0xffffffff;
726bbb3e 1421
1422 return 0;
1423}
1424
1425
1426void ssp1601_dyn_reset(ssp1601_t *ssp)
1427{
1428 ssp1601_reset_local(ssp);
bad5731d 1429 ssp->ptr_rom = (unsigned int) Pico.rom;
1430 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
d274c33b 1431 ssp->ptr_dram = (unsigned int) svp->dram;
726bbb3e 1432}
1433
726bbb3e 1434void ssp1601_dyn_run(int cycles)
1435{
b9c1d012 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
5d817c91 1440#ifdef DUMP_BLOCK
1441 rPC = DUMP_BLOCK >> 1;
1442#endif
726bbb3e 1443 while (cycles > 0)
1444 {
e807ac75 1445 int (*trans_entry)(void);
df143b36 1446 if (rPC < 0x800/2)
1447 {
1448 if (iram_dirty) {
1449 iram_context = get_iram_context();
892b1dd2 1450 iram_dirty--;
df143b36 1451 }
1452 if (block_table_iram[iram_context][rPC] == NULL)
1453 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 1454 trans_entry = (void *) block_table_iram[iram_context][rPC];
df143b36 1455 }
1456 else
1457 {
1458 if (block_table[rPC] == NULL)
1459 block_table[rPC] = translate_block(rPC);
5c129565 1460 trans_entry = (void *) block_table[rPC];
df143b36 1461 }
726bbb3e 1462
e807ac75 1463 //printf("enter %04x\n", rPC<<1);
1464 cycles -= trans_entry();
1465 //printf("leave %04x\n", rPC<<1);
726bbb3e 1466 }
1467// debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1468// exit(1);
1469}
1470