svp compiler: more ops, idle 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
726bbb3e 11static int nblocks = 0;
df143b36 12static int iram_context = 0;
726bbb3e 13
5d817c91 14#ifndef ARM
d274c33b 15#define DUMP_BLOCK 0x1d7c
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];
536} const_regs;
537
538#define CRREG_X (1 << SSP_X)
539#define CRREG_Y (1 << SSP_Y)
540#define CRREG_A (1 << SSP_A) /* AH only */
541#define CRREG_ST (1 << SSP_ST)
542#define CRREG_STACK (1 << SSP_STACK)
543#define CRREG_PC (1 << SSP_PC)
544#define CRREG_P (1 << SSP_P)
545#define CRREG_PR0 (1 << 8)
546#define CRREG_PR4 (1 << 12)
547#define CRREG_AL (1 << 16)
548
549static u32 const_regb = 0; /* bitfield of known register values */
d274c33b 550static u32 dirty_regb = 0; /* known vals, which need to be flushed (only P, r0-r7) */
5d817c91 551
552/* known values of host regs.
d274c33b 553 * -1 - unknown
554 * 000000-00ffff - 16bit value
555 * 100000-10ffff - base reg (r7) + 16bit val
556 * 0r0000 - means reg (low) eq gr[r].h
5d817c91 557 */
558static int hostreg_r[4];
559
560static void hostreg_clear(void)
561{
562 int i;
563 for (i = 0; i < 4; i++)
564 hostreg_r[i] = -1;
565}
566
567/*static*/ void hostreg_ah_changed(void)
568{
569 int i;
570 for (i = 0; i < 4; i++)
d274c33b 571 if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1;
5d817c91 572}
573
726bbb3e 574
5c129565 575#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
726bbb3e 576
5d817c91 577/* load 16bit val into host reg r0-r3. Nothing is trashed */
578static void tr_mov16(int r, int val)
e807ac75 579{
5d817c91 580 if (hostreg_r[r] != val) {
581 emit_mov_const(r, val);
582 hostreg_r[r] = val;
583 }
584}
585
d274c33b 586/* update P, if needed. Trashes r1 */
587static void tr_flush_dirty_P(void)
588{
589 // TODO: const regs
590 if (!(dirty_regb & CRREG_P)) return;
591 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
592 EOP_MOV_REG_LSL( 1, 4, 16); // mov r1, r4, lsl #16
593 EOP_MOV_REG_ASR( 1, 1, 15); // mov r1, r1, asr #15
594 EOP_MUL(10, 1, 10); // mul r10, r1, r10
595 dirty_regb &= ~CRREG_P;
596}
597
5d817c91 598/* write dirty r0-r7 to host regs. Nothing is trashed */
d274c33b 599static void tr_flush_dirty_pr(void)
5d817c91 600{
601 int i, ror = 0, reg;
602 dirty_regb >>= 8;
603 /* r0-r7 */
604 for (i = 0; dirty_regb && i < 8; i++, dirty_regb >>= 1)
605 {
606 if (!(dirty_regb&1)) continue;
607 switch (i&3) {
608 case 0: ror = 0; break;
609 case 1: ror = 24/2; break;
610 case 2: ror = 16/2; break;
611 }
612 reg = (i < 4) ? 8 : 9;
613 EOP_BIC_IMM(reg,reg,ror,0xff);
614 if (const_regs.r[i] != 0)
615 EOP_ORR_IMM(reg,reg,ror,const_regs.r[i]);
616 }
617}
618
619/* read bank word to r0 (MSW may contain trash). Thrashes r1. */
620static void tr_bank_read(int addr) /* word addr 0-0x1ff */
621{
622 if (addr&1) {
623 int breg = 7;
624 if (addr > 0x7f) {
d274c33b 625 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 626 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 627 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 628 }
629 breg = 1;
630 }
631 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
632 } else {
633 EOP_LDR_IMM(0,7,(addr&0x1ff)<<1); // ldr r0, [r1, (op&0x1ff)<<1]
634 }
635 hostreg_r[0] = -1;
636}
637
638/* write r0 to bank. Trashes r1. */
639static void tr_bank_write(int addr)
640{
641 int breg = 7;
642 if (addr > 0x7f) {
d274c33b 643 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 644 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 645 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 646 }
647 breg = 1;
648 }
b9c1d012 649 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 650}
651
652/* handle RAM bank pointer modifiers. Nothing is trashed. */
653static void tr_ptrr_mod(int r, int mod, int need_modulo)
654{
655 int modulo = -1, modulo_shift = -1; /* unknown */
656
657 if (mod == 0) return;
658
659 if (!need_modulo || mod == 1) // +!
660 modulo_shift = 8;
661 else if (need_modulo && (const_regb & CRREG_ST)) {
662 modulo_shift = const_regs.gr[SSP_ST].h & 7;
663 if (modulo_shift == 0) modulo_shift = 8;
664 }
665
666 if (mod > 1 && modulo_shift == -1) { printf("need var modulo\n"); exit(1); }
667 modulo = (1 << modulo_shift) - 1;
668
669 if (const_regb & (1 << (r + 8))) {
670 if (mod == 2)
671 const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] - 1) & modulo);
672 else const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] + 1) & modulo);
673 } else {
674 int reg = (r < 4) ? 8 : 9;
675 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
676 EOP_MOV_REG_ROR(reg,reg,ror);
677 // {add|sub} reg, reg, #1<<shift
678 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
679 EOP_MOV_REG_ROR(reg,reg,32-ror);
680 }
681}
682
b9c1d012 683// SSP_GR0, SSP_X, SSP_Y, SSP_A,
684// SSP_ST, SSP_STACK, SSP_PC, SSP_P,
685//@ r4: XXYY
686//@ r5: A
687//@ r6: STACK and emu flags
688//@ r7: SSP context
689//@ r10: P
690
d274c33b 691static void tr_GR0_to_r0(void)
692{
693 tr_mov16(0, 0xffff);
694}
695
696static void tr_X_to_r0(void)
697{
698 if (hostreg_r[0] != (SSP_X<<16)) {
699 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
700 hostreg_r[0] = SSP_X<<16;
701 }
702}
703
704static void tr_Y_to_r0(void)
705{
706 // TODO..
707 if (hostreg_r[0] != (SSP_Y<<16)) {
708 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
709 hostreg_r[0] = SSP_Y<<16;
710 }
711}
712
713static void tr_A_to_r0(void)
714{
715 if (hostreg_r[0] != (SSP_A<<16)) {
716 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
717 hostreg_r[0] = SSP_A<<16;
718 }
719}
720
721static void tr_ST_to_r0(void)
722{
723 // VR doesn't need much accuracy here..
724 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
725 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
726 hostreg_r[0] = -1;
727}
728
729static void tr_STACK_to_r0(void)
730{
731 // 448
732 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
733 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
734 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
735 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
736 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
737 hostreg_r[0] = hostreg_r[1] = -1;
738}
739
740static void tr_PC_to_r0(void)
741{
742 tr_mov16(0, const_regs.gr[SSP_PC].h);
743}
744
745static void tr_P_to_r0(void)
746{
747 tr_flush_dirty_P();
748 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
749 hostreg_r[0] = -1;
750}
751
752typedef void (tr_read_func)(void);
753
754static tr_read_func *tr_read_funcs[8] =
755{
756 tr_GR0_to_r0,
757 tr_X_to_r0,
758 tr_Y_to_r0,
759 tr_A_to_r0,
760 tr_ST_to_r0,
761 tr_STACK_to_r0,
762 tr_PC_to_r0,
763 tr_P_to_r0
764};
765
766
b9c1d012 767// write r0 to general reg handlers. Trashes r1
d274c33b 768static void tr_unhandled(void)
b9c1d012 769{
d274c33b 770 printf("unhandled @ %04x\n", const_regs.gr[SSP_PC].h<<1);
b9c1d012 771 exit(1);
772}
773
774static void tr_r0_to_GR0(void)
775{
776 // do nothing
777}
778
779static void tr_r0_to_X(void)
780{
781 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
782 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
783 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
d274c33b 784 dirty_regb |= CRREG_P; // touching X or Y makes P dirty.
b9c1d012 785}
786
787static void tr_r0_to_Y(void)
788{
789 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
790 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
791 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
d274c33b 792 dirty_regb |= CRREG_P;
b9c1d012 793}
794
795static void tr_r0_to_A(void)
796{
797 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
d274c33b 798 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
b9c1d012 799 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
b9c1d012 800}
801
802static void tr_r0_to_ST(void)
803{
804 // VR doesn't need much accuracy here..
805 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
806 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
807 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
808 hostreg_r[1] = -1;
809}
810
811static void tr_r0_to_STACK(void)
812{
813 // 448
814 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
815 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
d274c33b 816 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
b9c1d012 817 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
d274c33b 818 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
b9c1d012 819 hostreg_r[1] = -1;
820}
821
822static void tr_r0_to_PC(void)
823{
824 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
d274c33b 825 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
b9c1d012 826 hostreg_r[1] = -1;
827}
828
829typedef void (tr_write_func)(void);
830
831static tr_write_func *tr_write_funcs[8] =
832{
833 tr_r0_to_GR0,
834 tr_r0_to_X,
835 tr_r0_to_Y,
836 tr_r0_to_A,
837 tr_r0_to_ST,
838 tr_r0_to_STACK,
839 tr_r0_to_PC,
d274c33b 840 tr_unhandled
b9c1d012 841};
842
5d817c91 843
844static int translate_op(unsigned int op, int *pc, int imm)
845{
d274c33b 846 u32 tmpv, tmpv2;
5d817c91 847 int ret = 0;
d274c33b 848 const_regs.gr[SSP_PC].h = *pc;
5d817c91 849
e807ac75 850 switch (op >> 9)
851 {
852 // ld d, s
f48f5e3b 853 case 0x00:
5d817c91 854 if (op == 0) { ret++; break; } // nop
d274c33b 855 tmpv = op & 0xf; // src
856 tmpv2 = (op >> 4) & 0xf; // dst
857 if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
858 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
859 tr_flush_dirty_P();
860 EOP_MOV_REG_SIMPLE(5, 10);
861 const_regb &= ~(CRREG_A|CRREG_AL);
862 ret++; break;
863 }
864 tr_read_funcs[tmpv]();
865 tr_write_funcs[tmpv2]();
866 if (const_regb & (1 << tmpv)) {
867 const_regs.gr[tmpv2].h = const_regs.gr[tmpv].h;
868 const_regb |= 1 << tmpv2;
869 } else
870 const_regb &= ~(1 << tmpv2);
871 ret++; break;
f48f5e3b 872
873 // ld a, adr
874 case 0x03:
5d817c91 875 tr_bank_read(op&0x1ff);
b9c1d012 876 tr_r0_to_A();
5d817c91 877 const_regb &= ~CRREG_A;
d274c33b 878 hostreg_r[0] = SSP_A<<16;
5d817c91 879 ret++; break;
880
b9c1d012 881 // ldi d, imm
882 case 0x04:
883 tmpv = (op & 0xf0) >> 4;
884 if (tmpv < 8)
885 {
886 tr_mov16(0, imm);
887 tr_write_funcs[tmpv]();
888 const_regs.gr[tmpv].h = imm;
889 const_regb |= 1 << tmpv;
890 ret++; break;
891 }
892 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
893 {
894 // programming PMC..
895 (*pc)++;
896 tmpv = imm | (PROGRAM((*pc)++) << 16);
897 emit_mov_const(0, tmpv);
898 EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status
899 EOP_STR_IMM(0,7,0x400+14*4); // PMC
d274c33b 900 // reads on fe06, fe08; next op is ld -,
901 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
902 {
903 int flag = (tmpv == 0x187f03) ? (SSP_WAIT_30FE06) : (SSP_WAIT_30FE08);
b9c1d012 904 EOP_LDR_IMM(0,7,0x490); // dram_ptr
905 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
906 EOP_LDRH_IMM(0,0,8); // ldrh r0, [r0, #8]
907 EOP_TST_REG_SIMPLE(0,0);
d274c33b 908 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
909 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
b9c1d012 910 }
911 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
912 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
913 hostreg_r[0] = hostreg_r[1] = -1;
914 ret += 2; break;
915 }
916 else
917 return -1; /* TODO.. */
918
919
5d817c91 920 // ldi (ri), imm
921 case 0x06:
5d817c91 922 // int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
923 tr_mov16(0, imm);
924 if ((op&3) == 3)
925 {
926 tmpv = (op>>2) & 3; // direct addressing
927 if (op & 0x100) {
d274c33b 928 if (hostreg_r[1] != 0x100200) {
5d817c91 929 EOP_ADD_IMM(1,7,30/2,0x200>>2); // add r1, r7, 0x200
d274c33b 930 hostreg_r[1] = 0x100200;
5d817c91 931 }
932 EOP_STRH_IMM(0,1,tmpv<<1); // str r0, [r1, {0,2,4,6}]
933 } else {
934 EOP_STRH_IMM(0,7,tmpv<<1); // str r0, [r7, {0,2,4,6}]
935 }
936 }
937 else
938 {
939 int r = (op&3) | ((op>>6)&4);
940 if (const_regb & (1 << (r + 8))) {
941 tr_bank_write(const_regs.r[r] | ((r < 4) ? 0 : 0x100));
942 } else {
943 int reg = (r < 4) ? 8 : 9;
944 int ror = ((4 - (r&3))*8) & 0x1f;
945 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
946 if (r >= 4)
947 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
948 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
949 else EOP_ADD_REG_LSL(1,7,1,1);
950 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
951 hostreg_r[1] = -1;
952 }
953 tr_ptrr_mod(r, (op>>2) & 3, 0);
954 }
955 ret++; break;
f48f5e3b 956
957 // ld adr, a
958 case 0x07:
d274c33b 959 if (hostreg_r[0] != (SSP_A<<16)) {
5d817c91 960 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
d274c33b 961 hostreg_r[0] = SSP_A<<16;
5d817c91 962 }
963 tr_bank_write(op&0x1ff);
964 ret++; break;
965
d274c33b 966 // ld d, ri
967 case 0x09: {
968 int r, reg;
969 r = (op&3) | ((op>>6)&4); // src
970 tmpv2 = (op >> 4) & 0xf; // dst
971 if (tmpv2 >= 8) tr_unhandled();
972
973 if (const_regb & (1 << (r+8))) {
974 tr_mov16(0, const_regs.r[r]);
975 const_regs.gr[tmpv2].h = const_regs.r[r];
976 const_regb |= 1 << tmpv2;
977 } else {
978 reg = (r < 4) ? 8 : 9;
979 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
980 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
981 hostreg_r[0] = -1;
982 const_regb &= ~(1 << tmpv2);
983 }
984 tr_write_funcs[tmpv2]();
985 ret++; break;
986 }
987
5d817c91 988 // ldi ri, simm
989 case 0x0c ... 0x0f:
990 tmpv = (op>>8)&7;
991 const_regs.r[tmpv] = op;
992 const_regb |= 1 << (tmpv + 8);
993 dirty_regb |= 1 << (tmpv + 8);
994 ret++; break;
e807ac75 995 }
996
5d817c91 997 return ret;
e807ac75 998}
999
df143b36 1000static void *translate_block(int pc)
726bbb3e 1001{
e807ac75 1002 unsigned int op, op1, imm, ccount = 0;
5c129565 1003 unsigned int *block_start;
d274c33b 1004 int ret, ret_prev = -1;
5c129565 1005
1006 // create .pool
e807ac75 1007 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
726bbb3e 1008
259ed0ea 1009 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 1010 block_start = tcache_ptr;
d274c33b 1011 const_regb = 0;
1012 dirty_regb = CRREG_P;
5d817c91 1013 hostreg_clear();
5c129565 1014
1015 emit_block_prologue();
726bbb3e 1016
e807ac75 1017 for (; ccount < 100;)
726bbb3e 1018 {
259ed0ea 1019 //printf(" insn #%i\n", icount);
726bbb3e 1020 op = PROGRAM(pc++);
1021 op1 = op >> 9;
e807ac75 1022 imm = (u32)-1;
5c129565 1023
e807ac75 1024 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1025 imm = PROGRAM(pc++); // immediate
5c129565 1026
5d817c91 1027 ret = translate_op(op, &pc, imm);
e807ac75 1028 if (ret <= 0)
1029 {
d274c33b 1030 tr_flush_dirty_pr();
5d817c91 1031
e807ac75 1032 emit_mov_const(0, op);
5c129565 1033
e807ac75 1034 // need immediate?
1035 if (imm != (u32)-1)
1036 emit_mov_const(1, imm);
5c129565 1037
e807ac75 1038 // dump PC
1039 emit_pc_dump(pc);
5c129565 1040
d274c33b 1041 if (ret_prev > 0) emit_call(regfile_store);
1042 emit_call(in_funcs[op1]);
1043 emit_call(regfile_load);
e807ac75 1044
1045 if (in_funcs[op1] == NULL) {
1046 printf("NULL func! op=%08x (%02x)\n", op, op1);
1047 exit(1);
1048 }
1049 ccount++;
5d817c91 1050 hostreg_clear();
d274c33b 1051 dirty_regb |= CRREG_P;
892b1dd2 1052 }
e807ac75 1053 else
1054 ccount += ret;
1055
726bbb3e 1056 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1057 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1058 (op & 0xf0) == 0x60)) { // ld PC
1059 break;
1060 }
d274c33b 1061 ret_prev = ret;
726bbb3e 1062 }
5c129565 1063
d274c33b 1064 tr_flush_dirty_pr();
e807ac75 1065 emit_block_epilogue(ccount + 1);
5c129565 1066 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 1067 //printf(" %i inst\n", icount);
1068
892b1dd2 1069 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 1070 printf("tcache overflow!\n");
1071 fflush(stdout);
1072 exit(1);
1073 }
1074
1075 // stats
1076 nblocks++;
df143b36 1077 //if (pc >= 0x400)
892b1dd2 1078 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
259ed0ea 1079 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
df143b36 1080
5d817c91 1081#ifdef DUMP_BLOCK
5c129565 1082 {
1083 FILE *f = fopen("tcache.bin", "wb");
1084 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1085 fclose(f);
1086 }
1087 exit(0);
1088#endif
259ed0ea 1089
1090 handle_caches();
1091
5c129565 1092 return block_start;
726bbb3e 1093}
1094
1095
1096
1097// -----------------------------------------------------
1098
e807ac75 1099int ssp1601_dyn_startup(void)
726bbb3e 1100{
e807ac75 1101 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 1102 memset(block_table, 0, sizeof(block_table));
df143b36 1103 memset(block_table_iram, 0, sizeof(block_table_iram));
e807ac75 1104 tcache_ptr = tcache;
5c129565 1105 *tcache_ptr++ = 0xffffffff;
726bbb3e 1106
1107 return 0;
1108}
1109
1110
1111void ssp1601_dyn_reset(ssp1601_t *ssp)
1112{
1113 ssp1601_reset_local(ssp);
d274c33b 1114 ssp->ptr_rom = (unsigned int) Pico.rom;
1115 ssp->ptr_iram = (unsigned int) svp->iram_rom;
1116 ssp->ptr_dram = (unsigned int) svp->dram;
726bbb3e 1117}
1118
726bbb3e 1119void ssp1601_dyn_run(int cycles)
1120{
b9c1d012 1121 if (ssp->emu_status & SSP_WAIT_MASK) return;
1122 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1123 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1124
5d817c91 1125#ifdef DUMP_BLOCK
1126 rPC = DUMP_BLOCK >> 1;
1127#endif
726bbb3e 1128 while (cycles > 0)
1129 {
e807ac75 1130 int (*trans_entry)(void);
df143b36 1131 if (rPC < 0x800/2)
1132 {
1133 if (iram_dirty) {
1134 iram_context = get_iram_context();
892b1dd2 1135 iram_dirty--;
df143b36 1136 }
1137 if (block_table_iram[iram_context][rPC] == NULL)
1138 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 1139 trans_entry = (void *) block_table_iram[iram_context][rPC];
df143b36 1140 }
1141 else
1142 {
1143 if (block_table[rPC] == NULL)
1144 block_table[rPC] = translate_block(rPC);
5c129565 1145 trans_entry = (void *) block_table[rPC];
df143b36 1146 }
726bbb3e 1147
e807ac75 1148 //printf("enter %04x\n", rPC<<1);
1149 cycles -= trans_entry();
1150 //printf("leave %04x\n", rPC<<1);
726bbb3e 1151 }
1152// debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
1153// exit(1);
1154}
1155