1 /* emit_ack.c - emit ACK assembly Author: Kees J. Bot
2 * emit NCC assembly 27 Dec 1993
13 #include "languages.h"
15 typedef struct mnemonic
{ /* ACK as86 mnemonics translation table. */
20 static mnemonic_t mnemtab
[] = {
47 { CMPXCHG
, "cmpxchg" },
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" },
95 { FDECSTP
, "fdecstp" },
100 { FDIVRS
, "fdivrs" },
103 { FIADDL
, "fiaddl" },
104 { FIADDS
, "fiadds" },
106 { FICOMP
, "ficomp" },
107 { FIDIVL
, "fidivl" },
108 { FIDIVRL
, "fidivrl" },
109 { FIDIVRS
, "fidivrs" },
110 { FIDIVS
, "fidivs" },
114 { FIMULL
, "fimull" },
115 { FIMULS
, "fimuls" },
116 { FINCSTP
, "fincstp" },
121 { FISUBL
, "fisubl" },
122 { FISUBRL
, "fisubrl" },
123 { FISUBRS
, "fisubrs" },
124 { FISUBS
, "fisubs" },
128 { FLDENV
, "fldenv" },
129 { FLDL2E
, "fldl2e" },
130 { FLDL2T
, "fldl2t" },
131 { FLDLG2
, "fldlg2" },
132 { FLDLN2
, "fldln2" },
141 { FPATAN
, "fpatan" },
143 { FPREM1
, "fprem1" },
145 { FRNDINT
, "frndint" },
146 { FRSTOR
, "frstor" },
148 { FSCALE
, "fscale" },
150 { FSINCOS
, "fsincos" },
154 { FSTENV
, "fstenv" },
162 { FSUBPR
, "fsubpr" },
163 { FSUBRD
, "fsubrd" },
164 { FSUBRS
, "fsubrs" },
168 { FUCOMP
, "fucomp" },
169 { FUCOMPP
, "fucompp" },
172 { FXTRACT
, "fxtract" },
174 { FYL2XP1
, "fyl2xp1" },
184 { INVLPG
, "invlpg" },
222 { LOOPNE
, "loopne" },
229 { MOVSXB
, "movsxb" },
231 { MOVZXB
, "movzxb" },
290 { WBINVD
, "wbinvd" },
297 #define farjmp(o) ((o) == JMPF || (o) == CALLF)
300 static long eline
= 1;
302 static char *orig_efile
;
303 static char *opcode2name_tab
[N_OPCODES
];
304 static enum dialect
{ ACK
, NCC
} dialect
= ACK
;
306 static void ack_putchar(int c
)
307 /* LOOK, this programmer checks the return code of putc! What an idiot, noone
311 if (putc(c
, ef
) == EOF
) fatal(orig_efile
);
314 static void ack_printf(const char *fmt
, ...)
319 if (vfprintf(ef
, fmt
, ap
) == EOF
) fatal(orig_efile
);
323 void ack_emit_init(char *file
, const char *banner
)
324 /* Prepare producing an ACK assembly file. */
332 if ((ef
= fopen(file
, "w")) == nil
) fatal(file
);
336 ack_printf("! %s", banner
);
337 if (dialect
== ACK
) {
338 /* Declare the four sections used under Minix. */
340 "\n.sect .text; .sect .rom; .sect .data; .sect .bss\n.sect .text");
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
;
350 #define opcode2name(op) (opcode2name_tab[op] + 0)
352 static void ack_put_string(const char *s
, size_t n
)
353 /* Emit a string with weird characters quoted. */
358 if (c
< ' ' || c
> 0177) {
359 ack_printf("\\%03o", c
& 0xFF);
361 if (c
== '"' || c
== '\\') {
362 ack_printf("\\%c", c
);
371 static 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.
378 switch (e
->operator) {
380 if (dialect
== NCC
&& farjmp(a
->opcode
)) {
381 /* ACK jmpf seg:off -> NCC jmpf off,seg */
382 ack_put_expression(a
, e
->right
, deref
);
384 ack_put_expression(a
, e
->left
, deref
);
386 ack_put_expression(a
, e
->left
, deref
);
387 ack_printf(farjmp(a
->opcode
) ? ":" : ", ");
388 ack_put_expression(a
, e
->right
, deref
);
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);
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(')');
404 ack_printf("(%s)", e
->name
);
410 ack_printf((use16() && e
->operator == '1')
411 ? "(%s)" : "(%s*%c)", e
->name
, e
->operator);
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);
431 if (deref
&& a
->optype
!= JUMP
) ack_putchar('#');
432 ack_put_expression(a
, e
->left
, 0);
433 if (e
->operator == S_LEFTSHIFT
) {
436 if (e
->operator == S_RIGHTSHIFT
) {
439 ack_putchar(e
->operator);
441 ack_put_expression(a
, e
->right
, 0);
444 if (deref
&& a
->optype
!= JUMP
) ack_putchar('#');
446 ack_put_expression(a
, e
->middle
, 0);
450 if (deref
&& a
->optype
== JUMP
&& isregister(e
->name
))
452 ack_printf("(%s)", e
->name
);
455 if (deref
&& a
->optype
!= JUMP
&& !isregister(e
->name
)) {
458 ack_printf("%s", e
->name
);
462 ack_put_string(e
->name
, e
->len
);
467 "asmconv: internal error, unknown expression operator '%d'\n",
473 void ack_emit_instruction(asm86_t
*a
)
474 /* Output one instruction and its operands. */
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) {
491 ack_printf("# %ld \"%s\"\n", a
->line
, a
->file
);
495 if (a
->line
== eline
) {
499 while (eline
< a
->line
) {
505 if (a
->opcode
== DOT_LABEL
) {
506 assert(a
->args
->operator == ':');
507 ack_printf("%s:", a
->args
->name
);
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);
514 if ((p
= opcode2name(a
->opcode
)) != nil
) {
515 char *sep
= dialect
== ACK
? "" : ";";
517 if (!is_pseudo(a
->opcode
) && !same
) ack_putchar('\t');
521 case REP
: ack_printf("rep"); break;
522 case REPE
: ack_printf("repe"); break;
523 case REPNE
: ack_printf("repne"); break;
526 if (a
->rep
!= ONCE
) {
527 ack_printf(dialect
== ACK
? " " : "; ");
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;
539 if (a
->seg
!= DEFSEG
) {
540 ack_printf(dialect
== ACK
? " " : "; ");
542 if (a
->oaz
& OPZ
) ack_printf(use16() ? "o32 " : "o16 ");
543 if (a
->oaz
& ADZ
) ack_printf(use16() ? "a32 " : "a16 ");
545 if (a
->opcode
== CBW
) {
546 p
= !(a
->oaz
& OPZ
) == use16() ? "cbw" : "cwde";
549 if (a
->opcode
== CWD
) {
550 p
= !(a
->oaz
& OPZ
) == use16() ? "cwd" : "cdq";
553 if (a
->opcode
== DOT_COMM
&& a
->args
!= nil
554 && a
->args
->operator == ','
555 && a
->args
->left
->operator == 'W'
557 ack_printf(".define\t%s; ", a
->args
->left
->name
);
561 if (a
->optype
== BYTE
) ack_putchar('b');
567 if (a
->args
!= nil
) {
576 deref
= (dialect
== NCC
&& a
->optype
!= PSEUDO
);
578 ack_put_expression(a
, a
->args
, deref
);
580 if (a
->opcode
== DOT_USE16
) set_use16();
581 if (a
->opcode
== DOT_USE32
) set_use32();
584 "asmconv: internal error, unknown opcode '%d'\n",
590 /* A few ncc mnemonics are different. */
591 static mnemonic_t ncc_mnemtab
[] = {
593 { DOT_DATA
, ".data" },
596 { DOT_TEXT
, ".text" },
599 void 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.)
610 ack_emit_init(file
, banner
);
612 /* Replace a few mnemonics. */
613 for (mp
= ncc_mnemtab
; mp
< arraylimit(ncc_mnemtab
); mp
++) {
614 opcode2name_tab
[mp
->opcode
]= mp
->name
;
618 void ncc_emit_instruction(asm86_t
*a
)
620 ack_emit_instruction(a
);