svp compiler: added first wait loop detection
[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
11static int had_jump = 0;
12static int nblocks = 0;
df143b36 13static int iram_context = 0;
726bbb3e 14
5d817c91 15#ifndef ARM
b9c1d012 16#define DUMP_BLOCK 0x84a
5d817c91 17unsigned int tcache[512*1024];
18void regfile_load(void){}
19void regfile_store(void){}
20#endif
21
726bbb3e 22#define EMBED_INTERPRETER
23#define ssp1601_reset ssp1601_reset_local
24#define ssp1601_run ssp1601_run_local
25
5c129565 26#define GET_PC() rPC
27#define GET_PPC_OFFS() (GET_PC()*2 - 2)
726bbb3e 28#define SET_PC(d) { had_jump = 1; rPC = d; } /* must return to dispatcher after this */
29//#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
30//#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
31//#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
32
33#include "ssp16.c"
5c129565 34#include "gen_arm.c"
726bbb3e 35
36// -----------------------------------------------------
37
892b1dd2 38// ld d, s
39static void op00(unsigned int op, unsigned int imm)
40{
41 unsigned int tmpv;
259ed0ea 42 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
892b1dd2 43 if (op == 0) return; // nop
44 if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
45 // not sure. MAME claims that only hi word is transfered.
46 read_P(); // update P
47 rA32 = rP.v;
48 }
49 else
50 {
51 tmpv = REG_READ(op & 0x0f);
52 REG_WRITE((op & 0xf0) >> 4, tmpv);
53 }
54}
55
56// ld d, (ri)
57static void op01(unsigned int op, unsigned int imm)
58{
59 unsigned int tmpv;
60 tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
61}
62
63// ld (ri), s
64static void op02(unsigned int op, unsigned int imm)
65{
66 unsigned int tmpv;
67 tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
68}
69
70// ldi d, imm
71static void op04(unsigned int op, unsigned int imm)
72{
73 REG_WRITE((op & 0xf0) >> 4, imm);
74}
75
76// ld d, ((ri))
77static void op05(unsigned int op, unsigned int imm)
78{
79 unsigned int tmpv;
80 tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
81}
82
83// ldi (ri), imm
84static void op06(unsigned int op, unsigned int imm)
85{
86 ptr1_write(op, imm);
87}
88
89// ld adr, a
90static void op07(unsigned int op, unsigned int imm)
91{
92 ssp->RAM[op & 0x1ff] = rA;
93}
94
95// ld d, ri
96static void op09(unsigned int op, unsigned int imm)
97{
98 unsigned int tmpv;
99 tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
100}
101
102// ld ri, s
103static void op0a(unsigned int op, unsigned int imm)
104{
105 rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
106}
107
108// ldi ri, simm (also op0d op0e op0f)
109static void op0c(unsigned int op, unsigned int imm)
110{
111 rIJ[(op>>8)&7] = op;
112}
113
114// call cond, addr
115static void op24(unsigned int op, unsigned int imm)
116{
117 int cond = 0;
118 do {
119 COND_CHECK
259ed0ea 120 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
892b1dd2 121 }
122 while (0);
123}
124
125// ld d, (a)
126static void op25(unsigned int op, unsigned int imm)
127{
128 unsigned int tmpv;
129 tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
130}
131
132// bra cond, addr
133static void op26(unsigned int op, unsigned int imm)
134{
135 do
136 {
137 int cond = 0;
138 COND_CHECK
259ed0ea 139 if (cond) SET_PC(imm);
892b1dd2 140 }
259ed0ea 141 while (0);
892b1dd2 142}
143
144// mod cond, op
145static void op48(unsigned int op, unsigned int imm)
146{
147 do
148 {
149 int cond = 0;
150 COND_CHECK
151 if (cond) {
152 switch (op & 7) {
153 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
154 case 3: rA32 <<= 1; break; // shl
155 case 6: rA32 = -(signed int)rA32; break; // neg
156 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
157 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
158 op&7, GET_PPC_OFFS());
159 }
160 UPD_ACC_ZN // ?
161 }
162 }
163 while(0);
164}
165
166// mpys?
167static void op1b(unsigned int op, unsigned int imm)
168{
169 read_P(); // update P
170 rA32 -= rP.v; // maybe only upper word?
171 UPD_ACC_ZN // there checking flags after this
172 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
173 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
174}
175
176// mpya (rj), (ri), b
177static void op4b(unsigned int op, unsigned int imm)
178{
179 read_P(); // update P
180 rA32 += rP.v; // confirmed to be 32bit
181 UPD_ACC_ZN // ?
182 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
183 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
184}
185
186// mld (rj), (ri), b
187static void op5b(unsigned int op, unsigned int imm)
188{
189 rA32 = 0;
190 rST &= 0x0fff; // ?
191 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
192 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
193}
194
195// OP a, s
196static void op10(unsigned int op, unsigned int imm)
197{
198 do
199 {
200 unsigned int tmpv;
201 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
202 }
203 while(0);
204}
205
206static void op30(unsigned int op, unsigned int imm)
207{
208 do
209 {
210 unsigned int tmpv;
211 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
212 }
213 while(0);
214}
215
216static void op40(unsigned int op, unsigned int imm)
217{
218 do
219 {
220 unsigned int tmpv;
221 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
222 }
223 while(0);
224}
225
226static void op50(unsigned int op, unsigned int imm)
227{
228 do
229 {
230 unsigned int tmpv;
231 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
232 }
233 while(0);
234}
235
236static void op60(unsigned int op, unsigned int imm)
237{
238 do
239 {
240 unsigned int tmpv;
241 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
242 }
243 while(0);
244}
245
246static void op70(unsigned int op, unsigned int imm)
247{
248 do
249 {
250 unsigned int tmpv;
251 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
252 }
253 while(0);
254}
255
256// OP a, (ri)
257static void op11(unsigned int op, unsigned int imm)
258{
259 unsigned int tmpv;
260 tmpv = ptr1_read(op); OP_SUBA(tmpv);
261}
262
263static void op31(unsigned int op, unsigned int imm)
264{
265 unsigned int tmpv;
266 tmpv = ptr1_read(op); OP_CMPA(tmpv);
267}
268
269static void op41(unsigned int op, unsigned int imm)
270{
271 unsigned int tmpv;
272 tmpv = ptr1_read(op); OP_ADDA(tmpv);
273}
274
275static void op51(unsigned int op, unsigned int imm)
276{
277 unsigned int tmpv;
278 tmpv = ptr1_read(op); OP_ANDA(tmpv);
279}
280
281static void op61(unsigned int op, unsigned int imm)
282{
283 unsigned int tmpv;
284 tmpv = ptr1_read(op); OP_ORA (tmpv);
285}
286
287static void op71(unsigned int op, unsigned int imm)
288{
289 unsigned int tmpv;
290 tmpv = ptr1_read(op); OP_EORA(tmpv);
291}
292
293// OP a, adr
294static void op03(unsigned int op, unsigned int imm)
295{
296 unsigned int tmpv;
297 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
298}
299
300static void op13(unsigned int op, unsigned int imm)
301{
302 unsigned int tmpv;
303 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
304}
305
306static void op33(unsigned int op, unsigned int imm)
307{
308 unsigned int tmpv;
309 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
310}
311
312static void op43(unsigned int op, unsigned int imm)
313{
314 unsigned int tmpv;
315 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
316}
317
318static void op53(unsigned int op, unsigned int imm)
319{
320 unsigned int tmpv;
321 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
322}
323
324static void op63(unsigned int op, unsigned int imm)
325{
326 unsigned int tmpv;
327 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
328}
329
330static void op73(unsigned int op, unsigned int imm)
331{
332 unsigned int tmpv;
333 tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
334}
335
336// OP a, imm
337static void op14(unsigned int op, unsigned int imm)
338{
339 OP_SUBA(imm);
340}
341
342static void op34(unsigned int op, unsigned int imm)
343{
344 OP_CMPA(imm);
345}
346
347static void op44(unsigned int op, unsigned int imm)
348{
349 OP_ADDA(imm);
350}
351
352static void op54(unsigned int op, unsigned int imm)
353{
354 OP_ANDA(imm);
355}
356
357static void op64(unsigned int op, unsigned int imm)
358{
359 OP_ORA (imm);
360}
361
362static void op74(unsigned int op, unsigned int imm)
363{
364 OP_EORA(imm);
365}
366
367// OP a, ((ri))
368static void op15(unsigned int op, unsigned int imm)
369{
370 unsigned int tmpv;
371 tmpv = ptr2_read(op); OP_SUBA(tmpv);
372}
373
374static void op35(unsigned int op, unsigned int imm)
375{
376 unsigned int tmpv;
377 tmpv = ptr2_read(op); OP_CMPA(tmpv);
378}
379
380static void op45(unsigned int op, unsigned int imm)
381{
382 unsigned int tmpv;
383 tmpv = ptr2_read(op); OP_ADDA(tmpv);
384}
385
386static void op55(unsigned int op, unsigned int imm)
387{
388 unsigned int tmpv;
389 tmpv = ptr2_read(op); OP_ANDA(tmpv);
390}
391
392static void op65(unsigned int op, unsigned int imm)
393{
394 unsigned int tmpv;
395 tmpv = ptr2_read(op); OP_ORA (tmpv);
396}
397
398static void op75(unsigned int op, unsigned int imm)
399{
400 unsigned int tmpv;
401 tmpv = ptr2_read(op); OP_EORA(tmpv);
402}
403
404// OP a, ri
405static void op19(unsigned int op, unsigned int imm)
406{
407 unsigned int tmpv;
408 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
409}
410
411static void op39(unsigned int op, unsigned int imm)
412{
413 unsigned int tmpv;
414 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
415}
416
417static void op49(unsigned int op, unsigned int imm)
418{
419 unsigned int tmpv;
420 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
421}
422
423static void op59(unsigned int op, unsigned int imm)
424{
425 unsigned int tmpv;
426 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
427}
428
429static void op69(unsigned int op, unsigned int imm)
430{
431 unsigned int tmpv;
432 tmpv = rIJ[IJind]; OP_ORA (tmpv);
433}
434
435static void op79(unsigned int op, unsigned int imm)
436{
437 unsigned int tmpv;
438 tmpv = rIJ[IJind]; OP_EORA(tmpv);
439}
440
441// OP simm
442static void op1c(unsigned int op, unsigned int imm)
443{
444 OP_SUBA(op & 0xff);
445}
446
447static void op3c(unsigned int op, unsigned int imm)
448{
449 OP_CMPA(op & 0xff);
450}
451
452static void op4c(unsigned int op, unsigned int imm)
453{
454 OP_ADDA(op & 0xff);
455}
456
457static void op5c(unsigned int op, unsigned int imm)
458{
459 OP_ANDA(op & 0xff);
460}
461
462static void op6c(unsigned int op, unsigned int imm)
463{
464 OP_ORA (op & 0xff);
465}
466
467static void op7c(unsigned int op, unsigned int imm)
468{
469 OP_EORA(op & 0xff);
470}
471
472typedef void (in_func)(unsigned int op, unsigned int imm);
473
474static in_func *in_funcs[0x80] =
475{
476 op00, op01, op02, op03, op04, op05, op06, op07,
477 NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
478 op10, op11, NULL, op13, op14, op15, NULL, NULL,
479 NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
480 NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
481 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
482 op30, op31, NULL, op33, op34, op35, NULL, NULL,
483 NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
484 op40, op41, NULL, op43, op44, op45, NULL, NULL,
485 op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
486 op50, op51, NULL, op53, op54, op55, NULL, NULL,
487 NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
488 op60, op61, NULL, op63, op64, op65, NULL, NULL,
489 NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
490 op70, op71, NULL, op73, op74, op75, NULL, NULL,
491 NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
492};
493
494// -----------------------------------------------------
495
df143b36 496static unsigned char iram_context_map[] =
497{
498 0, 0, 0, 0, 1, 0, 0, 0, // 04
499 0, 0, 0, 0, 0, 0, 2, 0, // 0e
500 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
501 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
502 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
503 0, 0, 0, 0, 0, 0, 0, 0,
504 0, 0,11, 0, 0,12, 0, 0, // 32 35
505 13,14, 0, 0, 0, 0, 0, 0 // 38 39
506};
507
df143b36 508static int get_iram_context(void)
509{
510 unsigned char *ir = (unsigned char *)svp->iram_rom;
511 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
df143b36 512 val1 = iram_context_map[(val>>1)&0x3f];
513
5c129565 514 if (val1 == 0) {
df143b36 515 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
df143b36 516 //debug_dump2file(name, svp->iram_rom, 0x800);
517 exit(1);
518 }
5c129565 519// elprintf(EL_ANOMALY, "iram_context: %02i", val1);
df143b36 520 return val1;
521}
522
5d817c91 523// -----------------------------------------------------
524/*
525enum {
526 SSP_GR0, SSP_X, SSP_Y, SSP_A,
527 SSP_ST, SSP_STACK, SSP_PC, SSP_P,
528 SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
529 SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
530};
531*/
532/* regs with known values */
533static struct
534{
535 ssp_reg_t gr[8];
536 unsigned char r[8];
537} const_regs;
538
539#define CRREG_X (1 << SSP_X)
540#define CRREG_Y (1 << SSP_Y)
541#define CRREG_A (1 << SSP_A) /* AH only */
542#define CRREG_ST (1 << SSP_ST)
543#define CRREG_STACK (1 << SSP_STACK)
544#define CRREG_PC (1 << SSP_PC)
545#define CRREG_P (1 << SSP_P)
546#define CRREG_PR0 (1 << 8)
547#define CRREG_PR4 (1 << 12)
548#define CRREG_AL (1 << 16)
549
550static u32 const_regb = 0; /* bitfield of known register values */
551static u32 dirty_regb = 0; /* known vals, which need to be flushed (only r0-r7) */
552
553/* known values of host regs.
554 * -1 - unknown
555 * 00000-0ffff - 16bit value
556 * 10000-1ffff - base reg (r7) + 16bit val
557 * 20000 - means reg (low) eq AH
558 */
559static int hostreg_r[4];
560
561static void hostreg_clear(void)
562{
563 int i;
564 for (i = 0; i < 4; i++)
565 hostreg_r[i] = -1;
566}
567
568/*static*/ void hostreg_ah_changed(void)
569{
570 int i;
571 for (i = 0; i < 4; i++)
572 if (hostreg_r[i] == 0x20000) hostreg_r[i] = -1;
573}
574
726bbb3e 575
5c129565 576#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
726bbb3e 577
5d817c91 578/* load 16bit val into host reg r0-r3. Nothing is trashed */
579static void tr_mov16(int r, int val)
e807ac75 580{
5d817c91 581 if (hostreg_r[r] != val) {
582 emit_mov_const(r, val);
583 hostreg_r[r] = val;
584 }
585}
586
587/* write dirty r0-r7 to host regs. Nothing is trashed */
588static void tr_flush_dirty(void)
589{
590 int i, ror = 0, reg;
591 dirty_regb >>= 8;
592 /* r0-r7 */
593 for (i = 0; dirty_regb && i < 8; i++, dirty_regb >>= 1)
594 {
595 if (!(dirty_regb&1)) continue;
596 switch (i&3) {
597 case 0: ror = 0; break;
598 case 1: ror = 24/2; break;
599 case 2: ror = 16/2; break;
600 }
601 reg = (i < 4) ? 8 : 9;
602 EOP_BIC_IMM(reg,reg,ror,0xff);
603 if (const_regs.r[i] != 0)
604 EOP_ORR_IMM(reg,reg,ror,const_regs.r[i]);
605 }
606}
607
608/* read bank word to r0 (MSW may contain trash). Thrashes r1. */
609static void tr_bank_read(int addr) /* word addr 0-0x1ff */
610{
611 if (addr&1) {
612 int breg = 7;
613 if (addr > 0x7f) {
614 if (hostreg_r[1] != (0x10000|((addr&0x180)<<1))) {
615 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
616 hostreg_r[1] = 0x10000|((addr&0x180)<<1);
617 }
618 breg = 1;
619 }
620 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
621 } else {
622 EOP_LDR_IMM(0,7,(addr&0x1ff)<<1); // ldr r0, [r1, (op&0x1ff)<<1]
623 }
624 hostreg_r[0] = -1;
625}
626
627/* write r0 to bank. Trashes r1. */
628static void tr_bank_write(int addr)
629{
630 int breg = 7;
631 if (addr > 0x7f) {
632 if (hostreg_r[1] != (0x10000|((addr&0x180)<<1))) {
633 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
634 hostreg_r[1] = 0x10000|((addr&0x180)<<1);
635 }
636 breg = 1;
637 }
b9c1d012 638 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 639}
640
641/* handle RAM bank pointer modifiers. Nothing is trashed. */
642static void tr_ptrr_mod(int r, int mod, int need_modulo)
643{
644 int modulo = -1, modulo_shift = -1; /* unknown */
645
646 if (mod == 0) return;
647
648 if (!need_modulo || mod == 1) // +!
649 modulo_shift = 8;
650 else if (need_modulo && (const_regb & CRREG_ST)) {
651 modulo_shift = const_regs.gr[SSP_ST].h & 7;
652 if (modulo_shift == 0) modulo_shift = 8;
653 }
654
655 if (mod > 1 && modulo_shift == -1) { printf("need var modulo\n"); exit(1); }
656 modulo = (1 << modulo_shift) - 1;
657
658 if (const_regb & (1 << (r + 8))) {
659 if (mod == 2)
660 const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] - 1) & modulo);
661 else const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] + 1) & modulo);
662 } else {
663 int reg = (r < 4) ? 8 : 9;
664 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
665 EOP_MOV_REG_ROR(reg,reg,ror);
666 // {add|sub} reg, reg, #1<<shift
667 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
668 EOP_MOV_REG_ROR(reg,reg,32-ror);
669 }
670}
671
b9c1d012 672// SSP_GR0, SSP_X, SSP_Y, SSP_A,
673// SSP_ST, SSP_STACK, SSP_PC, SSP_P,
674//@ r4: XXYY
675//@ r5: A
676//@ r6: STACK and emu flags
677//@ r7: SSP context
678//@ r10: P
679
680// write r0 to general reg handlers. Trashes r1
681static void tr_r0_unhandled(void)
682{
683 printf("unhandled\n");
684 exit(1);
685}
686
687static void tr_r0_to_GR0(void)
688{
689 // do nothing
690}
691
692static void tr_r0_to_X(void)
693{
694 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
695 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
696 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
697}
698
699static void tr_r0_to_Y(void)
700{
701 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
702 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
703 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
704}
705
706static void tr_r0_to_A(void)
707{
708 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
709 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsl #16 @ AL
710 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
711 hostreg_r[0] = 0x20000;
712}
713
714static void tr_r0_to_ST(void)
715{
716 // VR doesn't need much accuracy here..
717 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
718 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
719 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
720 hostreg_r[1] = -1;
721}
722
723static void tr_r0_to_STACK(void)
724{
725 // 448
726 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
727 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
728 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #26
729 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
730 EOP_ADD_IMM(6, 6, 24/2, 0x20); // add r6, r6, #1<<29
731 hostreg_r[1] = -1;
732}
733
734static void tr_r0_to_PC(void)
735{
736 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
737 EOP_STR_IMM(0,7,0x400+6*4); // str r0, [r7, #(0x400+6*8)]
738 hostreg_r[1] = -1;
739}
740
741typedef void (tr_write_func)(void);
742
743static tr_write_func *tr_write_funcs[8] =
744{
745 tr_r0_to_GR0,
746 tr_r0_to_X,
747 tr_r0_to_Y,
748 tr_r0_to_A,
749 tr_r0_to_ST,
750 tr_r0_to_STACK,
751 tr_r0_to_PC,
752 tr_r0_unhandled
753};
754
5d817c91 755
756static int translate_op(unsigned int op, int *pc, int imm)
757{
758 u32 tmpv;
759 int ret = 0;
760
e807ac75 761 switch (op >> 9)
762 {
763 // ld d, s
f48f5e3b 764 case 0x00:
5d817c91 765 if (op == 0) { ret++; break; } // nop
f48f5e3b 766 break;
767
768 // ld a, adr
769 case 0x03:
5d817c91 770 tr_bank_read(op&0x1ff);
b9c1d012 771 tr_r0_to_A();
5d817c91 772 const_regb &= ~CRREG_A;
773 hostreg_r[0] = 0x20000;
774 ret++; break;
775
b9c1d012 776 // ldi d, imm
777 case 0x04:
778 tmpv = (op & 0xf0) >> 4;
779 if (tmpv < 8)
780 {
781 tr_mov16(0, imm);
782 tr_write_funcs[tmpv]();
783 const_regs.gr[tmpv].h = imm;
784 const_regb |= 1 << tmpv;
785 ret++; break;
786 }
787 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
788 {
789 // programming PMC..
790 (*pc)++;
791 tmpv = imm | (PROGRAM((*pc)++) << 16);
792 emit_mov_const(0, tmpv);
793 EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status
794 EOP_STR_IMM(0,7,0x400+14*4); // PMC
795 // TODO: do this only on reads
796 if (tmpv == 0x187f04) { // fe08
797 EOP_LDR_IMM(0,7,0x490); // dram_ptr
798 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
799 EOP_LDRH_IMM(0,0,8); // ldrh r0, [r0, #8]
800 EOP_TST_REG_SIMPLE(0,0);
801 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
802 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,SSP_WAIT_30FE08>>8); // orr r1, r1, #SSP_WAIT_30FE08
803 }
804 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
805 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
806 hostreg_r[0] = hostreg_r[1] = -1;
807 ret += 2; break;
808 }
809 else
810 return -1; /* TODO.. */
811
812
5d817c91 813 // ldi (ri), imm
814 case 0x06:
5d817c91 815 // int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
816 tr_mov16(0, imm);
817 if ((op&3) == 3)
818 {
819 tmpv = (op>>2) & 3; // direct addressing
820 if (op & 0x100) {
821 if (hostreg_r[1] != 0x10200) {
822 EOP_ADD_IMM(1,7,30/2,0x200>>2); // add r1, r7, 0x200
823 hostreg_r[1] = 0x10200;
824 }
825 EOP_STRH_IMM(0,1,tmpv<<1); // str r0, [r1, {0,2,4,6}]
826 } else {
827 EOP_STRH_IMM(0,7,tmpv<<1); // str r0, [r7, {0,2,4,6}]
828 }
829 }
830 else
831 {
832 int r = (op&3) | ((op>>6)&4);
833 if (const_regb & (1 << (r + 8))) {
834 tr_bank_write(const_regs.r[r] | ((r < 4) ? 0 : 0x100));
835 } else {
836 int reg = (r < 4) ? 8 : 9;
837 int ror = ((4 - (r&3))*8) & 0x1f;
838 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
839 if (r >= 4)
840 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
841 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
842 else EOP_ADD_REG_LSL(1,7,1,1);
843 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
844 hostreg_r[1] = -1;
845 }
846 tr_ptrr_mod(r, (op>>2) & 3, 0);
847 }
848 ret++; break;
f48f5e3b 849
850 // ld adr, a
851 case 0x07:
5d817c91 852 if (hostreg_r[0] != 0x20000) {
853 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
854 hostreg_r[0] = 0x20000;
855 }
856 tr_bank_write(op&0x1ff);
857 ret++; break;
858
859 // ldi ri, simm
860 case 0x0c ... 0x0f:
861 tmpv = (op>>8)&7;
862 const_regs.r[tmpv] = op;
863 const_regb |= 1 << (tmpv + 8);
864 dirty_regb |= 1 << (tmpv + 8);
865 ret++; break;
e807ac75 866 }
867
5d817c91 868 return ret;
e807ac75 869}
870
df143b36 871static void *translate_block(int pc)
726bbb3e 872{
e807ac75 873 unsigned int op, op1, imm, ccount = 0;
5c129565 874 unsigned int *block_start;
e807ac75 875 int ret;
5c129565 876
877 // create .pool
e807ac75 878 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
726bbb3e 879
259ed0ea 880 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 881 block_start = tcache_ptr;
5d817c91 882 const_regb = dirty_regb = 0;
883 hostreg_clear();
5c129565 884
885 emit_block_prologue();
726bbb3e 886
e807ac75 887 for (; ccount < 100;)
726bbb3e 888 {
259ed0ea 889 //printf(" insn #%i\n", icount);
726bbb3e 890 op = PROGRAM(pc++);
891 op1 = op >> 9;
e807ac75 892 imm = (u32)-1;
5c129565 893
e807ac75 894 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
895 imm = PROGRAM(pc++); // immediate
5c129565 896
5d817c91 897 ret = translate_op(op, &pc, imm);
e807ac75 898 if (ret <= 0)
899 {
5d817c91 900 tr_flush_dirty();
901
e807ac75 902 emit_mov_const(0, op);
5c129565 903
e807ac75 904 // need immediate?
905 if (imm != (u32)-1)
906 emit_mov_const(1, imm);
5c129565 907
e807ac75 908 // dump PC
909 emit_pc_dump(pc);
5c129565 910
e807ac75 911 emit_interpreter_call(in_funcs[op1]);
912
913 if (in_funcs[op1] == NULL) {
914 printf("NULL func! op=%08x (%02x)\n", op, op1);
915 exit(1);
916 }
917 ccount++;
5d817c91 918 hostreg_clear();
892b1dd2 919 }
e807ac75 920 else
921 ccount += ret;
922
726bbb3e 923 if (op1 == 0x24 || op1 == 0x26 || // call, bra
924 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
925 (op & 0xf0) == 0x60)) { // ld PC
926 break;
927 }
928 }
5c129565 929
5d817c91 930 tr_flush_dirty();
e807ac75 931 emit_block_epilogue(ccount + 1);
5c129565 932 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 933 //printf(" %i inst\n", icount);
934
892b1dd2 935 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 936 printf("tcache overflow!\n");
937 fflush(stdout);
938 exit(1);
939 }
940
941 // stats
942 nblocks++;
df143b36 943 //if (pc >= 0x400)
892b1dd2 944 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
259ed0ea 945 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
df143b36 946
5d817c91 947#ifdef DUMP_BLOCK
5c129565 948 {
949 FILE *f = fopen("tcache.bin", "wb");
950 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
951 fclose(f);
952 }
953 exit(0);
954#endif
259ed0ea 955
956 handle_caches();
957
5c129565 958 return block_start;
726bbb3e 959}
960
961
962
963// -----------------------------------------------------
964
e807ac75 965int ssp1601_dyn_startup(void)
726bbb3e 966{
e807ac75 967 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 968 memset(block_table, 0, sizeof(block_table));
df143b36 969 memset(block_table_iram, 0, sizeof(block_table_iram));
e807ac75 970 tcache_ptr = tcache;
5c129565 971 *tcache_ptr++ = 0xffffffff;
726bbb3e 972
973 return 0;
974}
975
976
977void ssp1601_dyn_reset(ssp1601_t *ssp)
978{
979 ssp1601_reset_local(ssp);
b9c1d012 980 ssp->rom_ptr = (unsigned int) Pico.rom;
981 ssp->iram_ptr = (unsigned int) svp->iram_rom;
982 ssp->dram_ptr = (unsigned int) svp->dram;
726bbb3e 983}
984
726bbb3e 985void ssp1601_dyn_run(int cycles)
986{
b9c1d012 987 if (ssp->emu_status & SSP_WAIT_MASK) return;
988 //{ printf("%i wait\n", Pico.m.frame_count); return; }
989 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
990
5d817c91 991#ifdef DUMP_BLOCK
992 rPC = DUMP_BLOCK >> 1;
993#endif
726bbb3e 994 while (cycles > 0)
995 {
e807ac75 996 int (*trans_entry)(void);
df143b36 997 if (rPC < 0x800/2)
998 {
999 if (iram_dirty) {
1000 iram_context = get_iram_context();
892b1dd2 1001 iram_dirty--;
df143b36 1002 }
1003 if (block_table_iram[iram_context][rPC] == NULL)
1004 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 1005 trans_entry = (void *) block_table_iram[iram_context][rPC];
df143b36 1006 }
1007 else
1008 {
1009 if (block_table[rPC] == NULL)
1010 block_table[rPC] = translate_block(rPC);
5c129565 1011 trans_entry = (void *) block_table[rPC];
df143b36 1012 }
726bbb3e 1013
726bbb3e 1014 had_jump = 0;
1015
e807ac75 1016 //printf("enter %04x\n", rPC<<1);
1017 cycles -= trans_entry();
1018 //printf("leave %04x\n", rPC<<1);
726bbb3e 1019 }
1020// debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1021// exit(1);
1022}
1023