svp compiler: ops completed? last ver. with interpreter built in
[picodrive.git] / Pico / carthw / svp / compiler.c
CommitLineData
726bbb3e 1
2#include "../../PicoInt.h"
e807ac75 3#include "compiler.h"
726bbb3e 4
892b1dd2 5static unsigned int *block_table[0x5090/2];
6static unsigned int *block_table_iram[15][0x800/2];
892b1dd2 7static unsigned int *tcache_ptr = NULL;
726bbb3e 8
726bbb3e 9static int nblocks = 0;
df143b36 10static int iram_context = 0;
726bbb3e 11
5d817c91 12#ifndef ARM
0b5e8296 13#define DUMP_BLOCK 0x0c9a
5d817c91 14unsigned int tcache[512*1024];
15void regfile_load(void){}
16void regfile_store(void){}
17#endif
18
726bbb3e 19#define EMBED_INTERPRETER
20#define ssp1601_reset ssp1601_reset_local
21#define ssp1601_run ssp1601_run_local
22
5c129565 23#define GET_PC() rPC
24#define GET_PPC_OFFS() (GET_PC()*2 - 2)
d274c33b 25#define SET_PC(d) { rPC = d; } /* must return to dispatcher after this */
726bbb3e 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"
5c129565 31#include "gen_arm.c"
726bbb3e 32
33// -----------------------------------------------------
34
892b1dd2 35// ld d, s
36static void op00(unsigned int op, unsigned int imm)
37{
38 unsigned int tmpv;
259ed0ea 39 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
892b1dd2 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
259ed0ea 117 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
892b1dd2 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
259ed0ea 136 if (cond) SET_PC(imm);
892b1dd2 137 }
259ed0ea 138 while (0);
892b1dd2 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
d5276282 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;
d5276282 500 return 0;
501 }
502
d5276282 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;
e122fae6 564 ssp->drc.iram_dirty = 1;
d5276282 565 }
566
567 rPMC.v = ssp->pmac_write[reg];
568}
569
570
892b1dd2 571// -----------------------------------------------------
572
0b5e8296 573// 14 IRAM blocks
df143b36 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
df143b36 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];
df143b36 590 val1 = iram_context_map[(val>>1)&0x3f];
591
5c129565 592 if (val1 == 0) {
df143b36 593 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
df143b36 594 //debug_dump2file(name, svp->iram_rom, 0x800);
595 exit(1);
596 }
5c129565 597// elprintf(EL_ANOMALY, "iram_context: %02i", val1);
df143b36 598 return val1;
599}
600
5d817c91 601// -----------------------------------------------------
0b5e8296 602
5d817c91 603/* regs with known values */
604static struct
605{
606 ssp_reg_t gr[8];
607 unsigned char r[8];
ede7220f 608 unsigned int pmac_read[5];
609 unsigned int pmac_write[5];
d5276282 610 ssp_reg_t pmc;
ede7220f 611 unsigned int emu_status;
bad5731d 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)
d5276282 624#define KRREG_PMCM (1 << 18) /* only mode word of PMC */
625#define KRREG_PMC (1 << 19)
ede7220f 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)
bad5731d 636
637/* bitfield of known register values */
638static u32 known_regb = 0;
639
640/* known vals, which need to be flushed
d5276282 641 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
bad5731d 642 * ST means flags are being held in ARM PSR
89fea1e9 643 * P means that it needs to be recalculated
bad5731d 644 */
645static u32 dirty_regb = 0;
5d817c91 646
647/* known values of host regs.
d274c33b 648 * -1 - unknown
649 * 000000-00ffff - 16bit value
650 * 100000-10ffff - base reg (r7) + 16bit val
6e39239f 651 * 0r0000 - means reg (low) eq gr[r].h, r != AL
5d817c91 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
6e39239f 662static void hostreg_sspreg_changed(int sspreg)
5d817c91 663{
664 int i;
665 for (i = 0; i < 4; i++)
6e39239f 666 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
5d817c91 667}
668
726bbb3e 669
ede7220f 670#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
671#define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
726bbb3e 672
6e39239f 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
0e4d7ba5 682/* update P, if needed. Trashes r0 */
d274c33b 683static void tr_flush_dirty_P(void)
684{
685 // TODO: const regs
bad5731d 686 if (!(dirty_regb & KRREG_P)) return;
d274c33b 687 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
0e4d7ba5 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
bad5731d 691 dirty_regb &= ~KRREG_P;
0e4d7ba5 692 hostreg_r[0] = -1;
d274c33b 693}
694
89fea1e9 695/* write dirty pr to host reg. Nothing is trashed */
696static void tr_flush_dirty_pr(int r)
697{
698 int ror = 0, reg;
6e39239f 699
89fea1e9 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)
5d817c91 716{
717 int i, ror = 0, reg;
bad5731d 718 int dirty = dirty_regb >> 8;
5d817c91 719 /* r0-r7 */
bad5731d 720 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
5d817c91 721 {
bad5731d 722 if (!(dirty&1)) continue;
5d817c91 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);
bad5731d 730 if (known_regs.r[i] != 0)
731 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
5d817c91 732 }
bad5731d 733 dirty_regb &= ~0xff00;
734}
735
89fea1e9 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
6e39239f 743/* fush ARM PSR to r6. Trashes r1 */
bad5731d 744static void tr_flush_dirty_ST(void)
745{
746 if (!(dirty_regb & KRREG_ST)) return;
747 EOP_BIC_IMM(6,6,0,0x0f);
6e39239f 748 EOP_MRS(1);
749 EOP_ORR_REG_LSR(6,6,1,28);
bad5731d 750 dirty_regb &= ~KRREG_ST;
6e39239f 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;
bad5731d 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);
a6fb500b 783 hostreg_r[r] = -1;
5d817c91 784}
785
ede7220f 786/* trashes r0 */
787static void tr_flush_dirty_pmcrs(void)
788{
789 u32 i, val = (u32)-1;
d5276282 790 if (!(dirty_regb & 0x3ff80000)) return;
ede7220f 791
d5276282 792 if (dirty_regb & KRREG_PMC) {
793 val = known_regs.pmc.v;
e122fae6 794 emit_mov_const(A_COND_AL, 1, val);
795 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
ede7220f 796
d5276282 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 }
ede7220f 801 }
802 for (i = 0; i < 5; i++)
803 {
d5276282 804 if (dirty_regb & (1 << (20+i))) {
ede7220f 805 if (val != known_regs.pmac_read[i]) {
806 val = known_regs.pmac_read[i];
e122fae6 807 emit_mov_const(A_COND_AL, 1, val);
ede7220f 808 }
e122fae6 809 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
ede7220f 810 }
d5276282 811 if (dirty_regb & (1 << (25+i))) {
ede7220f 812 if (val != known_regs.pmac_write[i]) {
813 val = known_regs.pmac_write[i];
e122fae6 814 emit_mov_const(A_COND_AL, 1, val);
ede7220f 815 }
e122fae6 816 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
ede7220f 817 }
818 }
d5276282 819 dirty_regb &= ~0x3ff80000;
e122fae6 820 hostreg_r[1] = -1;
ede7220f 821}
822
0e4d7ba5 823/* read bank word to r0 (upper bits zero). Thrashes r1. */
5d817c91 824static void tr_bank_read(int addr) /* word addr 0-0x1ff */
825{
bad5731d 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);
5d817c91 831 }
bad5731d 832 breg = 1;
5d817c91 833 }
bad5731d 834 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
5d817c91 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) {
d274c33b 843 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 844 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 845 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 846 }
847 breg = 1;
848 }
b9c1d012 849 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 850}
851
89fea1e9 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)
5d817c91 854{
a6fb500b 855 int modulo_shift = -1; /* unknown */
5d817c91 856
857 if (mod == 0) return;
858
859 if (!need_modulo || mod == 1) // +!
860 modulo_shift = 8;
bad5731d 861 else if (need_modulo && (known_regb & KRREG_ST)) {
862 modulo_shift = known_regs.gr[SSP_ST].h & 7;
5d817c91 863 if (modulo_shift == 0) modulo_shift = 8;
864 }
865
89fea1e9 866 if (modulo_shift == -1)
867 {
a6fb500b 868 int reg = (r < 4) ? 8 : 9;
89fea1e9 869 tr_release_pr(r);
0e4d7ba5 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 }
89fea1e9 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;
a6fb500b 892 }
893 else if (known_regb & (1 << (r + 8)))
894 {
895 int modulo = (1 << modulo_shift) - 1;
5d817c91 896 if (mod == 2)
89fea1e9 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);
a6fb500b 899 }
900 else
901 {
5d817c91 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
89fea1e9 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));
5d817c91 907 EOP_MOV_REG_ROR(reg,reg,32-ror);
908 }
909}
910
bad5731d 911/* handle writes r0 to (rX). Trashes r1.
912 * fortunately we can ignore modulo increment modes for writes. */
0e4d7ba5 913static void tr_rX_write(int op)
bad5731d 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 }
89fea1e9 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))) {
6e39239f 950 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
89fea1e9 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]
0e4d7ba5 960 hostreg_r[0] = hostreg_r[1] = -1;
89fea1e9 961 }
962 tr_ptrr_mod(r, mod, 1, 1);
bad5731d 963 }
964}
965
0e4d7ba5 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}
89fea1e9 999
bad5731d 1000/* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1001static int tr_cond_check(int op)
1002{
6e39239f 1003 int f = (op & 0x100) >> 8;
bad5731d 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");
6e39239f 1016 tr_unhandled();
bad5731d 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
ede7220f 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
b9c1d012 1051//@ r4: XXYY
1052//@ r5: A
1053//@ r6: STACK and emu flags
1054//@ r7: SSP context
1055//@ r10: P
1056
bad5731d 1057// read general reg to r0. Trashes r1
d5276282 1058static void tr_GR0_to_r0(int op)
d274c33b 1059{
1060 tr_mov16(0, 0xffff);
1061}
1062
d5276282 1063static void tr_X_to_r0(int op)
d274c33b 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
d5276282 1071static void tr_Y_to_r0(int op)
d274c33b 1072{
d274c33b 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
d5276282 1079static void tr_A_to_r0(int op)
d274c33b 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
d5276282 1087static void tr_ST_to_r0(int op)
d274c33b 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
d5276282 1095static void tr_STACK_to_r0(int op)
d274c33b 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
d5276282 1106static void tr_PC_to_r0(int op)
d274c33b 1107{
bad5731d 1108 tr_mov16(0, known_regs.gr[SSP_PC].h);
d274c33b 1109}
1110
d5276282 1111static void tr_P_to_r0(int op)
d274c33b 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}
d5276282 1117
1118static void tr_AL_to_r0(int op)
ede7220f 1119{
d5276282 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 }
ede7220f 1134}
ede7220f 1135
d5276282 1136static void tr_PMX_to_r0(int reg)
ede7220f 1137{
ede7220f 1138 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1139 {
d5276282 1140 known_regs.pmac_read[reg] = known_regs.pmc.v;
ede7220f 1141 known_regs.emu_status &= ~SSP_PMC_SET;
0336d643 1142 known_regb |= 1 << (20+reg);
d5276282 1143 dirty_regb |= 1 << (20+reg);
1144 return;
ede7220f 1145 }
1146
d5276282 1147 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
ede7220f 1148 {
d5276282 1149 u32 pmcv = known_regs.pmac_read[reg];
1150 int mode = pmcv>>16;
1151 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1152
ede7220f 1153 if ((mode & 0xfff0) == 0x0800)
1154 {
ede7220f 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]
d5276282 1158 known_regs.pmac_read[reg] += 1;
ede7220f 1159 }
1160 else if ((mode & 0x47ff) == 0x0018) // DRAM
1161 {
1162 int inc = get_inc(mode);
ede7220f 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]
d5276282 1166 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
ede7220f 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);
d5276282 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
ede7220f 1174 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1175 }
d5276282 1176 known_regs.pmac_read[reg] += inc;
ede7220f 1177 }
1178 else
1179 {
1180 tr_unhandled();
1181 }
d5276282 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 }
ede7220f 1189
d5276282 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;
ede7220f 1254 }
ede7220f 1255}
1256
d274c33b 1257
d5276282 1258typedef void (tr_read_func)(int op);
d274c33b 1259
d5276282 1260static tr_read_func *tr_read_funcs[16] =
d274c33b 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,
d5276282 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
d274c33b 1278};
1279
1280
b9c1d012 1281// write r0 to general reg handlers. Trashes r1
6e39239f 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 } \
b9c1d012 1292}
1293
6e39239f 1294static void tr_r0_to_GR0(int const_val)
b9c1d012 1295{
1296 // do nothing
1297}
1298
6e39239f 1299static void tr_r0_to_X(int const_val)
b9c1d012 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
6e39239f 1304 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1305 TR_WRITE_R0_TO_REG(SSP_X);
b9c1d012 1306}
1307
6e39239f 1308static void tr_r0_to_Y(int const_val)
b9c1d012 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
bad5731d 1313 dirty_regb |= KRREG_P;
6e39239f 1314 TR_WRITE_R0_TO_REG(SSP_Y);
b9c1d012 1315}
1316
6e39239f 1317static void tr_r0_to_A(int const_val)
b9c1d012 1318{
1319 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
d274c33b 1320 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
b9c1d012 1321 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
6e39239f 1322 TR_WRITE_R0_TO_REG(SSP_A);
b9c1d012 1323}
1324
6e39239f 1325static void tr_r0_to_ST(int const_val)
b9c1d012 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
6e39239f 1331 TR_WRITE_R0_TO_REG(SSP_ST);
b9c1d012 1332 hostreg_r[1] = -1;
6e39239f 1333 dirty_regb &= ~KRREG_ST;
b9c1d012 1334}
1335
6e39239f 1336static void tr_r0_to_STACK(int const_val)
b9c1d012 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
d274c33b 1341 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
b9c1d012 1342 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
d274c33b 1343 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
b9c1d012 1344 hostreg_r[1] = -1;
1345}
1346
6e39239f 1347static void tr_r0_to_PC(int const_val)
b9c1d012 1348{
1349 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
d274c33b 1350 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
b9c1d012 1351 hostreg_r[1] = -1;
1352}
1353
d5276282 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{
d5276282 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 }
0b5e8296 1377
d5276282 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]
e122fae6 1409 EOP_MOV_IMM(1,0,1);
1410 EOP_STR_IMM(1,7,0x494); // iram_dirty
d5276282 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;
e122fae6 1421 return;
d5276282 1422 }
1423
1424 known_regb &= ~KRREG_PMC;
1425 dirty_regb &= ~KRREG_PMC;
1426 known_regb &= ~(1 << (25+reg));
1427 dirty_regb &= ~(1 << (25+reg));
d5276282 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
6e39239f 1492typedef void (tr_write_func)(int const_val);
b9c1d012 1493
d5276282 1494static tr_write_func *tr_write_funcs[16] =
b9c1d012 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,
d5276282 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
b9c1d012 1512};
1513
0e4d7ba5 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
ede7220f 1527// -----------------------------------------------------
1528
ede7220f 1529static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
0e4d7ba5 1530{
ede7220f 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);
d5276282 1539 known_regs.pmc.v = pmcv;
ede7220f 1540 known_regb |= KRREG_PMC;
d5276282 1541 dirty_regb |= KRREG_PMC;
ede7220f 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();
d5276282 1551 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
ede7220f 1552 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1553 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
d5276282 1554 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
ede7220f 1555 known_regs.emu_status &= ~SSP_PMC_SET;
1556 (*pc)++;
1557 return 5;
0e4d7ba5 1558 }
1559
d5276282 1560 tr_unhandled();
ede7220f 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;
0e4d7ba5 1585}
5d817c91 1586
d5276282 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
ede7220f 1603// -----------------------------------------------------
1604
5d817c91 1605static int translate_op(unsigned int op, int *pc, int imm)
1606{
0e4d7ba5 1607 u32 tmpv, tmpv2, tmpv3;
5d817c91 1608 int ret = 0;
bad5731d 1609 known_regs.gr[SSP_PC].h = *pc;
5d817c91 1610
e807ac75 1611 switch (op >> 9)
1612 {
1613 // ld d, s
f48f5e3b 1614 case 0x00:
5d817c91 1615 if (op == 0) { ret++; break; } // nop
d274c33b 1616 tmpv = op & 0xf; // src
1617 tmpv2 = (op >> 4) & 0xf; // dst
d274c33b 1618 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1619 tr_flush_dirty_P();
1620 EOP_MOV_REG_SIMPLE(5, 10);
d5276282 1621 hostreg_sspreg_changed(SSP_A);
bad5731d 1622 known_regb &= ~(KRREG_A|KRREG_AL);
d274c33b 1623 ret++; break;
1624 }
d5276282 1625 tr_read_funcs[tmpv](op);
6e39239f 1626 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
ede7220f 1627 if (tmpv2 == SSP_PC) ret |= 0x10000;
bad5731d 1628 ret++; break;
1629
1630 // ld d, (ri)
89fea1e9 1631 case 0x01: {
89fea1e9 1632 int r = (op&3) | ((op>>6)&4);
1633 int mod = (op>>2)&3;
1634 tmpv = (op >> 4) & 0xf; // dst
d5276282 1635 ret = tr_detect_rotate(op, pc, imm);
1636 if (ret > 0) break;
89fea1e9 1637 if (tmpv != 0)
1638 tr_rX_read(r, mod);
1639 else tr_ptrr_mod(r, mod, 1, 1);
6e39239f 1640 tr_write_funcs[tmpv](-1);
ede7220f 1641 if (tmpv == SSP_PC) ret |= 0x10000;
89fea1e9 1642 ret++; break;
1643 }
bad5731d 1644
1645 // ld (ri), s
1646 case 0x02:
1647 tmpv = (op >> 4) & 0xf; // src
d5276282 1648 tr_read_funcs[tmpv](op);
0e4d7ba5 1649 tr_rX_write(op);
d274c33b 1650 ret++; break;
f48f5e3b 1651
1652 // ld a, adr
1653 case 0x03:
5d817c91 1654 tr_bank_read(op&0x1ff);
6e39239f 1655 tr_r0_to_A(-1);
5d817c91 1656 ret++; break;
1657
b9c1d012 1658 // ldi d, imm
1659 case 0x04:
ede7220f 1660 tmpv = (op & 0xf0) >> 4; // dst
1661 ret = tr_detect_pm0_block(op, pc, imm);
1662 if (ret > 0) break;
ede7220f 1663 ret = tr_detect_set_pm(op, pc, imm);
1664 if (ret > 0) break;
0b5e8296 1665 tr_mov16(0, imm);
1666 tr_write_funcs[tmpv](imm);
ede7220f 1667 if (tmpv == SSP_PC) ret |= 0x10000;
0b5e8296 1668 ret += 2; break;
b9c1d012 1669
bad5731d 1670 // ld d, ((ri))
0e4d7ba5 1671 case 0x05:
bad5731d 1672 tmpv2 = (op >> 4) & 0xf; // dst
0e4d7ba5 1673 tr_rX_read2(op);
6e39239f 1674 tr_write_funcs[tmpv2](-1);
ede7220f 1675 if (tmpv2 == SSP_PC) ret |= 0x10000;
0e4d7ba5 1676 ret += 3; break;
b9c1d012 1677
5d817c91 1678 // ldi (ri), imm
1679 case 0x06:
5d817c91 1680 tr_mov16(0, imm);
0e4d7ba5 1681 tr_rX_write(op);
a6fb500b 1682 ret += 2; break;
f48f5e3b 1683
1684 // ld adr, a
1685 case 0x07:
d5276282 1686 tr_A_to_r0(op);
5d817c91 1687 tr_bank_write(op&0x1ff);
1688 ret++; break;
1689
d274c33b 1690 // ld d, ri
1691 case 0x09: {
bad5731d 1692 int r;
d274c33b 1693 r = (op&3) | ((op>>6)&4); // src
bad5731d 1694 tmpv2 = (op >> 4) & 0xf; // dst
bad5731d 1695 if ((r&3) == 3) tr_unhandled();
d274c33b 1696
bad5731d 1697 if (known_regb & (1 << (r+8))) {
1698 tr_mov16(0, known_regs.r[r]);
6e39239f 1699 tr_write_funcs[tmpv2](known_regs.r[r]);
d274c33b 1700 } else {
bad5731d 1701 int reg = (r < 4) ? 8 : 9;
d274c33b 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;
6e39239f 1705 tr_write_funcs[tmpv2](-1);
d274c33b 1706 }
d274c33b 1707 ret++; break;
1708 }
1709
bad5731d 1710 // ld ri, s
1711 case 0x0a: {
1712 int r;
1713 r = (op&3) | ((op>>6)&4); // dst
1714 tmpv = (op >> 4) & 0xf; // src
bad5731d 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;
d5276282 1724 tr_read_funcs[tmpv](op);
bad5731d 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
5d817c91 1735 // ldi ri, simm
1736 case 0x0c ... 0x0f:
1737 tmpv = (op>>8)&7;
bad5731d 1738 known_regs.r[tmpv] = op;
1739 known_regb |= 1 << (tmpv + 8);
5d817c91 1740 dirty_regb |= 1 << (tmpv + 8);
1741 ret++; break;
bad5731d 1742
a6fb500b 1743 // call cond, addr
6e39239f 1744 case 0x24: {
1745 u32 *jump_op = NULL;
a6fb500b 1746 tmpv = tr_cond_check(op);
6e39239f 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 }
a6fb500b 1759 tr_mov16_cond(tmpv, 0, imm);
1760 if (tmpv != A_COND_AL) {
1761 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1762 }
6e39239f 1763 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
ede7220f 1764 ret |= 0x10000;
a6fb500b 1765 ret += 2; break;
6e39239f 1766 }
a6fb500b 1767
bad5731d 1768 // ld d, (a)
1769 case 0x25:
bad5731d 1770 tmpv2 = (op >> 4) & 0xf; // dst
d5276282 1771 tr_A_to_r0(op);
bad5731d 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;
6e39239f 1776 tr_write_funcs[tmpv2](-1);
ede7220f 1777 if (tmpv2 == SSP_PC) ret |= 0x10000;
a6fb500b 1778 ret += 3; break;
bad5731d 1779
1780 // bra cond, addr
a6fb500b 1781 case 0x26:
bad5731d 1782 tmpv = tr_cond_check(op);
1783 tr_mov16_cond(tmpv, 0, imm);
1784 if (tmpv != A_COND_AL) {
bad5731d 1785 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1786 }
6e39239f 1787 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
ede7220f 1788 ret |= 0x10000;
a6fb500b 1789 ret += 2; break;
bad5731d 1790
89fea1e9 1791 // mod cond, op
89fea1e9 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 }
6e39239f 1798 if ((op&0xf0) != 0) // !always
1799 tr_make_dirty_ST();
1800
89fea1e9 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
6e39239f 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
89fea1e9 1808 hostreg_r[1] = -1; break; // abs
1809 default: tr_unhandled();
1810 }
6e39239f 1811
1812 hostreg_sspreg_changed(SSP_A);
1813 dirty_regb |= KRREG_ST;
1814 known_regb &= ~KRREG_ST;
1815 known_regb &= ~(KRREG_A|KRREG_AL);
89fea1e9 1816 ret += tmpv; break;
1817 }
0e4d7ba5 1818
bad5731d 1819 // mpys?
1820 case 0x1b:
0e4d7ba5 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;
bad5731d 1829
1830 // mpya (rj), (ri), b
1831 case 0x4b:
0e4d7ba5 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;
bad5731d 1840
1841 // mld (rj), (ri), b
1842 case 0x5b:
0e4d7ba5 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;
bad5731d 1846 known_regb |= (KRREG_A|KRREG_AL);
0e4d7ba5 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;
0e4d7ba5 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 {
d5276282 1867 tr_read_funcs[tmpv](op);
0e4d7ba5 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;
bad5731d 1981 ret++; break;
e807ac75 1982 }
1983
5d817c91 1984 return ret;
e807ac75 1985}
1986
df143b36 1987static void *translate_block(int pc)
726bbb3e 1988{
e807ac75 1989 unsigned int op, op1, imm, ccount = 0;
5c129565 1990 unsigned int *block_start;
ede7220f 1991 int ret, ret_prev = -1, tpc;
5c129565 1992
259ed0ea 1993 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 1994 block_start = tcache_ptr;
bad5731d 1995 known_regb = 0;
1996 dirty_regb = KRREG_P;
d5276282 1997 known_regs.emu_status = 0;
5d817c91 1998 hostreg_clear();
5c129565 1999
2000 emit_block_prologue();
726bbb3e 2001
e807ac75 2002 for (; ccount < 100;)
726bbb3e 2003 {
2004 op = PROGRAM(pc++);
2005 op1 = op >> 9;
e807ac75 2006 imm = (u32)-1;
5c129565 2007
e807ac75 2008 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2009 imm = PROGRAM(pc++); // immediate
ede7220f 2010 tpc = pc;
5c129565 2011
5d817c91 2012 ret = translate_op(op, &pc, imm);
e807ac75 2013 if (ret <= 0)
2014 {
89fea1e9 2015 tr_flush_dirty_prs();
2016 tr_flush_dirty_ST();
ede7220f 2017 tr_flush_dirty_pmcrs();
d5276282 2018 known_regs.emu_status = 0;
5d817c91 2019
bad5731d 2020 emit_mov_const(A_COND_AL, 0, op);
5c129565 2021
e807ac75 2022 // need immediate?
2023 if (imm != (u32)-1)
bad5731d 2024 emit_mov_const(A_COND_AL, 1, imm);
5c129565 2025
e807ac75 2026 // dump PC
2027 emit_pc_dump(pc);
5c129565 2028
d274c33b 2029 if (ret_prev > 0) emit_call(regfile_store);
2030 emit_call(in_funcs[op1]);
2031 emit_call(regfile_load);
e807ac75 2032
2033 if (in_funcs[op1] == NULL) {
2034 printf("NULL func! op=%08x (%02x)\n", op, op1);
2035 exit(1);
2036 }
2037 ccount++;
5d817c91 2038 hostreg_clear();
bad5731d 2039 dirty_regb |= KRREG_P;
2040 known_regb = 0;
892b1dd2 2041 }
e807ac75 2042 else
ede7220f 2043 {
2044 ccount += ret & 0xffff;
2045 if (ret & 0x10000) break;
726bbb3e 2046 }
ede7220f 2047
d274c33b 2048 ret_prev = ret;
726bbb3e 2049 }
5c129565 2050
0b5e8296 2051 if (ccount >= 100)
2052 emit_pc_dump(pc);
2053
89fea1e9 2054 tr_flush_dirty_prs();
2055 tr_flush_dirty_ST();
ede7220f 2056 tr_flush_dirty_pmcrs();
e807ac75 2057 emit_block_epilogue(ccount + 1);
5c129565 2058 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 2059
892b1dd2 2060 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 2061 printf("tcache overflow!\n");
2062 fflush(stdout);
2063 exit(1);
2064 }
2065
2066 // stats
2067 nblocks++;
892b1dd2 2068 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
df143b36 2069
5d817c91 2070#ifdef DUMP_BLOCK
5c129565 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
259ed0ea 2078
2079 handle_caches();
2080
5c129565 2081 return block_start;
726bbb3e 2082}
2083
2084
2085
2086// -----------------------------------------------------
2087
e807ac75 2088int ssp1601_dyn_startup(void)
726bbb3e 2089{
e807ac75 2090 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 2091 memset(block_table, 0, sizeof(block_table));
df143b36 2092 memset(block_table_iram, 0, sizeof(block_table_iram));
e807ac75 2093 tcache_ptr = tcache;
5c129565 2094 *tcache_ptr++ = 0xffffffff;
726bbb3e 2095
d5276282 2096#ifdef ARM
2097 // hle'd blocks
2098 block_table[0x400] = (void *) ssp_hle_800;
2099#endif
2100
6e39239f 2101// TODO: rm
2102{
2103static unsigned short dummy = 0;
2104PC = &dummy;
2105}
726bbb3e 2106 return 0;
2107}
2108
2109
2110void ssp1601_dyn_reset(ssp1601_t *ssp)
2111{
2112 ssp1601_reset_local(ssp);
e122fae6 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;
726bbb3e 2117}
2118
726bbb3e 2119void ssp1601_dyn_run(int cycles)
2120{
b9c1d012 2121 if (ssp->emu_status & SSP_WAIT_MASK) return;
b9c1d012 2122
5d817c91 2123#ifdef DUMP_BLOCK
2124 rPC = DUMP_BLOCK >> 1;
2125#endif
726bbb3e 2126 while (cycles > 0)
2127 {
e807ac75 2128 int (*trans_entry)(void);
df143b36 2129 if (rPC < 0x800/2)
2130 {
e122fae6 2131 if (ssp->drc.iram_dirty) {
df143b36 2132 iram_context = get_iram_context();
e122fae6 2133 ssp->drc.iram_dirty--;
df143b36 2134 }
2135 if (block_table_iram[iram_context][rPC] == NULL)
2136 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 2137 trans_entry = (void *) block_table_iram[iram_context][rPC];
df143b36 2138 }
2139 else
2140 {
2141 if (block_table[rPC] == NULL)
2142 block_table[rPC] = translate_block(rPC);
5c129565 2143 trans_entry = (void *) block_table[rPC];
df143b36 2144 }
726bbb3e 2145
e807ac75 2146 cycles -= trans_entry();
726bbb3e 2147 }
726bbb3e 2148}
2149