|
|
1.1 root 1: /*****************************************************************************/
2: /* Generator - Sega Genesis emulation - (c) James Ponder 1997-1998 */
3: /*****************************************************************************/
4: /* */
5: /* compile-arm.c */
6: /* */
7: /*****************************************************************************/
8:
9: #include <stdio.h>
10: #include <stdlib.h>
11:
12: #include <sys/swis.h>
13: #include <sys/os.h>
14:
15: #include <generator.h>
16: #include <cpu68k.h>
17: #include <mem68k.h>
18:
19: #define MAXBLOCKSIZE 10240
20: #define true 1
21: #define false 0
22:
23: /* static global variables */
24:
25: static uint8 *curpos;
26: static sint32 regstate[6]; /* 0 = unused, 1 = used, 2 = updated */
27: static sint32 regnum[6]; /* register number or -1 */
28: static sint32 regtimer[6]; /* instructions since used */
29:
30: /* forward references */
31:
32: inline uint8 *compile_w(uint32 i)
33: {
34: *(uint32 *)curpos = i;
35: curpos+= 4;
36: return curpos;
37: }
38:
39: /*** compile_initregs - set all registers to unused ***/
40:
41: void compile_initregs(void)
42: {
43: int i;
44:
45: for (i = 1; i < 6; i++) {
46: regstate[i] = 0;
47: regnum[i] = -1;
48: regtimer[i] = 0;
49: }
50: }
51:
52: /*** compile_getreg - given a 68000 register or -1 return an ARM register ***/
53:
54: int compile_getreg(int reg)
55: {
56: int i;
57: int free = -1;
58: int reg_last = -1;
59: int reg_lasttime = -1;
60:
61: /* check for an ARM register already holding the 68000 register or a free
62: ARM register if we can't find it */
63:
64: for (i = 1; i < 6; i++) {
65: if (reg != -1 && regstate[i] && regnum[i] == reg) {
66: regtimer[i] = 0;
67: return i;
68: }
69: if (!regstate[i]) {
70: free = i;
71: }
72: }
73: if (free == -1) {
74: /* no free registers, find a register not holding a specific 68000
75: register if pos - if we can't find one then use the oldest 68000
76: register cached even if it was used this instruction */
77:
78: for (i = 1; i < 6; i++) {
79: if (regtimer[i] && regnum[i] == -1) {
80: free = i;
81: } else {
82: if (regtimer[i] >= reg_lasttime) {
83: /* we always prefer higher registers */
84: reg_last = i;
85: reg_lasttime = regtimer[i];
86: }
87: }
88: }
89: if (free == -1) {
90: free = reg_last;
91: if (free == -1) {
92: fprintf(stderr, "free: %d\n", free);
93: fprintf(stderr, "reg_last: %d\n", reg_last);
94: fprintf(stderr, "reg_lasttime: %d\n", reg_lasttime);
95: fprintf(stderr, "5 state: %d\n", regstate[5]);
96: fprintf(stderr, "5 num: %d\n", regnum[5]);
97: fprintf(stderr, "5 timer: %d\n", regtimer[5]);
98: compile_w(0);
99: compile_w((uint32)(-1));
100: compile_finalregs();
101: fprintf(stderr, "5 state: %d\n", regstate[5]);
102: fprintf(stderr, "5 num: %d\n", regnum[5]);
103: fprintf(stderr, "5 timer: %d\n", regtimer[5]);
104: fprintf(stderr, "Insufficient registers\n");
105: exit(1);
106: }
107: if (regstate[reg_last] == 2) {
108: /* STR r(reg_last),[r8,#x] */
109: compile_w(0xE5880000 | (regnum[reg_last]*4) | reg_last<<12);
110: }
111: }
112: }
113: regstate[free] = 1;
114: regnum[free] = reg;
115: regtimer[free] = 0;
116: if (reg != -1) {
117: compile_w(0xE5980000 | (reg*4) | free<<12); /* LDR rfree,[r8,#x] */
118: }
119: return free;
120: }
121:
122: /*** compile_findreg - given a 68000 register return an ARM register ***/
123:
124: int compile_findreg(int reg)
125: {
126: int i;
127:
128: for (i = 1; i < 6; i++) {
129: if (regstate[i] && regnum[i] == reg) {
130: return i;
131: }
132: }
133: return -1;
134: }
135:
136: /*** compile_updatereg - we have changed a register ***/
137:
138: void compile_updatereg(int reg)
139: {
140: if (!regstate[reg]) {
141: fprintf(stderr, "Compiler error - updatereg %d\n", reg);
142: exit(1);
143: }
144: regstate[reg] = 2;
145: }
146:
147: /*** compile_inctimer - update timers on registers ***/
148:
149: void compile_inctimer(void) {
150: int i;
151:
152: for (i = 1; i < 6; i++) {
153: if (regstate[i]) {
154: if (regnum[i] == -1)
155: regstate[i] = 0;
156: else
157: regtimer[i]++;
158: }
159: }
160: }
161:
162: /*** compile_finalregs - write back all changed registers ***/
163:
164: void compile_finalregs(void) {
165: int i;
166:
167: for (i = 1; i < 6; i++) {
168: if (regstate[i] == 2 && regnum[i] != -1) {
169: compile_w(0xE5880000 | (regnum[i]*4) | i<<12); /* STR ri,[r8,#x] */
170: }
171: regstate[i] = 0;
172: regnum[i] = -1;
173: regtimer[i] = 0;
174: }
175: }
176:
177: void compile_ea(t_iib *iib, t_ipc *ipc, t_type type, int update, int *reg)
178: {
179: t_datatype datatype = type ? iib->dtype : iib->stype;
180: int reg68;
181: int a, b, c, pos;
182:
183: /* compile EA to register(s) regea/regval */
184:
185: switch(datatype) {
186: case dt_Dreg:
187: case dt_Areg:
188: *reg = -1;
189: break;
190: case dt_Aind:
191: reg68 = 8 + ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7);
192: a = compile_getreg(reg68);
193: b = compile_getreg(-1); /* effective address */
194: compile_w(0xE1A00000 | b<<12 | a); /* MOV rb,ra */
195: *reg = b;
196: break;
197: case dt_Ainc:
198: reg68 = 8 + ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7);
199: a = compile_getreg(reg68); /* 68000 register */
200: if (update) {
201: b = compile_getreg(-1); /* effective address */
202: regnum[a] = -1;
203: regnum[b] = reg68; /* swap */
204: /* ADD rb,ra,#size */
205: compile_w(0xE2800000 | 1<<(iib->size-1) | a<<16 | b<<12);
206: compile_updatereg(b);
207: }
208: *reg = a;
209: break;
210: case dt_Adec:
211: reg68 = 8 + ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7);
212: a = compile_getreg(reg68); /* 68000 register */
213: if (update) {
214: /* SUB ra,ra,#size */
215: compile_w(0xE2400000 | 1<<(iib->size-1) | a<<16 | a<<12);
216: compile_updatereg(a);
217: }
218: *reg = a;
219: break;
220: case dt_Adis:
221: reg68 = 8 + ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7);
222: a = compile_getreg(reg68); /* 68000 register */
223: b = compile_getreg(-1); /* effective address */
224: pos = (uint32)(type ? &ipc->dst : &ipc->src) - (uint32)ipc;
225: /* LDR rb,[r6,#pos] ADD rb,rb,ra */
226: compile_w(0xE5960000 | pos | b<<12);
227: compile_w(0xE0800000 | b<<16 | b<<12 | a);
228: *reg = b;
229: break;
230: case dt_Aidx:
231: reg68 = 8 + ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7);
232: b = compile_getreg(-1); /* effective address */
233: c = compile_getreg(((type ? ipc->dst : ipc->src)>>28) & 15); /* idx reg */
234: pos = (uint32)(type ? &ipc->dst : &ipc->src) - (uint32)ipc;
235: /* LDR rb,[r6,#pos] MOV rb,rb,LSL#8 MOV rb,rb,ASR#8 */
236: compile_w(0xE5960000 | pos | b<<12);
237: compile_w(0xE1A00400 | b<<12 | b);
238: compile_w(0xE1A00440 | b<<12 | b);
239: if ((ipc->src>>27) & 1) {
240: /* ADD rb,rb,rc */
241: compile_w(0xE0800000 | b<<16 | b<<12 | c);
242: } else {
243: /* MOV r14,rc,LSL#16 MOV r14,r14,ASR#16 ADD rb,rb,r14 */
244: compile_w(0xE1A0E800 | c);
245: compile_w(0xE1A0E84E);
246: compile_w(0xE080000E | b<<16 | b<<12);
247: }
248: a = compile_getreg(reg68); /* 68000 register */
249: /* ADD rb,rb,ra */
250: compile_w(0xE0800000 | b<<16 | b<<12 | a);
251: *reg = b;
252: break;
253: case dt_AbsW:
254: case dt_AbsL:
255: case dt_Pdis:
256: a = compile_getreg(-1); /* effective address */
257: pos = (uint32)(type ? &ipc->dst : &ipc->src) - (uint32)ipc;
258: /* LDR ra,[r6,#pos] */
259: compile_w(0xE5960000 | pos | a<<12);
260: *reg = a;
261: break;
262: case dt_Pidx:
263: b = compile_getreg(-1); /* effective address */
264: c = compile_getreg(((type ? ipc->dst : ipc->src)>>28) & 15); /* idx reg */
265: pos = (uint32)(type ? &ipc->dst : &ipc->src) - (uint32)ipc;
266: /* LDR rb,[r6,#pos] MOV rb,rb,LSL#8 MOV rb,rb,ASL#8 */
267: compile_w(0xE5960000 | pos | b<<12);
268: compile_w(0xE1A00400 | b<<12 | b);
269: compile_w(0xE1A00440 | b<<12 | b);
270: if ((ipc->src>>27) & 1) {
271: /* ADD rb,rb,rc */
272: compile_w(0xE0800000 | b<<16 | b<<12 | c);
273: } else {
274: /* MOV r14,rc,LSL#16 MOV r14,r14,ASR#16 ADD rb,rb,r14 */
275: compile_w(0xE1A0E800 | c);
276: compile_w(0xE1A0E84E);
277: compile_w(0xE080000E | b<<16 | b<<12);
278: }
279: *reg = b;
280: break;
281: case dt_ImmB:
282: case dt_ImmW:
283: case dt_ImmL:
284: case dt_ImmS:
285: case dt_Imm3:
286: case dt_Imm4:
287: case dt_Imm8:
288: case dt_Imm8s:
289: *reg = -1;
290: break;
291: default:
292: fprintf(stderr, "Invalid datatype %d\n", datatype);
293: exit(1);
294: }
295: }
296:
297: void compile_eaval(t_iib *iib, t_ipc *ipc, t_type type, int update,
298: int eareg, int *eaval)
299: {
300: t_datatype datatype = type ? iib->dtype : iib->stype;
301: int reg68;
302: int a, b, pos;
303:
304: /* compile EA value */
305:
306: switch(datatype) {
307: case dt_Dreg:
308: case dt_Areg:
309: reg68 = ((datatype == dt_Areg ? 8 : 0) +
310: ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7));
311: a = compile_getreg(reg68);
312: b = compile_getreg(-1);
313: switch(iib->size) {
314: case sz_byte:
315: compile_w(0xE20000FF | b<<12 | a<<16); /* AND rb,ra,#&FF */
316: break;
317: case sz_word:
318: compile_w(0xE1A00800 | b<<12 | a); /* MOV rb,ra,LSL#16 */
319: compile_w(0xE1A00820 | b<<12 | b); /* MOV rb,rb,LSR#16 */
320: break;
321: case sz_long:
322: compile_w(0xE1A00000 | b<<12 | a); /* MOV rb,ra */
323: break;
324: default:
325: fprintf(stderr, "Invalid size %d\n", iib->size);
326: exit(1);
327: }
328: *eaval = b;
329: break;
330: case dt_Aind:
331: case dt_Ainc:
332: case dt_Adec:
333: case dt_Adis:
334: case dt_Aidx:
335: case dt_AbsW:
336: case dt_AbsL:
337: case dt_Pdis:
338: case dt_Pidx:
339: a = compile_getreg(-1);
340: compile_w(0xE92D100E); /* STMFD r13!,{r1-r3,r12} */
341: compile_w(0xE3C004FF | eareg<<16); /* BIC r0,eareg,#&FF000000 */
342: compile_w(0xE1A03620); /* MOV r3,r0,LSR#12 */
343: compile_w(0xE59F2004); /* LDR r2,[PC,#4] */
344: compile_w(0xE28FE004); /* ADD r14,PC,#4 */
345: compile_w(0xE792F103); /* LDR PC,[r2,r3,LSL#2]; */
346: /* EQUD <array address> */
347: switch (iib->size) {
348: case sz_byte:
349: compile_w((uint32)mem68k_fetch_byte);
350: break;
351: case sz_word:
352: compile_w((uint32)mem68k_fetch_word);
353: break;
354: case sz_long:
355: compile_w((uint32)mem68k_fetch_long);
356: break;
357: default:
358: fprintf(stderr, "Invalid size %d\n", iib->size);
359: exit(1);
360: }
361: compile_w(0xE8BD100E); /* LDMFD r13!,{r1-r3,r12} */
362: compile_w(0xE1A00000 | a<<12); /* MOV ra, r0 */
363: *eaval = a;
364: break;
365: case dt_ImmB:
366: a = compile_getreg(-1);
367: /* MOV eaval,#data */
368: compile_w(0xE3A00000 | (type ? ipc->dst : ipc->src) | a<<12);
369: *eaval = a;
370: break;
371: case dt_ImmW:
372: case dt_ImmL:
373: case dt_Imm3: /* I want optimising */
374: case dt_Imm4:
375: case dt_Imm8:
376: case dt_Imm8s:
377: a = compile_getreg(-1);
378: pos = (uint32)(type ? &ipc->dst : &ipc->src) - (uint32)ipc;
379: /* LDR eaval,[r6,#pos] */
380: compile_w(0xE5960000 | pos | a<<12);
381: *eaval = a;
382: break;
383: case dt_ImmS:
384: a = compile_getreg(-1);
385: /* MOV a,#val */
386: compile_w(0xE3A00000 | iib->immvalue | a<<12);
387: *eaval = a;
388: break;
389: default:
390: fprintf(stderr, "Invalid datatype %d\n", datatype);
391: exit(1);
392: }
393: }
394:
395: void compile_eastore(t_iib *iib, t_ipc *ipc, t_type type, int eareg,
396: int eaval)
397: {
398: t_datatype datatype = type ? iib->dtype : iib->stype;
399: int reg68;
400: int a, b, pos;
401:
402: /* store EA value */
403:
404: switch(datatype) {
405: case dt_Dreg:
406: case dt_Areg:
407: reg68 = ((datatype == dt_Areg ? 8 : 0) +
408: ((ipc->opcode >> (type ? iib->dbitpos : iib->sbitpos)) & 7));
409: a = compile_findreg(reg68);
410: if (a == eaval) {
411: fprintf(stderr, "Compiler error - eastore\n");
412: exit(1);
413: }
414: switch(iib->size) {
415: case sz_byte:
416: if (a == -1)
417: a = compile_getreg(reg68);
418: compile_w(0xE3C000FF | a<<16 | a<<12); /* BIC ra,ra,#&FF */
419: compile_w(0xE1800000 | a<<16 | a<<12 | eaval); /* ORR ra,ra,eaval */
420: compile_updatereg(a);
421: break;
422: case sz_word:
423: if (a == -1)
424: a = compile_getreg(reg68);
425: compile_w(0xE1A00820 | a<<12 | a); /* MOV ra,ra,LSR#16 */
426: /* ORR ra,eaval,ra,LSL#16 */
427: compile_w(0xE1800800 | eaval<<16 | a<<12 | a);
428: compile_updatereg(a);
429: break;
430: case sz_long:
431: if (a != -1) {
432: /* the 68000 reg is in an ARM register */
433: regnum[a] = -1;
434: regnum[eaval] = reg68;
435: regstate[eaval] = 2; /* needs writing back */
436: } else {
437: /* the 68000 reg is not in an ARM reg and we're writing all 32
438: bits so we can just name the ARM reg as the 68000 reg */
439: regnum[eaval] = reg68;
440: regstate[eaval] = 2; /* needs writing back */
441: }
442: break;
443: default:
444: fprintf(stderr, "Invalid size %d\n", iib->size);
445: exit(1);
446: }
447: break;
448: case dt_Aind:
449: case dt_Ainc:
450: case dt_Adec:
451: case dt_Adis:
452: case dt_Aidx:
453: case dt_AbsW:
454: case dt_AbsL:
455: case dt_Pdis:
456: case dt_Pidx:
457: compile_w(0xE92D100E); /* STMFD r13!,{r1-r3,r12} */
458: compile_w(0xE3C004FF | eareg<<16); /* BIC r0,eareg,#&FF000000 */
459: compile_w(0xE1A01000 | eaval); /* MOV r1,eaval */
460: compile_w(0xE1A03620); /* MOV r3,r0,LSR#12 */
461: compile_w(0xE59F2004); /* LDR r2,[PC,#4] */
462: compile_w(0xE28FE004); /* ADD r14,PC,#4 */
463: compile_w(0xE792F103); /* LDR PC,[r2,r3,LSL#2]; */
464: /* EQUD <array address> */
465: switch (iib->size) {
466: case sz_byte:
467: compile_w((uint32)mem68k_store_byte);
468: break;
469: case sz_word:
470: compile_w((uint32)mem68k_store_word);
471: break;
472: case sz_long:
473: compile_w((uint32)mem68k_store_long);
474: break;
475: default:
476: fprintf(stderr, "Invalid size %d\n", iib->size);
477: exit(1);
478: }
479: compile_w(0xE8BD100E); /* LDMFD r13!,{r1-r3,r12} */
480: break;
481: case dt_ImmB:
482: case dt_ImmW:
483: case dt_ImmL:
484: case dt_Imm3: /* I want optimising */
485: case dt_Imm4:
486: case dt_Imm8:
487: case dt_Imm8s:
488: case dt_ImmS:
489: default:
490: fprintf(stderr, "Invalid datatype %d\n", datatype);
491: exit(1);
492: }
493: }
494:
495: void compile_clrflag_v(t_iib *iib)
496: {
497: compile_w(0xE3C99000 | SR_VFLAG); /* BIC r9,r9,#SR_VFLAG */
498: }
499:
500: void compile_clrflag_c(t_iib *iib)
501: {
502: compile_w(0xE3C99000 | SR_CFLAG); /* BIC r9,r9,#SR_CFLAG */
503: }
504:
505: void compile_stdflag_n(t_iib *iib, int reg)
506: {
507: switch(iib->size) {
508: case sz_byte:
509: compile_w(0xE3100080 | reg<<16); /* TST reg,#1<<7 */
510: break;
511: case sz_word:
512: compile_w(0xE3100902 | reg<<16); /* TST reg,#1<<15 */
513: break;
514: case sz_long:
515: compile_w(0xE3100102 | reg<<16); /* TST reg,#1<<31 */
516: break;
517: default:
518: fprintf(stderr, "Invalid size %d\n", iib->size);
519: exit(1);
520: }
521: compile_w(0x13899000 | SR_NFLAG); /* ORRNE r9,r9,#SR_NFLAG */
522: compile_w(0x03C99000 | SR_NFLAG); /* BICEQ r9,r9,#SR_NFLAG */
523: }
524:
525: void compile_stdflag_z(t_iib *iib, int reg)
526: {
527: switch(iib->size) {
528: case sz_byte:
529: compile_w(0xE1B0EC00 | reg); /* MOVS r14,r1,LSL#24 */
530: break;
531: case sz_word:
532: compile_w(0xE1B0E800 | reg); /* MOVS r14,r1,LSL#16 */
533: break;
534: case sz_long:
535: compile_w(0xE1B00000 | reg<<12 | reg); /* MOVS r1,r1 */
536: break;
537: default:
538: fprintf(stderr, "Invalid size %d\n", iib->size);
539: exit(1);
540: }
541: compile_w(0x03899000 | SR_ZFLAG); /* ORREQ r9,r9,#SR_ZFLAG */
542: compile_w(0x13C99000 | SR_ZFLAG); /* BICNE r9,r9,#SR_ZFLAG */
543: }
544:
545: /*
546: * R0-R5 = work registers
547: * R6 = IPC
548: * R7 = PC
549: * R8-> registers
550: * R9 = SR
551: */
552:
553: char *compile_make(t_ipclist *list)
554: {
555: int instrs = 0;
556: uint8 *block = malloc(MAXBLOCKSIZE);
557: t_ipc *ipc = (t_ipc *)(list+1);
558: t_iib *iib;
559: int len;
560: uint8 *stmia, *p;
561: uint32 r[10];
562: int srcreg, dstreg, srcval, dstval;
563: static int blockno = 1;
564: static char tmp[256];
565: FILE *file;
566: int normal;
567:
568: *(uint32 *)0x7004 = (uint32)block;
569: *(uint32 *)0x7008 = (uint32)list->pc;
570:
571: if (!block) {
572: fprintf(stderr, "Out of memory!\n");
573: exit(1);
574: }
575: curpos = block;
576:
577: compile_w(0xE92D4070); /* STMDB r13!,{r4-r6,r14} */
578: compile_w(0xE1A06000); /* MOV r6,r0 */
579:
580: compile_initregs();
581:
582: while(*(int *)ipc) {
583: if ((curpos - block) > MAXBLOCKSIZE-1024) {
584: fprintf(stderr, "Block too short\n");
585: exit(1);
586: }
587: instrs++;
588: iib = cpu68k_iibtable[ipc->opcode];
589:
590: normal = 1;
591:
592: switch(iib->mnemonic) {
593: case i_MOVE:
594: if ((iib->stype == dt_Dreg || iib->stype == dt_Areg) &&
595: (iib->dtype == dt_Dreg || iib->dtype == dt_Areg)) {
596: compile_ea(iib, ipc, tp_src, true, &srcreg);
597: compile_eaval(iib, ipc, tp_src, true, srcreg, &srcval);
598: if (srcreg != -1)
599: regtimer[srcreg]++;
600: compile_ea(iib, ipc, tp_dst, true, &dstreg);
601: compile_eastore(iib, ipc, tp_dst, dstreg, srcval);
602: if (ipc->set & IIB_FLAG_V)
603: compile_clrflag_v(iib);
604: if (ipc->set & IIB_FLAG_C)
605: compile_clrflag_c(iib);
606: if (ipc->set & IIB_FLAG_N)
607: compile_stdflag_n(iib, srcval);
608: if (ipc->set & IIB_FLAG_Z)
609: compile_stdflag_z(iib, srcval);
610: compile_w(0xE2877000 | 2*iib->wordlen); /* ADD r7,r7,#wordlen */
611: normal = 0;
612: }
613: break;
614: default:
615: break;
616: }
617: if (normal) {
618: compile_finalregs();
619: compile_w(0xE1A00006); /* MOV r0,r6 */
620: /* BL ipc->function */
621: compile_w(0xEB000000 + ( ((((uint32)ipc->function -
622: (uint32)curpos)>>2)-2) & 0xFFFFFF));
623: }
624: ipc++;
625: if (*(int *)ipc) {
626: compile_w(0xE2866000 + sizeof(t_ipc)); /* ADD r6,r6,#sizeof(t_ipc) */
627: compile_inctimer();
628: }
629: }
630: compile_finalregs();
631: compile_w(0xE8FD8070); /* LDMIA r13!,{r4-r6,PC}^ */
632: compile_w(list->pc);
633: p = realloc(block, curpos - block);
634: if (p != block) {
635: fprintf(stderr, "realloc moved block!\n");
636: exit(1);
637: }
638: *(uint32 *)0x7000 = (uint32)block;
639:
640: /*
641: sprintf(tmp, "b/%02x/blk%d", blockno/77, blockno++ % 77);
642: file = fopen(tmp, "w");
643: fwrite(block, 1, curpos - block, file);
644: fclose(file);
645: */
646:
647: r[0] = (uint32)1;
648: r[1] = (uint32)block;
649: r[2] = (uint32)(curpos-4);
650: os_swi(0x20000 | OS_SynchroniseCodeAreas, r);
651:
652: return block;
653: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.