source: trunk/minix/commands/i386/asmconv/emit_ack.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 13.7 KB
Line 
1/* emit_ack.c - emit ACK assembly Author: Kees J. Bot
2 * emit NCC assembly 27 Dec 1993
3 */
4#define nil 0
5#include <stdio.h>
6#include <stdlib.h>
7#include <stdarg.h>
8#include <string.h>
9#include <assert.h>
10#include "asmconv.h"
11#include "token.h"
12#include "asm86.h"
13#include "languages.h"
14
15typedef struct mnemonic { /* ACK as86 mnemonics translation table. */
16 opcode_t opcode;
17 char *name;
18} mnemonic_t;
19
20static mnemonic_t mnemtab[] = {
21 { AAA, "aaa" },
22 { AAD, "aad" },
23 { AAM, "aam" },
24 { AAS, "aas" },
25 { ADC, "adc%" },
26 { ADD, "add%" },
27 { AND, "and%" },
28 { ARPL, "arpl" },
29 { BOUND, "bound" },
30 { BSF, "bsf" },
31 { BSR, "bsr" },
32 { BSWAP, "bswap" },
33 { BT, "bt" },
34 { BTC, "btc" },
35 { BTR, "btr" },
36 { BTS, "bts" },
37 { CALL, "call" },
38 { CALLF, "callf" },
39 { CBW, "cbw" },
40 { CLC, "clc" },
41 { CLD, "cld" },
42 { CLI, "cli" },
43 { CLTS, "clts" },
44 { CMC, "cmc" },
45 { CMP, "cmp%" },
46 { CMPS, "cmps%" },
47 { CMPXCHG, "cmpxchg" },
48 { CWD, "cwd" },
49 { DAA, "daa" },
50 { DAS, "das" },
51 { DEC, "dec%" },
52 { DIV, "div%" },
53 { DOT_ALIGN, ".align" },
54 { DOT_ASCII, ".ascii" },
55 { DOT_ASCIZ, ".asciz" },
56 { DOT_ASSERT, ".assert" },
57 { DOT_BASE, ".base" },
58 { DOT_BSS, ".sect .bss" },
59 { DOT_COMM, ".comm" },
60 { DOT_DATA, ".sect .data" },
61 { DOT_DATA1, ".data1" },
62 { DOT_DATA2, ".data2" },
63 { DOT_DATA4, ".data4" },
64 { DOT_DEFINE, ".define" },
65 { DOT_END, ".sect .end" },
66 { DOT_EXTERN, ".extern" },
67 { DOT_FILE, ".file" },
68 { DOT_LCOMM, ".comm" },
69 { DOT_LINE, ".line" },
70 { DOT_LIST, ".list" },
71 { DOT_NOLIST, ".nolist" },
72 { DOT_ROM, ".sect .rom" },
73 { DOT_SPACE, ".space" },
74 { DOT_SYMB, ".symb" },
75 { DOT_TEXT, ".sect .text" },
76 { DOT_USE16, ".use16" },
77 { DOT_USE32, ".use32" },
78 { ENTER, "enter" },
79 { F2XM1, "f2xm1" },
80 { FABS, "fabs" },
81 { FADD, "fadd" },
82 { FADDD, "faddd" },
83 { FADDP, "faddp" },
84 { FADDS, "fadds" },
85 { FBLD, "fbld" },
86 { FBSTP, "fbstp" },
87 { FCHS, "fchs" },
88 { FCLEX, "fclex" },
89 { FCOMD, "fcomd" },
90 { FCOMPD, "fcompd" },
91 { FCOMPP, "fcompp" },
92 { FCOMPS, "fcomps" },
93 { FCOMS, "fcoms" },
94 { FCOS, "fcos" },
95 { FDECSTP, "fdecstp" },
96 { FDIVD, "fdivd" },
97 { FDIVP, "fdivp" },
98 { FDIVRD, "fdivrd" },
99 { FDIVRP, "fdivrp" },
100 { FDIVRS, "fdivrs" },
101 { FDIVS, "fdivs" },
102 { FFREE, "ffree" },
103 { FIADDL, "fiaddl" },
104 { FIADDS, "fiadds" },
105 { FICOM, "ficom" },
106 { FICOMP, "ficomp" },
107 { FIDIVL, "fidivl" },
108 { FIDIVRL, "fidivrl" },
109 { FIDIVRS, "fidivrs" },
110 { FIDIVS, "fidivs" },
111 { FILDL, "fildl" },
112 { FILDQ, "fildq" },
113 { FILDS, "filds" },
114 { FIMULL, "fimull" },
115 { FIMULS, "fimuls" },
116 { FINCSTP, "fincstp" },
117 { FINIT, "finit" },
118 { FISTL, "fistl" },
119 { FISTP, "fistp" },
120 { FISTS, "fists" },
121 { FISUBL, "fisubl" },
122 { FISUBRL, "fisubrl" },
123 { FISUBRS, "fisubrs" },
124 { FISUBS, "fisubs" },
125 { FLD1, "fld1" },
126 { FLDCW, "fldcw" },
127 { FLDD, "fldd" },
128 { FLDENV, "fldenv" },
129 { FLDL2E, "fldl2e" },
130 { FLDL2T, "fldl2t" },
131 { FLDLG2, "fldlg2" },
132 { FLDLN2, "fldln2" },
133 { FLDPI, "fldpi" },
134 { FLDS, "flds" },
135 { FLDX, "fldx" },
136 { FLDZ, "fldz" },
137 { FMULD, "fmuld" },
138 { FMULP, "fmulp" },
139 { FMULS, "fmuls" },
140 { FNOP, "fnop" },
141 { FPATAN, "fpatan" },
142 { FPREM, "fprem" },
143 { FPREM1, "fprem1" },
144 { FPTAN, "fptan" },
145 { FRNDINT, "frndint" },
146 { FRSTOR, "frstor" },
147 { FSAVE, "fsave" },
148 { FSCALE, "fscale" },
149 { FSIN, "fsin" },
150 { FSINCOS, "fsincos" },
151 { FSQRT, "fsqrt" },
152 { FSTCW, "fstcw" },
153 { FSTD, "fstd" },
154 { FSTENV, "fstenv" },
155 { FSTPD, "fstpd" },
156 { FSTPS, "fstps" },
157 { FSTPX, "fstpx" },
158 { FSTS, "fsts" },
159 { FSTSW, "fstsw" },
160 { FSUBD, "fsubd" },
161 { FSUBP, "fsubp" },
162 { FSUBPR, "fsubpr" },
163 { FSUBRD, "fsubrd" },
164 { FSUBRS, "fsubrs" },
165 { FSUBS, "fsubs" },
166 { FTST, "ftst" },
167 { FUCOM, "fucom" },
168 { FUCOMP, "fucomp" },
169 { FUCOMPP, "fucompp" },
170 { FXAM, "fxam" },
171 { FXCH, "fxch" },
172 { FXTRACT, "fxtract" },
173 { FYL2X, "fyl2x" },
174 { FYL2XP1, "fyl2xp1" },
175 { HLT, "hlt" },
176 { IDIV, "idiv%" },
177 { IMUL, "imul%" },
178 { IN, "in%" },
179 { INC, "inc%" },
180 { INS, "ins%" },
181 { INT, "int" },
182 { INTO, "into" },
183 { INVD, "invd" },
184 { INVLPG, "invlpg" },
185 { IRET, "iret" },
186 { IRETD, "iretd" },
187 { JA, "ja" },
188 { JAE, "jae" },
189 { JB, "jb" },
190 { JBE, "jbe" },
191 { JCXZ, "jcxz" },
192 { JE, "je" },
193 { JG, "jg" },
194 { JGE, "jge" },
195 { JL, "jl" },
196 { JLE, "jle" },
197 { JMP, "jmp" },
198 { JMPF, "jmpf" },
199 { JNE, "jne" },
200 { JNO, "jno" },
201 { JNP, "jnp" },
202 { JNS, "jns" },
203 { JO, "jo" },
204 { JP, "jp" },
205 { JS, "js" },
206 { LAHF, "lahf" },
207 { LAR, "lar" },
208 { LDS, "lds" },
209 { LEA, "lea" },
210 { LEAVE, "leave" },
211 { LES, "les" },
212 { LFS, "lfs" },
213 { LGDT, "lgdt" },
214 { LGS, "lgs" },
215 { LIDT, "lidt" },
216 { LLDT, "lldt" },
217 { LMSW, "lmsw" },
218 { LOCK, "lock" },
219 { LODS, "lods%" },
220 { LOOP, "loop" },
221 { LOOPE, "loope" },
222 { LOOPNE, "loopne" },
223 { LSL, "lsl" },
224 { LSS, "lss" },
225 { LTR, "ltr" },
226 { MOV, "mov%" },
227 { MOVS, "movs%" },
228 { MOVSX, "movsx" },
229 { MOVSXB, "movsxb" },
230 { MOVZX, "movzx" },
231 { MOVZXB, "movzxb" },
232 { MUL, "mul%" },
233 { NEG, "neg%" },
234 { NOP, "nop" },
235 { NOT, "not%" },
236 { OR, "or%" },
237 { OUT, "out%" },
238 { OUTS, "outs%" },
239 { POP, "pop" },
240 { POPA, "popa" },
241 { POPF, "popf" },
242 { PUSH, "push" },
243 { PUSHA, "pusha" },
244 { PUSHF, "pushf" },
245 { RCL, "rcl%" },
246 { RCR, "rcr%" },
247 { RET, "ret" },
248 { RETF, "retf" },
249 { ROL, "rol%" },
250 { ROR, "ror%" },
251 { SAHF, "sahf" },
252 { SAL, "sal%" },
253 { SAR, "sar%" },
254 { SBB, "sbb%" },
255 { SCAS, "scas%" },
256 { SETA, "seta" },
257 { SETAE, "setae" },
258 { SETB, "setb" },
259 { SETBE, "setbe" },
260 { SETE, "sete" },
261 { SETG, "setg" },
262 { SETGE, "setge" },
263 { SETL, "setl" },
264 { SETLE, "setle" },
265 { SETNE, "setne" },
266 { SETNO, "setno" },
267 { SETNP, "setnp" },
268 { SETNS, "setns" },
269 { SETO, "seto" },
270 { SETP, "setp" },
271 { SETS, "sets" },
272 { SGDT, "sgdt" },
273 { SHL, "shl%" },
274 { SHLD, "shld" },
275 { SHR, "shr%" },
276 { SHRD, "shrd" },
277 { SIDT, "sidt" },
278 { SLDT, "sldt" },
279 { SMSW, "smsw" },
280 { STC, "stc" },
281 { STD, "std" },
282 { STI, "sti" },
283 { STOS, "stos%" },
284 { STR, "str" },
285 { SUB, "sub%" },
286 { TEST, "test%" },
287 { VERR, "verr" },
288 { VERW, "verw" },
289 { WAIT, "wait" },
290 { WBINVD, "wbinvd" },
291 { XADD, "xadd" },
292 { XCHG, "xchg%" },
293 { XLAT, "xlat" },
294 { XOR, "xor%" },
295};
296
297#define farjmp(o) ((o) == JMPF || (o) == CALLF)
298
299static FILE *ef;
300static long eline= 1;
301static char *efile;
302static char *orig_efile;
303static char *opcode2name_tab[N_OPCODES];
304static enum dialect { ACK, NCC } dialect= ACK;
305
306static void ack_putchar(int c)
307/* LOOK, this programmer checks the return code of putc! What an idiot, noone
308 * does that!
309 */
310{
311 if (putc(c, ef) == EOF) fatal(orig_efile);
312}
313
314static void ack_printf(const char *fmt, ...)
315{
316 va_list ap;
317
318 va_start(ap, fmt);
319 if (vfprintf(ef, fmt, ap) == EOF) fatal(orig_efile);
320 va_end(ap);
321}
322
323void ack_emit_init(char *file, const char *banner)
324/* Prepare producing an ACK assembly file. */
325{
326 mnemonic_t *mp;
327
328 if (file == nil) {
329 file= "stdout";
330 ef= stdout;
331 } else {
332 if ((ef= fopen(file, "w")) == nil) fatal(file);
333 }
334 orig_efile= file;
335 efile= file;
336 ack_printf("! %s", banner);
337 if (dialect == ACK) {
338 /* Declare the four sections used under Minix. */
339 ack_printf(
340 "\n.sect .text; .sect .rom; .sect .data; .sect .bss\n.sect .text");
341 }
342
343 /* Initialize the opcode to mnemonic translation table. */
344 for (mp= mnemtab; mp < arraylimit(mnemtab); mp++) {
345 assert(opcode2name_tab[mp->opcode] == nil);
346 opcode2name_tab[mp->opcode]= mp->name;
347 }
348}
349
350#define opcode2name(op) (opcode2name_tab[op] + 0)
351
352static void ack_put_string(const char *s, size_t n)
353/* Emit a string with weird characters quoted. */
354{
355 while (n > 0) {
356 int c= *s;
357
358 if (c < ' ' || c > 0177) {
359 ack_printf("\\%03o", c & 0xFF);
360 } else
361 if (c == '"' || c == '\\') {
362 ack_printf("\\%c", c);
363 } else {
364 ack_putchar(c);
365 }
366 s++;
367 n--;
368 }
369}
370
371static void ack_put_expression(asm86_t *a, expression_t *e, int deref)
372/* Send an expression, i.e. instruction operands, to the output file. Deref
373 * is true when the rewrite for the ncc dialect may be made.
374 */
375{
376 assert(e != nil);
377
378 switch (e->operator) {
379 case ',':
380 if (dialect == NCC && farjmp(a->opcode)) {
381 /* ACK jmpf seg:off -> NCC jmpf off,seg */
382 ack_put_expression(a, e->right, deref);
383 ack_printf(", ");
384 ack_put_expression(a, e->left, deref);
385 } else {
386 ack_put_expression(a, e->left, deref);
387 ack_printf(farjmp(a->opcode) ? ":" : ", ");
388 ack_put_expression(a, e->right, deref);
389 }
390 break;
391 case 'O':
392 if (deref && a->optype == JUMP) ack_putchar('@');
393 if (e->left != nil) ack_put_expression(a, e->left, 0);
394 if (e->middle != nil) ack_put_expression(a, e->middle, 0);
395 if (e->right != nil) ack_put_expression(a, e->right, 0);
396 break;
397 case '(':
398 if (deref && a->optype == JUMP) ack_putchar('@');
399 if (!deref) ack_putchar('(');
400 ack_put_expression(a, e->middle, 0);
401 if (!deref) ack_putchar(')');
402 break;
403 case 'B':
404 ack_printf("(%s)", e->name);
405 break;
406 case '1':
407 case '2':
408 case '4':
409 case '8':
410 ack_printf((use16() && e->operator == '1')
411 ? "(%s)" : "(%s*%c)", e->name, e->operator);
412 break;
413 case '+':
414 case '-':
415 case '~':
416 if (e->middle != nil) {
417 if (deref && a->optype != JUMP) ack_putchar('#');
418 ack_putchar(e->operator);
419 ack_put_expression(a, e->middle, 0);
420 break;
421 }
422 /*FALL THROUGH*/
423 case '*':
424 case '/':
425 case '%':
426 case '&':
427 case '|':
428 case '^':
429 case S_LEFTSHIFT:
430 case S_RIGHTSHIFT:
431 if (deref && a->optype != JUMP) ack_putchar('#');
432 ack_put_expression(a, e->left, 0);
433 if (e->operator == S_LEFTSHIFT) {
434 ack_printf("<<");
435 } else
436 if (e->operator == S_RIGHTSHIFT) {
437 ack_printf(">>");
438 } else {
439 ack_putchar(e->operator);
440 }
441 ack_put_expression(a, e->right, 0);
442 break;
443 case '[':
444 if (deref && a->optype != JUMP) ack_putchar('#');
445 ack_putchar('[');
446 ack_put_expression(a, e->middle, 0);
447 ack_putchar(']');
448 break;
449 case 'W':
450 if (deref && a->optype == JUMP && isregister(e->name))
451 {
452 ack_printf("(%s)", e->name);
453 break;
454 }
455 if (deref && a->optype != JUMP && !isregister(e->name)) {
456 ack_putchar('#');
457 }
458 ack_printf("%s", e->name);
459 break;
460 case 'S':
461 ack_putchar('"');
462 ack_put_string(e->name, e->len);
463 ack_putchar('"');
464 break;
465 default:
466 fprintf(stderr,
467 "asmconv: internal error, unknown expression operator '%d'\n",
468 e->operator);
469 exit(EXIT_FAILURE);
470 }
471}
472
473void ack_emit_instruction(asm86_t *a)
474/* Output one instruction and its operands. */
475{
476 int same= 0;
477 char *p;
478 static int high_seg;
479 int deref;
480
481 if (a == nil) {
482 /* Last call */
483 ack_putchar('\n');
484 return;
485 }
486
487 /* Make sure the line number of the line to be emitted is ok. */
488 if ((a->file != efile && strcmp(a->file, efile) != 0)
489 || a->line < eline || a->line > eline+10) {
490 ack_putchar('\n');
491 ack_printf("# %ld \"%s\"\n", a->line, a->file);
492 efile= a->file;
493 eline= a->line;
494 } else {
495 if (a->line == eline) {
496 ack_printf("; ");
497 same= 1;
498 }
499 while (eline < a->line) {
500 ack_putchar('\n');
501 eline++;
502 }
503 }
504
505 if (a->opcode == DOT_LABEL) {
506 assert(a->args->operator == ':');
507 ack_printf("%s:", a->args->name);
508 } else
509 if (a->opcode == DOT_EQU) {
510 assert(a->args->operator == '=');
511 ack_printf("\t%s = ", a->args->name);
512 ack_put_expression(a, a->args->middle, 0);
513 } else
514 if ((p= opcode2name(a->opcode)) != nil) {
515 char *sep= dialect == ACK ? "" : ";";
516
517 if (!is_pseudo(a->opcode) && !same) ack_putchar('\t');
518
519 switch (a->rep) {
520 case ONCE: break;
521 case REP: ack_printf("rep"); break;
522 case REPE: ack_printf("repe"); break;
523 case REPNE: ack_printf("repne"); break;
524 default: assert(0);
525 }
526 if (a->rep != ONCE) {
527 ack_printf(dialect == ACK ? " " : "; ");
528 }
529 switch (a->seg) {
530 case DEFSEG: break;
531 case CSEG: ack_printf("cseg"); break;
532 case DSEG: ack_printf("dseg"); break;
533 case ESEG: ack_printf("eseg"); break;
534 case FSEG: ack_printf("fseg"); break;
535 case GSEG: ack_printf("gseg"); break;
536 case SSEG: ack_printf("sseg"); break;
537 default: assert(0);
538 }
539 if (a->seg != DEFSEG) {
540 ack_printf(dialect == ACK ? " " : "; ");
541 }
542 if (a->oaz & OPZ) ack_printf(use16() ? "o32 " : "o16 ");
543 if (a->oaz & ADZ) ack_printf(use16() ? "a32 " : "a16 ");
544
545 if (a->opcode == CBW) {
546 p= !(a->oaz & OPZ) == use16() ? "cbw" : "cwde";
547 }
548
549 if (a->opcode == CWD) {
550 p= !(a->oaz & OPZ) == use16() ? "cwd" : "cdq";
551 }
552
553 if (a->opcode == DOT_COMM && a->args != nil
554 && a->args->operator == ','
555 && a->args->left->operator == 'W'
556 ) {
557 ack_printf(".define\t%s; ", a->args->left->name);
558 }
559 while (*p != 0) {
560 if (*p == '%') {
561 if (a->optype == BYTE) ack_putchar('b');
562 } else {
563 ack_putchar(*p);
564 }
565 p++;
566 }
567 if (a->args != nil) {
568 ack_putchar('\t');
569 switch (a->opcode) {
570 case IN:
571 case OUT:
572 case INT:
573 deref= 0;
574 break;
575 default:
576 deref= (dialect == NCC && a->optype != PSEUDO);
577 }
578 ack_put_expression(a, a->args, deref);
579 }
580 if (a->opcode == DOT_USE16) set_use16();
581 if (a->opcode == DOT_USE32) set_use32();
582 } else {
583 fprintf(stderr,
584 "asmconv: internal error, unknown opcode '%d'\n",
585 a->opcode);
586 exit(EXIT_FAILURE);
587 }
588}
589
590/* A few ncc mnemonics are different. */
591static mnemonic_t ncc_mnemtab[] = {
592 { DOT_BSS, ".bss" },
593 { DOT_DATA, ".data" },
594 { DOT_END, ".end" },
595 { DOT_ROM, ".rom" },
596 { DOT_TEXT, ".text" },
597};
598
599void ncc_emit_init(char *file, const char *banner)
600/* The assembly produced by the Minix ACK ANSI C compiler for the 8086 is
601 * different from the normal ACK assembly, and different from the old K&R
602 * assembler. This brings us endless joy. (It was supposed to make
603 * translation of the assembly used by the old K&R assembler easier by
604 * not deviating too much from that dialect.)
605 */
606{
607 mnemonic_t *mp;
608
609 dialect= NCC;
610 ack_emit_init(file, banner);
611
612 /* Replace a few mnemonics. */
613 for (mp= ncc_mnemtab; mp < arraylimit(ncc_mnemtab); mp++) {
614 opcode2name_tab[mp->opcode]= mp->name;
615 }
616}
617
618void ncc_emit_instruction(asm86_t *a)
619{
620 ack_emit_instruction(a);
621}
Note: See TracBrowser for help on using the repository browser.