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