svp compiler: ops completed? last ver. with interpreter built in
[picodrive.git] / Pico / carthw / svp / compiler.c
... / ...
CommitLineData
1
2#include "../../PicoInt.h"
3#include "compiler.h"
4
5static unsigned int *block_table[0x5090/2];
6static unsigned int *block_table_iram[15][0x800/2];
7static unsigned int *tcache_ptr = NULL;
8
9static int nblocks = 0;
10static int iram_context = 0;
11
12#ifndef ARM
13#define DUMP_BLOCK 0x0c9a
14unsigned int tcache[512*1024];
15void regfile_load(void){}
16void regfile_store(void){}
17#endif
18
19#define EMBED_INTERPRETER
20#define ssp1601_reset ssp1601_reset_local
21#define ssp1601_run ssp1601_run_local
22
23#define GET_PC() rPC
24#define GET_PPC_OFFS() (GET_PC()*2 - 2)
25#define SET_PC(d) { rPC = d; } /* must return to dispatcher after this */
26//#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
27//#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
28//#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
29
30#include "ssp16.c"
31#include "gen_arm.c"
32
33// -----------------------------------------------------
34
35// ld d, s
36static void op00(unsigned int op, unsigned int imm)
37{
38 unsigned int tmpv;
39 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
40 if (op == 0) return; // nop
41 if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
42 // not sure. MAME claims that only hi word is transfered.
43 read_P(); // update P
44 rA32 = rP.v;
45 }
46 else
47 {
48 tmpv = REG_READ(op & 0x0f);
49 REG_WRITE((op & 0xf0) >> 4, tmpv);
50 }
51}
52
53// ld d, (ri)
54static void op01(unsigned int op, unsigned int imm)
55{
56 unsigned int tmpv;
57 tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
58}
59
60// ld (ri), s
61static void op02(unsigned int op, unsigned int imm)
62{
63 unsigned int tmpv;
64 tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
65}
66
67// ldi d, imm
68static void op04(unsigned int op, unsigned int imm)
69{
70 REG_WRITE((op & 0xf0) >> 4, imm);
71}
72
73// ld d, ((ri))
74static void op05(unsigned int op, unsigned int imm)
75{
76 unsigned int tmpv;
77 tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
78}
79
80// ldi (ri), imm
81static void op06(unsigned int op, unsigned int imm)
82{
83 ptr1_write(op, imm);
84}
85
86// ld adr, a
87static void op07(unsigned int op, unsigned int imm)
88{
89 ssp->RAM[op & 0x1ff] = rA;
90}
91
92// ld d, ri
93static void op09(unsigned int op, unsigned int imm)
94{
95 unsigned int tmpv;
96 tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
97}
98
99// ld ri, s
100static void op0a(unsigned int op, unsigned int imm)
101{
102 rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
103}
104
105// ldi ri, simm (also op0d op0e op0f)
106static void op0c(unsigned int op, unsigned int imm)
107{
108 rIJ[(op>>8)&7] = op;
109}
110
111// call cond, addr
112static void op24(unsigned int op, unsigned int imm)
113{
114 int cond = 0;
115 do {
116 COND_CHECK
117 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
118 }
119 while (0);
120}
121
122// ld d, (a)
123static void op25(unsigned int op, unsigned int imm)
124{
125 unsigned int tmpv;
126 tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
127}
128
129// bra cond, addr
130static void op26(unsigned int op, unsigned int imm)
131{
132 do
133 {
134 int cond = 0;
135 COND_CHECK
136 if (cond) SET_PC(imm);
137 }
138 while (0);
139}
140
141// mod cond, op
142static void op48(unsigned int op, unsigned int imm)
143{
144 do
145 {
146 int cond = 0;
147 COND_CHECK
148 if (cond) {
149 switch (op & 7) {
150 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
151 case 3: rA32 <<= 1; break; // shl
152 case 6: rA32 = -(signed int)rA32; break; // neg
153 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
154 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
155 op&7, GET_PPC_OFFS());
156 }
157 UPD_ACC_ZN // ?
158 }
159 }
160 while(0);
161}
162
163// mpys?
164static void op1b(unsigned int op, unsigned int imm)
165{
166 read_P(); // update P
167 rA32 -= rP.v; // maybe only upper word?
168 UPD_ACC_ZN // there checking flags after this
169 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
170 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
171}
172
173// mpya (rj), (ri), b
174static void op4b(unsigned int op, unsigned int imm)
175{
176 read_P(); // update P
177 rA32 += rP.v; // confirmed to be 32bit
178 UPD_ACC_ZN // ?
179 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
180 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
181}
182
183// mld (rj), (ri), b
184static void op5b(unsigned int op, unsigned int imm)
185{
186 rA32 = 0;
187 rST &= 0x0fff; // ?
188 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
189 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
190}
191
192// OP a, s
193static void op10(unsigned int op, unsigned int imm)
194{
195 do
196 {
197 unsigned int tmpv;
198 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
199 }
200 while(0);
201}
202
203static void op30(unsigned int op, unsigned int imm)
204{
205 do
206 {
207 unsigned int tmpv;
208 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
209 }
210 while(0);
211}
212
213static void op40(unsigned int op, unsigned int imm)
214{
215 do
216 {
217 unsigned int tmpv;
218 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
219 }
220 while(0);
221}
222
223static void op50(unsigned int op, unsigned int imm)
224{
225 do
226 {
227 unsigned int tmpv;
228 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
229 }
230 while(0);
231}
232
233static void op60(unsigned int op, unsigned int imm)
234{
235 do
236 {
237 unsigned int tmpv;
238 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
239 }
240 while(0);
241}
242
243static void op70(unsigned int op, unsigned int imm)
244{
245 do
246 {
247 unsigned int tmpv;
248 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
249 }
250 while(0);
251}
252
253// OP a, (ri)
254static void op11(unsigned int op, unsigned int imm)
255{
256 unsigned int tmpv;
257 tmpv = ptr1_read(op); OP_SUBA(tmpv);
258}
259
260static void op31(unsigned int op, unsigned int imm)
261{
262 unsigned int tmpv;
263 tmpv = ptr1_read(op); OP_CMPA(tmpv);
264}
265
266static void op41(unsigned int op, unsigned int imm)
267{
268 unsigned int tmpv;
269 tmpv = ptr1_read(op); OP_ADDA(tmpv);
270}
271
272static void op51(unsigned int op, unsigned int imm)
273{
274 unsigned int tmpv;
275 tmpv = ptr1_read(op); OP_ANDA(tmpv);
276}
277
278static void op61(unsigned int op, unsigned int imm)
279{
280 unsigned int tmpv;
281 tmpv = ptr1_read(op); OP_ORA (tmpv);
282}
283
284static void op71(unsigned int op, unsigned int imm)
285{
286 unsigned int tmpv;
287 tmpv = ptr1_read(op); OP_EORA(tmpv);
288}
289
290// OP a, adr
291static void op03(unsigned int op, unsigned int imm)
292{
293 unsigned int tmpv;
294 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
295}
296
297static void op13(unsigned int op, unsigned int imm)
298{
299 unsigned int tmpv;
300 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
301}
302
303static void op33(unsigned int op, unsigned int imm)
304{
305 unsigned int tmpv;
306 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
307}
308
309static void op43(unsigned int op, unsigned int imm)
310{
311 unsigned int tmpv;
312 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
313}
314
315static void op53(unsigned int op, unsigned int imm)
316{
317 unsigned int tmpv;
318 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
319}
320
321static void op63(unsigned int op, unsigned int imm)
322{
323 unsigned int tmpv;
324 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
325}
326
327static void op73(unsigned int op, unsigned int imm)
328{
329 unsigned int tmpv;
330 tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
331}
332
333// OP a, imm
334static void op14(unsigned int op, unsigned int imm)
335{
336 OP_SUBA(imm);
337}
338
339static void op34(unsigned int op, unsigned int imm)
340{
341 OP_CMPA(imm);
342}
343
344static void op44(unsigned int op, unsigned int imm)
345{
346 OP_ADDA(imm);
347}
348
349static void op54(unsigned int op, unsigned int imm)
350{
351 OP_ANDA(imm);
352}
353
354static void op64(unsigned int op, unsigned int imm)
355{
356 OP_ORA (imm);
357}
358
359static void op74(unsigned int op, unsigned int imm)
360{
361 OP_EORA(imm);
362}
363
364// OP a, ((ri))
365static void op15(unsigned int op, unsigned int imm)
366{
367 unsigned int tmpv;
368 tmpv = ptr2_read(op); OP_SUBA(tmpv);
369}
370
371static void op35(unsigned int op, unsigned int imm)
372{
373 unsigned int tmpv;
374 tmpv = ptr2_read(op); OP_CMPA(tmpv);
375}
376
377static void op45(unsigned int op, unsigned int imm)
378{
379 unsigned int tmpv;
380 tmpv = ptr2_read(op); OP_ADDA(tmpv);
381}
382
383static void op55(unsigned int op, unsigned int imm)
384{
385 unsigned int tmpv;
386 tmpv = ptr2_read(op); OP_ANDA(tmpv);
387}
388
389static void op65(unsigned int op, unsigned int imm)
390{
391 unsigned int tmpv;
392 tmpv = ptr2_read(op); OP_ORA (tmpv);
393}
394
395static void op75(unsigned int op, unsigned int imm)
396{
397 unsigned int tmpv;
398 tmpv = ptr2_read(op); OP_EORA(tmpv);
399}
400
401// OP a, ri
402static void op19(unsigned int op, unsigned int imm)
403{
404 unsigned int tmpv;
405 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
406}
407
408static void op39(unsigned int op, unsigned int imm)
409{
410 unsigned int tmpv;
411 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
412}
413
414static void op49(unsigned int op, unsigned int imm)
415{
416 unsigned int tmpv;
417 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
418}
419
420static void op59(unsigned int op, unsigned int imm)
421{
422 unsigned int tmpv;
423 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
424}
425
426static void op69(unsigned int op, unsigned int imm)
427{
428 unsigned int tmpv;
429 tmpv = rIJ[IJind]; OP_ORA (tmpv);
430}
431
432static void op79(unsigned int op, unsigned int imm)
433{
434 unsigned int tmpv;
435 tmpv = rIJ[IJind]; OP_EORA(tmpv);
436}
437
438// OP simm
439static void op1c(unsigned int op, unsigned int imm)
440{
441 OP_SUBA(op & 0xff);
442}
443
444static void op3c(unsigned int op, unsigned int imm)
445{
446 OP_CMPA(op & 0xff);
447}
448
449static void op4c(unsigned int op, unsigned int imm)
450{
451 OP_ADDA(op & 0xff);
452}
453
454static void op5c(unsigned int op, unsigned int imm)
455{
456 OP_ANDA(op & 0xff);
457}
458
459static void op6c(unsigned int op, unsigned int imm)
460{
461 OP_ORA (op & 0xff);
462}
463
464static void op7c(unsigned int op, unsigned int imm)
465{
466 OP_EORA(op & 0xff);
467}
468
469typedef void (in_func)(unsigned int op, unsigned int imm);
470
471static in_func *in_funcs[0x80] =
472{
473 op00, op01, op02, op03, op04, op05, op06, op07,
474 NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
475 op10, op11, NULL, op13, op14, op15, NULL, NULL,
476 NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
477 NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
478 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
479 op30, op31, NULL, op33, op34, op35, NULL, NULL,
480 NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
481 op40, op41, NULL, op43, op44, op45, NULL, NULL,
482 op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
483 op50, op51, NULL, op53, op54, op55, NULL, NULL,
484 NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
485 op60, op61, NULL, op63, op64, op65, NULL, NULL,
486 NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
487 op70, op71, NULL, op73, op74, op75, NULL, NULL,
488 NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
489};
490
491
492static u32 ssp_pm_read(int reg)
493{
494 u32 d = 0, mode;
495
496 if (ssp->emu_status & SSP_PMC_SET)
497 {
498 ssp->pmac_read[reg] = rPMC.v;
499 ssp->emu_status &= ~SSP_PMC_SET;
500 return 0;
501 }
502
503 // just in case
504 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
505
506 mode = ssp->pmac_read[reg]>>16;
507 if ((mode & 0xfff0) == 0x0800) // ROM
508 {
509 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
510 ssp->pmac_read[reg] += 1;
511 }
512 else if ((mode & 0x47ff) == 0x0018) // DRAM
513 {
514 unsigned short *dram = (unsigned short *)svp->dram;
515 int inc = get_inc(mode);
516 d = dram[ssp->pmac_read[reg]&0xffff];
517 ssp->pmac_read[reg] += inc;
518 }
519
520 // PMC value corresponds to last PMR accessed
521 rPMC.v = ssp->pmac_read[reg];
522
523 return d;
524}
525
526static void ssp_pm_write(u32 d, int reg)
527{
528 unsigned short *dram;
529 int mode, addr;
530
531 if (ssp->emu_status & SSP_PMC_SET)
532 {
533 ssp->pmac_write[reg] = rPMC.v;
534 ssp->emu_status &= ~SSP_PMC_SET;
535 return;
536 }
537
538 // just in case
539 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
540
541 dram = (unsigned short *)svp->dram;
542 mode = ssp->pmac_write[reg]>>16;
543 addr = ssp->pmac_write[reg]&0xffff;
544 if ((mode & 0x43ff) == 0x0018) // DRAM
545 {
546 int inc = get_inc(mode);
547 if (mode & 0x0400) {
548 overwrite_write(dram[addr], d);
549 } else dram[addr] = d;
550 ssp->pmac_write[reg] += inc;
551 }
552 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
553 {
554 if (mode & 0x0400) {
555 overwrite_write(dram[addr], d);
556 } else dram[addr] = d;
557 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
558 }
559 else if ((mode & 0x47ff) == 0x001c) // IRAM
560 {
561 int inc = get_inc(mode);
562 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
563 ssp->pmac_write[reg] += inc;
564 ssp->drc.iram_dirty = 1;
565 }
566
567 rPMC.v = ssp->pmac_write[reg];
568}
569
570
571// -----------------------------------------------------
572
573// 14 IRAM blocks
574static unsigned char iram_context_map[] =
575{
576 0, 0, 0, 0, 1, 0, 0, 0, // 04
577 0, 0, 0, 0, 0, 0, 2, 0, // 0e
578 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
579 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
580 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
581 0, 0, 0, 0, 0, 0, 0, 0,
582 0, 0,11, 0, 0,12, 0, 0, // 32 35
583 13,14, 0, 0, 0, 0, 0, 0 // 38 39
584};
585
586static int get_iram_context(void)
587{
588 unsigned char *ir = (unsigned char *)svp->iram_rom;
589 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
590 val1 = iram_context_map[(val>>1)&0x3f];
591
592 if (val1 == 0) {
593 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
594 //debug_dump2file(name, svp->iram_rom, 0x800);
595 exit(1);
596 }
597// elprintf(EL_ANOMALY, "iram_context: %02i", val1);
598 return val1;
599}
600
601// -----------------------------------------------------
602
603/* regs with known values */
604static struct
605{
606 ssp_reg_t gr[8];
607 unsigned char r[8];
608 unsigned int pmac_read[5];
609 unsigned int pmac_write[5];
610 ssp_reg_t pmc;
611 unsigned int emu_status;
612} known_regs;
613
614#define KRREG_X (1 << SSP_X)
615#define KRREG_Y (1 << SSP_Y)
616#define KRREG_A (1 << SSP_A) /* AH only */
617#define KRREG_ST (1 << SSP_ST)
618#define KRREG_STACK (1 << SSP_STACK)
619#define KRREG_PC (1 << SSP_PC)
620#define KRREG_P (1 << SSP_P)
621#define KRREG_PR0 (1 << 8)
622#define KRREG_PR4 (1 << 12)
623#define KRREG_AL (1 << 16)
624#define KRREG_PMCM (1 << 18) /* only mode word of PMC */
625#define KRREG_PMC (1 << 19)
626#define KRREG_PM0R (1 << 20)
627#define KRREG_PM1R (1 << 21)
628#define KRREG_PM2R (1 << 22)
629#define KRREG_PM3R (1 << 23)
630#define KRREG_PM4R (1 << 24)
631#define KRREG_PM0W (1 << 25)
632#define KRREG_PM1W (1 << 26)
633#define KRREG_PM2W (1 << 27)
634#define KRREG_PM3W (1 << 28)
635#define KRREG_PM4W (1 << 29)
636
637/* bitfield of known register values */
638static u32 known_regb = 0;
639
640/* known vals, which need to be flushed
641 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
642 * ST means flags are being held in ARM PSR
643 * P means that it needs to be recalculated
644 */
645static u32 dirty_regb = 0;
646
647/* known values of host regs.
648 * -1 - unknown
649 * 000000-00ffff - 16bit value
650 * 100000-10ffff - base reg (r7) + 16bit val
651 * 0r0000 - means reg (low) eq gr[r].h, r != AL
652 */
653static int hostreg_r[4];
654
655static void hostreg_clear(void)
656{
657 int i;
658 for (i = 0; i < 4; i++)
659 hostreg_r[i] = -1;
660}
661
662static void hostreg_sspreg_changed(int sspreg)
663{
664 int i;
665 for (i = 0; i < 4; i++)
666 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
667}
668
669
670#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
671#define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
672
673static void tr_unhandled(void)
674{
675 FILE *f = fopen("tcache.bin", "wb");
676 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
677 fclose(f);
678 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
679 exit(1);
680}
681
682/* update P, if needed. Trashes r0 */
683static void tr_flush_dirty_P(void)
684{
685 // TODO: const regs
686 if (!(dirty_regb & KRREG_P)) return;
687 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
688 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
689 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
690 EOP_MUL(10, 0, 10); // mul r10, r0, r10
691 dirty_regb &= ~KRREG_P;
692 hostreg_r[0] = -1;
693}
694
695/* write dirty pr to host reg. Nothing is trashed */
696static void tr_flush_dirty_pr(int r)
697{
698 int ror = 0, reg;
699
700 if (!(dirty_regb & (1 << (r+8)))) return;
701
702 switch (r&3) {
703 case 0: ror = 0; break;
704 case 1: ror = 24/2; break;
705 case 2: ror = 16/2; break;
706 }
707 reg = (r < 4) ? 8 : 9;
708 EOP_BIC_IMM(reg,reg,ror,0xff);
709 if (known_regs.r[r] != 0)
710 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
711 dirty_regb &= ~(1 << (r+8));
712}
713
714/* write all dirty pr0-pr7 to host regs. Nothing is trashed */
715static void tr_flush_dirty_prs(void)
716{
717 int i, ror = 0, reg;
718 int dirty = dirty_regb >> 8;
719 /* r0-r7 */
720 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
721 {
722 if (!(dirty&1)) continue;
723 switch (i&3) {
724 case 0: ror = 0; break;
725 case 1: ror = 24/2; break;
726 case 2: ror = 16/2; break;
727 }
728 reg = (i < 4) ? 8 : 9;
729 EOP_BIC_IMM(reg,reg,ror,0xff);
730 if (known_regs.r[i] != 0)
731 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
732 }
733 dirty_regb &= ~0xff00;
734}
735
736/* write dirty pr and "forget" it. Nothing is trashed. */
737static void tr_release_pr(int r)
738{
739 tr_flush_dirty_pr(r);
740 known_regb &= ~(1 << (r+8));
741}
742
743/* fush ARM PSR to r6. Trashes r1 */
744static void tr_flush_dirty_ST(void)
745{
746 if (!(dirty_regb & KRREG_ST)) return;
747 EOP_BIC_IMM(6,6,0,0x0f);
748 EOP_MRS(1);
749 EOP_ORR_REG_LSR(6,6,1,28);
750 dirty_regb &= ~KRREG_ST;
751 hostreg_r[1] = -1;
752}
753
754/* inverse of above. Trashes r1 */
755static void tr_make_dirty_ST(void)
756{
757 if (dirty_regb & KRREG_ST) return;
758 if (known_regb & KRREG_ST) {
759 int flags = 0;
760 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
761 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
762 EOP_MSR_IMM(4/2, flags);
763 } else {
764 EOP_MOV_REG_LSL(1, 6, 28);
765 EOP_MSR_REG(1);
766 hostreg_r[1] = -1;
767 }
768 dirty_regb |= KRREG_ST;
769}
770
771/* load 16bit val into host reg r0-r3. Nothing is trashed */
772static void tr_mov16(int r, int val)
773{
774 if (hostreg_r[r] != val) {
775 emit_mov_const(A_COND_AL, r, val);
776 hostreg_r[r] = val;
777 }
778}
779
780static void tr_mov16_cond(int cond, int r, int val)
781{
782 emit_mov_const(cond, r, val);
783 hostreg_r[r] = -1;
784}
785
786/* trashes r0 */
787static void tr_flush_dirty_pmcrs(void)
788{
789 u32 i, val = (u32)-1;
790 if (!(dirty_regb & 0x3ff80000)) return;
791
792 if (dirty_regb & KRREG_PMC) {
793 val = known_regs.pmc.v;
794 emit_mov_const(A_COND_AL, 1, val);
795 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
796
797 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
798 printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
799 tr_unhandled();
800 }
801 }
802 for (i = 0; i < 5; i++)
803 {
804 if (dirty_regb & (1 << (20+i))) {
805 if (val != known_regs.pmac_read[i]) {
806 val = known_regs.pmac_read[i];
807 emit_mov_const(A_COND_AL, 1, val);
808 }
809 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
810 }
811 if (dirty_regb & (1 << (25+i))) {
812 if (val != known_regs.pmac_write[i]) {
813 val = known_regs.pmac_write[i];
814 emit_mov_const(A_COND_AL, 1, val);
815 }
816 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
817 }
818 }
819 dirty_regb &= ~0x3ff80000;
820 hostreg_r[1] = -1;
821}
822
823/* read bank word to r0 (upper bits zero). Thrashes r1. */
824static void tr_bank_read(int addr) /* word addr 0-0x1ff */
825{
826 int breg = 7;
827 if (addr > 0x7f) {
828 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
829 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
830 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
831 }
832 breg = 1;
833 }
834 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
835 hostreg_r[0] = -1;
836}
837
838/* write r0 to bank. Trashes r1. */
839static void tr_bank_write(int addr)
840{
841 int breg = 7;
842 if (addr > 0x7f) {
843 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
844 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
845 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
846 }
847 breg = 1;
848 }
849 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
850}
851
852/* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
853static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
854{
855 int modulo_shift = -1; /* unknown */
856
857 if (mod == 0) return;
858
859 if (!need_modulo || mod == 1) // +!
860 modulo_shift = 8;
861 else if (need_modulo && (known_regb & KRREG_ST)) {
862 modulo_shift = known_regs.gr[SSP_ST].h & 7;
863 if (modulo_shift == 0) modulo_shift = 8;
864 }
865
866 if (modulo_shift == -1)
867 {
868 int reg = (r < 4) ? 8 : 9;
869 tr_release_pr(r);
870 if (dirty_regb & KRREG_ST) {
871 // avoid flushing ARM flags
872 EOP_AND_IMM(1, 6, 0, 0x70);
873 EOP_SUB_IMM(1, 1, 0, 0x10);
874 EOP_AND_IMM(1, 1, 0, 0x70);
875 EOP_ADD_IMM(1, 1, 0, 0x10);
876 } else {
877 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
878 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
879 }
880 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
881 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
882 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
883 if (r&3)
884 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
885 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
886 if (mod == 2)
887 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
888 else EOP_ADD_REG2_LSL(reg,reg,3,2);
889 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
890 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
891 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
892 }
893 else if (known_regb & (1 << (r + 8)))
894 {
895 int modulo = (1 << modulo_shift) - 1;
896 if (mod == 2)
897 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
898 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
899 }
900 else
901 {
902 int reg = (r < 4) ? 8 : 9;
903 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
904 EOP_MOV_REG_ROR(reg,reg,ror);
905 // {add|sub} reg, reg, #1<<shift
906 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
907 EOP_MOV_REG_ROR(reg,reg,32-ror);
908 }
909}
910
911/* handle writes r0 to (rX). Trashes r1.
912 * fortunately we can ignore modulo increment modes for writes. */
913static void tr_rX_write(int op)
914{
915 if ((op&3) == 3)
916 {
917 int mod = (op>>2) & 3; // direct addressing
918 tr_bank_write((op & 0x100) + mod);
919 }
920 else
921 {
922 int r = (op&3) | ((op>>6)&4);
923 if (known_regb & (1 << (r + 8))) {
924 tr_bank_write((op&0x100) | known_regs.r[r]);
925 } else {
926 int reg = (r < 4) ? 8 : 9;
927 int ror = ((4 - (r&3))*8) & 0x1f;
928 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
929 if (r >= 4)
930 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
931 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
932 else EOP_ADD_REG_LSL(1,7,1,1);
933 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
934 hostreg_r[1] = -1;
935 }
936 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
937 }
938}
939
940/* read (rX) to r0. Trashes r1-r3. */
941static void tr_rX_read(int r, int mod)
942{
943 if ((r&3) == 3)
944 {
945 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
946 }
947 else
948 {
949 if (known_regb & (1 << (r + 8))) {
950 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
951 } else {
952 int reg = (r < 4) ? 8 : 9;
953 int ror = ((4 - (r&3))*8) & 0x1f;
954 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
955 if (r >= 4)
956 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
957 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
958 else EOP_ADD_REG_LSL(1,7,1,1);
959 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
960 hostreg_r[0] = hostreg_r[1] = -1;
961 }
962 tr_ptrr_mod(r, mod, 1, 1);
963 }
964}
965
966/* read ((rX)) to r0. Trashes r1,r2. */
967static void tr_rX_read2(int op)
968{
969 int r = (op&3) | ((op>>6)&4); // src
970
971 if ((r&3) == 3) {
972 tr_bank_read((op&0x100) | ((op>>2)&3));
973 } else if (known_regb & (1 << (r+8))) {
974 tr_bank_read((op&0x100) | known_regs.r[r]);
975 } else {
976 int reg = (r < 4) ? 8 : 9;
977 int ror = ((4 - (r&3))*8) & 0x1f;
978 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
979 if (r >= 4)
980 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
981 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
982 else EOP_ADD_REG_LSL(1,7,1,1);
983 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
984 }
985 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
986 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
987 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
988 if ((r&3) == 3) {
989 tr_bank_write((op&0x100) | ((op>>2)&3));
990 } else if (known_regb & (1 << (r+8))) {
991 tr_bank_write((op&0x100) | known_regs.r[r]);
992 } else {
993 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
994 hostreg_r[1] = -1;
995 }
996 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
997 hostreg_r[0] = hostreg_r[2] = -1;
998}
999
1000/* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1001static int tr_cond_check(int op)
1002{
1003 int f = (op & 0x100) >> 8;
1004 switch (op&0xf0) {
1005 case 0x00: return A_COND_AL; /* always true */
1006 case 0x50: /* Z matches f(?) bit */
1007 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1008 EOP_TST_IMM(6, 0, 4);
1009 return f ? A_COND_NE : A_COND_EQ;
1010 case 0x70: /* N matches f(?) bit */
1011 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1012 EOP_TST_IMM(6, 0, 8);
1013 return f ? A_COND_NE : A_COND_EQ;
1014 default:
1015 printf("unimplemented cond?\n");
1016 tr_unhandled();
1017 return 0;
1018 }
1019}
1020
1021static int tr_neg_cond(int cond)
1022{
1023 switch (cond) {
1024 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1025 case A_COND_EQ: return A_COND_NE;
1026 case A_COND_NE: return A_COND_EQ;
1027 case A_COND_MI: return A_COND_PL;
1028 case A_COND_PL: return A_COND_MI;
1029 default: printf("bad cond for neg\n"); exit(1);
1030 }
1031 return 0;
1032}
1033
1034static int tr_aop_ssp2arm(int op)
1035{
1036 switch (op) {
1037 case 1: return A_OP_SUB;
1038 case 3: return A_OP_CMP;
1039 case 4: return A_OP_ADD;
1040 case 5: return A_OP_AND;
1041 case 6: return A_OP_ORR;
1042 case 7: return A_OP_EOR;
1043 }
1044
1045 tr_unhandled();
1046 return 0;
1047}
1048
1049// -----------------------------------------------------
1050
1051//@ r4: XXYY
1052//@ r5: A
1053//@ r6: STACK and emu flags
1054//@ r7: SSP context
1055//@ r10: P
1056
1057// read general reg to r0. Trashes r1
1058static void tr_GR0_to_r0(int op)
1059{
1060 tr_mov16(0, 0xffff);
1061}
1062
1063static void tr_X_to_r0(int op)
1064{
1065 if (hostreg_r[0] != (SSP_X<<16)) {
1066 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
1067 hostreg_r[0] = SSP_X<<16;
1068 }
1069}
1070
1071static void tr_Y_to_r0(int op)
1072{
1073 if (hostreg_r[0] != (SSP_Y<<16)) {
1074 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1075 hostreg_r[0] = SSP_Y<<16;
1076 }
1077}
1078
1079static void tr_A_to_r0(int op)
1080{
1081 if (hostreg_r[0] != (SSP_A<<16)) {
1082 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1083 hostreg_r[0] = SSP_A<<16;
1084 }
1085}
1086
1087static void tr_ST_to_r0(int op)
1088{
1089 // VR doesn't need much accuracy here..
1090 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1091 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1092 hostreg_r[0] = -1;
1093}
1094
1095static void tr_STACK_to_r0(int op)
1096{
1097 // 448
1098 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1099 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1100 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1101 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1102 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1103 hostreg_r[0] = hostreg_r[1] = -1;
1104}
1105
1106static void tr_PC_to_r0(int op)
1107{
1108 tr_mov16(0, known_regs.gr[SSP_PC].h);
1109}
1110
1111static void tr_P_to_r0(int op)
1112{
1113 tr_flush_dirty_P();
1114 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1115 hostreg_r[0] = -1;
1116}
1117
1118static void tr_AL_to_r0(int op)
1119{
1120 if (op == 0x000f) {
1121 if (known_regb & KRREG_PMC) {
1122 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1123 } else {
1124 EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1125 EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1126 EOP_STR_IMM(0,7,0x484);
1127 }
1128 }
1129
1130 if (hostreg_r[0] != (SSP_AL<<16)) {
1131 EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
1132 hostreg_r[0] = SSP_AL<<16;
1133 }
1134}
1135
1136static void tr_PMX_to_r0(int reg)
1137{
1138 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1139 {
1140 known_regs.pmac_read[reg] = known_regs.pmc.v;
1141 known_regs.emu_status &= ~SSP_PMC_SET;
1142 known_regb |= 1 << (20+reg);
1143 dirty_regb |= 1 << (20+reg);
1144 return;
1145 }
1146
1147 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1148 {
1149 u32 pmcv = known_regs.pmac_read[reg];
1150 int mode = pmcv>>16;
1151 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1152
1153 if ((mode & 0xfff0) == 0x0800)
1154 {
1155 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1156 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1157 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1158 known_regs.pmac_read[reg] += 1;
1159 }
1160 else if ((mode & 0x47ff) == 0x0018) // DRAM
1161 {
1162 int inc = get_inc(mode);
1163 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1164 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1165 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1166 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
1167 {
1168 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1169 tr_flush_dirty_ST();
1170 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1171 EOP_TST_REG_SIMPLE(0,0);
1172 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1173 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
1174 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1175 }
1176 known_regs.pmac_read[reg] += inc;
1177 }
1178 else
1179 {
1180 tr_unhandled();
1181 }
1182 known_regs.pmc.v = known_regs.pmac_read[reg];
1183 //known_regb |= KRREG_PMC;
1184 dirty_regb |= KRREG_PMC;
1185 dirty_regb |= 1 << (20+reg);
1186 hostreg_r[0] = hostreg_r[1] = -1;
1187 return;
1188 }
1189
1190 known_regb &= ~KRREG_PMC;
1191 dirty_regb &= ~KRREG_PMC;
1192 known_regb &= ~(1 << (20+reg));
1193 dirty_regb &= ~(1 << (20+reg));
1194
1195 // call the C code to handle this
1196 tr_flush_dirty_ST();
1197 //tr_flush_dirty_pmcrs();
1198 tr_mov16(0, reg);
1199 emit_call(ssp_pm_read);
1200 hostreg_clear();
1201}
1202
1203static void tr_PM0_to_r0(int op)
1204{
1205 tr_PMX_to_r0(0);
1206}
1207
1208static void tr_PM1_to_r0(int op)
1209{
1210 tr_PMX_to_r0(1);
1211}
1212
1213static void tr_PM2_to_r0(int op)
1214{
1215 tr_PMX_to_r0(2);
1216}
1217
1218static void tr_XST_to_r0(int op)
1219{
1220 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1221 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1222}
1223
1224static void tr_PM4_to_r0(int op)
1225{
1226 tr_PMX_to_r0(4);
1227}
1228
1229static void tr_PMC_to_r0(int op)
1230{
1231 if (known_regb & KRREG_PMC)
1232 {
1233 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1234 known_regs.emu_status |= SSP_PMC_SET;
1235 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1236 // do nothing - this is handled elsewhere
1237 } else {
1238 tr_mov16(0, known_regs.pmc.l);
1239 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1240 }
1241 }
1242 else
1243 {
1244 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1245 tr_flush_dirty_ST();
1246 if (op != 0x000e)
1247 EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1248 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1249 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1250 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1251 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1252 EOP_STR_IMM(1,7,0x484);
1253 hostreg_r[0] = hostreg_r[1] = -1;
1254 }
1255}
1256
1257
1258typedef void (tr_read_func)(int op);
1259
1260static tr_read_func *tr_read_funcs[16] =
1261{
1262 tr_GR0_to_r0,
1263 tr_X_to_r0,
1264 tr_Y_to_r0,
1265 tr_A_to_r0,
1266 tr_ST_to_r0,
1267 tr_STACK_to_r0,
1268 tr_PC_to_r0,
1269 tr_P_to_r0,
1270 tr_PM0_to_r0,
1271 tr_PM1_to_r0,
1272 tr_PM2_to_r0,
1273 tr_XST_to_r0,
1274 tr_PM4_to_r0,
1275 (tr_read_func *)tr_unhandled,
1276 tr_PMC_to_r0,
1277 tr_AL_to_r0
1278};
1279
1280
1281// write r0 to general reg handlers. Trashes r1
1282#define TR_WRITE_R0_TO_REG(reg) \
1283{ \
1284 hostreg_sspreg_changed(reg); \
1285 hostreg_r[0] = (reg)<<16; \
1286 if (const_val != -1) { \
1287 known_regs.gr[reg].h = const_val; \
1288 known_regb |= 1 << (reg); \
1289 } else { \
1290 known_regb &= ~(1 << (reg)); \
1291 } \
1292}
1293
1294static void tr_r0_to_GR0(int const_val)
1295{
1296 // do nothing
1297}
1298
1299static void tr_r0_to_X(int const_val)
1300{
1301 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1302 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1303 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1304 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1305 TR_WRITE_R0_TO_REG(SSP_X);
1306}
1307
1308static void tr_r0_to_Y(int const_val)
1309{
1310 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1311 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1312 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
1313 dirty_regb |= KRREG_P;
1314 TR_WRITE_R0_TO_REG(SSP_Y);
1315}
1316
1317static void tr_r0_to_A(int const_val)
1318{
1319 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
1320 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
1321 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1322 TR_WRITE_R0_TO_REG(SSP_A);
1323}
1324
1325static void tr_r0_to_ST(int const_val)
1326{
1327 // VR doesn't need much accuracy here..
1328 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1329 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1330 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
1331 TR_WRITE_R0_TO_REG(SSP_ST);
1332 hostreg_r[1] = -1;
1333 dirty_regb &= ~KRREG_ST;
1334}
1335
1336static void tr_r0_to_STACK(int const_val)
1337{
1338 // 448
1339 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1340 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1341 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1342 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1343 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1344 hostreg_r[1] = -1;
1345}
1346
1347static void tr_r0_to_PC(int const_val)
1348{
1349 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1350 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1351 hostreg_r[1] = -1;
1352}
1353
1354static void tr_r0_to_AL(int const_val)
1355{
1356 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
1357 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1358 EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
1359 hostreg_sspreg_changed(SSP_AL);
1360 if (const_val != -1) {
1361 known_regs.gr[SSP_A].l = const_val;
1362 known_regb |= 1 << SSP_AL;
1363 } else
1364 known_regb &= ~(1 << SSP_AL);
1365}
1366
1367static void tr_r0_to_PMX(int reg)
1368{
1369 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1370 {
1371 known_regs.pmac_write[reg] = known_regs.pmc.v;
1372 known_regs.emu_status &= ~SSP_PMC_SET;
1373 known_regb |= 1 << (25+reg);
1374 dirty_regb |= 1 << (25+reg);
1375 return;
1376 }
1377
1378 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1379 {
1380 int mode, addr;
1381
1382 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1383
1384 mode = known_regs.pmac_write[reg]>>16;
1385 addr = known_regs.pmac_write[reg]&0xffff;
1386 if ((mode & 0x43ff) == 0x0018) // DRAM
1387 {
1388 int inc = get_inc(mode);
1389 if (mode & 0x0400) tr_unhandled();
1390 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1391 emit_mov_const(A_COND_AL, 2, addr<<1);
1392 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1393 known_regs.pmac_write[reg] += inc;
1394 }
1395 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1396 {
1397 if (mode & 0x0400) tr_unhandled();
1398 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1399 emit_mov_const(A_COND_AL, 2, addr<<1);
1400 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1401 known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1402 }
1403 else if ((mode & 0x47ff) == 0x001c) // IRAM
1404 {
1405 int inc = get_inc(mode);
1406 EOP_LDR_IMM(1,7,0x48c); // iram_ptr
1407 emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1408 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1409 EOP_MOV_IMM(1,0,1);
1410 EOP_STR_IMM(1,7,0x494); // iram_dirty
1411 known_regs.pmac_write[reg] += inc;
1412 }
1413 else
1414 tr_unhandled();
1415
1416 known_regs.pmc.v = known_regs.pmac_write[reg];
1417 //known_regb |= KRREG_PMC;
1418 dirty_regb |= KRREG_PMC;
1419 dirty_regb |= 1 << (25+reg);
1420 hostreg_r[1] = hostreg_r[2] = -1;
1421 return;
1422 }
1423
1424 known_regb &= ~KRREG_PMC;
1425 dirty_regb &= ~KRREG_PMC;
1426 known_regb &= ~(1 << (25+reg));
1427 dirty_regb &= ~(1 << (25+reg));
1428
1429 // call the C code to handle this
1430 tr_flush_dirty_ST();
1431 //tr_flush_dirty_pmcrs();
1432 tr_mov16(1, reg);
1433 emit_call(ssp_pm_write);
1434 hostreg_clear();
1435}
1436
1437static void tr_r0_to_PM0(int const_val)
1438{
1439 tr_r0_to_PMX(0);
1440}
1441
1442static void tr_r0_to_PM1(int const_val)
1443{
1444 tr_r0_to_PMX(1);
1445}
1446
1447static void tr_r0_to_PM2(int const_val)
1448{
1449 tr_r0_to_PMX(2);
1450}
1451
1452static void tr_r0_to_PM4(int const_val)
1453{
1454 tr_r0_to_PMX(4);
1455}
1456
1457static void tr_r0_to_PMC(int const_val)
1458{
1459 if ((known_regb & KRREG_PMC) && const_val != -1)
1460 {
1461 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1462 known_regs.emu_status |= SSP_PMC_SET;
1463 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1464 known_regs.pmc.h = const_val;
1465 } else {
1466 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1467 known_regs.pmc.l = const_val;
1468 }
1469 }
1470 else
1471 {
1472 tr_flush_dirty_ST();
1473 if (known_regb & KRREG_PMC) {
1474 emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1475 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1476 known_regb &= ~KRREG_PMC;
1477 dirty_regb &= ~KRREG_PMC;
1478 }
1479 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1480 EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
1481 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1482 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
1483 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1484 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1485 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1486 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1487 EOP_STR_IMM(1,7,0x484);
1488 hostreg_r[1] = hostreg_r[2] = -1;
1489 }
1490}
1491
1492typedef void (tr_write_func)(int const_val);
1493
1494static tr_write_func *tr_write_funcs[16] =
1495{
1496 tr_r0_to_GR0,
1497 tr_r0_to_X,
1498 tr_r0_to_Y,
1499 tr_r0_to_A,
1500 tr_r0_to_ST,
1501 tr_r0_to_STACK,
1502 tr_r0_to_PC,
1503 (tr_write_func *)tr_unhandled,
1504 tr_r0_to_PM0,
1505 tr_r0_to_PM1,
1506 tr_r0_to_PM2,
1507 (tr_write_func *)tr_unhandled,
1508 tr_r0_to_PM4,
1509 (tr_write_func *)tr_unhandled,
1510 tr_r0_to_PMC,
1511 tr_r0_to_AL
1512};
1513
1514static void tr_mac_load_XY(int op)
1515{
1516 tr_rX_read(op&3, (op>>2)&3); // X
1517 EOP_MOV_REG_LSL(4, 0, 16);
1518 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1519 EOP_ORR_REG_SIMPLE(4, 0);
1520 dirty_regb |= KRREG_P;
1521 hostreg_sspreg_changed(SSP_X);
1522 hostreg_sspreg_changed(SSP_Y);
1523 known_regb &= ~KRREG_X;
1524 known_regb &= ~KRREG_Y;
1525}
1526
1527// -----------------------------------------------------
1528
1529static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1530{
1531 u32 pmcv, tmpv;
1532 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1533
1534 // programming PMC:
1535 // ldi PMC, imm1
1536 // ldi PMC, imm2
1537 (*pc)++;
1538 pmcv = imm | (PROGRAM((*pc)++) << 16);
1539 known_regs.pmc.v = pmcv;
1540 known_regb |= KRREG_PMC;
1541 dirty_regb |= KRREG_PMC;
1542 known_regs.emu_status |= SSP_PMC_SET;
1543
1544 // check for possible reg programming
1545 tmpv = PROGRAM(*pc);
1546 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1547 {
1548 int is_write = (tmpv & 0xff8f) == 0x80;
1549 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1550 if (reg > 4) tr_unhandled();
1551 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1552 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1553 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1554 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1555 known_regs.emu_status &= ~SSP_PMC_SET;
1556 (*pc)++;
1557 return 5;
1558 }
1559
1560 tr_unhandled();
1561 return 4;
1562}
1563
1564static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1565
1566static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1567{
1568 // ldi ST, 0
1569 // ldi PM0, 0
1570 // ldi PM0, 0
1571 // ldi ST, 60h
1572 unsigned short *pp;
1573 if (op != 0x0840 || imm != 0) return 0;
1574 pp = PROGRAM_P(*pc);
1575 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1576
1577 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1578 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1579 hostreg_sspreg_changed(SSP_ST);
1580 known_regs.gr[SSP_ST].h = 0x60;
1581 known_regb |= 1 << SSP_ST;
1582 dirty_regb &= ~KRREG_ST;
1583 (*pc) += 3*2;
1584 return 4*2;
1585}
1586
1587static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1588{
1589 // @ 3DA2 and 426A
1590 // ld PMC, (r3|00)
1591 // ld (r3|00), PMC
1592 // ld -, AL
1593 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1594
1595 tr_bank_read(0);
1596 EOP_MOV_REG_LSL(0, 0, 4);
1597 EOP_ORR_REG_LSR(0, 0, 0, 16);
1598 tr_bank_write(0);
1599 (*pc) += 2;
1600 return 3;
1601}
1602
1603// -----------------------------------------------------
1604
1605static int translate_op(unsigned int op, int *pc, int imm)
1606{
1607 u32 tmpv, tmpv2, tmpv3;
1608 int ret = 0;
1609 known_regs.gr[SSP_PC].h = *pc;
1610
1611 switch (op >> 9)
1612 {
1613 // ld d, s
1614 case 0x00:
1615 if (op == 0) { ret++; break; } // nop
1616 tmpv = op & 0xf; // src
1617 tmpv2 = (op >> 4) & 0xf; // dst
1618 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1619 tr_flush_dirty_P();
1620 EOP_MOV_REG_SIMPLE(5, 10);
1621 hostreg_sspreg_changed(SSP_A);
1622 known_regb &= ~(KRREG_A|KRREG_AL);
1623 ret++; break;
1624 }
1625 tr_read_funcs[tmpv](op);
1626 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1627 if (tmpv2 == SSP_PC) ret |= 0x10000;
1628 ret++; break;
1629
1630 // ld d, (ri)
1631 case 0x01: {
1632 int r = (op&3) | ((op>>6)&4);
1633 int mod = (op>>2)&3;
1634 tmpv = (op >> 4) & 0xf; // dst
1635 ret = tr_detect_rotate(op, pc, imm);
1636 if (ret > 0) break;
1637 if (tmpv != 0)
1638 tr_rX_read(r, mod);
1639 else tr_ptrr_mod(r, mod, 1, 1);
1640 tr_write_funcs[tmpv](-1);
1641 if (tmpv == SSP_PC) ret |= 0x10000;
1642 ret++; break;
1643 }
1644
1645 // ld (ri), s
1646 case 0x02:
1647 tmpv = (op >> 4) & 0xf; // src
1648 tr_read_funcs[tmpv](op);
1649 tr_rX_write(op);
1650 ret++; break;
1651
1652 // ld a, adr
1653 case 0x03:
1654 tr_bank_read(op&0x1ff);
1655 tr_r0_to_A(-1);
1656 ret++; break;
1657
1658 // ldi d, imm
1659 case 0x04:
1660 tmpv = (op & 0xf0) >> 4; // dst
1661 ret = tr_detect_pm0_block(op, pc, imm);
1662 if (ret > 0) break;
1663 ret = tr_detect_set_pm(op, pc, imm);
1664 if (ret > 0) break;
1665 tr_mov16(0, imm);
1666 tr_write_funcs[tmpv](imm);
1667 if (tmpv == SSP_PC) ret |= 0x10000;
1668 ret += 2; break;
1669
1670 // ld d, ((ri))
1671 case 0x05:
1672 tmpv2 = (op >> 4) & 0xf; // dst
1673 tr_rX_read2(op);
1674 tr_write_funcs[tmpv2](-1);
1675 if (tmpv2 == SSP_PC) ret |= 0x10000;
1676 ret += 3; break;
1677
1678 // ldi (ri), imm
1679 case 0x06:
1680 tr_mov16(0, imm);
1681 tr_rX_write(op);
1682 ret += 2; break;
1683
1684 // ld adr, a
1685 case 0x07:
1686 tr_A_to_r0(op);
1687 tr_bank_write(op&0x1ff);
1688 ret++; break;
1689
1690 // ld d, ri
1691 case 0x09: {
1692 int r;
1693 r = (op&3) | ((op>>6)&4); // src
1694 tmpv2 = (op >> 4) & 0xf; // dst
1695 if ((r&3) == 3) tr_unhandled();
1696
1697 if (known_regb & (1 << (r+8))) {
1698 tr_mov16(0, known_regs.r[r]);
1699 tr_write_funcs[tmpv2](known_regs.r[r]);
1700 } else {
1701 int reg = (r < 4) ? 8 : 9;
1702 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1703 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1704 hostreg_r[0] = -1;
1705 tr_write_funcs[tmpv2](-1);
1706 }
1707 ret++; break;
1708 }
1709
1710 // ld ri, s
1711 case 0x0a: {
1712 int r;
1713 r = (op&3) | ((op>>6)&4); // dst
1714 tmpv = (op >> 4) & 0xf; // src
1715 if ((r&3) == 3) tr_unhandled();
1716
1717 if (known_regb & (1 << tmpv)) {
1718 known_regs.r[r] = known_regs.gr[tmpv].h;
1719 known_regb |= 1 << (r + 8);
1720 dirty_regb |= 1 << (r + 8);
1721 } else {
1722 int reg = (r < 4) ? 8 : 9;
1723 int ror = ((4 - (r&3))*8) & 0x1f;
1724 tr_read_funcs[tmpv](op);
1725 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1726 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1727 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1728 hostreg_r[0] = -1;
1729 known_regb &= ~(1 << (r+8));
1730 dirty_regb &= ~(1 << (r+8));
1731 }
1732 ret++; break;
1733 }
1734
1735 // ldi ri, simm
1736 case 0x0c ... 0x0f:
1737 tmpv = (op>>8)&7;
1738 known_regs.r[tmpv] = op;
1739 known_regb |= 1 << (tmpv + 8);
1740 dirty_regb |= 1 << (tmpv + 8);
1741 ret++; break;
1742
1743 // call cond, addr
1744 case 0x24: {
1745 u32 *jump_op = NULL;
1746 tmpv = tr_cond_check(op);
1747 if (tmpv != A_COND_AL) {
1748 jump_op = tcache_ptr;
1749 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1750 }
1751 tr_mov16(0, *pc);
1752 tr_r0_to_STACK(*pc);
1753 if (tmpv != A_COND_AL) {
1754 u32 *real_ptr = tcache_ptr;
1755 tcache_ptr = jump_op;
1756 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1757 tcache_ptr = real_ptr;
1758 }
1759 tr_mov16_cond(tmpv, 0, imm);
1760 if (tmpv != A_COND_AL) {
1761 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1762 }
1763 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1764 ret |= 0x10000;
1765 ret += 2; break;
1766 }
1767
1768 // ld d, (a)
1769 case 0x25:
1770 tmpv2 = (op >> 4) & 0xf; // dst
1771 tr_A_to_r0(op);
1772 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1773 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1774 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1775 hostreg_r[0] = hostreg_r[1] = -1;
1776 tr_write_funcs[tmpv2](-1);
1777 if (tmpv2 == SSP_PC) ret |= 0x10000;
1778 ret += 3; break;
1779
1780 // bra cond, addr
1781 case 0x26:
1782 tmpv = tr_cond_check(op);
1783 tr_mov16_cond(tmpv, 0, imm);
1784 if (tmpv != A_COND_AL) {
1785 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1786 }
1787 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1788 ret |= 0x10000;
1789 ret += 2; break;
1790
1791 // mod cond, op
1792 case 0x48: {
1793 // check for repeats of this op
1794 tmpv = 1; // count
1795 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1796 (*pc)++; tmpv++;
1797 }
1798 if ((op&0xf0) != 0) // !always
1799 tr_make_dirty_ST();
1800
1801 tmpv2 = tr_cond_check(op);
1802 switch (op & 7) {
1803 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1804 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1805 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1806 case 7: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_EOR,0,5,1,31,A_AM1_ASR,5); // eor r1, r5, r5, asr #31
1807 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1808 hostreg_r[1] = -1; break; // abs
1809 default: tr_unhandled();
1810 }
1811
1812 hostreg_sspreg_changed(SSP_A);
1813 dirty_regb |= KRREG_ST;
1814 known_regb &= ~KRREG_ST;
1815 known_regb &= ~(KRREG_A|KRREG_AL);
1816 ret += tmpv; break;
1817 }
1818
1819 // mpys?
1820 case 0x1b:
1821 tr_flush_dirty_P();
1822 tr_mac_load_XY(op);
1823 tr_make_dirty_ST();
1824 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1825 hostreg_sspreg_changed(SSP_A);
1826 known_regb &= ~(KRREG_A|KRREG_AL);
1827 dirty_regb |= KRREG_ST;
1828 ret++; break;
1829
1830 // mpya (rj), (ri), b
1831 case 0x4b:
1832 tr_flush_dirty_P();
1833 tr_mac_load_XY(op);
1834 tr_make_dirty_ST();
1835 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1836 hostreg_sspreg_changed(SSP_A);
1837 known_regb &= ~(KRREG_A|KRREG_AL);
1838 dirty_regb |= KRREG_ST;
1839 ret++; break;
1840
1841 // mld (rj), (ri), b
1842 case 0x5b:
1843 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1844 hostreg_sspreg_changed(SSP_A);
1845 known_regs.gr[SSP_A].v = 0;
1846 known_regb |= (KRREG_A|KRREG_AL);
1847 dirty_regb |= KRREG_ST;
1848 tr_mac_load_XY(op);
1849 ret++; break;
1850
1851 // OP a, s
1852 case 0x10:
1853 case 0x30:
1854 case 0x40:
1855 case 0x50:
1856 case 0x60:
1857 case 0x70:
1858 tmpv = op & 0xf; // src
1859 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1860 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1861 if (tmpv == SSP_P) {
1862 tr_flush_dirty_P();
1863 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1864 } else if (tmpv == SSP_A) {
1865 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1866 } else {
1867 tr_read_funcs[tmpv](op);
1868 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1869 }
1870 hostreg_sspreg_changed(SSP_A);
1871 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1872 dirty_regb |= KRREG_ST;
1873 ret++; break;
1874
1875 // OP a, (ri)
1876 case 0x11:
1877 case 0x31:
1878 case 0x41:
1879 case 0x51:
1880 case 0x61:
1881 case 0x71:
1882 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1883 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1884 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1885 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1886 hostreg_sspreg_changed(SSP_A);
1887 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1888 dirty_regb |= KRREG_ST;
1889 ret++; break;
1890
1891 // OP a, adr
1892 case 0x13:
1893 case 0x33:
1894 case 0x43:
1895 case 0x53:
1896 case 0x63:
1897 case 0x73:
1898 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1899 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1900 tr_bank_read(op&0x1ff);
1901 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1902 hostreg_sspreg_changed(SSP_A);
1903 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1904 dirty_regb |= KRREG_ST;
1905 ret++; break;
1906
1907 // OP a, imm
1908 case 0x14:
1909 case 0x34:
1910 case 0x44:
1911 case 0x54:
1912 case 0x64:
1913 case 0x74:
1914 tmpv = (op & 0xf0) >> 4;
1915 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1916 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1917 tr_mov16(0, imm);
1918 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1919 hostreg_sspreg_changed(SSP_A);
1920 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1921 dirty_regb |= KRREG_ST;
1922 ret += 2; break;
1923
1924 // OP a, ((ri))
1925 case 0x15:
1926 case 0x35:
1927 case 0x45:
1928 case 0x55:
1929 case 0x65:
1930 case 0x75:
1931 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1932 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1933 tr_rX_read2(op);
1934 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1935 hostreg_sspreg_changed(SSP_A);
1936 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1937 dirty_regb |= KRREG_ST;
1938 ret += 3; break;
1939
1940 // OP a, ri
1941 case 0x19:
1942 case 0x39:
1943 case 0x49:
1944 case 0x59:
1945 case 0x69:
1946 case 0x79: {
1947 int r;
1948 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1949 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1950 r = (op&3) | ((op>>6)&4); // src
1951 if ((r&3) == 3) tr_unhandled();
1952
1953 if (known_regb & (1 << (r+8))) {
1954 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1955 } else {
1956 int reg = (r < 4) ? 8 : 9;
1957 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1958 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1959 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1960 hostreg_r[0] = -1;
1961 }
1962 hostreg_sspreg_changed(SSP_A);
1963 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1964 dirty_regb |= KRREG_ST;
1965 ret++; break;
1966 }
1967
1968 // OP simm
1969 case 0x1c:
1970 case 0x3c:
1971 case 0x4c:
1972 case 0x5c:
1973 case 0x6c:
1974 case 0x7c:
1975 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1976 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1977 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
1978 hostreg_sspreg_changed(SSP_A);
1979 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1980 dirty_regb |= KRREG_ST;
1981 ret++; break;
1982 }
1983
1984 return ret;
1985}
1986
1987static void *translate_block(int pc)
1988{
1989 unsigned int op, op1, imm, ccount = 0;
1990 unsigned int *block_start;
1991 int ret, ret_prev = -1, tpc;
1992
1993 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1994 block_start = tcache_ptr;
1995 known_regb = 0;
1996 dirty_regb = KRREG_P;
1997 known_regs.emu_status = 0;
1998 hostreg_clear();
1999
2000 emit_block_prologue();
2001
2002 for (; ccount < 100;)
2003 {
2004 op = PROGRAM(pc++);
2005 op1 = op >> 9;
2006 imm = (u32)-1;
2007
2008 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2009 imm = PROGRAM(pc++); // immediate
2010 tpc = pc;
2011
2012 ret = translate_op(op, &pc, imm);
2013 if (ret <= 0)
2014 {
2015 tr_flush_dirty_prs();
2016 tr_flush_dirty_ST();
2017 tr_flush_dirty_pmcrs();
2018 known_regs.emu_status = 0;
2019
2020 emit_mov_const(A_COND_AL, 0, op);
2021
2022 // need immediate?
2023 if (imm != (u32)-1)
2024 emit_mov_const(A_COND_AL, 1, imm);
2025
2026 // dump PC
2027 emit_pc_dump(pc);
2028
2029 if (ret_prev > 0) emit_call(regfile_store);
2030 emit_call(in_funcs[op1]);
2031 emit_call(regfile_load);
2032
2033 if (in_funcs[op1] == NULL) {
2034 printf("NULL func! op=%08x (%02x)\n", op, op1);
2035 exit(1);
2036 }
2037 ccount++;
2038 hostreg_clear();
2039 dirty_regb |= KRREG_P;
2040 known_regb = 0;
2041 }
2042 else
2043 {
2044 ccount += ret & 0xffff;
2045 if (ret & 0x10000) break;
2046 }
2047
2048 ret_prev = ret;
2049 }
2050
2051 if (ccount >= 100)
2052 emit_pc_dump(pc);
2053
2054 tr_flush_dirty_prs();
2055 tr_flush_dirty_ST();
2056 tr_flush_dirty_pmcrs();
2057 emit_block_epilogue(ccount + 1);
2058 *tcache_ptr++ = 0xffffffff; // end of block
2059
2060 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2061 printf("tcache overflow!\n");
2062 fflush(stdout);
2063 exit(1);
2064 }
2065
2066 // stats
2067 nblocks++;
2068 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2069
2070#ifdef DUMP_BLOCK
2071 {
2072 FILE *f = fopen("tcache.bin", "wb");
2073 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2074 fclose(f);
2075 }
2076 exit(0);
2077#endif
2078
2079 handle_caches();
2080
2081 return block_start;
2082}
2083
2084
2085
2086// -----------------------------------------------------
2087
2088int ssp1601_dyn_startup(void)
2089{
2090 memset(tcache, 0, TCACHE_SIZE);
2091 memset(block_table, 0, sizeof(block_table));
2092 memset(block_table_iram, 0, sizeof(block_table_iram));
2093 tcache_ptr = tcache;
2094 *tcache_ptr++ = 0xffffffff;
2095
2096#ifdef ARM
2097 // hle'd blocks
2098 block_table[0x400] = (void *) ssp_hle_800;
2099#endif
2100
2101// TODO: rm
2102{
2103static unsigned short dummy = 0;
2104PC = &dummy;
2105}
2106 return 0;
2107}
2108
2109
2110void ssp1601_dyn_reset(ssp1601_t *ssp)
2111{
2112 ssp1601_reset_local(ssp);
2113 ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2114 ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2115 ssp->drc.ptr_dram = (unsigned int) svp->dram;
2116 ssp->drc.iram_dirty = 0;
2117}
2118
2119void ssp1601_dyn_run(int cycles)
2120{
2121 if (ssp->emu_status & SSP_WAIT_MASK) return;
2122
2123#ifdef DUMP_BLOCK
2124 rPC = DUMP_BLOCK >> 1;
2125#endif
2126 while (cycles > 0)
2127 {
2128 int (*trans_entry)(void);
2129 if (rPC < 0x800/2)
2130 {
2131 if (ssp->drc.iram_dirty) {
2132 iram_context = get_iram_context();
2133 ssp->drc.iram_dirty--;
2134 }
2135 if (block_table_iram[iram_context][rPC] == NULL)
2136 block_table_iram[iram_context][rPC] = translate_block(rPC);
2137 trans_entry = (void *) block_table_iram[iram_context][rPC];
2138 }
2139 else
2140 {
2141 if (block_table[rPC] == NULL)
2142 block_table[rPC] = translate_block(rPC);
2143 trans_entry = (void *) block_table[rPC];
2144 }
2145
2146 cycles -= trans_entry();
2147 }
2148}
2149