|
|
1.1 root 1:
2: #include <assert.h>
3: #include <stdio.h>
4: #include <stdlib.h>
5: #include <string.h>
6: #include <ctype.h>
7: #include <stdarg.h>
8: #include "dict.h"
9: #include "as68k.h"
10: #include "output.h"
11:
12: static op_t pending;
13: static enum M68K_OPS next_op_type;
14: static char *pending_labels, *cur_labels;
15: static int cur_bitpos;
16: /* last instruction was a jsr/bsr, so must create an entry
17: * in the computed jump table for return point (this instr) */
18: static int return_target;
19:
20: #define LABBUF_LEN 32768
21:
22: /* enable bounds checking and debug info in the generated turd */
23: #define GEN_DEBUG
24: //#define DUMP_LOADS_OF_CRAP
25:
26: /* which flags an M68K_OP thingy may set */
27: #define fZ (1<<0)
28: #define fNVC (1<<1)
29: #define fX (1<<2)
30: #define fNZVCX (fZ | fNVC | fX)
31: #define fNZVC (fZ | fNVC)
32: #define fNVCX (fX | fNVC)
33: #define _fSafe 0
34: /* _fSafe are ones i haven't got round to doing yet. */
35:
36: /* does the flag need to be set? if the next instruction will
37: * set the flag then no. */
38: #define ifZ if(!(sets_flags[next_op_type] & fZ))
39: #define ifNVC if(!(sets_flags[next_op_type] & fNVC))
40: #define ifZNVC if((!(sets_flags[next_op_type] & fZ)) || (!(sets_flags[next_op_type] & fNVC)))
41: #define ifNVCX if((!(sets_flags[next_op_type] & fNVCX)))
42: #define ifX if(!(sets_flags[next_op_type] & fX))
43:
44: /* XXX ONLY SET X FLAG FOR INSTRUCTIONS THAT OVERWRITE
45: * THE X FLAG __WITHOUT__ USING IT */
46:
47: static int sets_flags[OP_MAX+1] = {
48: _fSafe, /* OP_NONE */
49: 0, // OP_JMP
50: fZ, // OP_BCHG
51: fZ, // OP_BCLR
52: fZ, // OP_BSET
53: fZ, // OP_BTST
54: fNZVC, // OP_MULS
55: fNZVC, // OP_MULU,
56: fNZVC, // OP_AND
57: fNZVC, // OP_OR
58: fNZVC, // OP_XOR
59: fNZVC, // OP_NOT
60: fNZVC, // OP_NEGX
61: fNZVC, // OP_NEG
62: fNZVC, // OP_DIVU
63: fNZVC, // OP_DIVS
64: fNZVC, // OP_ASL,
65: fNZVCX, // OP_LSL
66: fNZVC, // OP_ROXR
67: fNZVC, // OP_ROXL
68: fNZVC, // OP_ROL
69: fNZVC, // OP_ROR
70: fNZVC, // OP_ASR
71: fNZVC, // OP_LSR,
72: 0, // OP_MOVEM
73: fNZVC, // OP_SUBX
74: fNZVC, // OP_ADDX
75: fNZVCX, // OP_ADD
76: fNZVC, // OP_CMPA
77: fNZVC, // OP_CMP
78: fNZVCX, // OP_SUB,
79: _fSafe, // OP_ADDA
80: _fSafe, // OP_SUBA
81: fNZVC, // OP_SWAP
82: _fSafe, // OP_JSR
83: 0, // OP_BCC
84: 0, // OP_DBCC
85: fNZVC, // OP_CLR,
86: 0, // OP_EXG
87: fNZVC, // OP_EXT
88: 0, // OP_RTE
89: 0, // OP_RTS
90: 0, // OP_ILLEGAL
91: 0, // OP_HCALL
92: 0, // OP_LINK,
93: 0, // OP_UNLK
94: fNZVC, // OP_MOVE
95: _fSafe, // OP_MOVEA
96: fNZVC, // OP_TST
97: 0, // OP_PEA
98: 0, // OP_LEA
99: 0, // OP_SCC
100: _fSafe, // OP_MAX.....
101: };
102:
103: FILE *asm_out;
104:
105: static void output_op (op_t *op, op_t *next);
106: static void init_regalloc ();
107: static void xflush_all ();
108:
109: /* raw output */
110: static void rout (const char *str)
111: {
112: fputs (str, asm_out);
113: }
114:
115: /* formatted output */
116: static void xout (const char *format, ...)
117: {
118: va_list argptr;
119:
120: va_start (argptr, format);
121: vfprintf (asm_out, format, argptr);
122: va_end (argptr);
123: }
124: static void xln (const char *format, ...)
125: {
126: va_list argptr;
127:
128: fputc ('\t', asm_out);
129: va_start (argptr, format);
130: vfprintf (asm_out, format, argptr);
131: va_end (argptr);
132: fputc ('\n', asm_out);
133: }
134:
135: static int regpos (int num)
136: {
137: assert ((num >=0) && (num < 16));
138: return -64 + 4*num;
139: }
140:
141: #ifdef GEN_DEBUG
142: static void set_line (int num)
143: {
144: char buf[256];
145:
146: snprintf (buf, sizeof (buf), " movl $%d, line_no\n", num);
147: strcat (cur_labels, buf);
148: }
149: #endif
150:
151: static int pending_flush, cur_flush;
152:
153: void i386_label (const char *lab)
154: {
155: char buf[256];
156:
157: /* lines that might be jumped to must have a consistent
158: * register state, so flush registers to memory before
159: * these lines. */
160: cur_flush = 1;
161:
162: snprintf (buf, sizeof (buf), "__N%s:\n", lab);
163: strcat (cur_labels, buf);
164:
165: add_fixup (0, C_ADDR, lab);
166: }
167:
168: void i386_addr_label (int labelled)
169: {
170: char buf[256];
171:
172: if (labelled) {
173: cur_flush = 1;
174: }
175:
176: if (labelled || return_target) {
177: snprintf (buf, sizeof (buf), "__l%x", get_bitpos ());
178: add_fixup (get_bitpos (), C_ADDR, buf);
179:
180: snprintf (buf, sizeof (buf), "__l%x:\n", get_bitpos ());
181: strcat (cur_labels, buf);
182: } else {
183: #ifdef GEN_DEBUG
184: snprintf (buf, sizeof (buf), "/* 0x%x */\n", get_bitpos ());
185: strcat (cur_labels, buf);
186: #endif
187: }
188:
189: cur_bitpos = get_bitpos ();
190:
191: #ifdef GEN_DEBUG
192: set_line (line_no);
193:
194: #ifdef DUMP_LOADS_OF_CRAP
195: strcat (cur_labels, " call DumpRegsChanged\n");
196: #endif /* DUMP_LOADS_OF_CRAP */
197: #endif /* GEN_DEBUG */
198: }
199:
200: #ifdef WIN32
201: void winsym (const char *sym)
202: {
203: xout ("#define %s _%s\n", sym, sym);
204: }
205: #endif /* WIN32 */
206:
207: void i386_begin (const char *src_filename, const char *bin_filename)
208: {
209: char buf[128];
210: snprintf (buf, sizeof (buf), ".%s.S", src_filename);
211: if ((asm_out = fopen (buf, "w"))==NULL) {
212: fprintf (stderr, "Error: Cannot open %s for writing.\n", buf);
213: exit (-1);
214: }
215:
216: init_regalloc ();
217:
218: pending_labels = NULL;
219: cur_labels = calloc (LABBUF_LEN, 1);
220:
221: xout ("#define MEM_SIZE 0x110000\n");
222: xout ("#define PROC_STATE 64\n");
223: xout ("#define MemBase STData+PROC_STATE\n\n");
224:
225: xln (".data");
226: /* memory size + registers */
227: xln (".comm STData,MEM_SIZE+PROC_STATE");
228: xln (".comm X,4");
229: xln (".comm N,4");
230: xln (".comm Z,4");
231: xln (".comm V,4");
232: xln (".comm C,4");
233: /* register backing store for during exception handling */
234: xln (".comm bX,4");
235: xln (".comm bN,4");
236: xln (".comm bZ,4");
237: xln (".comm bV,4");
238: xln (".comm bC,4");
239: /* exception return address */
240: xln (".comm rdest,4");
241: xln (".comm exceptions_pending_mask,4");
242: xln (".comm exceptions_pending_nums,32");
243: xln (".comm exception_handlers,4*32");
244: xln (".comm line_no,4");
245: #ifdef GEN_DEBUG
246: xout ("debugstr: .string \"$%%x $%%x $%%x $%%x $%%x $%%x $%%x $%%x*$%%x $%%x $%%x $%%x $%%x $%%x $%%x $%%x:%%d\\n\"\n");
247: #endif
248: xout (" .global STRam\n");
249: xout ("STRam: .long STData+PROC_STATE\n");
250:
251: xout (" .section .rodata\n");
252: xout ("bin_filename: .string \"%s\"\n", bin_filename);
253: xout ("open_mode: .string \"r\"\n\n");
254: xout ("dreg_fmt: .string \"D%%d = $%%08x\t\"\n");
255: xout ("areg_fmt: .string \"A%%d = $%%08x\\n\"\n");
256: xout ("cr: .string \"\\n\"\n");
257: xout ("cc_names: .string \"XNZVC\"\n");
258: xout ("hex_fmt: .string \"$%%02x \"\n");
259: xout ("illegal_fmt: .string \"Illegal instruction at line %%d.\\n\"\n");
260:
261: xout (" .text\n");
262:
263: xout (".globl SetZFlag\n");
264: xout ("SetZFlag:\n");
265: rout (
266: " movl 4(%esp),%eax\n"
267: " movb %al,Z\n"
268: " ret\n");
269:
270: xout (".globl GetXFlag\n");
271: xout ("GetXFlag:\n");
272: rout (
273: " movl X,%eax\n"
274: " ret\n");
275:
276: xout (".globl GetZFlag\n");
277: xout ("GetZFlag:\n");
278: rout (
279: " movl Z,%eax\n"
280: " ret\n");
281:
282: xout (".globl GetCFlag\n");
283: xout ("GetCFlag:\n");
284: rout (
285: " movl C,%eax\n"
286: " ret\n");
287:
288: xout (".globl GetNFlag\n");
289: xout ("GetNFlag:\n");
290: rout (
291: " movl N,%eax\n"
292: " ret\n");
293:
294: xout (".globl GetVFlag\n");
295: xout ("GetVFlag:\n");
296: rout (
297: " movl V,%eax\n"
298: " ret\n");
299:
300: xout (".globl DumpRegs\n");
301: xout ("DumpRegs:\n");
302: rout (
303: " pushl %ebp\n"
304: " pushl %ebx\n"
305: " pushl %ecx\n"
306: " pushl %esi\n"
307: " movl $STData,%ebx\n"
308: " xorl %eax,%eax\n"
309: "1: pushl %eax\n"
310: " pushl (%ebx,%eax,4)\n"
311: " pushl %eax\n"
312: " pushl $dreg_fmt\n"
313: " call printf\n"
314: " addl $12,%esp\n"
315: " movl (%esp),%eax\n"
316: " pushl 8*4(%ebx,%eax,4)\n"
317: " pushl %eax\n"
318: " pushl $areg_fmt\n"
319: " call printf\n"
320: " addl $12,%esp\n"
321: " popl %eax\n"
322: " inc %eax\n"
323: " cmpl $8,%eax\n"
324: " jl 1b\n"
325: /* print status flags */
326: " movb X,%al\n"
327: " movl $0,%ecx\n"
328: " call print_scat\n"
329: " movb N,%al\n"
330: " movl $1,%ecx\n"
331: " call print_scat\n"
332: " movb Z,%al\n"
333: " movl $2,%ecx\n"
334: " call print_scat\n"
335: " movb V,%al\n"
336: " movl $3,%ecx\n"
337: " call print_scat\n"
338: " movb C,%al\n"
339: " movl $4,%ecx\n"
340: " call print_scat\n"
341: " pushl $cr\n"
342: " call printf\n"
343: " addl $4,%esp\n"
344: /* print memory contents */
345:
346: " movl $STData+PROC_STATE,%esi\n"
347: " movl $MEM_SIZE,%ebx\n"
348: "1: movzbl (%esi),%eax\n"
349: " pushl %eax\n"
350: " pushl $hex_fmt\n"
351: " call printf\n"
352: " addl $8,%esp\n"
353: " inc %esi\n"
354: " dec %ebx\n"
355:
356: " testl $15,%ebx\n"
357: " jz 3f\n"
358:
359: "2: testl %ebx,%ebx\n"
360: " jnz 1b\n"
361:
362:
363: " popl %esi\n"
364: " popl %ecx\n"
365: " popl %ebx\n"
366: " popl %ebp\n"
367: " ret\n"
368:
369: "3: pushl $cr\n"
370: " call printf\n"
371: " addl $4,%esp\n"
372: " jmp 2b\n"
373:
374: "print_scat:\n"
375: " xorl %ebx,%ebx\n"
376: " cmpb %al,%bl\n"
377: " jz 1f\n"
378: " movb cc_names(%ecx),%al\n"
379: " pushl %eax\n"
380: " call putchar\n"
381: " addl $4,%esp\n"
382: "1: ret\n"
383: );
384:
385: xout (".globl FlagException\n");
386: xout ("FlagException:\n");
387: rout (
388: " movl 4(%esp),%eax\n"
389: " btsl %eax,exceptions_pending_mask\n"
390: " incb exceptions_pending_nums(%eax)\n"
391: " ret\n");
392:
393: xout (".globl MemReadByte\n");
394: xout ("MemReadByte:\n");
395: rout (
396: " movl 4(%esp),%eax\n"
397: " movsbl STData+PROC_STATE(%eax),%eax\n"
398: " ret\n");
399:
400: xout (".globl MemReadWord\n");
401: xout ("MemReadWord:\n");
402: rout (
403: " movl 4(%esp),%eax\n"
404: " movswl STData+PROC_STATE(%eax),%eax\n"
405: " xchg %al,%ah\n"
406: " ret\n");
407:
408: xout (".globl MemReadLong\n");
409: xout ("MemReadLong:\n");
410: rout (
411: " movl 4(%esp),%eax\n"
412: " movl STData+PROC_STATE(%eax),%eax\n"
413: " bswap %eax\n"
414: " ret\n");
415:
416: xout (".globl MemWriteByte\n");
417: xout ("MemWriteByte:\n");
418: rout (
419: " movl 4(%esp),%eax\n"
420: " movl 8(%esp),%edx\n"
421: " movb %dl,STData+PROC_STATE(%eax)\n"
422: " ret\n");
423:
424: xout (".globl MemWriteWord\n");
425: xout ("MemWriteWord:\n");
426: rout (
427: " movl 8(%esp),%edx\n"
428: " movl 4(%esp),%eax\n"
429: " xchg %dl,%dh\n"
430: " movw %dx,STData+PROC_STATE(%eax)\n"
431: " ret\n");
432:
433: xout (".globl MemWriteLong\n");
434: xout ("MemWriteLong:\n");
435: rout (
436: " movl 8(%esp),%edx\n"
437: " movl 4(%esp),%eax\n"
438: " bswap %edx\n"
439: " movl %edx,STData+PROC_STATE(%eax)\n"
440: " ret\n");
441:
442: xout (".globl GetReg\n");
443: xout ("GetReg:\n");
444: rout (
445: " movl 4(%esp),%eax\n"
446: " movl STData(,%eax,4),%eax\n"
447: " ret\n");
448:
449: xout (".globl SetReg\n");
450: xout ("SetReg:\n");
451: rout (
452: " movl 4(%esp),%eax\n"
453: " movl 8(%esp),%edx\n"
454: " movl %edx,STData(,%eax,4)\n"
455: " ret\n");
456:
457: xout (".globl Init680x0\n");
458: xout ("Init680x0:\n");
459: rout (
460: " pushl %esi\n"
461: " pushl %ebx\n"
462: " pushl $open_mode\n"
463: " pushl $bin_filename\n"
464: " call fopen\n"
465: " movl %eax, %ebx\n"
466: " popl %eax\n"
467: " xorl %eax, %eax\n"
468: " testl %ebx, %ebx\n"
469: " popl %edx\n"
470: " je 1f\n"
471: " pushl $2\n"
472: " pushl $0\n"
473: " pushl %ebx\n"
474: " call fseek\n"
475: " pushl %ebx\n"
476: " call ftell\n"
477: " pushl $0\n"
478: " movl %eax, %esi\n"
479: " pushl $0\n"
480: " pushl %ebx\n"
481: " call fseek\n"
482: " addl $28, %esp\n"
483: " xorl %eax, %eax\n"
484: " cmpl $MEM_SIZE, %esi\n"
485: " jge 1f\n"
486: " pushl %ebx\n"
487: " pushl %esi\n"
488: " pushl $1\n"
489: " pushl $STData+PROC_STATE\n"
490: " call fread\n"
491: " pushl %ebx\n"
492: " call fclose\n"
493: " movl $1, %eax\n"
494: " addl $20, %esp\n"
495: "1:\n"
496: " popl %ebx\n"
497: " popl %esi\n"
498: " ret\n");
499:
500: xout (".globl Start680x0\n");
501: xout ("Start680x0:\n");
502: xout (" pushl %%ebp\n");
503: xout (" pushl %%esi\n");
504: xout (" pushl %%edi\n");
505: xout (" pushl %%edx\n");
506: xout (" pushl %%ecx\n");
507: xout (" pushl %%ebx\n");
508: xout (" movl $STData+PROC_STATE,%%ebp\n\n");
509: //xout (" movl $0x110000,Regs+15*4");
510: // xout (" movl $0x1c,%%edx");
511:
512: // xout (" jmp jumptable");
513: }
514:
515: static void do_pending ();
516:
517: void i386_end (const char *src_filename)
518: {
519: /* some more crap needs to be added to the top */
520: int prev, i;
521: char c, buf[128];
522: FILE *f;
523: struct Fixup *fix;
524: struct Label *lab;
525:
526: /* output last instruction */
527: next_op_type = OP_NONE;
528: do_pending ();
529:
530: xout ("\n");
531: xflush_all ();
532: xln ("popl %%ebx");
533: xln ("popl %%ecx");
534: xln ("popl %%edx");
535: xln ("popl %%edi");
536: xln ("popl %%esi");
537: xln ("popl %%ebp");
538: xln ("ret");
539:
540: fclose (asm_out);
541:
542: snprintf (buf, sizeof (buf), "%s.S", src_filename);
543: if ((asm_out = fopen (buf, "w"))==NULL) {
544: fprintf (stderr, "Error: Cannot open %s for writing.\n", buf);
545: exit (-1);
546: }
547:
548: #ifdef WIN32
549: winsym ("printf");
550: winsym ("hcalls");
551: winsym ("fopen");
552: winsym ("fseek");
553: winsym ("ftell");
554: winsym ("fclose");
555: winsym ("abort");
556: winsym ("putchar");
557: winsym ("fread");
558: winsym ("SetReg");
559: winsym ("GetReg");
560: winsym ("STRam");
561: winsym ("MemReadLong");
562: winsym ("MemReadWord");
563: winsym ("MemReadByte");
564: winsym ("MemWriteLong");
565: winsym ("MemWriteWord");
566: winsym ("MemWriteByte");
567: winsym ("GetZFlag");
568: winsym ("GetNFlag");
569: winsym ("GetVFlag");
570: winsym ("GetCFlag");
571: winsym ("GetXFlag");
572: winsym ("Init680x0");
573: winsym ("Start680x0");
574: winsym ("FlagException");
575: winsym ("line_no");
576: winsym ("exception_handlers");
577: #endif /* WIN32 */
578:
579: /* address 'fixups' */
580: fix = fix_first;
581: for (; fix != NULL; fix = fix->next) {
582: if (fix->size != C_ADDR) continue;
583:
584: lab = get_label (fix->label);
585: if ((fix->adr != 0) || (!lab)) {
586: continue;
587: }
588: xout ("#define __D%s 0x%x\n", lab->name, lab->val+BASE);
589: }
590:
591: /* computed jump table */
592: xln (".align 4");
593: xout ("jtab:\n");
594:
595: prev = -2;
596: fix = fix_first;
597: for (; fix != NULL; fix = fix->next) {
598: if (fix->size != C_ADDR) continue;
599:
600: lab = get_label (fix->label);
601:
602: if (!fix->adr) {
603: /* ignore. let pass2 throw the error. */
604: continue;
605: }
606: /* add ones since prev */
607: for (i=prev+2; i<fix->adr; i+=2) {
608: xln (".long bad_jmp");
609: }
610: xln (".long %s", fix->label);
611: prev = fix->adr;
612: }
613: xout ("jumptable:\n");
614: xln ("jmp *jtab(,%%eax,2)");
615: #ifdef GEN_DEBUG
616: xout (" .section .rodata\n");
617: xout ("bad_jmp_str: .string \"Error. Bad jump target: $%%x at line %%d.\\n\"\n");
618: xln (".text");
619: xout ("bad_jmp:\n");
620: xln ("shll $1,%%eax");
621: xln ("pushl line_no");
622: xln ("pushl %%eax");
623: xln ("pushl $bad_jmp_str");
624: xln ("call printf");
625: xln ("addl $8,%%esp");
626: xln ("call abort");
627: #else
628: xout ("bad_jmp:\n");
629: xout ("bad_jmp2:\n");
630: xln ("call abort");
631: #endif
632:
633: /* the code we made */
634: snprintf (buf, sizeof (buf), ".%s.S", src_filename);
635: if ((f = fopen (buf, "r"))==NULL) {
636: fprintf (stderr, "Error: Cannot open %s for writing.\n", buf);
637: exit (-1);
638: }
639: while ((c = fgetc (f)) != EOF) fputc (c, asm_out);
640: fclose (f);
641: remove (buf);
642:
643: xout ("handle_exception:\n");
644:
645: /* no exceptions while in an exception handler */
646: xln ("movl rdest,%%ebx");
647: xln ("testl %%ebx,%%ebx");
648: xln ("jnz jumptable");
649:
650: xln ("movl %%eax,rdest");
651:
652: xln ("movl exceptions_pending_mask,%%edx");
653: xln ("xorl %%ecx,%%ecx");
654: xout ("1:\n");
655: xln ("btl %%ecx,%%edx");
656: xln ("jnc 2f");
657:
658: /* yay. exception num %ecx pending */
659: xln ("movl $exception_handlers,%%ebx");
660: xln ("movb exceptions_pending_nums(%%ecx),%%al");
661: xln ("decb %%al");
662: xln ("jnz 3f");
663: xln ("btrl %%ecx,exceptions_pending_mask");
664: xln ("3: movb %%al,exceptions_pending_nums(%%ecx)");
665: xln ("movl (%%ebx,%%ecx,4),%%eax");
666: xln ("movb X,%%bh");
667: xln ("movb N,%%bl");
668: xln ("movb Z,%%ch");
669: xln ("movb V,%%cl");
670: xln ("movb C,%%dh");
671: xln ("movb %%bh,bX");
672: xln ("movb %%bl,bN");
673: xln ("movb %%ch,bZ");
674: xln ("movb %%cl,bV");
675: xln ("movb %%dh,bC");
676: xln ("jmp jumptable");
677:
678: xout ("2:\n");
679: xln ("inc %%ecx");
680: xln ("cmpl $32,%%ecx");
681: xln ("jl 1b");
682: /* shouldn't get here... */
683: xln ("movl rdest,%%eax");
684: xln ("movl $0,rdest");
685: xln ("jmp jumptable");
686: fclose (asm_out);
687: }
688:
689: static int is_reg (ea_t *ea)
690: {
691: return ((ea->mode == 0) || (ea->mode == 1));
692: }
693:
694: static int is_immediate (ea_t *ea)
695: {
696: return ((ea->mode == 7) && (ea->reg == 4));
697: }
698:
699: /* only x86 regs used in effective address shit. */
700: enum X86REG {
701: EAX, EBX, ECX, EDX, ESI, EDI, X86REG_MAX
702: };
703:
704: /* m68k -> i386 reg allocation. age goes up with disuse */
705: struct reg_alloc {
706: int m68k_reg;
707: int age;
708: int dirty;
709: int locked;
710: };
711:
712: #define xreg_unlock(reg) i386_regalloc[reg].locked--;
713: #define xdirty_reg(reg) {if (reg!=-1) i386_regalloc[reg].dirty = 1; }
714:
715: /* set m68k_reg to REG_TEMP when allocating a reg as a temporary value,
716: * ie not holding a specific m68k reg's value */
717: #define REG_TEMP 16
718:
719: static struct reg_alloc i386_regalloc[X86REG_MAX];
720:
721: /* x86 asm syntax is a pain in the arse for auto-generated stuff */
722: static const char *reg_turd[3][X86REG_MAX] = {
723: { "%al", "%bl", "%cl", "%dl", "%invalid1", "%invalid2" },
724: { "%ax", "%bx", "%cx", "%dx", "%si", "%di" },
725: { "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" }
726: };
727:
728: static const char *szsconv[] = { "sbl", "swl", "l" };
729: //static const char *szuconv[] = { "zbl", "zwl", "l" };
730: static const char *szmov[] = { "b", "w", "l" };
731: static const char *szfull[] = { "l", "l", "l" };
732:
733: static const char *xreg (enum X86REG _reg, int size)
734: {
735: return reg_turd[size][_reg];
736: }
737:
738: static void init_regalloc ()
739: {
740: int i;
741: for (i=0; i<X86REG_MAX; i++) {
742: i386_regalloc[i].m68k_reg = -1;
743: i386_regalloc[i].locked = 0;
744: }
745: }
746:
747: static void xflush_reg (int x86_reg)
748: {
749: int m68k_reg = i386_regalloc[x86_reg].m68k_reg;
750:
751: if (i386_regalloc[x86_reg].locked != 0) {
752: bug_error ("Internal compiler error. Attept to flush locked register.");
753: }
754: if (m68k_reg == -1) return;
755: assert (m68k_reg <= REG_TEMP);
756:
757: /* temps can simply be discarded. */
758: if (m68k_reg == REG_TEMP) {
759: i386_regalloc[x86_reg].m68k_reg = -1;
760: return;
761: }
762: /* while real m68k reg values must be flushed to memory */
763: if (i386_regalloc[x86_reg].dirty)
764: xln ("movl %s,%d(%%ebp)", xreg (x86_reg, LONG), regpos (m68k_reg));
765: i386_regalloc[x86_reg].m68k_reg = -1;
766: i386_regalloc[x86_reg].dirty = 0;
767: }
768:
769: static void xflush_all ()
770: {
771: int i;
772: for (i=0; i<X86REG_MAX; i++) {
773: if (i386_regalloc[i].m68k_reg != -1)
774: xflush_reg (i);
775: }
776: }
777:
778: /* return -1 if not cached */
779: static int xfind_reg (int m68k_reg)
780: {
781: int i;
782: for (i=0; i<X86REG_MAX; i++) {
783: if (i386_regalloc[i].m68k_reg == m68k_reg) {
784: i386_regalloc[i].age = 0;
785: return i;
786: }
787: }
788: return -1;
789: }
790:
791: static void xregalloc_age ()
792: {
793: int i;
794: for (i=0; i<X86REG_MAX; i++) {
795: i386_regalloc[i].age++;
796: }
797: }
798:
799: /* set x86reg_preferred = whatever X86REG you MUST HAVE.
800: * need_bswap=1 means that */
801: static enum X86REG xalloc_reg (int size, int x86reg_preferred)
802: {
803: int i, top, oldest, age;
804: if (x86reg_preferred != -1) {
805: xflush_reg (x86reg_preferred);
806: i386_regalloc[x86reg_preferred].m68k_reg = REG_TEMP;
807: i386_regalloc[x86reg_preferred].dirty = 0;
808: return x86reg_preferred;
809: }
810: /* look for unused reg */
811: /* if we want BYTE size then regs esi,edi are no use */
812: oldest = -1;
813: age = -1;
814: top = ((size == BYTE) ? ESI : X86REG_MAX);
815: for (i=0; i<top; i++) {
816: if (i386_regalloc[i].locked) continue;
817: /* unallocated and unlocked temps can always be discarded */
818: if ((i386_regalloc[i].m68k_reg == -1) ||
819: (i386_regalloc[i].m68k_reg == REG_TEMP)) {
820: i386_regalloc[i].m68k_reg = REG_TEMP;
821: i386_regalloc[i].dirty = 0;
822: i386_regalloc[i].locked = 1;
823: return i;
824: }
825: if (oldest == -1) {
826: oldest = i;
827: age = i386_regalloc[i].age;
828: } else if (i386_regalloc[i].age > age) {
829: oldest = i;
830: age = i386_regalloc[i].age;
831: }
832: }
833: /* oh well.. we must evict a cached reg */
834: if (oldest == -1) {
835: error ("Internal compiler error: Run out of x86 registers (leaked temporaries?)");
836: }
837: xflush_reg (oldest);
838: i386_regalloc[oldest].m68k_reg = REG_TEMP;
839: i386_regalloc[oldest].dirty = 0;
840: i386_regalloc[oldest].locked = 1;
841: return oldest;
842: }
843:
844: #define XLOADREG_FOR_OVERWRITE (1<<0)
845:
846: static enum X86REG xmove_reg (int size, enum X86REG src, enum X86REG dest)
847: {
848: assert (!i386_regalloc[src].locked);
849: i386_regalloc[src].locked = 1;
850: dest = xalloc_reg (size, dest);
851: xln ("movl %s,%s", xreg (src,LONG), xreg (dest,LONG));
852: i386_regalloc[dest] = i386_regalloc[src];
853: i386_regalloc[dest].age = 0;
854: i386_regalloc[src].locked = 0;
855: i386_regalloc[src].dirty = 0;
856: i386_regalloc[src].m68k_reg = -1;
857: return dest;
858: }
859:
860: static enum X86REG xload_reg2 (int m68k_reg, int size, int required_x86_reg, int flags, const char **conv)
861: {
862: int i;
863: //static int crap;
864: /* is it already loaded? */
865: for (i=0; i<X86REG_MAX; i++) {
866: if (i386_regalloc[i].m68k_reg != m68k_reg) {
867: continue;
868: } else {
869: if ((required_x86_reg != -1) &&
870: (i != required_x86_reg)) {
871: /* reg loaded but not in desired place. do it */
872: return xmove_reg (size, i, required_x86_reg);
873: }
874: }
875:
876: if ((size == BYTE) && (i >= ESI)) {
877: /* can't operate on byte values in the esi/edi regs */
878: //printf ("stupid esi/edi shit (no worries mate (n %d, line %d)\n", crap++, line_no);
879:
880: xflush_reg (i);
881: //return xmove_reg (size, i);
882: } else {
883: i386_regalloc[i].age = 0;
884: i386_regalloc[i].locked++;
885: return i;
886: }
887: }
888: /* otherwise allocate.. */
889: i = xalloc_reg (size, required_x86_reg);
890:
891: /* registers loaded for overwrite size long do not need the original value */
892: if (! ((flags & XLOADREG_FOR_OVERWRITE) && (size == LONG)))
893: xln ("mov%s %d(%%ebp),%s", conv[size], regpos (m68k_reg), xreg (i, LONG));
894:
895: i386_regalloc[i].m68k_reg = m68k_reg;
896: i386_regalloc[i].age = 0;
897: i386_regalloc[i].dirty = 0;
898: i386_regalloc[i].locked = 1;
899: return i;
900: }
901: static enum X86REG xload_reg (int m68k_reg, int size, int required_x86_reg)
902: {
903: return xload_reg2 (m68k_reg, size, required_x86_reg, 0, szfull);
904: }
905:
906: enum RegConversion { XCONV_NONE, XCONV_SWL, XCONV_ZWL };
907: /* returns a temporary reg alloc copy of an m68k register, that you can do
908: * what the fuck you like with */
909: #define xcopy_reg(m68k_reg,size,required_x86_reg) \
910: xcopy_reg2 (m68k_reg, size, required_x86_reg, 0)
911: static enum X86REG xcopy_reg2 (int m68k_reg, int size, int required_x86_reg, enum RegConversion conversion)
912: {
913: int reg, copy_reg;
914:
915: /* i wonder if it is an optimisation to load directly to copy reg
916: * when the reg is not already cached.. */
917: reg = xload_reg (m68k_reg, size, -1);
918: copy_reg = xalloc_reg (size, required_x86_reg);
919:
920: switch (conversion) {
921: case XCONV_NONE:
922: xln ("mov%s %s,%s", szmov[size], xreg (reg, size), xreg (copy_reg, size));
923: break;
924: case XCONV_SWL:
925: assert (size == LONG);
926: xln ("movswl %s,%s", szmov[size], xreg (reg, WORD), xreg (copy_reg, LONG));
927: break;
928: case XCONV_ZWL:
929: assert (size == LONG);
930: xln ("movzwl %s,%s", szmov[size], xreg (reg, WORD), xreg (copy_reg, LONG));
931: break;
932: }
933: xreg_unlock (reg);
934: return copy_reg;
935: }
936:
937: static int rset[2] = { EAX, EBX };
938: static int rdirty[2] = { ECX, EDX };
939:
940: #define sreg(reg) xreg ((reg), size)
941:
942: static void x_postea (ea_t *ea)
943: {
944: int inc, reg;
945:
946: inc = 1<<ea->op_size;
947: if ((ea->reg == 15) && (inc == 1)) inc = 2;
948: /* deallocate temporary register allocations */
949: if (ea->x86_reg != -1) {
950: xreg_unlock (ea->x86_reg);
951: }
952: if (ea->x86_reg_writeback != -1) {
953: xreg_unlock (ea->x86_reg_writeback);
954: }
955:
956: switch (ea->mode) {
957: /* areg postinc */
958: case 3:
959: reg = xload_reg (ea->reg, LONG, -1);
960: xdirty_reg (reg);
961: if (inc == 1)
962: xln ("incl %s", xreg (reg, LONG));
963: else
964: xln ("addl $%d,%s", inc, xreg (reg, LONG));
965: xreg_unlock (reg);
966: break;
967: /* areg predec */
968: case 4:
969: reg = xload_reg (ea->reg, LONG, -1);
970: xdirty_reg (reg);
971: if (inc == 1)
972: xln ("decl %s", xreg (reg, LONG));
973: else
974: xln ("subl $%d,%s", inc, xreg (reg, LONG));
975: xreg_unlock (reg);
976: break;
977: default: break;
978: }
979: }
980:
981: #define _S(x) if (stage[arg] == (x))
982:
983: /*
984: * Note on these multi-stage pipeline turds. The value must be actually
985: * set in val_reg on the final stage, final instruction, so that the
986: * condition codes are available.
987: *
988: * Actually used stages should be the final ones, if not all are needed.
989: */
990:
991: /*
992: * Returns zero when done.
993: */
994: static void xold_ea_get_address (ea_t *ea, int arg, int advance_stage)
995: {
996: static int stage[2] = {1,1};
997: int rpos, inc;
998:
999: if (!advance_stage) {
1000: if (stage[arg] != 1) error ("xold_ea_get_address stages missed. (as68k bug).");
1001:
1002: stage[arg] = 0;
1003: } else {
1004: stage[arg]++;
1005: }
1006:
1007: ea->x86_reg = -1;
1008:
1009: switch (ea->mode) {
1010: /* dreg, areg */
1011: case 0: case 1: assert (0);
1012: /* areg indirect, postinc */
1013: case 2: case 3:
1014: _S(1) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rset[arg],LONG));
1015: break;
1016: /* areg predec */
1017: case 4:
1018: inc = 1<<ea->op_size;
1019: /* stack pointer always by 2 */
1020: if ((ea->reg == 15) && (inc == 1)) inc = 2;
1021:
1022: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rset[arg],LONG));
1023: //XXX
1024: _S(1) {
1025: if (inc == 1) xln ("dec %s", xreg (rset[arg],LONG));
1026: else xln ("subl $%d,%s", inc, xreg (rset[arg],LONG));
1027: }
1028: break;
1029: /* areg offset */
1030: case 5:
1031: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rset[arg],LONG));
1032: //XXX
1033: _S(1) xln ("addl $%d,%s", ea->imm.val, xreg (rset[arg],LONG));
1034: break;
1035: /* areg offset + reg */
1036: case 6:
1037: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rset[arg],LONG));
1038: if (ea->ext._.size) {
1039: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[arg], LONG));
1040: } else {
1041: _S(0) xln ("movswl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[arg], LONG));
1042: }
1043: _S(0) xln ("addl $%d,%s", ea->ext._.displacement, xreg (rset[arg],LONG));
1044: //XXX
1045: _S(1) xln ("addl %s,%s", xreg (rdirty[arg], LONG), xreg (rset[arg],LONG));
1046: break;
1047: /* yes */
1048: case 7:
1049: /* $xxx.w */
1050: if (ea->reg == 0) {
1051: _S(1) xln ("movl $%d,%s", ea->imm.val, xreg (rset[arg],LONG));
1052: }
1053: /* $xxx.l */
1054: else if (ea->reg == 1) {
1055: if (ea->imm.has_label) {
1056: _S(1) xln ("movl $__D%s,%s", ea->imm.label, xreg (rset[arg],LONG));
1057: } else {
1058: _S(1) xln ("movl $%d,%s", ea->imm.val, xreg (rset[arg],LONG));
1059: }
1060: }
1061: /* immediate */
1062: else if (ea->reg == 4) {
1063: assert (0);
1064: }
1065: /* PC + offset */
1066: else if (ea->reg == 2) {
1067: if (ea->imm.has_label) {
1068: _S(1) xln ("movl $__D%s,%s", ea->imm.label, xreg (rset[arg],LONG));
1069: } else
1070: error ("Absolute value not allowed.");
1071: }
1072: /* PC + INDEX + OFFSET */
1073: else if (ea->reg == 3) {
1074: if (!ea->imm.has_label) error ("Absolute value not allowed.");
1075: rpos = regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0));
1076: if (ea->ext._.size) {
1077: _S(0) xln ("movl %d(%%ebp),%s", rpos, xreg (rset[arg],LONG));
1078: } else {
1079: _S(0) xln ("movswl %d(%%ebp),%s", rpos, xreg (rset[arg],LONG));
1080: }
1081: // XXX
1082: _S(1) xln ("addl $__D%s,%s", ea->imm.label, xreg (rset[arg],LONG));
1083: }
1084: break;
1085: default:
1086: assert (0);
1087: }
1088: }
1089:
1090: static void do_bswap (enum X86REG val, int size)
1091: {
1092: switch (size) {
1093: case BYTE: return;
1094: case WORD: xln ("rorw $8,%s", xreg (val, WORD));
1095: return;
1096: case LONG: xln ("bswap %s", xreg (val, LONG));
1097: return;
1098: }
1099: }
1100:
1101: /*
1102: * To avoid pipeline stalls the function outputs code until
1103: * a pipeline stall occurs, and then returns.
1104: * First call should be made with advance_stage == 0, subsequent
1105: * calls with advance_stage==1.
1106: * And then put shit inbetween.
1107: *
1108: * flag XQUICK_REGS means that for "reading" immediate values,
1109: * and XQUICK_REGS values in registers, nothing is done and instead ea->identifier
1110: * string is set to (for example) "$1234" or the i386 EA of the reg.
1111: *
1112: * XCAN_OVERWRITE means that you can modify the returned value because
1113: * it is a copy of the cached register (if it is a register, otherwise
1114: * this flag has no effect).
1115: */
1116: #define XQUICK_REGS (1<<0)
1117: #define XQUICK_IMMS (1<<1)
1118: #define XQUICK_WRITEBACK (1<<2)
1119: #define XCAN_OVERWRITE (1<<3)
1120: #define XSIGN_EXTEND_REGS (1<<4)
1121:
1122: #define xold_readea(ea,arg,adv) xold_readea2(ea,arg,adv,0);
1123: static void xold_readea2 (ea_t *ea, int arg, int advance_stage, int flags)
1124: {
1125: static int stage[2] = {2,2};
1126: int inc, size;
1127: size = ea->op_size;
1128:
1129: if (!advance_stage) {
1130: if (stage[arg] != 2) error ("xold_readea stages missed. (as68k bug).");
1131:
1132: stage[arg] = 0;
1133: } else {
1134: stage[arg]++;
1135: }
1136:
1137: ea->do_writeback = 1;
1138: ea->x86_reg_writeback = -1;
1139: ea->x86_reg = -1;
1140:
1141: switch (ea->mode) {
1142: /* dreg, areg */
1143: case 0:
1144: case 1:
1145: if (flags & XQUICK_REGS) {
1146: /* operate in-place (in memory) */
1147: _S(0) snprintf (ea->identifier, sizeof (ea->identifier), "%d(%%ebp)", regpos (ea->reg));
1148: ea->do_writeback = 0;
1149: return;
1150: }
1151: _S(2) xln ("mov%s %d(%%ebp),%s", szmov[size], regpos (ea->reg), xreg (rset[arg], size));
1152: break;
1153: /* areg indirect */
1154: case 2:
1155: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[arg], LONG));
1156: _S(1) xln ("mov%s (%%ebp,%s),%s", szmov[size], xreg (rdirty[arg], LONG), xreg (rset[arg], size));
1157: _S(2) do_bswap (rset[arg], size);
1158: break;
1159: /* areg postinc */
1160: case 3:
1161: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[arg], LONG));
1162: _S(1) xln ("mov%s (%%ebp,%s),%s", szmov[size], xreg (rdirty[arg], LONG), xreg (rset[arg], size));
1163: _S(2) do_bswap (rset[arg], size);
1164: break;
1165: /* areg predec */
1166: case 4:
1167: inc = 1<<size;
1168: /* stack pointer always by 2 */
1169: if ((ea->reg == 15) && (inc == 1)) inc = 2;
1170:
1171: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[arg], LONG));
1172: _S(1) xln ("mov%s -%d(%%ebp,%s),%s", szmov[size], inc, xreg (rdirty[arg], LONG), xreg (rset[arg], size));
1173: _S(2) do_bswap (rset[arg], size);
1174: break;
1175: /* areg offset */
1176: case 5:
1177: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[arg], LONG));
1178: _S(1) xln ("mov%s %d(%%ebp,%s),%s", szmov[size], ea->imm.val, xreg (rdirty[arg], LONG), xreg (rset[arg], size));
1179: _S(2) do_bswap (rset[arg], size);
1180: break;
1181: /* areg offset + reg */
1182: case 6:
1183: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[arg],LONG));
1184: if (ea->ext._.size) {
1185: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rset[arg],LONG));
1186: } else {
1187: _S(0) xln ("movswl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rset[arg], LONG));
1188: }
1189: _S(0) xln ("addl %%ebp,%s", xreg (rdirty[arg],LONG));
1190: _S(1) xln ("mov%s %d(%s,%s),%s", szmov[size], ea->ext._.displacement, xreg (rdirty[arg],LONG), xreg (rset[arg],LONG), xreg (rset[arg], size));
1191: _S(2) do_bswap (rset[arg], size);
1192: break;
1193: /* yes */
1194: case 7:
1195: /* $xxx.w */
1196: if (ea->reg == 0) {
1197: _S(1) xln ("mov%s %d(%%ebp),%s", szmov[size], ea->imm.val, xreg (rset[arg], size));
1198: _S(1) do_bswap (rset[arg], size);
1199: }
1200: /* $xxx.l */
1201: else if (ea->reg == 1) {
1202: if (ea->imm.has_label) {
1203: _S(1) xln ("mov%s __D%s(%%ebp),%s", szmov[size], ea->imm.label, xreg (rset[arg], size));
1204: _S(2) do_bswap (rset[arg], size);
1205: } else {
1206: _S(1) xln ("mov%s %d(%%ebp),%s", szmov[size], ea->imm.val, xreg (rset[arg], size));
1207: _S(2) do_bswap (rset[arg], size);
1208: }
1209: }
1210: /* immediate */
1211: else if (ea->reg == 4) {
1212: if (flags & XQUICK_IMMS) {
1213: if (ea->imm.has_label) {
1214: _S(0) snprintf (ea->identifier, sizeof (ea->identifier),
1215: "$__D%s", ea->imm.label);
1216: } else {
1217: _S(0) snprintf (ea->identifier, sizeof (ea->identifier),
1218: "$%d", ea->imm.val);
1219: }
1220: return;
1221: }
1222: if (ea->imm.has_label) {
1223: _S(2) xln ("movl $__D%s,%s", ea->imm.label, xreg (rset [arg], LONG));
1224: } else {
1225: _S(2) xln ("movl $%d,%s", ea->imm.val, xreg (rset [arg], LONG));
1226: }
1227: }
1228: /* PC + offset */
1229: else if (ea->reg == 2) {
1230: assert (ea->imm.has_label);
1231:
1232: _S(1) xln ("mov%s __D%s(%%ebp),%s", szmov[size], ea->imm.label, xreg (rset[arg], size));
1233: _S(2) do_bswap (rset[arg], size);
1234: }
1235: /* PC + INDEX + OFFSET */
1236: else if (ea->reg == 3) {
1237: assert (ea->imm.has_label);
1238: if (ea->ext._.size) {
1239: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[arg],LONG));
1240: } else {
1241: _S(0) xln ("movswl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[arg], LONG));
1242: }
1243: _S(1) xln ("mov%s __D%s(%%ebp,%s),%s", szmov[size], ea->imm.label, xreg (rdirty[arg],LONG), xreg (rset[arg], size));
1244: _S(2) do_bswap (rset[arg], size);
1245: }
1246: break;
1247: default:
1248: error ("nasty error in c_readea()");
1249: }
1250: _S(0) snprintf (ea->identifier, sizeof (ea->identifier),
1251: "%s", reg_turd[size][arg]);
1252: }
1253:
1254: /*
1255: * Uses dirty regs of arg1 and arg2 (so they can't be pipelined together).
1256: */
1257: static void xold_writeea (ea_t *ea, int size, enum X86REG val, int advance_stage)
1258: {
1259: int inc;
1260: const int arg = 1; /* hack. _S macro ;-) */
1261: static int stage[2] = {2,2};
1262:
1263: assert ((val == EAX) || (val == EBX));
1264:
1265: if (!advance_stage) {
1266: if (stage[arg] != 2) error ("xold_writeea stages missed. (as68k bug).");
1267:
1268: stage[arg] = 0;
1269: } else {
1270: stage[arg]++;
1271: }
1272:
1273: if (!ea->do_writeback) return;
1274: ea->x86_reg_writeback = -1;
1275: ea->x86_reg = -1;
1276:
1277: switch (ea->mode) {
1278: /* dreg, areg */
1279: case 0: case 1:
1280: _S(2) xln ("mov%s %s,%d(%%ebp)", szmov[size], xreg (val, size), regpos (ea->reg));
1281: break;
1282: /* areg indirect */
1283: case 2:
1284: _S(1) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[0], LONG));
1285: _S(1) do_bswap (val, size);
1286: _S(2) xln ("mov%s %s,(%%ebp,%s)", szmov[size], xreg (val, size), xreg (rdirty[0], LONG));
1287: break;
1288: /* areg postinc */
1289: case 3:
1290: _S(1) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[0], LONG));
1291: _S(1) do_bswap (val, size);
1292: _S(2) xln ("mov%s %s,(%%ebp,%s)", szmov[size], xreg (val, size), xreg (rdirty[0], LONG));
1293: break;
1294: /* areg predec */
1295: case 4:
1296: inc = 1<<size;
1297: /* stack pointer always by 2 */
1298: if ((ea->reg == 15) && (inc == 1)) inc = 2;
1299:
1300: _S(1) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[0], LONG));
1301: _S(1) do_bswap (val, size);
1302: _S(2) xln ("mov%s %s,-%d(%%ebp,%s)", szmov[size], xreg (val, size), inc, xreg (rdirty[0], LONG));
1303: break;
1304: /* areg offset */
1305: case 5:
1306: _S(1) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[0], LONG));
1307: _S(1) do_bswap (val, size);
1308: _S(2) xln ("mov%s %s,%d(%%ebp,%s)", szmov[size], xreg (val, size), ea->imm.val, xreg (rdirty[0], LONG));
1309: break;
1310: /* areg offset + reg */
1311: case 6:
1312: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->reg), xreg (rdirty[1],LONG));
1313: if (ea->ext._.size) {
1314: _S(0) xln ("movl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[0],LONG));
1315: } else {
1316: _S(0) xln ("movswl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[0], LONG));
1317: }
1318: _S(0) xln ("addl %%ebp,%s", xreg (rdirty[1],LONG));
1319: _S(0) do_bswap (val, size);
1320: _S(1) xln ("mov%s %s,%d(%s,%s)", szmov[size], xreg (val, size), ea->ext._.displacement, xreg (rdirty[1],LONG), xreg (rdirty[0],LONG));
1321: break;
1322: /* yes */
1323: case 7:
1324: /* $xxx.w */
1325: if (ea->reg == 0) {
1326: _S(1) do_bswap (val, size);
1327: _S(2) xln ("mov%s %s,%d(%%ebp)", szmov[size], xreg (val, size), ea->imm.val);
1328: }
1329: /* $xxx.l */
1330: else if (ea->reg == 1) {
1331: if (ea->imm.has_label) {
1332: _S(1) do_bswap (val, size);
1333: _S(2) xln ("mov%s %s,__D%s(%%ebp)", szmov[size], xreg (val, size), ea->imm.label);
1334: } else {
1335: _S(1) do_bswap (val, size);
1336: _S(2) xln ("mov%s %s,%d(%%ebp)", szmov[size], xreg (val, size), ea->imm.val);
1337: }
1338: }
1339: /* immediate */
1340: else if (ea->reg == 4) {
1341: assert (0);
1342: }
1343: /* PC + offset */
1344: else if (ea->reg == 2) {
1345: assert (ea->imm.has_label);
1346:
1347: _S(1) do_bswap (val, size);
1348: _S(2) xln ("mov%s %s,__D%s(%%ebp)", szmov[size], xreg (val, size), ea->imm.label);
1349: }
1350: /* PC + INDEX + OFFSET */
1351: else if (ea->reg == 3) {
1352: assert (ea->imm.has_label);
1353: if (ea->ext._.size) {
1354: _S(1) xln ("movl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[0],LONG));
1355: } else {
1356: _S(1) xln ("movswl %d(%%ebp),%s", regpos (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0)), xreg (rdirty[0], LONG));
1357: }
1358: _S(1) do_bswap (val, size);
1359: _S(2) xln ("mov%s %s,__D%s(%%ebp,%s)", szmov[size], xreg (val,size), ea->imm.label, xreg (rdirty[0],LONG));
1360: }
1361: else {
1362: error ("wtf in c_writeea ()");
1363: }
1364: break;
1365: default:
1366: error ("nasty error in c_writeea()");
1367: }
1368: }
1369:
1370: /* loads effective address, not value pointed to */
1371: static void x_loadea (ea_t *ea)
1372: {
1373: int reg2, reg3, inc, out_reg;
1374:
1375: ea->do_writeback = 1;
1376: ea->x86_reg_writeback = -1;
1377:
1378: switch (ea->mode) {
1379: /* dreg, areg */
1380: case 0: case 1: assert (0);
1381: /* areg indirect, postinc */
1382: case 2: case 3:
1383: out_reg = xcopy_reg (ea->reg, LONG, -1);
1384: break;
1385: /* areg predec */
1386: case 4:
1387: inc = 1<<ea->op_size;
1388: /* stack pointer always by 2 */
1389: if ((ea->reg == 15) && (inc == 1)) inc = 2;
1390:
1391: out_reg = xcopy_reg (ea->reg, LONG, -1);
1392: if (inc == 1) xln ("dec %s", xreg (out_reg,LONG));
1393: else xln ("subl $%d,%s", inc, xreg (out_reg,LONG));
1394: break;
1395: /* areg offset */
1396: case 5:
1397: out_reg = xcopy_reg (ea->reg, LONG, -1);
1398: xln ("addl $%d,%s", ea->imm.val, xreg (out_reg,LONG));
1399: break;
1400: /* areg offset + reg */
1401: case 6:
1402: out_reg = xcopy_reg (ea->reg, LONG, -1);
1403: if (ea->ext._.size) {
1404: reg2 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1405: } else {
1406: /* need fucking 16-bit chunk of variable sign extended to 32... */
1407: reg3 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1408: reg2 = xalloc_reg (LONG, -1);
1409: xln ("movswl %s,%s", xreg (reg3, WORD), xreg (reg2, LONG));
1410: xreg_unlock (reg3);
1411:
1412: }
1413: xln ("leal %d(%s,%s),%s", ea->ext._.displacement, xreg (reg2, LONG), xreg(out_reg, LONG), xreg (out_reg, LONG));
1414: xreg_unlock (reg2);
1415: break;
1416: /* yes */
1417: case 7:
1418: /* $xxx.w */
1419: if (ea->reg == 0) {
1420: out_reg = xalloc_reg (LONG, -1);
1421: xln ("movl $%d,%s", ea->imm.val, out_reg, LONG);
1422: }
1423: /* $xxx.l */
1424: else if (ea->reg == 1) {
1425: out_reg = xalloc_reg (LONG, -1);
1426: if (ea->imm.has_label) {
1427: xln ("movl $__D%s,%s", ea->imm.label, xreg (out_reg,LONG));
1428: } else {
1429: xln ("movl $%d,%s", ea->imm.val, xreg (out_reg,LONG));
1430: }
1431: }
1432: /* immediate */
1433: else if (ea->reg == 4) {
1434: assert (0);
1435: }
1436: /* PC + offset */
1437: else if (ea->reg == 2) {
1438: if (ea->imm.has_label) {
1439: out_reg = xalloc_reg (LONG, -1);
1440: xln ("movl $__D%s,%s", ea->imm.label, xreg (out_reg,LONG));
1441: } else
1442: error ("Absolute value not allowed.");
1443: }
1444: /* PC + INDEX + OFFSET */
1445: else if (ea->reg == 3) {
1446: if (!ea->imm.has_label) error ("Absolute value not allowed.");
1447: out_reg = xalloc_reg (LONG, -1);
1448: if (ea->ext._.size) {
1449: reg2 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1450: } else {
1451: /* need fucking 16-bit chunk of variable sign extended to 32... */
1452: reg3 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1453: reg2 = xalloc_reg (LONG, -1);
1454: xln ("movswl %s,%s", xreg (reg3, WORD), xreg (reg2, LONG));
1455: xreg_unlock (reg3);
1456: }
1457: // XXX
1458: xln ("leal __D%s(%s),%s", ea->imm.label, xreg (reg2, LONG), xreg (out_reg, LONG));
1459: xreg_unlock (reg2);
1460: }
1461: break;
1462: default:
1463: assert (0);
1464: }
1465: ea->x86_reg = out_reg;
1466: snprintf (ea->identifier, sizeof (ea->identifier),
1467: "%s", xreg (out_reg, LONG));
1468: }
1469:
1470: /* that is, preferred x86 reg.
1471: * XXX nothing preferred about it. it is a fucking demand. */
1472: static void x_loadval (ea_t *ea, int preferred_reg, int flags)
1473: {
1474: int inc, size, reg1, reg2, reg3, out_reg;
1475: size = ea->op_size;
1476:
1477: ea->do_writeback = 1;
1478: ea->x86_reg_writeback = -1;
1479:
1480: switch (ea->mode) {
1481: /* dreg, areg */
1482: case 0:
1483: case 1:
1484: if (flags & XCAN_OVERWRITE) {
1485: out_reg = xcopy_reg (ea->reg, LONG, preferred_reg);
1486: } else
1487: if ((flags & XQUICK_REGS) && (xfind_reg (ea->reg)==-1)) {
1488: /* operate in-place (in memory) */
1489: snprintf (ea->identifier, sizeof (ea->identifier), "%d(%%ebp)", regpos (ea->reg));
1490: ea->do_writeback = 0;
1491: return;
1492: } else {
1493: out_reg = xload_reg2 (ea->reg, size, preferred_reg,
1494: 0, (flags & XSIGN_EXTEND_REGS ? szsconv : szfull));
1495: }
1496: break;
1497: /* areg indirect */
1498: case 2:
1499: reg1 = xload_reg (ea->reg, LONG, -1);
1500: out_reg = xalloc_reg (size, preferred_reg);
1501:
1502: xln ("mov%s (%%ebp,%s),%s", szmov[size], xreg (reg1, LONG), xreg (out_reg, size));
1503: xreg_unlock (reg1);
1504: do_bswap (out_reg, size);
1505: break;
1506: /* areg postinc */
1507: case 3:
1508: reg1 = xload_reg (ea->reg, LONG, -1);
1509: out_reg = xalloc_reg (size, preferred_reg);
1510:
1511: xln ("mov%s (%%ebp,%s),%s", szmov[size], xreg (reg1, LONG), xreg (out_reg, size));
1512: xreg_unlock (reg1);
1513: do_bswap (out_reg, size);
1514: break;
1515: /* areg predec */
1516: case 4:
1517: inc = 1<<size;
1518: /* stack pointer always by 2 */
1519: if ((ea->reg == 15) && (inc == 1)) inc = 2;
1520:
1521: reg1 = xload_reg (ea->reg, LONG, -1);
1522: out_reg = xalloc_reg (size, preferred_reg);
1523: xln ("mov%s -%d(%%ebp,%s),%s", szmov[size], inc, xreg (reg1, LONG), xreg (out_reg, size));
1524: xreg_unlock (reg1);
1525: do_bswap (out_reg, size);
1526: break;
1527: /* areg offset */
1528: case 5:
1529: reg1 = xload_reg (ea->reg, LONG, -1);
1530: out_reg = xalloc_reg (size, preferred_reg);
1531:
1532: xln ("mov%s %d(%%ebp,%s),%s", szmov[size], ea->imm.val, xreg (reg1, LONG), xreg (out_reg, size));
1533: xreg_unlock (reg1);
1534: do_bswap (out_reg, size);
1535: break;
1536: /* areg offset + reg */
1537: case 6:
1538: reg1 = xload_reg (ea->reg, LONG, -1);
1539: out_reg = xalloc_reg (size, preferred_reg);
1540: if (ea->ext._.size) {
1541: reg2 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1542: } else {
1543: /* need fucking 16-bit chunk of variable sign extended to 32... */
1544: reg3 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1545: reg2 = xalloc_reg (LONG, -1);
1546: xln ("movswl %s,%s", xreg (reg3, WORD), xreg (reg2, LONG));
1547: }
1548: if (flags & XQUICK_WRITEBACK) {
1549: xln ("lea (MemBase+%d)(%s,%s),%s", ea->ext._.displacement, xreg (reg1,LONG), xreg (reg2,LONG), xreg (reg2, LONG));
1550: xln ("mov%s (%s),%s", szmov[size], xreg (reg2,LONG), xreg (out_reg, size));
1551: ea->x86_reg_writeback = reg2;
1552:
1553: xreg_unlock (reg1);
1554: xreg_unlock (reg3);
1555: } else {
1556: xln ("mov%s (MemBase+%d)(%s,%s),%s", szmov[size], ea->ext._.displacement, xreg (reg1,LONG), xreg (reg2,LONG), xreg (out_reg, size));
1557: if (!ea->ext._.size) xreg_unlock (reg3);
1558: xreg_unlock (reg1);
1559: xreg_unlock (reg2);
1560: }
1561: do_bswap (out_reg, size);
1562: break;
1563: /* yes */
1564: case 7:
1565: /* $xxx.w */
1566: if (ea->reg == 0) {
1567: out_reg = xalloc_reg (size, preferred_reg);
1568: xln ("mov%s %d(%%ebp),%s", szmov[size], ea->imm.val, xreg (out_reg, size));
1569: do_bswap (out_reg, size);
1570: }
1571: /* $xxx.l */
1572: else if (ea->reg == 1) {
1573: out_reg = xalloc_reg (size, preferred_reg);
1574: if (ea->imm.has_label) {
1575: xln ("mov%s __D%s(%%ebp),%s", szmov[size], ea->imm.label, xreg (out_reg, size));
1576: } else {
1577: xln ("mov%s %d(%%ebp),%s", szmov[size], ea->imm.val, xreg (out_reg, size));
1578: }
1579: do_bswap (out_reg, size);
1580: }
1581: /* immediate */
1582: else if (ea->reg == 4) {
1583: if (flags & XQUICK_IMMS) {
1584: if (ea->imm.has_label) {
1585: snprintf (ea->identifier, sizeof (ea->identifier),
1586: "$__D%s", ea->imm.label);
1587: } else {
1588: snprintf (ea->identifier, sizeof (ea->identifier),
1589: "$%d", ea->imm.val);
1590: }
1591: ea->x86_reg = -1;
1592: return;
1593: }
1594: out_reg = xalloc_reg (size, preferred_reg);
1595: if (ea->imm.has_label) {
1596: xln ("movl $__D%s,%s", ea->imm.label, xreg (out_reg, LONG));
1597: } else {
1598: xln ("movl $%d,%s", ea->imm.val, xreg (out_reg, LONG));
1599: }
1600: }
1601: /* PC + offset */
1602: else if (ea->reg == 2) {
1603: assert (ea->imm.has_label);
1604:
1605: out_reg = xalloc_reg (size, preferred_reg);
1606: xln ("mov%s __D%s(%%ebp),%s", szmov[size], ea->imm.label, xreg (out_reg, size));
1607: do_bswap (out_reg, size);
1608: }
1609: /* PC + INDEX + OFFSET */
1610: else if (ea->reg == 3) {
1611: assert (ea->imm.has_label);
1612:
1613: out_reg = xalloc_reg (size, preferred_reg);
1614: if (ea->ext._.size) {
1615: reg2 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1616: } else {
1617: /* need fucking 16-bit chunk of variable sign extended to 32... */
1618: reg3 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1619: reg2 = xalloc_reg (LONG, -1);
1620: xln ("movswl %s,%s", xreg (reg3, WORD), xreg (reg2, LONG));
1621: xreg_unlock (reg3);
1622: }
1623: xln ("mov%s __D%s(%%ebp,%s),%s", szmov[size], ea->imm.label, xreg (reg2,LONG), xreg (out_reg, size));
1624: do_bswap (out_reg, size);
1625: xreg_unlock (reg2);
1626: }
1627: break;
1628: default:
1629: error ("nasty error in c_readea()");
1630: }
1631:
1632: ea->x86_reg = out_reg;
1633: snprintf (ea->identifier, sizeof (ea->identifier),
1634: "%s", xreg (out_reg, size));
1635: }
1636:
1637: static void x_saveval (ea_t *ea, int size)
1638: {
1639: int inc, reg1, reg2, reg3;
1640:
1641: if (!ea->do_writeback) return;
1642:
1643: if (ea->x86_reg_writeback != -1) {
1644: do_bswap (ea->x86_reg, size);
1645: xln ("mov%s %s,(%s)", szmov[size], xreg (ea->x86_reg, size), xreg (ea->x86_reg_writeback, LONG));
1646: return;
1647: }
1648:
1649: switch (ea->mode) {
1650: /* dreg, areg */
1651: case 0: case 1:
1652: /* don't need to act until xflush_reg... */
1653: break;
1654: /* areg indirect */
1655: case 2:
1656: reg1 = xload_reg (ea->reg, LONG, -1);
1657: do_bswap (ea->x86_reg, size);
1658: xln ("mov%s %s,(%%ebp,%s)", szmov[size], xreg (ea->x86_reg, size), xreg (reg1, LONG));
1659: xreg_unlock (reg1);
1660: break;
1661: /* areg postinc */
1662: case 3:
1663: reg1 = xload_reg (ea->reg, LONG, -1);
1664: do_bswap (ea->x86_reg, size);
1665: xln ("mov%s %s,(%%ebp,%s)", szmov[size], xreg (ea->x86_reg, size), xreg (reg1, LONG));
1666: xreg_unlock (reg1);
1667: break;
1668: /* areg predec */
1669: case 4:
1670: inc = 1<<size;
1671: /* stack pointer always by 2 */
1672: if ((ea->reg == 15) && (inc == 1)) inc = 2;
1673:
1674: reg1 = xload_reg (ea->reg, LONG, -1);
1675: do_bswap (ea->x86_reg, size);
1676: xln ("mov%s %s,-%d(%%ebp,%s)", szmov[size], xreg (ea->x86_reg, size), inc, xreg (reg1, LONG));
1677: xreg_unlock (reg1);
1678: break;
1679: /* areg offset */
1680: case 5:
1681: reg1 = xload_reg (ea->reg, LONG, -1);
1682: do_bswap (ea->x86_reg, size);
1683: xln ("mov%s %s,%d(%%ebp,%s)", szmov[size], xreg (ea->x86_reg, size), ea->imm.val, xreg (reg1, LONG));
1684: xreg_unlock (reg1);
1685: break;
1686: /* areg offset + reg */
1687: case 6:
1688: reg1 = xload_reg (ea->reg, LONG, -1);
1689: if (ea->ext._.size) {
1690: reg2 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1691: } else {
1692: /* need fucking 16-bit chunk of variable sign extended to 32... */
1693: reg3 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1694: reg2 = xalloc_reg (LONG, -1);
1695: xln ("movswl %s,%s", xreg (reg3, WORD), xreg (reg2, LONG));
1696: xreg_unlock (reg3);
1697: }
1698: do_bswap (ea->x86_reg, size);
1699: xln ("mov%s %s,(MemBase+%d)(%s,%s)", szmov[size], xreg (ea->x86_reg, size), ea->ext._.displacement, xreg (reg1,LONG), xreg (reg2,LONG));
1700: xreg_unlock (reg1);
1701: xreg_unlock (reg2);
1702: break;
1703: /* yes */
1704: case 7:
1705: /* XXX TO DO */
1706: /* $xxx.w */
1707: if (ea->reg == 0) {
1708: do_bswap (ea->x86_reg, size);
1709: xln ("mov%s %s,%d(%%ebp)", szmov[size], xreg (ea->x86_reg, size), ea->imm.val);
1710: }
1711: /* $xxx.l */
1712: else if (ea->reg == 1) {
1713: if (ea->imm.has_label) {
1714: do_bswap (ea->x86_reg, size);
1715: xln ("mov%s %s,__D%s(%%ebp)", szmov[size], xreg (ea->x86_reg, size), ea->imm.label);
1716: } else {
1717: do_bswap (ea->x86_reg, size);
1718: xln ("mov%s %s,%d(%%ebp)", szmov[size], xreg (ea->x86_reg, size), ea->imm.val);
1719: }
1720: }
1721: /* immediate */
1722: else if (ea->reg == 4) {
1723: assert (0);
1724: }
1725: /* PC + offset */
1726: else if (ea->reg == 2) {
1727: assert (ea->imm.has_label);
1728:
1729: do_bswap (ea->x86_reg, size);
1730: xln ("mov%s %s,__D%s(%%ebp)", szmov[size], xreg (ea->x86_reg, size), ea->imm.label);
1731: }
1732: /* PC + INDEX + OFFSET */
1733: else if (ea->reg == 3) {
1734: assert (ea->imm.has_label);
1735: if (ea->ext._.size) {
1736: reg2 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1737: } else {
1738: /* need fucking 16-bit chunk of variable sign extended to 32... */
1739: reg3 = xload_reg (ea->ext._.reg + (ea->ext._.d_or_a ? 8 : 0), LONG, -1);
1740: reg2 = xalloc_reg (LONG, -1);
1741: xln ("movswl %s,%s", xreg (reg3, WORD), xreg (reg2, LONG));
1742: xreg_unlock (reg3);
1743: }
1744: do_bswap (ea->x86_reg, size);
1745: xln ("mov%s %s,__D%s(%%ebp,%s)", szmov[size], xreg (ea->x86_reg,size), ea->imm.label, xreg (reg2,LONG));
1746: xreg_unlock (reg2);
1747: }
1748: else {
1749: error ("wtf in c_writeea ()");
1750: }
1751: break;
1752: default:
1753: error ("nasty error in c_writeea()");
1754: }
1755: }
1756:
1757: static void x_ea_set_val_2_reg (ea_t *ea, int size, int x86_reg)
1758: {
1759: int i;
1760: assert (size == LONG);
1761:
1762: ea->do_writeback = 1;
1763: ea->x86_reg_writeback = -1;
1764:
1765: if ((ea->mode == 0) || (ea->mode == 1)) {
1766: i = xfind_reg (ea->reg);
1767:
1768: if (i != -1) {
1769: /* reg already loaded, but we are wiping
1770: * the bastard with a full LONG write so drop
1771: * the existing regalloc */
1772: assert (i386_regalloc[i].locked == 0);
1773: i386_regalloc[i].m68k_reg = -1;
1774: i386_regalloc[i].dirty = 0;
1775: }
1776: i386_regalloc[x86_reg].m68k_reg = ea->reg;
1777: i386_regalloc[x86_reg].dirty = 1;
1778:
1779: ea->x86_reg = x86_reg;
1780: } else {
1781: i386_regalloc[x86_reg].m68k_reg = REG_TEMP;
1782: ea->x86_reg = x86_reg;
1783: }
1784: i386_regalloc[x86_reg].locked++;
1785: i386_regalloc[x86_reg].age = 0;
1786: }
1787:
1788: static void x_cond_end ()
1789: {
1790: xout ("2:\n");
1791: }
1792:
1793: static void x_cond_begin (int cond)
1794: {
1795: switch (cond) {
1796: /* t */
1797: case 0: break;
1798: /* f */
1799: case 1: xln ("jmp 2f"); break;
1800: /* hi */
1801: case 2:
1802: xln ("movb C,%%al");
1803: xln ("orb Z,%%al");
1804: xln ("jnz 2f");
1805: break;
1806: //cout ("((!C) && !Z)"); break;
1807: /* ls */
1808: case 3:
1809: xln ("movb C,%%al");
1810: xln ("orb Z,%%al");
1811: xln ("jz 2f");
1812: break;
1813: //cout ("(C || Z)"); break;
1814: /* cc */
1815: case 4:
1816: xln ("testb $1,C");
1817: xln ("jnz 2f");
1818: break;
1819: //cout ("(!C)"); break;
1820: /* cs */
1821: case 5:
1822: xln ("testb $1,C");
1823: xln ("jz 2f");
1824: break;
1825: //cout ("C"); break;
1826: /* ne */
1827: case 6:
1828: xln ("testb $1,Z");
1829: xln ("jnz 2f");
1830: break;
1831: //cout ("!Z"); break;
1832: /* eq */
1833: case 7:
1834: xln ("testb $1,Z");
1835: xln ("jz 2f");
1836: break;
1837: //cout ("(Z)"); break;
1838: /* vc */
1839: case 8:
1840: xln ("testb $1,V");
1841: xln ("jnz 2f");
1842: break;
1843: //cout ("(!V)"); break;
1844: /* vs */
1845: case 9:
1846: xln ("testb $1,V");
1847: xln ("jz 2f");
1848: break;
1849: //cout ("V"); break;
1850: /* pl */
1851: case 10:
1852: xln ("testb $1,N");
1853: xln ("jnz 2f");
1854: break;
1855: //cout ("(!N)"); break;
1856: /* mi */
1857: case 11:
1858: xln ("testb $1,N");
1859: xln ("jz 2f");
1860: break;
1861: //cout ("N"); break;
1862: /* ge */
1863: case 12:
1864: xln ("movb N,%%al");
1865: xln ("xorb V,%%al");
1866: xln ("jnz 2f");
1867: break;
1868: //cout ("((N && V) || ((!N) && (!V)))"); break;
1869: /* lt */
1870: case 13:
1871: xln ("movb V,%%al");
1872: xln ("xorb $1,%%al");
1873: xln ("xorb N,%%al");
1874: xln ("jnz 2f");
1875: break;
1876: //cout ("((N && (!V)) || ((!N) && V))"); break;
1877: /* gt */
1878: case 14:
1879: xln ("movb N,%%al");
1880: xln ("xorb V,%%al");
1881: xln ("orb Z,%%al");
1882: xln ("jnz 2f");
1883: break;
1884: //cout ("((N && V && (!Z)) || ((!N) && (!V) && (!Z)))"); break;
1885: /* le */
1886: case 15:
1887: xln ("movb Z,%%ah");
1888: xln ("movb V,%%al");
1889: xln ("xorb $1,%%ah");
1890: xln ("xorb $1,%%al");
1891: xln ("xorb N,%%al");
1892: xln ("andb %%ah,%%al");
1893: xln ("jnz 2f");
1894: break;
1895: //cout ("((Z) || (N && (!V)) || ((!N) && V))"); break;
1896: }
1897: }
1898:
1899: void i386_jump (ea_t *ea)
1900: {
1901: xflush_all ();
1902: if (((ea->mode == 7) && (ea->reg == 1)) ||
1903: ((ea->mode == 7) && (ea->reg == 2))) {
1904: xln ("jmp __N%s", ea->imm.label);
1905: } else {
1906: xold_ea_get_address (ea, 0, 0);
1907: xold_ea_get_address (ea, 0, 1);
1908: x_postea (ea);
1909: //xln ("jmp jumptable");
1910: xln ("jmp *jtab(,%%eax,2)");
1911: }
1912: }
1913:
1914: /* Check for pending exceptions also */
1915: void i386_jump_e (ea_t *ea)
1916: {
1917: xflush_all ();
1918: xln ("cmpl $0,exceptions_pending_mask");
1919:
1920: /* yay! exception */
1921: if (((ea->mode == 7) && (ea->reg == 1)) ||
1922: ((ea->mode == 7) && (ea->reg == 2))) {
1923: xln ("movl $__D%s,%%eax", ea->imm.label);
1924: } else {
1925: xold_ea_get_address (ea, 0, 0);
1926: xold_ea_get_address (ea, 0, 1);
1927: x_postea (ea);
1928: }
1929: xln ("jnz handle_exception");
1930: i386_jump (ea);
1931: }
1932:
1933: static void i386_func_bitop (ea_t *src, ea_t *dest, int size, const char *op)
1934: {
1935: int len = size2len [size];
1936:
1937: xflush_all ();
1938:
1939: if (is_immediate (src)) {
1940: xold_readea (dest, 1, 0);
1941: xold_readea (dest, 1, 1);
1942: xold_readea (dest, 1, 1);
1943:
1944: xln ("%sl $%d,%%ebx", op, src->imm.val & (len-1));
1945: ifZ xln ("setnc Z");
1946:
1947: xold_writeea (dest, size, EBX, 0);
1948: xold_writeea (dest, size, EBX, 1);
1949: xold_writeea (dest, size, EBX, 1);
1950:
1951: x_postea (dest);
1952: return;
1953: }
1954:
1955: xold_readea (src, 0, 0);
1956: xold_readea (dest, 1, 0);
1957: xold_readea (src, 0, 1);
1958: xold_readea (dest, 1, 1);
1959: xold_readea (src, 0, 1);
1960: xold_readea (dest, 1, 1);
1961:
1962: if (size == BYTE) xln ("andl $7,%%eax");
1963: xln ("%sl %%eax,%%ebx", op, src->imm.val);
1964: ifZ xln ("setnc Z");
1965:
1966: xold_writeea (dest, size, EBX, 0);
1967: xold_writeea (dest, size, EBX, 1);
1968: xold_writeea (dest, size, EBX, 1);
1969:
1970: x_postea (src);
1971: x_postea (dest);
1972: }
1973:
1974: void i386_func_bchg (ea_t *src, ea_t *dest, int size)
1975: {
1976: i386_func_bitop (src, dest, size, "btc");
1977: }
1978:
1979: void i386_func_bclr (ea_t *src, ea_t *dest, int size)
1980: {
1981: i386_func_bitop (src, dest, size, "btr");
1982: }
1983:
1984: void i386_func_bset (ea_t *src, ea_t *dest, int size)
1985: {
1986: i386_func_bitop (src, dest, size, "bts");
1987: }
1988:
1989: void i386_func_btst (ea_t *src, ea_t *dest, int size)
1990: {
1991: int len = size2len [size];
1992:
1993: xflush_all ();
1994:
1995: if (is_immediate (src)) {
1996: xold_readea (dest, 1, 0);
1997: xold_readea (dest, 1, 1);
1998: xold_readea (dest, 1, 1);
1999:
2000: xln ("btl $%d,%%ebx", src->imm.val & (len-1));
2001: xln ("setnc Z");
2002:
2003: x_postea (dest);
2004: return;
2005: }
2006:
2007: xold_readea (src, 0, 0);
2008: xold_readea (dest, 1, 0);
2009: xold_readea (src, 0, 1);
2010: xold_readea (dest, 1, 1);
2011: xold_readea (src, 0, 1);
2012: xold_readea (dest, 1, 1);
2013:
2014: if (size == BYTE) xln ("andl $7,%%eax");
2015: xln ("btl %%eax,%%ebx", src->imm.val);
2016: xln ("setnc Z");
2017:
2018: x_postea (src);
2019: x_postea (dest);
2020: }
2021:
2022: void i386_func_muls (ea_t *src, ea_t *dest)
2023: {
2024: assert (dest->mode == 0);
2025: src->op_size = WORD;
2026: x_loadval (src, -1, XCAN_OVERWRITE);
2027: dest->op_size = WORD;
2028: x_loadval (dest, -1, 0);//XSIGN_EXTEND_REGS);
2029:
2030: xln ("movswl %s,%s", src->identifier, xreg (src->x86_reg, LONG));
2031: xln ("movswl %s,%s", dest->identifier, xreg (dest->x86_reg, LONG));
2032:
2033: xln ("imull %s,%s", xreg (src->x86_reg, LONG), xreg (dest->x86_reg, LONG));
2034: ifNVC xln ("movb $0,C");
2035: ifNVC xln ("movb $0,V");
2036: ifZNVC xln ("testl %s,%s", xreg (dest->x86_reg, LONG), xreg (dest->x86_reg, LONG));
2037: ifNVC xln ("sets N");
2038: ifZ xln ("setz Z");
2039:
2040: xdirty_reg (dest->x86_reg);
2041: x_saveval (dest, WORD);
2042: x_postea (src);
2043: x_postea (dest);
2044: }
2045: void i386_func_mulu (ea_t *src, ea_t *dest)
2046: {
2047: xflush_all ();
2048: xold_readea2 (src, 1, 0, XQUICK_REGS);
2049: xold_readea2 (dest, 0, 0, XQUICK_REGS);
2050: xold_readea2 (src, 1, 1, XQUICK_REGS);
2051: xold_readea2 (dest, 0, 1, XQUICK_REGS);
2052: xold_readea2 (src, 1, 1, XQUICK_REGS);
2053: xold_readea2 (dest, 0, 1, XQUICK_REGS);
2054:
2055: xln ("movzwl %s,%%ebx", src->identifier);
2056: xln ("movzwl %s,%%eax", dest->identifier);
2057:
2058: xln ("mull %%ebx");
2059: ifNVC xln ("movb $0,C");
2060: ifNVC xln ("movb $0,V");
2061: ifZNVC xln ("testl %%eax,%%eax");
2062: ifNVC xln ("sets N");
2063: ifZ xln ("setz Z");
2064:
2065: /* hack - force writeback, because we didn't operate in-place */
2066: dest->do_writeback = 1;
2067:
2068: xold_writeea (dest, LONG, EAX, 0);
2069: xold_writeea (dest, LONG, EAX, 1);
2070: xold_writeea (dest, LONG, EAX, 1);
2071: x_postea (src);
2072: x_postea (dest);
2073: }
2074:
2075: void i386_func_logop (ea_t *src, ea_t *dest, int size, char op)
2076: {
2077: x_loadval (src, -1, XQUICK_REGS | XQUICK_IMMS);
2078: x_loadval (dest, -1, XQUICK_WRITEBACK);
2079:
2080: switch (op) {
2081: case '&': xln ("and%s %s,%s", szmov [size], src->identifier, dest->identifier); break;
2082: case '|': xln ("or%s %s,%s", szmov [size], src->identifier, dest->identifier); break;
2083: case '^': xln ("xor%s %s,%s", szmov [size], src->identifier, dest->identifier); break;
2084: default: assert (0);
2085: }
2086:
2087: ifNVC xln ("sets N");
2088: ifZ xln ("setz Z");
2089: ifNVC xln ("movb $0,V");
2090: ifNVC xln ("movb $0,C");
2091:
2092: xdirty_reg (dest->x86_reg);
2093: x_saveval (dest, size);
2094: x_postea (src);
2095: x_postea (dest);
2096: }
2097:
2098: void i386_func_not (ea_t *ea, int size)
2099: {
2100: int flags = XQUICK_WRITEBACK;
2101: /* mem to mem operations are crap */
2102: //ifZNVC {} else flags |= XQUICK_REGS;
2103:
2104: x_loadval (ea, -1, flags);
2105:
2106: xln ("not%s %s", szmov [size], ea->identifier);
2107:
2108: ifZNVC xln ("test%s %s,%s", szmov [size], ea->identifier, ea->identifier);
2109: ifNVC xln ("sets N");
2110: ifZ xln ("setz Z");
2111: ifNVC xln ("movb $0,V");
2112: ifNVC xln ("movb $0,C");
2113:
2114: xdirty_reg (ea->x86_reg);
2115: x_saveval (ea, size);
2116: x_postea (ea);
2117: }
2118:
2119: void i386_func_negx (ea_t *ea, int size)
2120: {
2121: xflush_all ();
2122: xold_readea (ea, 0, 0);
2123: xold_readea (ea, 0, 1);
2124: xold_readea (ea, 0, 1);
2125:
2126: // XXX this is crap. do without jumps (negx)
2127: // then again, negx and subx caused so many problems
2128: // and took so long to get right that who cares..
2129: xln ("xorl %%ebx,%%ebx");
2130: xln ("movb X,%%cl");
2131: xln ("testb %%cl,%%cl");
2132: xln ("jz 1f");
2133: xln ("stc");
2134: xln ("jmp 2f");
2135:
2136: xout ("1:\n");
2137: xln ("clc");
2138:
2139: xout ("2:\n");
2140: xln ("sbb%s %s,%s", szmov [size], sreg (EAX), sreg (EBX));
2141: ifNVC {
2142: xln ("sets N");
2143: xln ("seto V");
2144: xln ("setc C");
2145: }
2146: xln ("setc X");
2147: ifZ {
2148: xln ("test%s %s,%s", szmov[size], sreg (EBX), sreg (EBX));
2149: xln ("jz 1f");
2150: xln ("movb $0,Z");
2151: xout ("1:\n");
2152: }
2153:
2154: xold_writeea (ea, size, EBX, 0);
2155: xold_writeea (ea, size, EBX, 1);
2156: xold_writeea (ea, size, EBX, 1);
2157: x_postea (ea);
2158: }
2159: void i386_func_neg (ea_t *ea, int size)
2160: {
2161: x_loadval (ea, -1, XQUICK_WRITEBACK);
2162:
2163: xln ("neg%s %s", szmov [size], ea->identifier);
2164: ifNVC {
2165: xln ("sets N");
2166: xln ("seto V");
2167: xln ("setc C");
2168: }
2169: ifZ xln ("setz Z");
2170: xln ("setc X");
2171:
2172: xdirty_reg (ea->x86_reg);
2173: x_saveval (ea, size);
2174: x_postea (ea);
2175: }
2176:
2177: void i386_func_divu (ea_t *ea, int reg)
2178: {
2179: xflush_all ();
2180: ea->op_size = WORD;
2181: xold_readea (ea, 1, 0);
2182: xold_readea (ea, 1, 1);
2183: xold_readea (ea, 1, 1);
2184:
2185: xln ("movl %d(%%ebp),%%eax", regpos (reg));
2186: xln ("movzwl %%bx,%%ebx");
2187: xln ("xorl %%edx,%%edx");
2188: xln ("divl %%ebx");
2189:
2190: xln ("testl $0xffff0000,%%eax");
2191: /* overflow */
2192: xln ("jnz 1f");
2193:
2194: ifZNVC xln ("testl %%eax,%%eax");
2195: ifNVC xln ("sets N");
2196: ifZ xln ("setz Z");
2197: ifNVC xln ("movb $0,V");
2198: ifNVC xln ("movb $0,C");
2199:
2200: xln ("shll $16,%%edx");
2201: xln ("movw %%ax,%%dx");
2202:
2203: xln ("movl %%edx,%d(%%ebp)", regpos (reg));
2204: xln ("jmp 2f");
2205: xout ("1:\n");
2206: ifZNVC {
2207: xln ("movb $0,C");
2208: xln ("movb $1,N");
2209: xln ("movb $0,Z");
2210: xln ("movb $1,V");
2211: }
2212: xout ("2:\n");
2213: x_postea (ea);
2214: }
2215:
2216: void i386_func_divs (ea_t *ea, int reg)
2217: {
2218: xflush_all ();
2219: ea->op_size = WORD;
2220: xold_readea (ea, 1, 0);
2221: xold_readea (ea, 1, 1);
2222: xold_readea (ea, 1, 1);
2223:
2224: xln ("movl %d(%%ebp),%%eax", regpos (reg));
2225: xln ("movswl %%bx,%%ebx");
2226: /* sign-extend eax into edx */
2227: xln ("cltd");
2228: xln ("idivl %%ebx");
2229: xln ("jmp 3f");
2230: /* success */
2231: xout ("1:\n");
2232:
2233: ifZNVC xln ("testl %%eax,%%eax");
2234: ifNVC xln ("sets N");
2235: ifZ xln ("setz Z");
2236:
2237: xln ("shll $16,%%edx");
2238: ifNVC xln ("movb $0,V");
2239: xln ("movw %%ax,%%dx");
2240: ifNVC xln ("movb $0,C");
2241: xln ("movl %%edx,%d(%%ebp)", regpos (reg));
2242: xln ("jmp 2f");
2243: /* overflow */
2244: xout ("3:\n");
2245: xln ("movl %%eax,%%ecx");
2246: xln ("andl $0xffff8000,%%ecx");
2247: xln ("jz 1b");
2248: xln ("cmpl $0xffff8000,%%ecx");
2249: xln ("jz 1b");
2250: ifNVC {
2251: xln ("movb $0,C");
2252: xln ("movb $1,N");
2253: xln ("movb $1,V");
2254: } ifZ xln ("movb $0,Z");
2255: xout ("2:\n");
2256: x_postea (ea);
2257: }
2258:
2259: /* src is the shift */
2260: /* these are such cunts */
2261: void i386_func_asl (ea_t *src, ea_t *dest, int size)
2262: {
2263: /* special case we can optimise happily. no flags except X || Z needed, and
2264: * immediate src, reg dest. */
2265: ifNVC { } else if (is_immediate (src) && is_reg (dest)) {
2266: x_loadval (src, -1, XQUICK_IMMS);
2267: x_loadval (dest, -1, XQUICK_WRITEBACK);
2268:
2269: xln ("shl%s %s,%s", szmov [size], src->identifier, dest->identifier);
2270: xln ("setc X");
2271: ifZ xln ("setz Z");
2272:
2273: xdirty_reg (dest->x86_reg);
2274: x_saveval (dest, size);
2275: x_postea (src);
2276: x_postea (dest);
2277: return;
2278: }
2279: xflush_all ();
2280: xold_readea (src, 0, 0);
2281: xold_readea (dest, 1, 0);
2282: xold_readea (src, 0, 1);
2283: xold_readea (dest, 1, 1);
2284: xold_readea (src, 0, 1);
2285: xold_readea (dest, 1, 1);
2286:
2287: /* sets flags wrong. can use with flag optimisations one day */
2288:
2289: /* V flag not set by sal on x86 :( */
2290:
2291: xln ("and%s $63,%s", szmov[size], sreg (EAX));
2292: xln ("cmp%s $%d,%s", szmov[size], size2len[size], sreg (EAX));
2293: xln ("jl 2f");
2294:
2295: xln ("test%s %s,%s", szmov[size], sreg (EBX), sreg (EBX));
2296: xln ("setnz V");
2297: xln ("movb $1,Z");
2298: xln ("movb $0,N");
2299: /* XXX what should be done about C and X... */
2300: xln ("xor%s %s,%s", szmov[size], sreg (EBX), sreg (EBX));
2301: xln ("jmp 4f");
2302:
2303: /* mask in edx */
2304: xout ("2:\n");
2305: ifNVC {
2306: xln ("movb $%d,%%cl", size2len[size]-1);
2307: xln ("mov%s $0x%s,%s", szmov[size],
2308: (size == BYTE ? "ff" :
2309: (size == WORD ? "ffff" : "ffffffff")), sreg (EDX));
2310: xln ("subb %%al,%%cl");
2311: xln ("movb $0,V");
2312: xln ("shl%s %%cl,%s", szmov[size], sreg (EDX));
2313: xln ("mov%s %s,%s", szmov[size], sreg (EDX), sreg (ECX));
2314:
2315: /* V = ((val & mask) != mask &&)
2316: * ((val & mask != 0) */
2317: xln ("test%s %s,%s", szmov[size], sreg (EBX), sreg (EDX));
2318: xln ("jz 3f");
2319: xln ("and%s %s,%s", szmov[size], sreg (EBX), sreg (EDX));
2320: xln ("cmp%s %s,%s", szmov[size], sreg (ECX), sreg (EDX));
2321: xln ("setnz V");
2322: /* ^^ huge amount of code for one fucking flag... */
2323:
2324: xout ("3:\n");
2325: }
2326: xln ("movb %%al,%%cl");
2327: xln ("shl%s %%cl,%s", szmov [size], sreg (EBX));
2328:
2329: ifNVC {
2330: xln ("sets N");
2331: xln ("setc C");
2332: }
2333: xln ("setc X");
2334:
2335: if (!is_immediate (src)) {
2336: /* shifts of zero bits set the Z flag on x86, apparently */
2337: /* (immediate shifts can't be zero) */
2338: ifZ xln ("test%s %s,%s", szmov[size], sreg (EBX), sreg (EBX));
2339: }
2340: ifZ xln ("setz Z");
2341:
2342: xout ("4:\n");
2343:
2344: xold_writeea (dest, size, EBX, 0);
2345: xold_writeea (dest, size, EBX, 1);
2346: xold_writeea (dest, size, EBX, 1);
2347: x_postea (src);
2348: x_postea (dest);
2349: }
2350:
2351: void i386_func_lsl (ea_t *src, ea_t *dest, int size)
2352: {
2353: x_loadval (src, ECX, XQUICK_IMMS);
2354: x_loadval (dest, -1, XQUICK_WRITEBACK);
2355:
2356: if (is_immediate (src)) {
2357: xln ("shl%s %s,%s", szmov [size], src->identifier, dest->identifier);
2358: } else {
2359: xln ("shl%s %%cl,%s", szmov [size], dest->identifier);
2360: }
2361:
2362: ifZ xln ("setz Z");
2363: ifNVC {
2364: xln ("sets N");
2365: xln ("setc C");
2366: xln ("movb $0,V");
2367: }
2368: ifX xln ("setc X");
2369:
2370: xdirty_reg (dest->x86_reg);
2371: x_saveval (dest, size);
2372: x_postea (src);
2373: x_postea (dest);
2374: #if 0
2375: xflush_all ();
2376: xold_readea2 (src, 0, 0, XQUICK_REGS | XQUICK_IMMS);
2377: xold_readea2 (dest, 1, 0, XQUICK_REGS);
2378: xold_readea2 (src, 0, 1, XQUICK_REGS | XQUICK_IMMS);
2379: xold_readea2 (dest, 1, 1, XQUICK_REGS);
2380: xold_readea2 (src, 0, 1, XQUICK_REGS | XQUICK_IMMS);
2381: xold_readea2 (dest, 1, 1, XQUICK_REGS);
2382:
2383: if (is_immediate (src)) {
2384: xln ("shl%s %s,%s", szmov [size], src->identifier, dest->identifier);
2385: } else {
2386: xln ("movl %s,%%ecx", src->identifier);
2387: xln ("shl%s %%cl,%s", szmov [size], dest->identifier);
2388: }
2389:
2390: ifZ xln ("setz Z");
2391: ifNVC {
2392: xln ("sets N");
2393: xln ("setc C");
2394: xln ("movb $0,V");
2395: }
2396: xln ("setc X");
2397:
2398: xold_writeea (dest, size, EBX, 0);
2399: xold_writeea (dest, size, EBX, 1);
2400: xold_writeea (dest, size, EBX, 1);
2401: x_postea (src);
2402: x_postea (dest);
2403: #endif
2404: }
2405:
2406: void i386_func_roxr (ea_t *src, ea_t *dest, int size)
2407: {
2408: xflush_all ();
2409: if ((src->mode != F_IMM) && (src->imm.val != 1)) {
2410: error ("X86 output of roxr unfinished. Only supports 1 bit immediate shifts.");
2411: }
2412:
2413: xold_readea (dest, 1, 0);
2414: xold_readea (dest, 1, 1);
2415: xold_readea (dest, 1, 1);
2416:
2417: xln ("movb X,%%al");
2418: xln ("shr%s $1,%s", szmov [size], sreg (EBX));
2419: ifNVC xln ("setc C");
2420: xln ("setc X");
2421: xln ("shl%s $%d,%s", szmov[size], size2len [size]-1, sreg (EAX));
2422: ifNVC xln ("movb $0,V");
2423: xln ("or%s %s,%s", szmov [size], sreg (EAX), sreg (EBX));
2424: ifZNVC xln ("test%s %s,%s", szmov [size], sreg (EBX), sreg (EBX));
2425: ifNVC xln ("sets N");
2426: ifZ xln ("setz Z");
2427:
2428: xold_writeea (dest, size, EBX, 0);
2429: xold_writeea (dest, size, EBX, 1);
2430: xold_writeea (dest, size, EBX, 1);
2431: x_postea (dest);
2432: }
2433: void i386_func_roxl (ea_t *src, ea_t *dest, int size)
2434: {
2435: xflush_all ();
2436: if ((src->mode != F_IMM) && (src->imm.val != 1)) {
2437: error ("X86 output of roxr unfinished. Only supports 1 bit immediate shifts.");
2438: }
2439:
2440: xold_readea (dest, 1, 0);
2441: xold_readea (dest, 1, 1);
2442: xold_readea (dest, 1, 1);
2443:
2444: xln ("movzbl X,%%eax");
2445: xln ("shl%s $1,%s", szmov [size], sreg (EBX));
2446: ifNVC xln ("setc C");
2447: xln ("setc X");
2448: xln ("or%s %s,%s", szmov [size], sreg (EAX), sreg (EBX));
2449: ifNVC xln ("movb $0,V");
2450: ifZNVC xln ("test%s %s,%s", szmov [size], sreg (EBX), sreg (EBX));
2451: ifNVC xln ("sets N");
2452: ifZ xln ("setz Z");
2453:
2454: xold_writeea (dest, size, EBX, 0);
2455: xold_writeea (dest, size, EBX, 1);
2456: xold_writeea (dest, size, EBX, 1);
2457: x_postea (dest);
2458: }
2459: void i386_func_rol (ea_t *src, ea_t *dest, int size)
2460: {
2461: int len;
2462: len = size2len[size];
2463: /* fast case */
2464: ifZNVC {} else if (is_immediate (src)) {
2465: x_loadval (src, -1, XQUICK_IMMS);
2466: x_loadval (dest, -1, XQUICK_REGS);
2467:
2468: xln ("rol%s %s,%s", szmov [size], src->identifier, dest->identifier);
2469:
2470: xdirty_reg (dest->x86_reg);
2471: x_saveval (dest, size);
2472: x_postea (src);
2473: x_postea (dest);
2474: return;
2475: }
2476: xflush_all ();
2477: src->op_size = BYTE;
2478: xold_readea (src, 0, 0);
2479: xold_readea (dest, 1, 0);
2480: xold_readea (src, 0, 1);
2481: xold_readea (dest, 1, 1);
2482: xold_readea (src, 0, 1);
2483: xold_readea (dest, 1, 1);
2484:
2485: xln ("movb %%al,%%cl");
2486: xln ("decb %%cl");
2487: xln ("rol%s %%cl,%s", szmov [size], sreg (EBX));
2488: xln ("btl $%d,%%ebx", len-1);
2489: ifNVC xln ("setc C");
2490: xln ("rol%s $1,%s", szmov [size], sreg (EBX));
2491: ifNVC xln ("movb $0,V");
2492: ifZNVC xln ("test%s %s,%s", szmov [size], sreg (EBX), sreg (EBX));
2493: ifNVC xln ("sets N");
2494: ifZ xln ("setz Z");
2495:
2496: xold_writeea (dest, size, EBX, 0);
2497: xold_writeea (dest, size, EBX, 1);
2498: xold_writeea (dest, size, EBX, 1);
2499: x_postea (src);
2500: x_postea (dest);
2501: }
2502:
2503: void i386_func_ror (ea_t *src, ea_t *dest, int size)
2504: {
2505: /* fast case */
2506: ifZNVC {} else if (is_immediate (src)) {
2507: x_loadval (src, -1, XQUICK_IMMS);
2508: x_loadval (dest, -1, 0);
2509:
2510: xln ("ror%s %s,%s", szmov [size], src->identifier, dest->identifier);
2511:
2512: xdirty_reg (dest->x86_reg);
2513: x_saveval (dest, size);
2514: x_postea (src);
2515: x_postea (dest);
2516: return;
2517: }
2518: xflush_all ();
2519: xold_readea (src, 0, 0);
2520: xold_readea (dest, 1, 0);
2521: xold_readea (src, 0, 1);
2522: xold_readea (dest, 1, 1);
2523: xold_readea (src, 0, 1);
2524: xold_readea (dest, 1, 1);
2525:
2526: /* x86 ror doesn't set flags... */
2527: xln ("movb %%al,%%cl");
2528: xln ("decb %%cl");
2529: xln ("ror%s %%cl,%s", szmov [size], sreg (EBX));
2530: xln ("btl $0,%%ebx");
2531: ifNVC xln ("setc C");
2532: xln ("ror%s $1,%s", szmov [size], sreg (EBX));
2533: ifNVC xln ("movb $0,V");
2534: ifZNVC xln ("test%s %s,%s", szmov [size], sreg (EBX), sreg (EBX));
2535: ifNVC xln ("sets N");
2536: ifZ xln ("setz Z");
2537:
2538: xold_writeea (dest, size, EBX, 0);
2539: xold_writeea (dest, size, EBX, 1);
2540: xold_writeea (dest, size, EBX, 1);
2541: x_postea (src);
2542: x_postea (dest);
2543: }
2544:
2545: void i386_func_asr (ea_t *src, ea_t *dest, int size)
2546: {
2547: /* special case we can optimise happily. immediate src. */
2548: if (is_immediate (src) && is_reg (dest)) {
2549: x_loadval (src, -1, XQUICK_IMMS);
2550: x_loadval (dest, -1, XQUICK_WRITEBACK);
2551:
2552: xln ("sar%s %s,%s", szmov [size], src->identifier, dest->identifier);
2553: ifNVC {
2554: xln ("seto V");
2555: xln ("setc C");
2556: }
2557: ifX xln ("setc X");
2558: ifZ xln ("setz Z");
2559: ifNVC xln ("sets N");
2560:
2561: xdirty_reg (dest->x86_reg);
2562: x_saveval (dest, size);
2563: x_postea (src);
2564: x_postea (dest);
2565: return;
2566: }
2567: xflush_all ();
2568: xold_readea (src, 0, 0);
2569: xold_readea (dest, 1, 0);
2570: xold_readea (src, 0, 1);
2571: xold_readea (dest, 1, 1);
2572: xold_readea (src, 0, 1);
2573: xold_readea (dest, 1, 1);
2574:
2575: /* XXX warning if correct shift count zero behaviour matters then uncomment these */
2576: // xln ("movb X,%%ch");
2577: xln ("movb %%al,%%cl");
2578: xln ("cmpb $%d,%%al", size2len[size]);
2579: xln ("jns 2f");
2580: xln ("sar%s %%cl,%s", szmov [size], sreg (EBX));
2581:
2582: ifNVC {
2583: xln ("seto V");
2584: xln ("setc C");
2585: }
2586: ifX xln ("setc X");
2587: ifZ xln ("setz Z");
2588: ifNVC xln ("sets N");
2589:
2590: /* shift count zero do not set X... */
2591: // xln ("testb %%al,%%al");
2592: // xln ("jnz 1f");
2593:
2594: // xln ("movb %%ch,X");
2595:
2596: xout ("1:\n");
2597: /* shift count > thingy. smeg */
2598: // xln ("cmpb $%d,%%al", size2len[size]);
2599: // xln ("jns 2f");
2600:
2601: //ifZNVC xln ("test%s %s,%s", szmov[size], sreg (EBX), sreg (EBX));
2602: //ifZ xln ("setz Z");
2603:
2604: /* Sign flag is crap with val=0 */
2605: //ifNVC xln ("sets N");
2606:
2607: xln ("jmp 3f");
2608: xout ("2:\n");
2609: xln ("mov%s $0,%s", szmov[size], sreg (EBX));
2610: xln ("movb $0,Z");
2611: xout ("3:\n");
2612:
2613: xold_writeea (dest, size, EBX, 0);
2614: xold_writeea (dest, size, EBX, 1);
2615: xold_writeea (dest, size, EBX, 1);
2616: x_postea (src);
2617: x_postea (dest);
2618: }
2619: void i386_func_lsr (ea_t *src, ea_t *dest, int size)
2620: {
2621: /* special case we can optimise happily. no flags except X || Z needed, and
2622: * immediate src, reg dest. */
2623: if (is_immediate (src) && is_reg (dest)) {
2624: x_loadval (src, -1, XQUICK_IMMS);
2625: x_loadval (dest, -1, XQUICK_WRITEBACK);
2626:
2627: xln ("shr%s %s,%s", szmov [size], src->identifier, dest->identifier);
2628: ifZ xln ("setz Z");
2629: ifX xln ("setc X");
2630: ifNVC {
2631: xln ("sets N");
2632: xln ("setc C");
2633: xln ("movb $0,V");
2634: }
2635:
2636: xdirty_reg (dest->x86_reg);
2637: x_saveval (dest, size);
2638: x_postea (src);
2639: x_postea (dest);
2640: return;
2641: }
2642: xflush_all ();
2643: xold_readea2 (src, 0, 0, XQUICK_REGS);
2644: xold_readea2 (dest, 1, 0, XQUICK_REGS);
2645: xold_readea2 (src, 0, 1, XQUICK_REGS);
2646: xold_readea2 (dest, 1, 1, XQUICK_REGS);
2647: xold_readea2 (src, 0, 1, XQUICK_REGS);
2648: xold_readea2 (dest, 1, 1, XQUICK_REGS);
2649:
2650: xln ("movl %s,%%ecx", src->identifier);
2651: xln ("movb X,%%ah");
2652: xln ("shr%s %%cl,%s", szmov [size], dest->identifier);
2653:
2654: ifZ xln ("setz Z");
2655: xln ("setc X");
2656: ifNVC {
2657: xln ("sets N");
2658: xln ("setc C");
2659: xln ("movb $0,V");
2660: }
2661:
2662: /* shift count of zero is special.. (and never in immediate case) */
2663: if (!is_immediate (src)) {
2664: xln ("testb %%al,%%al");
2665: xln ("jnz 1f");
2666: xln ("movb $0,C");
2667: xln ("movb %%ah,X");
2668: }
2669:
2670: xout ("1:\n");
2671: xold_writeea (dest, size, EBX, 0);
2672: xold_writeea (dest, size, EBX, 1);
2673: xold_writeea (dest, size, EBX, 1);
2674: x_postea (src);
2675: x_postea (dest);
2676: }
2677:
2678: void i386_func_movem (ea_t *ea, int sz, int dr, int reg_mask)
2679: {
2680: int i, offset, reg;
2681: sz++;
2682: ea_t dummy;
2683:
2684: x_loadea (ea);
2685:
2686: if (dr == 0) {
2687: /* reg to memory */
2688: if (ea->mode == 4) {
2689: /* pre-decrement mode */
2690: offset = 0;
2691: for (i=0; i<16; i++) {
2692: if (reg_mask & (1<<i)) {
2693: reg = xcopy_reg (15-i, sz, -1);
2694: do_bswap (reg, sz);
2695: xln ("mov%s %s,-%d(%%ebp,%s)", szmov[sz], xreg (reg, sz), offset, ea->identifier);
2696: xreg_unlock (reg);
2697: offset += 1<<sz;
2698: }
2699: }
2700: reg = xload_reg (ea->reg, LONG, -1);
2701: xln ("subl $%d,%s", offset, xreg (reg, LONG));
2702: xdirty_reg (reg);
2703: xreg_unlock (reg);
2704: } else {
2705: offset = 0;
2706: for (i=0; i<16; i++) {
2707: if (reg_mask & (1<<i)) {
2708: reg = xcopy_reg (i, sz, -1);
2709: do_bswap (reg, sz);
2710: xln ("mov%s %s,%d(%%ebp,%s)", szmov[sz], xreg (reg, sz), offset, ea->identifier);
2711: xreg_unlock (reg);
2712: offset += 1<<sz;
2713: }
2714: }
2715: }
2716: } else {
2717:
2718: /* mem to reg */
2719: offset = 0;
2720: for (i=0; i<16; i++) {
2721: if (reg_mask & (1<<i)) {
2722: dummy.mode = 0;
2723: dummy.op_size = LONG;
2724: dummy.x86_reg = -1;
2725: dummy.x86_reg_writeback = -1;
2726: dummy.reg = i;
2727: reg = xalloc_reg (sz, -1);
2728: x_ea_set_val_2_reg (&dummy, LONG, reg);
2729:
2730: xln ("mov%s %d(%%ebp,%s),%s", szmov[sz], offset, ea->identifier, xreg (reg, sz));
2731: do_bswap (reg, sz);
2732: if (sz == WORD) xln ("movswl %s,%s", xreg (reg, WORD), xreg (reg, LONG));
2733: offset += 1<<sz;
2734:
2735: /* once for xalloc_reg and once for x_ea_set_val_2_reg */
2736: xreg_unlock (reg);
2737: xreg_unlock (reg);
2738: }
2739: }
2740: /* post-inc mode */
2741: if (ea->mode == 3) {
2742: reg = xload_reg (ea->reg, LONG, -1);
2743: xln ("addl $%d,%s", offset, xreg (reg, LONG));
2744: xdirty_reg (reg);
2745: xreg_unlock (reg);
2746: }
2747: }
2748: /* deallocate temporary register allocations */
2749: if (ea->x86_reg != -1) {
2750: xreg_unlock (ea->x86_reg);
2751: }
2752: }
2753:
2754: void i386_func_subx (ea_t *src, ea_t *dest, int size)
2755: {
2756: xflush_all ();
2757: xold_readea (src, 0, 0);
2758: xold_readea (dest, 1, 0);
2759: xold_readea (src, 0, 1);
2760: xold_readea (dest, 1, 1);
2761: xold_readea (src, 0, 1);
2762: xold_readea (dest, 1, 1);
2763:
2764: /* fucking X flag */
2765: ifNVCX {
2766: xln ("mov%s %s,%s", szmov[size], sreg (EAX), sreg (ECX));
2767: xln ("mov%s %s,%s", szmov[size], sreg (EBX), sreg (EDX));
2768: xln ("shr%s $%d,%s", szmov[size], size2len[size]-1, sreg (ECX));
2769: xln ("shr%s $%d,%s", szmov[size], size2len[size]-1, sreg (EDX));
2770: }
2771: xln ("add%s X,%s", szmov [size], sreg (EAX));
2772: xln ("sub%s %s,%s", szmov [size], sreg (EAX), sreg (EBX));
2773:
2774: ifNVC {
2775: xln ("sets N");
2776: xln ("seto V");
2777: }
2778:
2779: ifZ {
2780: xln ("jz 1f");
2781: xln ("movb $0,Z");
2782: xout ("1:\n");
2783: }
2784:
2785: ifNVCX {
2786: /* fucking X flag */
2787: xln ("mov%s %s,%s", szmov[size], sreg (EBX), sreg (EAX));
2788: xln ("shr%s $%d,%s", szmov[size], size2len[size]-1, sreg (EAX));
2789: /* ecx=flgs, edx=flgo, eax=flgn */
2790: xln ("xor%s %s,%s", szmov[size], sreg (EAX), sreg (EDX));
2791: xln ("xor%s %s,%s", szmov[size], sreg (ECX), sreg (EAX));
2792: xln ("and%s %s,%s", szmov[size], sreg (EDX), sreg (EAX));
2793: xln ("xor%s %s,%s", szmov[size], sreg (EAX), sreg (ECX));
2794: ifX xln ("movb %%cl,X");
2795: ifNVC xln ("movb %%cl,C");
2796: }
2797:
2798: xold_writeea (dest, size, EBX, 0);
2799: xold_writeea (dest, size, EBX, 1);
2800: xold_writeea (dest, size, EBX, 1);
2801: x_postea (src);
2802: x_postea (dest);
2803: }
2804:
2805: void i386_func_addx (ea_t *src, ea_t *dest, int size)
2806: {
2807: xflush_all ();
2808: xold_readea (src, 0, 0);
2809: xold_readea (dest, 1, 0);
2810: xold_readea (src, 0, 1);
2811: xold_readea (dest, 1, 1);
2812: xold_readea (src, 0, 1);
2813: xold_readea (dest, 1, 1);
2814:
2815: /* fucking X flag */
2816: ifNVCX {
2817: xln ("mov%s %s,%s", szmov[size], sreg (EAX), sreg (ECX));
2818: xln ("mov%s %s,%s", szmov[size], sreg (EBX), sreg (EDX));
2819: xln ("shr%s $%d,%s", szmov[size], size2len[size]-1, sreg (ECX));
2820: xln ("shr%s $%d,%s", szmov[size], size2len[size]-1, sreg (EDX));
2821: }
2822: xln ("add%s X,%s", szmov [size], sreg (EAX));
2823: xln ("add%s %s,%s", szmov [size], sreg (EAX), sreg (EBX));
2824:
2825: ifNVC {
2826: xln ("sets N");
2827: xln ("seto V");
2828: }
2829:
2830: ifZ {
2831: xln ("jz 1f");
2832: xln ("movb $0,Z");
2833: xout ("1:\n");
2834: }
2835:
2836: ifNVCX {
2837: /* fucking X flag */
2838: xln ("mov%s %s,%s", szmov[size], sreg (EBX), sreg (EAX));
2839: xln ("shr%s $%d,%s", szmov[size], size2len[size]-1, sreg (EAX));
2840: /* ecx=flgs, edx=flgo, eax=flgn */
2841: xln ("xor%s %s,%s", szmov[size], sreg (EDX), sreg (EAX));
2842: xln ("xor%s %s,%s", szmov[size], sreg (ECX), sreg (EDX));
2843: xln ("and%s %s,%s", szmov[size], sreg (EDX), sreg (EAX));
2844: xln ("xor%s %s,%s", szmov[size], sreg (EAX), sreg (ECX));
2845: ifX xln ("movb %%cl,X");
2846: ifNVC xln ("movb %%cl,C");
2847: }
2848: xold_writeea (dest, size, EBX, 0);
2849: xold_writeea (dest, size, EBX, 1);
2850: xold_writeea (dest, size, EBX, 1);
2851: x_postea (src);
2852: x_postea (dest);
2853: }
2854:
2855: void i386_func_add (ea_t *src, ea_t *dest, int size)
2856: {
2857: x_loadval (src, -1, XQUICK_REGS | XQUICK_IMMS);
2858: x_loadval (dest, -1, XQUICK_WRITEBACK);
2859:
2860: xln ("add%s %s,%s", szmov [size], src->identifier, dest->identifier);
2861:
2862: ifNVC {
2863: xln ("sets N");
2864: xln ("seto V");
2865: xln ("setc C");
2866: }
2867: ifZ xln ("setz Z");
2868: ifX xln ("setc X");
2869:
2870: xdirty_reg (dest->x86_reg);
2871: x_saveval (dest, size);
2872: x_postea (src);
2873: x_postea (dest);
2874: }
2875:
2876: void i386_func_cmpa (ea_t *src, ea_t *dest, int size)
2877: {
2878: src->op_size = size;
2879: dest->op_size = LONG;
2880: x_loadval (src, -1, (size != WORD ? 0 : XCAN_OVERWRITE));
2881: x_loadval (dest, -1, 0);
2882:
2883: if (size == WORD) xln ("movswl %s,%s", xreg (src->x86_reg, WORD), xreg (src->x86_reg, LONG));
2884:
2885: xln ("cmpl %s,%s", xreg (src->x86_reg, LONG), dest->identifier);
2886:
2887: ifNVC {
2888: xln ("sets N");
2889: xln ("seto V");
2890: xln ("setc C");
2891: }
2892: ifZ xln ("setz Z");
2893:
2894: x_postea (src);
2895: x_postea (dest);
2896: }
2897:
2898: void i386_func_cmp (ea_t *src, ea_t *dest, int size)
2899: {
2900: x_loadval (src, -1, XQUICK_IMMS);
2901: x_loadval (dest, -1, 0);
2902:
2903: xln ("cmp%s %s,%s", szmov [size], src->identifier, dest->identifier);
2904:
2905: ifNVC {
2906: xln ("sets N");
2907: xln ("seto V");
2908: xln ("setc C");
2909: }
2910: ifZ xln ("setz Z");
2911:
2912: x_postea (src);
2913: x_postea (dest);
2914: }
2915:
2916: void i386_func_sub (ea_t *src, ea_t *dest, int size)
2917: {
2918: x_loadval (src, -1, XQUICK_REGS | XQUICK_IMMS);
2919: x_loadval (dest, -1, XQUICK_WRITEBACK);
2920:
2921: xln ("sub%s %s,%s", szmov [size], src->identifier, dest->identifier);
2922:
2923: ifNVC {
2924: xln ("sets N");
2925: xln ("seto V");
2926: xln ("setc C");
2927: }
2928: ifZ xln ("setz Z");
2929: ifX xln ("setc X");
2930:
2931: xdirty_reg (dest->x86_reg);
2932: x_saveval (dest, size);
2933: x_postea (src);
2934: x_postea (dest);
2935: }
2936:
2937: void i386_func_adda (ea_t *src, ea_t *dest, int size)
2938: {
2939: src->op_size = size;
2940: dest->op_size = LONG;
2941: x_loadval (src, -1, (size != WORD ? 0 : XCAN_OVERWRITE));
2942: x_loadval (dest, -1, 0);
2943:
2944: if (size == WORD) xln ("movswl %s,%s", xreg (src->x86_reg, WORD), xreg (src->x86_reg, LONG));
2945:
2946: xln ("addl %s,%s", xreg (src->x86_reg, LONG), dest->identifier);
2947:
2948: xdirty_reg (dest->x86_reg);
2949: x_saveval (dest, LONG);
2950: x_postea (src);
2951: x_postea (dest);
2952: }
2953:
2954: void i386_func_suba (ea_t *src, ea_t *dest, int size)
2955: {
2956: src->op_size = size;
2957: dest->op_size = LONG;
2958: x_loadval (src, -1, (size != WORD ? 0 : XCAN_OVERWRITE));
2959: x_loadval (dest, -1, 0);
2960:
2961: if (size == WORD) xln ("movswl %s,%s", xreg (src->x86_reg, WORD), xreg (src->x86_reg, LONG));
2962:
2963: xln ("subl %s,%s", xreg (src->x86_reg, LONG), dest->identifier);
2964:
2965: xdirty_reg (dest->x86_reg);
2966: x_saveval (dest, LONG);
2967: x_postea (src);
2968: x_postea (dest);
2969: }
2970:
2971: void i386_func_swap (int reg)
2972: {
2973: struct ea_t ea;
2974:
2975: ea.mode = 0;
2976: ea.reg = reg;
2977: ea.op_size = LONG;
2978: ea.x86_reg = -1;
2979: ea.x86_reg_writeback = -1;
2980:
2981: ifZNVC {
2982: x_loadval (&ea, -1, 0);
2983: ifNVC xln ("movb $0,V");
2984: xln ("rorl $16,%s", ea.identifier);
2985: ifNVC xln ("movb $0,C");
2986: ifZNVC xln ("testl %s,%s", ea.identifier, ea.identifier);
2987: ifNVC xln ("sets N");
2988: ifZ xln ("setz Z");
2989: } else {
2990: x_loadval (&ea, -1, 0);
2991: xln ("rorl $16,%s", ea.identifier);
2992: }
2993: xdirty_reg (ea.x86_reg);
2994: x_saveval (&ea, LONG);
2995: x_postea (&ea);
2996: }
2997:
2998: void i386_func_jsr (ea_t *dest)
2999: {
3000: char buf[256];
3001: xflush_all ();
3002: snprintf (buf, sizeof (buf), "%x", cur_bitpos);
3003: add_label (buf, C_ADDR, cur_bitpos - BASE);
3004: add_fixup (0, C_ADDR, buf);
3005:
3006: /* XXX this is a bit inefficient, since the label is a
3007: * constant and could be bswapped at compile-time
3008: * -- but the scheduling makes this irrelevant */
3009: xln ("movl %d(%%ebp),%%ebx", regpos (15));
3010: xln ("movl $__D%x,%%eax", cur_bitpos);
3011: xln ("subl $4,%%ebx");
3012: xln ("bswap %%eax");
3013: xln ("movl %%ebx,%d(%%ebp)", regpos (15));
3014: xln ("movl %%eax,(%%ebp,%%ebx)");
3015:
3016: i386_jump (dest);
3017: }
3018:
3019: void i386_func_bcc (ea_t *dest, int cond)
3020: {
3021: xflush_all ();
3022: if (cond == 0) {
3023: i386_jump (dest);
3024: } else {
3025: x_cond_begin (cond);
3026: i386_jump_e (dest);
3027: x_cond_end (cond);
3028: }
3029: }
3030:
3031: /* XXX note: this does not call i386_jump and therefore does not
3032: * check for pending exceptions. an infinite DBcc loop will not
3033: * allow exceptions to occur.
3034: * does it matter? */
3035: void i386_func_dbcc (const char *label, int cond, int reg)
3036: {
3037: xflush_all ();
3038: if (cond == 1) {
3039: xln ("decw %d(%%ebp)", regpos (reg));
3040: xln ("cmpw $-1,%d(%%ebp)", regpos (reg));
3041: xln ("jne __N%s", label);
3042: } else {
3043: /* relies on naming of x_cond_begin labels */
3044: x_cond_begin (cond);
3045: xln ("jmp 10f");
3046: x_cond_end ();
3047: xln ("decw %d(%%ebp)", regpos (reg));
3048: xln ("cmpw $-1,%d(%%ebp)", regpos (reg));
3049: xln ("jne __N%s", label);
3050: xout ("10:\n");
3051: }
3052: }
3053:
3054: void i386_func_clr (ea_t *dest)
3055: {
3056: xflush_all ();
3057: xln ("xorl %%eax,%%eax");
3058: ifZ xln ("movb $1,Z");
3059: ifNVC xln ("movb %%al,N");
3060: ifNVC xln ("movb %%al,V");
3061: ifNVC xln ("movb %%al,C");
3062:
3063: xold_writeea (dest, dest->op_size, EAX, 0);
3064: xold_writeea (dest, dest->op_size, EAX, 1);
3065: xold_writeea (dest, dest->op_size, EAX, 1);
3066: x_postea (dest);
3067: }
3068:
3069: void i386_func_exg (int reg1, int reg2)
3070: {
3071: xflush_all ();
3072: xln ("movl %d(%%ebp),%%eax", regpos (reg1));
3073: xln ("movl %d(%%ebp),%%ebx", regpos (reg2));
3074: xln ("movl %%eax,%d(%%ebp)", regpos (reg2));
3075: xln ("movl %%ebx,%d(%%ebp)", regpos (reg1));
3076: }
3077:
3078: void i386_func_ext (int reg, int size)
3079: {
3080: int x86reg = xload_reg (reg, size-1, -1);
3081:
3082: if (size == WORD) {
3083: xln ("movsbw %s,%s", xreg (x86reg, BYTE), xreg (x86reg, WORD));
3084: } else {
3085: xln ("movswl %s,%s", xreg (x86reg, WORD), xreg (x86reg, LONG));
3086: }
3087:
3088: ifNVC xln ("movb $0,V");
3089: ifNVC xln ("movb $0,C");
3090: ifZNVC xln ("test%s %s,%s", szmov[size], xreg (x86reg,size), xreg (x86reg,size));
3091: ifZ xln ("setz Z");
3092: ifNVC xln ("sets N");
3093: xdirty_reg (x86reg);
3094: xreg_unlock (x86reg);
3095: }
3096:
3097: void i386_func_rte ()
3098: {
3099: xflush_all ();
3100: xln ("movb bX,%%bh");
3101: xln ("movb bN,%%bl");
3102: xln ("movb bZ,%%ch");
3103: xln ("movb bV,%%cl");
3104: xln ("movb bC,%%dh");
3105: xln ("movb %%bh,X");
3106: xln ("movb %%bl,N");
3107: xln ("movb %%ch,Z");
3108: xln ("movb %%cl,V");
3109: xln ("movb %%dh,C");
3110: xln ("movl rdest,%%eax");
3111: xln ("movl $0,rdest");
3112: //xln ("jmp jumptable");
3113: xln ("jmp *jtab(,%%eax,2)");
3114: }
3115:
3116: void i386_func_rts ()
3117: {
3118: xflush_all ();
3119: xln ("movl %d(%%ebp),%%ebx", regpos (15));
3120: xln ("movl (%%ebx,%%ebp),%%eax");
3121: xln ("addl $4,%%ebx");
3122: xln ("bswap %%eax");
3123: xln ("movl %%ebx,%d(%%ebp)", regpos (15));
3124: //xln ("jmp jumptable");
3125: xln ("jmp *jtab(,%%eax,2)");
3126: }
3127:
3128: void i386_func_illegal ()
3129: {
3130: xflush_all ();
3131: xln ("pushl line_no");
3132: xln ("pushl $illegal_fmt");
3133: xln ("call printf");
3134: xln ("addl $8,%%esp");
3135: xln ("call abort");
3136: }
3137:
3138: void i386_func_hcall (int val)
3139: {
3140: xflush_all ();
3141: xln ("call *hcalls+%d", val*4);
3142: }
3143:
3144: void i386_func_link (int reg, int val)
3145: {
3146: xflush_all ();
3147: xln ("movl %d(%%ebp),%%ebx", regpos (15));
3148: xln ("subl $4,%%ebx");
3149:
3150: xln ("movl %d(%%ebp),%%eax", regpos (reg));
3151: xln ("bswap %%eax");
3152:
3153: xln ("movl %%eax,(%%ebp,%%ebx)");
3154: xln ("addl $%d,%d(%%ebp)", val-4, regpos (15));
3155: xln ("movl %%ebx,%d(%%ebp)", regpos (reg));
3156: }
3157:
3158: void i386_func_unlk (int reg)
3159: {
3160: xflush_all ();
3161: xln ("movl %d(%%ebp),%%eax", regpos (reg));
3162: xln ("movl (%%ebp,%%eax),%%ebx");
3163: xln ("addl $4,%%eax");
3164: xln ("bswap %%ebx");
3165: xln ("movl %%ebx,%d(%%ebp)", regpos (reg));
3166: xln ("movl %%eax,%d(%%ebp)", regpos (15));
3167: }
3168:
3169: void i386_func_move (ea_t *src, ea_t *dest, int size)
3170: {
3171: x_loadval (src, -1, XQUICK_IMMS);
3172:
3173: ifNVC xln ("movb $0,V");
3174: ifNVC xln ("movb $0,C");
3175:
3176: if (is_immediate (src)) {
3177: ifZ xln ("movb $%d,Z", src->imm.val == 0);
3178: ifNVC xln ("movb $%d,N", src->imm.val < 0);
3179: } else {
3180: ifZNVC xln ("test%s %s,%s", szmov [size], src->identifier, src->identifier);
3181: ifZ xln ("setz Z");
3182: ifNVC xln ("sets N");
3183: }
3184:
3185: if (is_reg (dest)) {
3186: dest->x86_reg = xload_reg2 (dest->reg, size, -1, XLOADREG_FOR_OVERWRITE, szfull);
3187: } else {
3188: dest->x86_reg = xalloc_reg (size, -1);
3189: }
3190: xln ("mov%s %s,%s", szmov[size], src->identifier,
3191: xreg (dest->x86_reg, size));
3192: xdirty_reg (dest->x86_reg);
3193:
3194: x_saveval (dest, size);
3195: x_postea (src);
3196: x_postea (dest);
3197: }
3198:
3199: void i386_func_movea (ea_t *src, int reg_dest)
3200: {
3201: #if 0
3202: xflush_all ();
3203: xold_readea (src, 0, 0);
3204: xold_readea (src, 0, 1);
3205: xold_readea (src, 0, 1);
3206: if (src->op_size == WORD) xln ("movswl %%ax,%%eax");
3207: xln ("movl %%eax,%d(%%ebp)", regpos (reg_dest));
3208: x_postea (src);
3209: #endif
3210: int reg;
3211: struct ea_t dest;
3212:
3213: dest.mode = 1;
3214: dest.reg = reg_dest;
3215: dest.op_size = LONG;
3216: dest.x86_reg = -1;
3217: dest.x86_reg_writeback = -1;
3218:
3219: x_loadval (src, -1, 0);
3220:
3221: reg = xalloc_reg (LONG, -1);
3222:
3223: if (src->op_size == WORD)
3224: xln ("movswl %s,%s", xreg (src->x86_reg, WORD), xreg (reg, LONG));
3225: else
3226: xln ("movl %s,%s", xreg (src->x86_reg, LONG), xreg (reg, LONG));
3227:
3228: x_ea_set_val_2_reg (&dest, LONG, reg);
3229:
3230: xreg_unlock (reg);
3231: xdirty_reg (reg);
3232:
3233: x_saveval (&dest, LONG);
3234: x_postea (src);
3235: x_postea (&dest);
3236: }
3237:
3238: void i386_func_tst (ea_t *ea)
3239: {
3240: x_loadval (ea, -1, 0);
3241: ifNVC xln ("movb $0,C");
3242: ifNVC xln ("movb $0,V");
3243: xln ("test%s %s,%s", szmov[ea->op_size], ea->identifier, ea->identifier);
3244: ifZ xln ("setz Z");
3245: ifNVC xln ("sets N");
3246: x_postea (ea);
3247: }
3248:
3249: void i386_func_pea (ea_t *ea)
3250: {
3251: int a7;
3252:
3253: x_loadea (ea);
3254: a7 = xload_reg (15, LONG, -1);
3255:
3256: xln ("subl $4,%s", xreg (a7, LONG));
3257: xln ("bswap %s", ea->identifier);
3258: xln ("movl %s,(%%ebp,%s)", ea->identifier, xreg (a7, LONG));
3259:
3260: xdirty_reg (a7);
3261: xreg_unlock (a7);
3262: x_postea (ea);
3263: }
3264:
3265: void i386_func_lea (ea_t *ea, int reg)
3266: {
3267: struct ea_t dest;
3268:
3269: dest.mode = 1;
3270: dest.reg = reg;
3271: dest.op_size = LONG;
3272: dest.x86_reg = -1;
3273: dest.x86_reg_writeback = -1;
3274:
3275: x_loadea (ea);
3276:
3277: x_ea_set_val_2_reg (&dest, LONG, ea->x86_reg);
3278: x_saveval (&dest, LONG);
3279: x_postea (ea);
3280: x_postea (&dest);
3281: }
3282:
3283: void i386_func_scc (ea_t *dest, int cond)
3284: {
3285: xflush_all ();
3286: x_cond_begin (cond);
3287:
3288: xln ("movb $0xff,%%al");
3289: xold_writeea (dest, BYTE, EAX, 0);
3290: xold_writeea (dest, BYTE, EAX, 1);
3291: xold_writeea (dest, BYTE, EAX, 1);
3292: x_postea (dest);
3293: xln ("jmp 10f");
3294:
3295: x_cond_end ();
3296:
3297: xln ("xorb %%al,%%al");
3298: xold_writeea (dest, BYTE, EAX, 0);
3299: xold_writeea (dest, BYTE, EAX, 1);
3300: xold_writeea (dest, BYTE, EAX, 1);
3301: x_postea (dest);
3302:
3303: xout ("10:\n");
3304: }
3305:
3306: static void output_op (op_t *op, op_t *next)
3307: {
3308: xregalloc_age ();
3309:
3310: op->src.x86_reg = -1;
3311: op->src.x86_reg_writeback = -1;
3312: op->dest.x86_reg = -1;
3313: op->dest.x86_reg_writeback = -1;
3314:
3315: switch (op->optype) {
3316: case OP_MULS: i386_func_muls (&op->src, &op->dest); break;
3317: case OP_MULU: i386_func_mulu (&op->src, &op->dest); break;
3318: case OP_ADDA: i386_func_adda (&op->src, &op->dest, op->size); break;
3319: case OP_SUBA: i386_func_suba (&op->src, &op->dest, op->size); break;
3320: case OP_ADD: i386_func_add (&op->src, &op->dest, op->size); break;
3321: case OP_SUB: i386_func_sub (&op->src, &op->dest, op->size); break;
3322: case OP_NOT: i386_func_not (&op->src, op->size); break;
3323: case OP_NEGX: i386_func_negx (&op->src, op->size); break;
3324: case OP_NEG: i386_func_neg (&op->src, op->size); break;
3325: case OP_DIVS: i386_func_divs (&op->src, op->dest.reg); break;
3326: case OP_DIVU: i386_func_divu (&op->src, op->dest.reg); break;
3327: case OP_ADDX: i386_func_addx (&op->src, &op->dest, op->size); break;
3328: case OP_SUBX: i386_func_subx (&op->src, &op->dest, op->size); break;
3329: case OP_BCHG: i386_func_bchg (&op->src, &op->dest, op->size); break;
3330: case OP_BCLR: i386_func_bclr (&op->src, &op->dest, op->size); break;
3331: case OP_BSET: i386_func_bset (&op->src, &op->dest, op->size); break;
3332: case OP_BTST: i386_func_btst (&op->src, &op->dest, op->size); break;
3333: case OP_ASL: i386_func_asl (&op->src, &op->dest, op->size); break;
3334: case OP_ASR: i386_func_asr (&op->src, &op->dest, op->size); break;
3335: case OP_LSL: i386_func_lsl (&op->src, &op->dest, op->size); break;
3336: case OP_LSR: i386_func_lsr (&op->src, &op->dest, op->size); break;
3337: case OP_ROL: i386_func_rol (&op->src, &op->dest, op->size); break;
3338: case OP_ROR: i386_func_ror (&op->src, &op->dest, op->size); break;
3339: case OP_ROXL: i386_func_roxl (&op->src, &op->dest, op->size); break;
3340: case OP_ROXR: i386_func_roxr (&op->src, &op->dest, op->size); break;
3341: case OP_OR: i386_func_logop (&op->src, &op->dest, op->size, '|'); break;
3342: case OP_AND: i386_func_logop (&op->src, &op->dest, op->size, '&'); break;
3343: case OP_XOR: i386_func_logop (&op->src, &op->dest, op->size, '^'); break;
3344: case OP_SWAP: i386_func_swap (op->src.reg); break;
3345: case OP_JSR: i386_func_jsr (&op->src); break;
3346: case OP_BCC: i386_func_bcc (&op->src, op->opcode.Bcc.cond); break;
3347: case OP_DBCC: i386_func_dbcc (op->dest.imm.label, op->opcode.Bcc.cond, op->src.reg); break;
3348: case OP_CLR: i386_func_clr (&op->src); break;
3349: case OP_CMP: i386_func_cmp (&op->src, &op->dest, op->size); break;
3350: case OP_CMPA: i386_func_cmpa (&op->src, &op->dest, op->size); break;
3351: case OP_EXG: i386_func_exg (op->src.reg, op->dest.reg); break;
3352: case OP_EXT: i386_func_ext (op->src.reg, op->size); break;
3353: case OP_MOVEM: i386_func_movem (&op->src, op->opcode.movem.sz, op->opcode.movem.dr, op->dest.reg); break;
3354: case OP_RTE: i386_func_rte (); break;
3355: case OP_RTS: i386_func_rts (); break;
3356: case OP_ILLEGAL: i386_func_illegal (); break;
3357: case OP_HCALL: i386_func_hcall (op->src.imm.val); break;
3358: case OP_LINK: i386_func_link (op->src.reg, op->dest.imm.val); break;
3359: case OP_UNLK: i386_func_unlk (op->src.reg); break;
3360: case OP_MOVE: i386_func_move (&op->src, &op->dest, op->size); break;
3361: case OP_MOVEA: i386_func_movea (&op->src, op->dest.reg); break;
3362: case OP_TST: i386_func_tst (&op->src); break;
3363: case OP_PEA: i386_func_pea (&op->src); break;
3364: case OP_LEA: i386_func_lea (&op->src, op->dest.reg); break;
3365: case OP_JMP: i386_jump (&op->src); break;
3366: case OP_SCC: i386_func_scc (&op->src, op->opcode.DBcc.cond); break;
3367:
3368: default:
3369: printf ("type %d\n", op->optype);
3370: assert (0);
3371: }
3372:
3373: /* int i;
3374: int fucked = 0;
3375: for (i=0; i<X86REG_MAX; i++) {
3376: printf ("l%d X86-reg %d: contained 68k reg %d, age %d, dirty %d, locked %d\n",
3377: line_no,
3378: i, i386_regalloc[i].m68k_reg,
3379: i386_regalloc[i].age,
3380: i386_regalloc[i].dirty,
3381: i386_regalloc[i].locked);
3382: if (i386_regalloc[i].locked) fucked = 1;
3383: }
3384: printf ("\n");
3385: assert (fucked == 0);*/
3386: }
3387:
3388: static void do_pending ()
3389: {
3390: if (pending_flush) {
3391: xflush_all ();
3392: }
3393: pending_flush = cur_flush;
3394: cur_flush = 0;
3395:
3396: #ifdef DUMP_LOADS_OF_CRAP
3397: /* state must be consistent to print reg contents */
3398: xflush_all ();
3399: #endif /* DUMP_LOADS_OF_CRAP */
3400:
3401: if (pending_labels) {
3402: rout (pending_labels);
3403: free (pending_labels);
3404: }
3405: pending_labels = cur_labels;
3406: cur_labels = calloc (LABBUF_LEN, 1);
3407: strcat (cur_labels, "\n");
3408:
3409: if (pending.optype) output_op (&pending, NULL);
3410: }
3411:
3412: void i386_push_op (enum M68K_OPS type, ea_t *src, ea_t *dest, int size)
3413: {
3414: i386_push_op2 (type, src, dest, size, 0);
3415: }
3416: void i386_push_op2 (enum M68K_OPS type, ea_t *src, ea_t *dest, int size, int opcode)
3417: {
3418: op_t op;
3419:
3420: op.size = size;
3421: op.opcode.code = opcode;
3422: op.optype = type;
3423: if (type == OP_JSR)
3424: return_target = 1;
3425: else
3426: return_target = 0;
3427: if (src) {
3428: op.src = *src;
3429: }
3430: if (dest) {
3431: op.dest = *dest;
3432: }
3433: next_op_type = op.optype;
3434:
3435: do_pending ();
3436: pending = op;
3437: }
3438: void i386_push_op_basic (enum M68K_OPS type)
3439: {
3440: i386_push_op2 (type, NULL, NULL, 0, 0);
3441: }
3442:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.