00001
00002
00003
00004 #define nil 0
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <stdarg.h>
00008 #include <string.h>
00009 #include <assert.h>
00010 #include "asmconv.h"
00011 #include "token.h"
00012 #include "asm86.h"
00013 #include "languages.h"
00014
00015 typedef struct mnemonic {
00016 opcode_t opcode;
00017 char *name;
00018 } mnemonic_t;
00019
00020 static mnemonic_t mnemtab[] = {
00021 { AAA, "aaa" },
00022 { AAD, "aad" },
00023 { AAM, "aam" },
00024 { AAS, "aas" },
00025 { ADC, "adc%" },
00026 { ADD, "add%" },
00027 { AND, "and%" },
00028 { ARPL, "arpl" },
00029 { BOUND, "bound" },
00030 { BSF, "bsf" },
00031 { BSR, "bsr" },
00032 { BSWAP, "bswap" },
00033 { BT, "bt" },
00034 { BTC, "btc" },
00035 { BTR, "btr" },
00036 { BTS, "bts" },
00037 { CALL, "call" },
00038 { CALLF, "callf" },
00039 { CBW, "cbw" },
00040 { CLC, "clc" },
00041 { CLD, "cld" },
00042 { CLI, "cli" },
00043 { CLTS, "clts" },
00044 { CMC, "cmc" },
00045 { CMP, "cmp%" },
00046 { CMPS, "cmps%" },
00047 { CMPXCHG, "cmpxchg" },
00048 { CWD, "cwd" },
00049 { DAA, "daa" },
00050 { DAS, "das" },
00051 { DEC, "dec%" },
00052 { DIV, "div%" },
00053 { DOT_ALIGN, ".align" },
00054 { DOT_ASCII, ".ascii" },
00055 { DOT_ASCIZ, ".asciz" },
00056 { DOT_ASSERT, ".assert" },
00057 { DOT_BASE, ".base" },
00058 { DOT_BSS, ".sect .bss" },
00059 { DOT_COMM, ".comm" },
00060 { DOT_DATA, ".sect .data" },
00061 { DOT_DATA1, ".data1" },
00062 { DOT_DATA2, ".data2" },
00063 { DOT_DATA4, ".data4" },
00064 { DOT_DEFINE, ".define" },
00065 { DOT_END, ".sect .end" },
00066 { DOT_EXTERN, ".extern" },
00067 { DOT_FILE, ".file" },
00068 { DOT_LCOMM, ".comm" },
00069 { DOT_LINE, ".line" },
00070 { DOT_LIST, ".list" },
00071 { DOT_NOLIST, ".nolist" },
00072 { DOT_ROM, ".sect .rom" },
00073 { DOT_SPACE, ".space" },
00074 { DOT_SYMB, ".symb" },
00075 { DOT_TEXT, ".sect .text" },
00076 { DOT_USE16, ".use16" },
00077 { DOT_USE32, ".use32" },
00078 { ENTER, "enter" },
00079 { F2XM1, "f2xm1" },
00080 { FABS, "fabs" },
00081 { FADD, "fadd" },
00082 { FADDD, "faddd" },
00083 { FADDP, "faddp" },
00084 { FADDS, "fadds" },
00085 { FBLD, "fbld" },
00086 { FBSTP, "fbstp" },
00087 { FCHS, "fchs" },
00088 { FCLEX, "fclex" },
00089 { FCOMD, "fcomd" },
00090 { FCOMPD, "fcompd" },
00091 { FCOMPP, "fcompp" },
00092 { FCOMPS, "fcomps" },
00093 { FCOMS, "fcoms" },
00094 { FCOS, "fcos" },
00095 { FDECSTP, "fdecstp" },
00096 { FDIVD, "fdivd" },
00097 { FDIVP, "fdivp" },
00098 { FDIVRD, "fdivrd" },
00099 { FDIVRP, "fdivrp" },
00100 { FDIVRS, "fdivrs" },
00101 { FDIVS, "fdivs" },
00102 { FFREE, "ffree" },
00103 { FIADDL, "fiaddl" },
00104 { FIADDS, "fiadds" },
00105 { FICOM, "ficom" },
00106 { FICOMP, "ficomp" },
00107 { FIDIVL, "fidivl" },
00108 { FIDIVRL, "fidivrl" },
00109 { FIDIVRS, "fidivrs" },
00110 { FIDIVS, "fidivs" },
00111 { FILDL, "fildl" },
00112 { FILDQ, "fildq" },
00113 { FILDS, "filds" },
00114 { FIMULL, "fimull" },
00115 { FIMULS, "fimuls" },
00116 { FINCSTP, "fincstp" },
00117 { FINIT, "finit" },
00118 { FISTL, "fistl" },
00119 { FISTP, "fistp" },
00120 { FISTS, "fists" },
00121 { FISUBL, "fisubl" },
00122 { FISUBRL, "fisubrl" },
00123 { FISUBRS, "fisubrs" },
00124 { FISUBS, "fisubs" },
00125 { FLD1, "fld1" },
00126 { FLDCW, "fldcw" },
00127 { FLDD, "fldd" },
00128 { FLDENV, "fldenv" },
00129 { FLDL2E, "fldl2e" },
00130 { FLDL2T, "fldl2t" },
00131 { FLDLG2, "fldlg2" },
00132 { FLDLN2, "fldln2" },
00133 { FLDPI, "fldpi" },
00134 { FLDS, "flds" },
00135 { FLDX, "fldx" },
00136 { FLDZ, "fldz" },
00137 { FMULD, "fmuld" },
00138 { FMULP, "fmulp" },
00139 { FMULS, "fmuls" },
00140 { FNOP, "fnop" },
00141 { FPATAN, "fpatan" },
00142 { FPREM, "fprem" },
00143 { FPREM1, "fprem1" },
00144 { FPTAN, "fptan" },
00145 { FRNDINT, "frndint" },
00146 { FRSTOR, "frstor" },
00147 { FSAVE, "fsave" },
00148 { FSCALE, "fscale" },
00149 { FSIN, "fsin" },
00150 { FSINCOS, "fsincos" },
00151 { FSQRT, "fsqrt" },
00152 { FSTCW, "fstcw" },
00153 { FSTD, "fstd" },
00154 { FSTENV, "fstenv" },
00155 { FSTPD, "fstpd" },
00156 { FSTPS, "fstps" },
00157 { FSTPX, "fstpx" },
00158 { FSTS, "fsts" },
00159 { FSTSW, "fstsw" },
00160 { FSUBD, "fsubd" },
00161 { FSUBP, "fsubp" },
00162 { FSUBPR, "fsubpr" },
00163 { FSUBRD, "fsubrd" },
00164 { FSUBRS, "fsubrs" },
00165 { FSUBS, "fsubs" },
00166 { FTST, "ftst" },
00167 { FUCOM, "fucom" },
00168 { FUCOMP, "fucomp" },
00169 { FUCOMPP, "fucompp" },
00170 { FXAM, "fxam" },
00171 { FXCH, "fxch" },
00172 { FXTRACT, "fxtract" },
00173 { FYL2X, "fyl2x" },
00174 { FYL2XP1, "fyl2xp1" },
00175 { HLT, "hlt" },
00176 { IDIV, "idiv%" },
00177 { IMUL, "imul%" },
00178 { IN, "in%" },
00179 { INC, "inc%" },
00180 { INS, "ins%" },
00181 { INT, "int" },
00182 { INTO, "into" },
00183 { INVD, "invd" },
00184 { INVLPG, "invlpg" },
00185 { IRET, "iret" },
00186 { IRETD, "iretd" },
00187 { JA, "ja" },
00188 { JAE, "jae" },
00189 { JB, "jb" },
00190 { JBE, "jbe" },
00191 { JCXZ, "jcxz" },
00192 { JE, "je" },
00193 { JG, "jg" },
00194 { JGE, "jge" },
00195 { JL, "jl" },
00196 { JLE, "jle" },
00197 { JMP, "jmp" },
00198 { JMPF, "jmpf" },
00199 { JNE, "jne" },
00200 { JNO, "jno" },
00201 { JNP, "jnp" },
00202 { JNS, "jns" },
00203 { JO, "jo" },
00204 { JP, "jp" },
00205 { JS, "js" },
00206 { LAHF, "lahf" },
00207 { LAR, "lar" },
00208 { LDS, "lds" },
00209 { LEA, "lea" },
00210 { LEAVE, "leave" },
00211 { LES, "les" },
00212 { LFS, "lfs" },
00213 { LGDT, "lgdt" },
00214 { LGS, "lgs" },
00215 { LIDT, "lidt" },
00216 { LLDT, "lldt" },
00217 { LMSW, "lmsw" },
00218 { LOCK, "lock" },
00219 { LODS, "lods%" },
00220 { LOOP, "loop" },
00221 { LOOPE, "loope" },
00222 { LOOPNE, "loopne" },
00223 { LSL, "lsl" },
00224 { LSS, "lss" },
00225 { LTR, "ltr" },
00226 { MOV, "mov%" },
00227 { MOVS, "movs%" },
00228 { MOVSX, "movsx" },
00229 { MOVSXB, "movsxb" },
00230 { MOVZX, "movzx" },
00231 { MOVZXB, "movzxb" },
00232 { MUL, "mul%" },
00233 { NEG, "neg%" },
00234 { NOP, "nop" },
00235 { NOT, "not%" },
00236 { OR, "or%" },
00237 { OUT, "out%" },
00238 { OUTS, "outs%" },
00239 { POP, "pop" },
00240 { POPA, "popa" },
00241 { POPF, "popf" },
00242 { PUSH, "push" },
00243 { PUSHA, "pusha" },
00244 { PUSHF, "pushf" },
00245 { RCL, "rcl%" },
00246 { RCR, "rcr%" },
00247 { RET, "ret" },
00248 { RETF, "retf" },
00249 { ROL, "rol%" },
00250 { ROR, "ror%" },
00251 { SAHF, "sahf" },
00252 { SAL, "sal%" },
00253 { SAR, "sar%" },
00254 { SBB, "sbb%" },
00255 { SCAS, "scas%" },
00256 { SETA, "seta" },
00257 { SETAE, "setae" },
00258 { SETB, "setb" },
00259 { SETBE, "setbe" },
00260 { SETE, "sete" },
00261 { SETG, "setg" },
00262 { SETGE, "setge" },
00263 { SETL, "setl" },
00264 { SETLE, "setle" },
00265 { SETNE, "setne" },
00266 { SETNO, "setno" },
00267 { SETNP, "setnp" },
00268 { SETNS, "setns" },
00269 { SETO, "seto" },
00270 { SETP, "setp" },
00271 { SETS, "sets" },
00272 { SGDT, "sgdt" },
00273 { SHL, "shl%" },
00274 { SHLD, "shld" },
00275 { SHR, "shr%" },
00276 { SHRD, "shrd" },
00277 { SIDT, "sidt" },
00278 { SLDT, "sldt" },
00279 { SMSW, "smsw" },
00280 { STC, "stc" },
00281 { STD, "std" },
00282 { STI, "sti" },
00283 { STOS, "stos%" },
00284 { STR, "str" },
00285 { SUB, "sub%" },
00286 { TEST, "test%" },
00287 { VERR, "verr" },
00288 { VERW, "verw" },
00289 { WAIT, "wait" },
00290 { WBINVD, "wbinvd" },
00291 { XADD, "xadd" },
00292 { XCHG, "xchg%" },
00293 { XLAT, "xlat" },
00294 { XOR, "xor%" },
00295 };
00296
00297 #define farjmp(o) ((o) == JMPF || (o) == CALLF)
00298
00299 static FILE *ef;
00300 static long eline= 1;
00301 static char *efile;
00302 static char *orig_efile;
00303 static char *opcode2name_tab[N_OPCODES];
00304 static enum dialect { ACK, NCC } dialect= ACK;
00305
00306 static void ack_putchar(int c)
00307
00308
00309
00310 {
00311 if (putc(c, ef) == EOF) fatal(orig_efile);
00312 }
00313
00314 static void ack_printf(const char *fmt, ...)
00315 {
00316 va_list ap;
00317
00318 va_start(ap, fmt);
00319 if (vfprintf(ef, fmt, ap) == EOF) fatal(orig_efile);
00320 va_end(ap);
00321 }
00322
00323 void ack_emit_init(char *file, const char *banner)
00324
00325 {
00326 mnemonic_t *mp;
00327
00328 if (file == nil) {
00329 file= "stdout";
00330 ef= stdout;
00331 } else {
00332 if ((ef= fopen(file, "w")) == nil) fatal(file);
00333 }
00334 orig_efile= file;
00335 efile= file;
00336 ack_printf("! %s", banner);
00337 if (dialect == ACK) {
00338
00339 ack_printf(
00340 "\n.sect .text; .sect .rom; .sect .data; .sect .bss\n.sect .text");
00341 }
00342
00343
00344 for (mp= mnemtab; mp < arraylimit(mnemtab); mp++) {
00345 assert(opcode2name_tab[mp->opcode] == nil);
00346 opcode2name_tab[mp->opcode]= mp->name;
00347 }
00348 }
00349
00350 #define opcode2name(op) (opcode2name_tab[op] + 0)
00351
00352 static void ack_put_string(const char *s, size_t n)
00353
00354 {
00355 while (n > 0) {
00356 int c= *s;
00357
00358 if (c < ' ' || c > 0177) {
00359 ack_printf("\\%03o", c & 0xFF);
00360 } else
00361 if (c == '"' || c == '\\') {
00362 ack_printf("\\%c", c);
00363 } else {
00364 ack_putchar(c);
00365 }
00366 s++;
00367 n--;
00368 }
00369 }
00370
00371 static void ack_put_expression(asm86_t *a, expression_t *e, int deref)
00372
00373
00374
00375 {
00376 assert(e != nil);
00377
00378 switch (e->operator) {
00379 case ',':
00380 if (dialect == NCC && farjmp(a->opcode)) {
00381
00382 ack_put_expression(a, e->right, deref);
00383 ack_printf(", ");
00384 ack_put_expression(a, e->left, deref);
00385 } else {
00386 ack_put_expression(a, e->left, deref);
00387 ack_printf(farjmp(a->opcode) ? ":" : ", ");
00388 ack_put_expression(a, e->right, deref);
00389 }
00390 break;
00391 case 'O':
00392 if (deref && a->optype == JUMP) ack_putchar('@');
00393 if (e->left != nil) ack_put_expression(a, e->left, 0);
00394 if (e->middle != nil) ack_put_expression(a, e->middle, 0);
00395 if (e->right != nil) ack_put_expression(a, e->right, 0);
00396 break;
00397 case '(':
00398 if (deref && a->optype == JUMP) ack_putchar('@');
00399 if (!deref) ack_putchar('(');
00400 ack_put_expression(a, e->middle, 0);
00401 if (!deref) ack_putchar(')');
00402 break;
00403 case 'B':
00404 ack_printf("(%s)", e->name);
00405 break;
00406 case '1':
00407 case '2':
00408 case '4':
00409 case '8':
00410 ack_printf((use16() && e->operator == '1')
00411 ? "(%s)" : "(%s*%c)", e->name, e->operator);
00412 break;
00413 case '+':
00414 case '-':
00415 case '~':
00416 if (e->middle != nil) {
00417 if (deref && a->optype != JUMP) ack_putchar('#');
00418 ack_putchar(e->operator);
00419 ack_put_expression(a, e->middle, 0);
00420 break;
00421 }
00422
00423 case '*':
00424 case '/':
00425 case '%':
00426 case '&':
00427 case '|':
00428 case '^':
00429 case S_LEFTSHIFT:
00430 case S_RIGHTSHIFT:
00431 if (deref && a->optype != JUMP) ack_putchar('#');
00432 ack_put_expression(a, e->left, 0);
00433 if (e->operator == S_LEFTSHIFT) {
00434 ack_printf("<<");
00435 } else
00436 if (e->operator == S_RIGHTSHIFT) {
00437 ack_printf(">>");
00438 } else {
00439 ack_putchar(e->operator);
00440 }
00441 ack_put_expression(a, e->right, 0);
00442 break;
00443 case '[':
00444 if (deref && a->optype != JUMP) ack_putchar('#');
00445 ack_putchar('[');
00446 ack_put_expression(a, e->middle, 0);
00447 ack_putchar(']');
00448 break;
00449 case 'W':
00450 if (deref && a->optype == JUMP && isregister(e->name))
00451 {
00452 ack_printf("(%s)", e->name);
00453 break;
00454 }
00455 if (deref && a->optype != JUMP && !isregister(e->name)) {
00456 ack_putchar('#');
00457 }
00458 ack_printf("%s", e->name);
00459 break;
00460 case 'S':
00461 ack_putchar('"');
00462 ack_put_string(e->name, e->len);
00463 ack_putchar('"');
00464 break;
00465 default:
00466 fprintf(stderr,
00467 "asmconv: internal error, unknown expression operator '%d'\n",
00468 e->operator);
00469 exit(EXIT_FAILURE);
00470 }
00471 }
00472
00473 void ack_emit_instruction(asm86_t *a)
00474
00475 {
00476 int same= 0;
00477 char *p;
00478 static int high_seg;
00479 int deref;
00480
00481 if (a == nil) {
00482
00483 ack_putchar('\n');
00484 return;
00485 }
00486
00487
00488 if ((a->file != efile && strcmp(a->file, efile) != 0)
00489 || a->line < eline || a->line > eline+10) {
00490 ack_putchar('\n');
00491 ack_printf("# %ld \"%s\"\n", a->line, a->file);
00492 efile= a->file;
00493 eline= a->line;
00494 } else {
00495 if (a->line == eline) {
00496 ack_printf("; ");
00497 same= 1;
00498 }
00499 while (eline < a->line) {
00500 ack_putchar('\n');
00501 eline++;
00502 }
00503 }
00504
00505 if (a->opcode == DOT_LABEL) {
00506 assert(a->args->operator == ':');
00507 ack_printf("%s:", a->args->name);
00508 } else
00509 if (a->opcode == DOT_EQU) {
00510 assert(a->args->operator == '=');
00511 ack_printf("\t%s = ", a->args->name);
00512 ack_put_expression(a, a->args->middle, 0);
00513 } else
00514 if ((p= opcode2name(a->opcode)) != nil) {
00515 char *sep= dialect == ACK ? "" : ";";
00516
00517 if (!is_pseudo(a->opcode) && !same) ack_putchar('\t');
00518
00519 switch (a->rep) {
00520 case ONCE: break;
00521 case REP: ack_printf("rep"); break;
00522 case REPE: ack_printf("repe"); break;
00523 case REPNE: ack_printf("repne"); break;
00524 default: assert(0);
00525 }
00526 if (a->rep != ONCE) {
00527 ack_printf(dialect == ACK ? " " : "; ");
00528 }
00529 switch (a->seg) {
00530 case DEFSEG: break;
00531 case CSEG: ack_printf("cseg"); break;
00532 case DSEG: ack_printf("dseg"); break;
00533 case ESEG: ack_printf("eseg"); break;
00534 case FSEG: ack_printf("fseg"); break;
00535 case GSEG: ack_printf("gseg"); break;
00536 case SSEG: ack_printf("sseg"); break;
00537 default: assert(0);
00538 }
00539 if (a->seg != DEFSEG) {
00540 ack_printf(dialect == ACK ? " " : "; ");
00541 }
00542 if (a->oaz & OPZ) ack_printf(use16() ? "o32 " : "o16 ");
00543 if (a->oaz & ADZ) ack_printf(use16() ? "a32 " : "a16 ");
00544
00545 if (a->opcode == CBW) {
00546 p= !(a->oaz & OPZ) == use16() ? "cbw" : "cwde";
00547 }
00548
00549 if (a->opcode == CWD) {
00550 p= !(a->oaz & OPZ) == use16() ? "cwd" : "cdq";
00551 }
00552
00553 if (a->opcode == DOT_COMM && a->args != nil
00554 && a->args->operator == ','
00555 && a->args->left->operator == 'W'
00556 ) {
00557 ack_printf(".define\t%s; ", a->args->left->name);
00558 }
00559 while (*p != 0) {
00560 if (*p == '%') {
00561 if (a->optype == BYTE) ack_putchar('b');
00562 } else {
00563 ack_putchar(*p);
00564 }
00565 p++;
00566 }
00567 if (a->args != nil) {
00568 ack_putchar('\t');
00569 switch (a->opcode) {
00570 case IN:
00571 case OUT:
00572 case INT:
00573 deref= 0;
00574 break;
00575 default:
00576 deref= (dialect == NCC && a->optype != PSEUDO);
00577 }
00578 ack_put_expression(a, a->args, deref);
00579 }
00580 if (a->opcode == DOT_USE16) set_use16();
00581 if (a->opcode == DOT_USE32) set_use32();
00582 } else {
00583 fprintf(stderr,
00584 "asmconv: internal error, unknown opcode '%d'\n",
00585 a->opcode);
00586 exit(EXIT_FAILURE);
00587 }
00588 }
00589
00590
00591 static mnemonic_t ncc_mnemtab[] = {
00592 { DOT_BSS, ".bss" },
00593 { DOT_DATA, ".data" },
00594 { DOT_END, ".end" },
00595 { DOT_ROM, ".rom" },
00596 { DOT_TEXT, ".text" },
00597 };
00598
00599 void ncc_emit_init(char *file, const char *banner)
00600
00601
00602
00603
00604
00605
00606 {
00607 mnemonic_t *mp;
00608
00609 dialect= NCC;
00610 ack_emit_init(file, banner);
00611
00612
00613 for (mp= ncc_mnemtab; mp < arraylimit(ncc_mnemtab); mp++) {
00614 opcode2name_tab[mp->opcode]= mp->name;
00615 }
00616 }
00617
00618 void ncc_emit_instruction(asm86_t *a)
00619 {
00620 ack_emit_instruction(a);
00621 }