%{ /******************************************************* * * a56 - a DSP56001 assembler * * Written by Quinn C. Jensen * July 1990 * *******************************************************/ /* * Copyright (C) 1990-1994 Quinn C. Jensen * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. The author makes no representations * about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. * */ /* * a56.y - The YACC grammar for the assembler. * * Note: This module requires a "BIG" version of YACC. I had to * recompile YACC in the largest mode available. * * Other notes: * * MOVEC, MOVEM and MOVEP must be used explicitly--MOVE can't yet figure * out which form to use. * */ #include "a56.h" #include unsigned int w0, w1; /* workspace for the actual generated code */ BOOL uses_w1; /* says whether w1 is alive */ unsigned int pc; /* current program counter */ int seg; /* current segment P: X: Y: or L: */ int expr_seg; /* segment of current expression */ int just_rep = 0; /* keeps track of REP instruction */ int hot_rreg = -1; /* rreg loaded by prev inst. or -1 */ int hot_nreg = -1; /* nreg loaded by prev inst. or -1 */ int hot_mreg = -1; /* mreg loaded by prev inst. or -1 */ int prev_hot_rreg = -1; /* rreg loaded by prev inst. or -1 */ int prev_hot_nreg = -1; /* nreg loaded by prev inst. or -1 */ int prev_hot_mreg = -1; /* mreg loaded by prev inst. or -1 */ int substatement = 0; /* in a substatement */ BOOL long_symbolic_expr = FALSE; /* a parser flag */ char *new_include = NULL; /* file to be included */ /* listing stuff */ char segs[] = "uPXYL*"; extern BOOL list_on_next; /* listing to turn on or off */ BOOL list_on; /* listing on at the moment */ extern char *cur_line; /* points to line being lex'd */ char list_buf[1024 + 80]; /* listing buffer */ char list_buf2[1024 + 80]; /* listing buffer for two-line code */ BOOL uses_buf2 = FALSE; /* list_buf2 is alive */ BOOL list_print_line = FALSE; /* whether or not to print line in listing */ char *spaces(), *luntab(); struct n binary_op(); struct n unary_op(); struct n sym_ref(); #define R_R6 0x0001 #define R_R5 0x0002 #define R_R4 0x0004 #define R_DATA_ALU_ACCUM 0x0008 #define R_CTL_REG 0x0010 #define R_FUNKY_CTL_REG 0x0020 #define R_SDX 0x0040 #define R_SDY 0x0080 #define R_LSD 0x0100 #define R_AB 0x0200 #define R_XREG 0x0400 #define R_YREG 0x0800 /* registers to which short immediate move is an unsigned int */ #define R_UINT 0x1000 /* registers to which short immediate move is an signed frac */ #define R_SFRAC 0x2000 %} %union { int ival; /* integer value */ struct n n; /* just like in struct sym */ double dval; /* floating point value */ char *sval; /* string */ int cval; /* character */ char cond; /* condition */ struct regs { int r6, r5, r4, data_alu_accum, ctl_reg, funky_ctl_reg; int sdx, sdy, lsd, ab, xreg, yreg; int flags; } regs; struct ea { int mode; int ext; int pp; } ea; } %token CHEX CDEC FRAC %token AREG BREG MREG NREG RREG XREG YREG %token OP OPA OPP %token OP_JCC OP_JSCC OP_TCC %token SYM %token STRING %token CHAR %token XMEM %token YMEM %token LMEM %token PMEM %token AAAA %token A10 %token BBBB %token B10 %token AABB %token BBAA %token XXXX %token YYYY %token SR %token MR %token CCR %token OMR %token SP %token SSH %token SSL %token LA %token LC %token EOL %token EOS %token LEXBAD %token OP_ABS %token OP_ADC %token OP_ADD %token OP_ADDL %token OP_ADDR %token OP_ASL %token OP_ASR %token OP_CLR %token OP_CMP %token OP_CMPM %token OP_DIV %token OP_MAC %token OP_MACR %token OP_MPY %token OP_MPYR %token OP_NEG %token OP_NORM %token OP_RND %token OP_SBC %token OP_SUB %token OP_SUBL %token OP_SUBR %token OP_TFR %token OP_TST %token OP_AND %token OP_ANDI %token OP_EOR %token OP_LSL %token OP_LSR %token OP_NOT %token OP_OR %token OP_ORI %token OP_ROL %token OP_ROR %token OP_BCLR %token OP_BSET %token OP_BCHG %token OP_BTST %token OP_DO %token OP_ENDDO %token OP_LUA %token OP_MOVE %token OP_MOVEC %token OP_MOVEM %token OP_MOVEP %token OP_ILLEGAL %token OP_INCLUDE %token OP_JMP %token OP_JCLR %token OP_JSET %token OP_JSR %token OP_JSCLR %token OP_JSSET %token OP_NOP %token OP_REP %token OP_RESET %token OP_RTI %token OP_RTS %token OP_STOP %token OP_SWI %token OP_WAIT %token OP_EQU %token OP_ORG %token OP_DC %token OP_DS %token OP_DSM %token OP_END %token OP_PAGE %token OP_PSECT %token OP_ALIGN %token OP_INT %token SHL %token SHR %token OP_PI %token OP_SIN %token OP_COS %token OP_TAN %token OP_ATAN %token OP_ASIN %token OP_ACOS %token OP_EXP %token OP_LN %token OP_LOG %token OP_POW %type num num_or_sym %type num_or_sym_expr %type expr %type ix %type ix_long %type abs_addr abs_short_addr io_short_addr %type a_b x_or_y ea b5_10111_max %type p6_ean_a6 ea_no_ext p6_ea_a6 ea_a6 ea_a12 %type ea_short %type prog_ctl_reg %type op8_1 op8_2 op8_3 op8_4 op8_5 op8_6 op8_7 op8_8 %type mpy_arg mpy_srcs plus_minus %type sd3 %type funky_ctl_reg tcc_sd space %type opt_label %type regs %type movep_ea_pp %left '|' %left '^' %left SHL SHR %left '&' %left '+' '-' %left '*' '/' '%' %right '~' %start input %% /*%%%********************* top syntax ***********************/ input : /* empty */ | input statement ; statement : good_stuff EOL { if(pass == 2 && list_on && list_print_line) { printf(ldebug ? "\n(%s|%s)\n" : "%s%s\n", list_buf, substatement == 0 ? luntab(cur_line) : ""); if(uses_buf2) printf(ldebug ? "\n(%s|)\n" : "%s\n", list_buf2); list_buf[0] = list_buf2[0] = '\0'; } curline++; uses_buf2 = FALSE; list_print_line = TRUE; list_on = list_on_next; substatement = 0; if(NOT check_psect(seg, pc) && pass == 2) yyerror("%04X: psect violation", pc); } | good_stuff EOS { if(pass == 2 && list_on && list_print_line) { printf(ldebug ? "\n(%s" : "%s", list_buf); if(substatement == 0) printf(ldebug ? "|%s)\n" : "%s\n", luntab(cur_line)); else printf(ldebug ? ")\n" : "\n"); if(uses_buf2) printf(ldebug ? "\n(%s|)\n" : "%s\n", list_buf2); list_buf[0] = list_buf2[0] = '\0'; } substatement++; uses_buf2 = FALSE; list_print_line = TRUE; list_on = list_on_next; if(NOT check_psect(seg, pc) && pass == 2) yyerror("%04X: psect violation", pc); } | error EOL {curline++; substatement = 0;} ; good_stuff : /* empty */ {sprintf(list_buf, "%s", spaces(0));} | cpp_droppings {list_print_line = FALSE;} | assembler_ops {long_symbolic_expr = FALSE;} | label_field operation_field {char *printcode(); if(pass == 2) { gencode(seg, pc, w0); sprintf(list_buf, "%c:%04X %s ", segs[seg], pc, printcode(w0)); pc++; if(uses_w1) { gencode(seg, pc, w1); sprintf(list_buf2, "%c:%04X %s", segs[seg], pc, printcode(w1 & 0xFFFFFF)); uses_buf2++; pc++; } } else { pc++; if(uses_w1) pc++; } w0 = w1 = 0; uses_w1 = FALSE; long_symbolic_expr = FALSE;} | SYM {sym_def($1, INT, seg, pc); free($1); if(pass == 2 && list_on) { sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8)); long_symbolic_expr = FALSE; }} ; cpp_droppings : '#' num STRING {if(strlen($3) > 0) curfile = $3; else curfile = ""; curline = $2.val.i - 1;} ; assembler_ops : SYM OP_EQU expr {sym_def($1, $3.type, ANY, $3.val.i, $3.val.f); free($1); if(pass == 2 && list_on) { if($3.type == INT) sprintf(list_buf, "%06X%s", $3.val.i & 0xFFFFFF, spaces(14-8)); else sprintf(list_buf, "%10g%s", $3.val.f, spaces(14-4)); }} | OP_ALIGN expr {int ival = n2int($2); if($2.type == UNDEF) { yyerror("illegal forward reference"); } else if (ival <= 1) { yyerror("%d: illegal alignment", ival); } else { if(pc % ival != 0) pc += ival - pc % ival; } if(pass == 2 && list_on) sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8)); } | OP_PSECT SYM {struct psect *pp = find_psect($2); if(NOT pp) { if(pass == 2) yyerror("%s: undefined psect", $2); } else { seg = pp->seg; pc = pp->pc; set_psect(pp); if(pass == 2 && list_on) sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8)); } free($2);} | OP_PSECT SYM space expr ':' expr {new_psect($2, $3, n2int($4), n2int($6)); if(pass == 2 && list_on) sprintf(list_buf, "%c:%04X %04X%s", segs[$3], n2int($4), n2int($6), spaces(14-8+4+1)); } | OP_ORG space expr {pc = n2int($3); seg = $2; if(pass == 2 && list_on) sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8)); } | OP_ORG space expr ',' space expr {pc = n2int($3); seg = $2; if(pass == 2 && list_on) sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8)); } | label_field OP_DC dc_list | label_field OP_DS expr {pc += n2int($3); if(pass == 2 && list_on) sprintf(list_buf, "%c:%04X%s", segs[seg], pc, spaces(14-8)); } | opt_label OP_DSM expr {int size = n2int($3); if(size) { int align = 1; while(align < size) align <<= 1; pc += (align - (pc % align)); } if($1) { sym_def($1, INT, seg, pc); free($1); } pc += size; } | OP_PAGE num ',' num ',' num ',' num {if(pass == 2 && list_on) { sprintf(list_buf, "%s", spaces(0)); }} | OP_INCLUDE STRING {if(pass == 2 && list_on) { printf(ldebug ? "\n(%s|%s)\n" : "%s%s\n", spaces(0), luntab(cur_line)); list_print_line = FALSE; } include($2); /* free($2); */ } | OP_END {if(pass == 2 && list_on) { sprintf(list_buf, "%s", spaces(0)); }} ; dc_list : dc_list ',' dc_stuff | dc_stuff ; dc_stuff : STRING {int len = strlen($1), i; char *cp; w0 = 0; if(len % 3 == 2) len++; /* force empty word */ for(i = 0, cp = $1; i < len; i++, cp++) { w0 |= (*cp & 0xFF) << (2 - (i % 3)) * 8; if(i % 3 == 2 || i == len - 1) { if(pass == 2) { if(list_on) sprintf(list_buf, "%c:%04X %06X%s", segs[seg], pc, w0, spaces(14-6+5)); gencode(seg, pc, w0); } pc++; w0 = 0; } } free($1);} | expr {int frac = n2frac($1); if(pass == 2) { if(list_on) { sprintf(list_buf, "%c:%04X %06X%s", segs[seg], pc, frac & 0xFFFFFF, spaces(14-6+5)); } gencode(seg, pc, frac); } pc++;} space : PMEM {$$ = PROG;} | XMEM {$$ = XDATA;} | YMEM {$$ = YDATA;} | LMEM {$$ = LDATA;} ; label_field : SYM {sym_def($1, INT, seg, pc); free($1);} | /* empty */ ; opt_label : SYM {$$ = $1;} | /* empty */ {$$ = NULL;} ; operation_field : operation {prev_hot_rreg = hot_rreg; prev_hot_nreg = hot_nreg; prev_hot_mreg = hot_mreg; hot_rreg = hot_nreg = hot_mreg = -1; if(just_rep) just_rep--;} ; operation : no_parallel | parallel_ok {w0 |= 0x200000;} | parallel_ok parallel_move ; /*%%%************* instructions that allow parallel moves ****************/ parallel_ok : OP_MPY mpy_arg {w0 |= 0x80 | $2 << 2;} | OP_MPYR mpy_arg {w0 |= 0x81 | $2 << 2;} | OP_MAC mpy_arg {w0 |= 0x82 | $2 << 2;} | OP_MACR mpy_arg {w0 |= 0x83 | $2 << 2;} | OP_SUB op8_1 {w0 |= 0x04 | $2 << 3;} | OP_ADD op8_1 {w0 |= 0x00 | $2 << 3;} | OP_MOVE {w0 |= 0x00;} | OP_TFR op8_2 {w0 |= 0x01 | $2 << 3;} | OP_CMP op8_2 {w0 |= 0x05 | $2 << 3;} | OP_CMPM op8_2 {w0 |= 0x07 | $2 << 3;} | OP_RND op8_3 {w0 |= 0x11 | $2 << 3;} | OP_ADDL op8_3 {w0 |= 0x12 | $2 << 3;} | OP_CLR op8_3 {w0 |= 0x13 | $2 << 3;} | OP_SUBL op8_3 {w0 |= 0x16 | $2 << 3;} | OP_NOT op8_3 {w0 |= 0x17 | $2 << 3;} | OP_ADDR op8_4 {w0 |= 0x02 | $2 << 3;} | OP_TST op8_4 {w0 |= 0x03 | $2 << 3;} | OP_SUBR op8_4 {w0 |= 0x06 | $2 << 3;} | OP_AND op8_5 {w0 |= 0x46 | $2 << 3;} | OP_OR op8_5 {w0 |= 0x42 | $2 << 3;} | OP_EOR op8_5 {w0 |= 0x43 | $2 << 3;} | OP_ASR op8_6 {w0 |= 0x22 | $2 << 3;} | OP_LSR op8_6 {w0 |= 0x23 | $2 << 3;} | OP_ABS op8_6 {w0 |= 0x26 | $2 << 3;} | OP_ROR op8_6 {w0 |= 0x27 | $2 << 3;} | OP_ASL op8_7 {w0 |= 0x32 | $2 << 3;} | OP_LSL op8_7 {w0 |= 0x33 | $2 << 3;} | OP_NEG op8_7 {w0 |= 0x36 | $2 << 3;} | OP_ROL op8_7 {w0 |= 0x37 | $2 << 3;} | OP_ADC op8_8 {w0 |= 0x21 | $2 << 3;} | OP_SBC op8_8 {w0 |= 0x25 | $2 << 3;} ; mpy_arg : plus_minus mpy_srcs ',' a_b {$$ = $1 | $4 << 1 | $2 << 2;} ; plus_minus : '+' {$$ = 0;} | '-' {$$ = 1;} | {$$ = 0;} ; mpy_srcs : XREG ',' XREG {switch ($1 << 4 | $3) { case 0x00: $$ = 0x0; break; case 0x01: case 0x10: $$ = 0x2; break; case 0x11: yyerror("illegal source operands"); break; }} | YREG ',' YREG {switch ($1 << 4 | $3) { case 0x00: $$ = 0x1; break; case 0x01: case 0x10: $$ = 0x3; break; case 0x11: yyerror("illegal source operands"); break; }} | XREG ',' YREG {switch ($1 << 4 | $3) { case 0x00: $$ = 0x5; break; case 0x01: $$ = 0x4; break; case 0x10: $$ = 0x6; break; case 0x11: $$ = 0x7; break; }} | YREG ',' XREG {switch ($1 << 4 | $3) { case 0x00: $$ = 0x5; break; case 0x01: $$ = 0x6; break; case 0x10: $$ = 0x4; break; case 0x11: $$ = 0x7; break; }} ; op8_1 : BBBB ',' AAAA {$$ = 0x2;} | AAAA ',' BBBB {$$ = 0x3;} | XXXX ',' a_b {$$ = 0x4 | $3;} | YYYY ',' a_b {$$ = 0x6 | $3;} | XREG ',' a_b {$$ = 0x8 | $1 << 2 | $3;} | YREG ',' a_b {$$ = 0xA | $1 << 2 | $3;} ; op8_2 : BBBB ',' AAAA {$$ = 0x0;} | AAAA ',' BBBB {$$ = 0x1;} | XREG ',' a_b {$$ = 0x8 | $1 << 2 | $3;} | YREG ',' a_b {$$ = 0xA | $1 << 2 | $3;} ; op8_3 : AAAA {$$ = 0x0;} | BBBB {$$ = 0x1;} | BBBB ',' AAAA {$$ = 0x0;} | AAAA ',' BBBB {$$ = 0x1;} ; op8_4 : op8_3 {$$ = $1;} ; op8_5 : XREG ',' a_b {$$ = 0x0 | $1 << 2 | $3;} | YREG ',' a_b {$$ = 0x2 | $1 << 2 | $3;} ; op8_6 : a_b {$$ = $1;} ; op8_7 : a_b {$$ = $1;} ; op8_8 : XXXX ',' a_b {$$ = 0x0 | $3;} | YYYY ',' a_b {$$ = 0x2 | $3;} ; a_b : AAAA {$$ = 0;} | BBBB {$$ = 1;} ; no_parallel : control_inst {if(just_rep == 1) yyerror("instruction not allowed after REP");} | bit_inst | move_inst | arith_inst ; /*%%%************** non-parallel arithmetic and logical ********************/ arith_inst : OP_NORM RREG ',' a_b {w0 |= 0x01D815 | $2 << 8 | $4 << 3;} | OP_DIV sd3 {w0 |= 0x018040 | $2 << 3;} | or_op ix ',' funky_ctl_reg {w0 |= 0x0000F8 | (n2int($2) & 0xFF) << 8 | $4;} | and_op ix ',' funky_ctl_reg {w0 |= 0x0000B8 | (n2int($2) & 0xFF) << 8 | $4;} ; or_op : OP_OR | OP_ORI ; and_op : OP_AND | OP_ANDI ; /*%%%******************************* control instructions **********************/ control_inst : OP_JSCC ea_a12 {if($2) { w0 |= 0x0BC0A0 | $1 << 0; } else { w0 |= 0x0F0000 | $1 << 12; }} | OP_JCC ea_a12 {if($2) { w0 |= 0x0AC0A0 | $1 << 0; } else { w0 |= 0x0E0000 | $1 << 12; }} | OP_JSR ea_a12 {if($2) { w0 |= 0x0BC080; } else { w0 |= 0x0D0000; }} | OP_JMP ea_a12 {if($2) { w0 |= 0x0AC080; } else { w0 |= 0x0C0000; }} | OP_JSSET control_args {w0 |= 0x0B0020;} | OP_JSCLR control_args {w0 |= 0x0B0000;} | OP_JSET control_args {w0 |= 0x0A0020;} | OP_JCLR control_args {w0 |= 0x0A0000;} | OP_REP rep_args {just_rep = 2;} | OP_DO do_args {uses_w1++;} | OP_ENDDO {w0 |= 0x00008C;} | OP_STOP {w0 |= 0x000087;} | OP_WAIT {w0 |= 0x000086;} | OP_RESET {w0 |= 0x000084;} | OP_RTS {w0 |= 0x00000C;} | OP_SWI {w0 |= 0x000006;} | OP_ILLEGAL {w0 |= 0x000005;} | OP_RTI {w0 |= 0x000004;} | OP_NOP {w0 |= 0x000000; just_rep = 0;} ; do_args : ix ',' abs_addr {int ival = n2int($1); w0 |= 0x060080 | (ival & 0xFF) << 8 | (ival & 0xF00)>> 8; if(ival > 0xFFF && pass == 2) { yywarning("warning: immediate operand truncated"); } w1 |= $3-1;} | regs ',' abs_addr {w0 |= 0x06C000 | $1.r6 << 8; hot_rreg = hot_nreg = hot_mreg = -1; w1 |= $3-1;} | x_or_y ea_no_ext ',' abs_addr {w0 |= 0x064000 | $2 << 8 | $1 << 6; w1 |= $4-1;} | x_or_y abs_short_addr ',' abs_addr /* allow forced */ {w0 |= 0x060000 | ($2 & 0x3F) << 8 | $1 << 6; /* * $$$ oops, can't check expr_seg because both abs_short_addr and * abs_addr touch it */ if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); w1 |= $4-1;} | x_or_y abs_addr ',' abs_addr {w0 |= 0x060000 | ($2 & 0x3F) << 8 | $1 << 6; /* * $$$ oops, can't check expr_seg because both abs_short_addr and * abs_addr touch it */ if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); w1 |= $4-1;} ; rep_args : ix {int ival = n2int($1); w0 |= 0x0600A0 | (ival & 0xFF) << 8 | (ival & 0xF00)>> 8; if(ival > 0xFFF && pass == 2) { yywarning("warning: immediate operand truncated"); }} | regs {w0 |= 0x06C020 | $1.r6 << 8; hot_rreg = hot_nreg = hot_mreg = -1;} | x_or_y ea_no_ext {w0 |= 0x064020 | $1 << 6 | $2 << 8;} | x_or_y abs_addr {w0 |= 0x060020 | $1 << 6 | ($2 & 0x3F) << 8; if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA || $1 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); } | x_or_y abs_short_addr /* forced */ {w0 |= 0x060020 | $1 << 6 | ($2 & 0x3F) << 8; if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA || $1 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); } ; control_args : b5_10111_max ',' x_or_y p6_ean_a6 ',' abs_addr {w0 |= $1 << 0 | $3 << 6; uses_w1++; w1 = $6;} | b5_10111_max ',' regs ',' abs_addr {w0 |= 0x00C000 | $1 << 0 | $3.r6 << 8; hot_rreg = hot_nreg = hot_mreg = -1; uses_w1++; w1 = $5;} ; p6_ean_a6 : abs_addr /* in pass 2 can always discern size. */ /* Sometimes in pass one, too. But since */ /* address extension is always used for the */ /* branch target, pass 1 can assume the */ /* symbol value will fit; warning in pass 2 */ /* if it doesn't */ {if($1 != -1) { /* symbol defined */ w0 |= ($1 & 0x3F) << 8; if($1 >= 0xFFC0) { w0 |= 0x008080; } else { w0 |= 0x000080; if($1 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); } }} | abs_short_addr {if($1 != -1) { if($1 > 0x3F && pass == 2) yywarning("warning: address operand truncated"); w0 |= 0x000080 | ($1 & 0x3F) << 8; }} | io_short_addr {if($1 != -1) { if($1 < 0xFFC0 && pass == 2) yywarning("warning: address operand truncated"); w0 |= 0x008080 | ($1 & 0x3F) << 8; }} | ea_no_ext {w0 |= 0x004080 | $1 << 8;} ; /*%%%**************************** bit instructions ***************************/ bit_inst : OP_BTST bit_args {w0 |= 0x0B0020;} | OP_BCHG bit_args {w0 |= 0x0B0000;} | OP_BSET bit_args {w0 |= 0x0A0020;} | OP_BCLR bit_args {w0 |= 0x0A0000;} ; bit_args : b5_10111_max ',' x_or_y p6_ea_a6 {w0 |= $1 << 0 | $3 << 6; } | b5_10111_max ',' regs {w0 |= 0x00C040 | $1 << 0 | $3.r6 << 8;} ; p6_ea_a6 : io_short_addr /* must be forced to tell from abs_addr */ {if($1 != -1) { w0 |= ($1 & 0x3F) << 8 | 0x008000; if($1 < 0xFFC0 && pass == 2) yywarning("warning: address operand truncated"); }} | abs_short_addr /* must be forced to tell from abs_addr */ {if($1 != -1) { w0 |= ($1 & 0x3F) << 8 | 0x000000; if($1 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); }} | ea /* can use abs_addr */ {w0 |= 0x004000;} ; /*%%%************************** move instructions **********************/ move_inst : OP_MOVEP movep_args | OP_MOVEM movem_args | OP_MOVEC movec_args | OP_LUA ea_short ',' regs {w0 |= 0x044010 | $2 << 8 | $4.r4;} | OP_TCC tcc_args {w0 |= $1 << 12;} ; tcc_args : tcc_sd {w0 |= 0x020000 | $1 << 3;} | tcc_sd RREG ',' RREG {w0 |= 0x030000 | $1 << 3 | $2 << 8 | $4;} ; tcc_sd : regs /* a_b */ ',' regs /* a_b */ {hot_rreg = hot_nreg = hot_mreg = -1; if($1.flags & R_AB && $3.flags & R_AB) { if($1.ab == $3.ab) yyerror("source and dest must be different"); $$ = $3.ab; } else if($1.flags & R_XREG && $3.flags & R_AB) { $$ = 0x8 | $1.xreg << 2 | $3.ab; } else if($1.flags & R_YREG && $3.flags & R_AB) { $$ = 0xA | $1.yreg << 2 | $3.ab; } else yyerror("illegal TCC operands"); } ; sd3 : regs /* XREG */ ',' regs /* a_b */ {hot_rreg = hot_nreg = hot_mreg = -1; if($1.flags & R_XREG && $3.flags & R_AB) { $$ = $1.xreg << 2 | $3.ab; } else if($1.flags & R_YREG && $3.flags & R_AB) { $$ = $1.yreg << 2 | 2 | $3.ab; }} ; movec_args : x_or_y ea ',' regs /* ctl_reg */ {if(NOT ($4.flags & R_CTL_REG)) yyerror("bad MOVEC target register"); if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA || $1 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($1 == 0) { w0 |= 0x05C020 | $4.ctl_reg; } else { w0 |= 0x05C060 | $4.ctl_reg; }} | regs /* ctl_reg */ ',' x_or_y ea {hot_rreg = hot_nreg = hot_mreg = -1; if(NOT ($1.flags & R_CTL_REG)) yyerror("bad MOVEC source register"); if($3 == 0) { w0 |= 0x054020 | $1.ctl_reg; } else { w0 |= 0x054060 | $1.ctl_reg; }} | ix ',' regs /* ctl_reg */ {int ival = n2int($1); if(NOT ($3.flags & R_CTL_REG)) yyerror("bad MOVEC target register"); if(ival < 256 && NOT long_symbolic_expr) { w0 |= 0x0500A0 | (ival & 0xFF) << 8 | $3.ctl_reg; } else { w0 |= 0x05C020 | 0x003400 | $3.ctl_reg; uses_w1++; w1 = ival & 0xFFFF; }} | x_or_y abs_short_addr ',' regs /* ctl_reg */ {if($1 == 0) { w0 |= 0x058020 | ($2 & 0x3F) << 8 | $4.ctl_reg; } else { w0 |= 0x058060 | ($2 & 0x3F) << 8 | $4.ctl_reg; } if(NOT ($4.flags & R_CTL_REG)) yyerror("bad MOVEC target register"); if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); } | regs /* ctl_reg */ ',' x_or_y abs_short_addr {hot_rreg = hot_nreg = hot_mreg = -1; if($3 == 0) { w0 |= 0x050020 | ($4 & 0x3F) << 8 | $1.ctl_reg; } else { w0 |= 0x050060 | ($4 & 0x3F) << 8 | $1.ctl_reg; } if(NOT ($1.flags & R_CTL_REG)) yyerror("bad MOVEC source register"); if($4 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); } | regs /* ctl_reg */ ',' regs {if($1.flags & R_CTL_REG) { w0 |= 0x0440A0 | $3.r6 << 8 | $1.ctl_reg; } else if($3.flags & R_CTL_REG) { w0 |= 0x04C0A0 | $1.r6 << 8 | $3.ctl_reg; } else if($1.flags & $3.flags & R_CTL_REG) { /* bogus? $$$ */ w0 |= 0x04C0A0 | ($1.ctl_reg | 0x20) << 8 | $3.ctl_reg; } else { yyerror("MOVEC must reference a control reg"); }} ; movep_args : x_or_y movep_ea_pp ',' x_or_y movep_ea_pp {w0 |= 0x084080; switch($2.pp << 1 | $5.pp) { case 0: case 3: yyerror("illegal MOVEP; can't move EA to EA or IO to IO"); break; case 1: /* ea, pp */ w0 |= $4 << 16 | 1 << 15 | $1 << 6 | ($5.ext & 0x3F); if($2.mode == 0x003000) { w0 |= 0x003000; uses_w1++; w1 = $2.ext; } else { w0 |= $2.mode; } break; case 2: /* pp, ea */ w0 |= $1 << 16 | 0 << 15 | $4 << 6 | ($2.ext & 0x3F); if($5.mode == 0x003000) { w0 |= 0x003000; uses_w1++; w1 = $5.ext; } else { w0 |= $5.mode; } break; }} | ix ',' x_or_y num_or_sym {w0 |= 0x084080; w0 |= $3 << 16 | 1 << 15 | 0x34 << 8 | (n2int($4) & 0x3F); uses_w1++; w1 = n2int($1);} | PMEM ea ',' x_or_y num_or_sym {w0 |= 0x084040; w0 |= $4 << 16 | 1 << 15 | (n2int($5) & 0x3F);} | x_or_y movep_ea_pp ',' PMEM ea {w0 |= 0x084040; if($2.mode != 0x003000 && $2.mode != 0) yyerror("illegal MOVEP"); w0 |= $1 << 16 | 0 << 15 | ($2.ext & 0x3F);} | regs ',' x_or_y num_or_sym {hot_rreg = hot_nreg = hot_mreg = -1; w0 |= 0x084000; w0 |= $3 << 16 | 1 << 15 | $1.r6 << 8 | (n2int($4) & 0x3F);} | x_or_y movep_ea_pp ',' regs {hot_rreg = hot_nreg = hot_mreg = -1; w0 |= 0x084000; if(!$2.pp) yyerror("illegal MOVEP"); w0 |= $1 << 16 | 0 << 15 | $4.r6 << 8 | ($2.ext & 0x3F);} ; movep_ea_pp : abs_addr {if($1 != UNDEF && $1 >= 0xFFC0) { /* defined symbol or constant, in i/o range */ $$.pp = 1; $$.mode = 0; } else { /* either out of i/o range or symbol not */ /* yet defined: assume ea extension */ $$.pp = 0; $$.mode = 0x003000; } $$.ext = $1;} | io_short_addr /* forced i/o short */ {$$.pp = 1; $$.mode = 0; if($1 < 0xFFC0 && pass == 2) yywarning("warning: address operand truncated"); $$.ext = $1;} | ea_no_ext {$$.pp = 0; $$.mode = $1 << 8; $$.ext = $1;} ; movem_args : regs ',' PMEM ea_a6 {w0 |= 0x070000 | 0 << 15 | $1.r6;} | PMEM ea_a6 ',' regs {hot_rreg = hot_nreg = hot_mreg = -1; w0 |= 0x070000 | 1 << 15 | $4.r6;} ; /*%%%**************** memory reference fields ************************/ b5_10111_max : ix {int ival = n2int($1); $$ = ival; if(ival > 0x17) yyerror("%d: illegal bit number", ival);} ; x_or_y : XMEM {$$ = 0;} | YMEM {$$ = 1;} ; /*%%%**************** effective address fields ************************/ ea_a6 : ea {w0 |= 0x004080;} | abs_short_addr {w0 |= ($1 & 0x3F) << 8; if($1 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); } ; ea_a12 : ea {$$ = 1;} | abs_short_addr {w0 |= $1 & 0xFFF; $$ = 0; if($1 > 0x0FFF && pass == 2) yywarning("warning: address operand truncated"); } ; ea : abs_addr {w0 |= 0x003000; uses_w1++; w1 |= $1; $$ = 0x003000;} | ea_no_ext {w0 |= $1 << 8; $$ = $1 << 8; expr_seg = ANY;} ; ea_no_ext : ea_short {$$ = $1;} | '(' RREG ')' {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2); $$ = 4 << 3 | $2;} | '(' RREG '+' NREG ')' {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2); if($4 == prev_hot_nreg) yywarning("warning: n%d just loaded", $4); if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2); $$ = 5 << 3 | $2; if($2 != $4) yyerror("Rn and Nn must be same number");} | '-' '(' RREG ')' {if($3 == prev_hot_rreg) yywarning("warning: r%d just loaded", $3); if($3 == prev_hot_mreg) yywarning("warning: m%d just loaded", $3); $$ = 7 << 3 | $3;} ; ea_short : '(' RREG ')' '-' NREG {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2); if($5 == prev_hot_nreg) yywarning("warning: n%d just loaded", $5); if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2); $$ = 0 << 3 | $2; expr_seg = ANY; if($2 != $5) yyerror("Rn and Nn must be same number");} | '(' RREG ')' '+' NREG {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2); if($5 == prev_hot_nreg) yywarning("warning: n%d just loaded", $5); if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2); $$ = 1 << 3 | $2; expr_seg = ANY; if($2 != $5) yyerror("Rn and Nn must be same number");} | '(' RREG ')' '-' {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2); if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2); expr_seg = ANY; $$ = 2 << 3 | $2;} | '(' RREG ')' '+' {if($2 == prev_hot_rreg) yywarning("warning: r%d just loaded", $2); if($2 == prev_hot_mreg) yywarning("warning: m%d just loaded", $2); expr_seg = ANY; $$ = 3 << 3 | $2;} ; /*%%%******************* register fields ******************************/ regs : XREG {$$.r6 = $$.r5 = 0x04 | $1; $$.sdx = $1; $$.xreg = $1; $$.flags = R_R6|R_R5|R_XREG|R_SDX|R_SFRAC;} | YREG {$$.r6 = $$.r5 = 0x06 | $1; $$.sdy = $1; $$.yreg = $1; $$.flags = R_R6|R_R5|R_SDY|R_YREG|R_SFRAC;} | AREG {switch($1) { case 0: $$.r6 = $$.r5 = 0x08 | 0; break; case 1: $$.r6 = $$.r5 = 0x08 | 4; break; case 2: $$.r6 = $$.r5 = 0x08 | 2; break; } $$.flags = R_R6|R_R5|R_UINT;} | BREG {switch($1) { case 0: $$.r6 = $$.r5 = 0x08 | 1; break; case 1: $$.r6 = $$.r5 = 0x08 | 5; break; case 2: $$.r6 = $$.r5 = 0x08 | 3; break; } $$.flags = R_R6|R_R5|R_UINT;} | AAAA {$$.r6 = $$.r5 = 0x0E; $$.sdx = $$.sdy = 0x2; $$.ab = 0; $$.lsd = 4; $$.flags = R_R6|R_R5|R_SDX|R_SDY|R_AB|R_LSD|R_SFRAC;} | BBBB {$$.r6 = $$.r5 = 0x0F; $$.sdx = $$.sdy = 0x3; $$.ab = 1; $$.lsd = 5; $$.flags = R_R6|R_R5|R_SDX|R_SDY|R_AB|R_LSD|R_SFRAC;} | RREG {$$.r6 = $$.r5 = 0x10 | $1; $$.r4 = 0x00 | $1; $$.flags = R_R6|R_R5|R_R4|R_UINT; hot_rreg = $1;} | NREG {$$.r6 = $$.r5 = 0x18 | $1; $$.r4 = 0x08 | $1; $$.flags = R_R6|R_R5|R_R4|R_UINT; hot_nreg = $1;} | MREG {$$.r6 = 0x20 | $1; $$.r5 = -1; $$.ctl_reg = $1; $$.flags = R_R6|R_R5|R_CTL_REG|R_UINT; hot_mreg = $1;} | prog_ctl_reg {$$.r6 = 0x38 | $1; $$.r5 = -1; $$.ctl_reg = 0x18 | $1; $$.flags = R_R6|R_R5|R_CTL_REG|R_UINT;} | A10 {$$.lsd = 0; $$.flags = R_LSD;} | B10 {$$.lsd = 1; $$.flags = R_LSD;} | XXXX {$$.lsd = 2; $$.flags = R_LSD;} | YYYY {$$.lsd = 3; $$.flags = R_LSD;} | AABB {$$.lsd = 6; $$.flags = R_LSD;} | BBAA {$$.lsd = 7; $$.flags = R_LSD;} ; prog_ctl_reg : SR {$$ = 1;} | OMR {$$ = 2;} | SP {$$ = 3;} | SSH {$$ = 4;} | SSL {$$ = 5;} | LA {$$ = 6;} | LC {$$ = 7;} ; funky_ctl_reg : MR {$$ = 0;} | CCR {$$ = 1;} | OMR {$$ = 2;} ; /*%%%************************* parallel moves *************/ parallel_move : i_move | u_move | x_or_y_move | xr_move | ry_move | r_move | xy_move | l_move ; i_move : ix ',' regs {int ival = n2int($1); int frac = n2frac($1); int value; BOOL shortform = FALSE; if($3.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } if(($3.flags & R_SFRAC) && $1.type == FLT) { if((frac & 0xFFFF) == 0 && NOT long_symbolic_expr) { value = frac >> 16; shortform++; } else { value = frac; } } else { if(ival <= 0xFF && ival >= -0xFF && NOT long_symbolic_expr) { value = ival; shortform++; } else { value = ival; } } if(shortform) { w0 |= 0x200000 | (value & 0xFF) << 8 | $3.r5 << 16; } else { w0 |= 0x400000 | 0x00F400 | ($3.r5 >> 3 & 3) << 20 | ($3.r5 & 7) << 16; uses_w1++; w1 = value; }} ; r_move : regs ',' regs { if($3.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } if($1.flags & R_R5 & $3.flags) w0 |= 0x200000 | $3.r5 << 8 | $1.r5 << 13; else yyerror("illegal R move"); } ; u_move : ea_short {w0 |= 0x204000 | $1 << 8;} ; x_or_y_move : x_or_y ea ',' regs {w0 |= 0x40C000 | $1 << 19; if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA || $1 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($4.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } w0 |= ($4.r5 >> 3 & 3) << 20 | ($4.r5 & 7) << 16;} | x_or_y abs_short_addr ',' regs {w0 |= 0x408000 | $1 << 19 | ($2 & 0x3F) << 8; if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA || $1 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($4.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); w0 |= ($4.r5>> 3 & 3) << 20 | ($4.r5 & 7) << 16;} | regs ',' x_or_y ea {hot_rreg = hot_nreg = hot_mreg = -1; w0 |= 0x404000 | $3 << 19; if(expr_seg != ANY && ($3 == 0 && expr_seg != XDATA || $3 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($1.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } w0 |= ($1.r5 >> 3 & 3) << 20 | ($1.r5 & 7) << 16;} | regs ',' x_or_y abs_short_addr {hot_rreg = hot_nreg = hot_mreg = -1; w0 |= 0x400000 | $3 << 19 | ($4 & 0x3F) << 8; if($1.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } if(expr_seg != ANY && ($3 == 0 && expr_seg != XDATA || $3 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($4 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); w0 |= ($1.r5 >> 3 & 3) << 20 | ($1.r5 & 7) << 16;} | ix_long ',' regs {w0 |= 0x400000 | 0x00F400 | ($3.r5 >> 3 & 3) << 20 | ($3.r5 & 7) << 16; if($3.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } uses_w1++; w1 = n2frac($1); } ; xr_move : x_or_y /* XMEM */ ea ',' regs regs /* a_b */ ',' YREG {hot_rreg = hot_nreg = hot_mreg = -1; if(expr_seg != ANY && ($1 == 0 && expr_seg != XDATA || $1 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($1 == 0 && $5.flags & R_AB) { w0 |= 0x108000 | $4.sdx << 18 | $5.ab << 17 | $7 << 16; } else { yyerror("illegal X:R move"); }} | ix ',' regs regs /* a_b */ ',' YREG {hot_rreg = hot_nreg = hot_mreg = -1; if($4.flags & R_AB) { w0 |= 0x10B400 | $3.sdx << 18 | $4.ab << 17 | $6 << 16; uses_w1++; w1 |= n2frac($1) & 0xFFFFFF; } else { yyerror("illegal X:R move"); }} | regs ',' x_or_y /* XMEM */ ea regs /* a_b */ ',' regs/*YREG*/ {hot_rreg = hot_nreg = hot_mreg = -1; if(expr_seg != ANY && ($3 == 0 && expr_seg != XDATA || $3 == 1 && expr_seg != YDATA)) yywarning("warning: space mismatch"); if($1.flags & R_SDX && $3 == 0 && $5.flags & R_AB && $7.flags & R_YREG) { w0 |= 0x100000 | $1.sdx << 18 | $5.ab << 17 | $7.yreg << 16; } else if($1.flags & R_AB && $3 == 0 && $5.flags & R_XREG && $7.flags & R_AB) { if($5.xreg != 0) yyerror("must use X0"); if($1.ab == 0 && $7.ab == 0) w0 |= 0x080000; else if($1.ab == 1 && $7.ab == 1) w0 |= 0x090000; else yyerror("illegal X:R move"); } else { yyerror("illegal X:R move"); }} ; ry_move : regs /* a_b */ ',' regs /* XREG */ YMEM ea ',' regs {hot_rreg = hot_nreg = hot_mreg = -1; if($3.flags & R_XREG && $7.flags & (R_YREG|R_AB)) { w0 |= 0x10C000 | $1.ab << 19 | $3.xreg << 18 | $7.sdy << 16; } else { yyerror("illegal R:Y move"); }} | regs /* a_b */ ',' regs /* XREG */ ix ',' regs {hot_rreg = hot_nreg = hot_mreg = -1; if($3.flags & R_XREG && $6.flags & (R_YREG|R_AB)) { w0 |= 0x10F400 | $1.ab << 19 | $3.xreg << 18 | $6.sdy << 16; uses_w1++; w1 |= n2frac($4) & 0xFFFFFF; } else { yyerror("illegal R:Y move"); }} | regs /* a_b */ ',' regs /* XREG */ regs ',' YMEM ea {hot_rreg = hot_nreg = hot_mreg = -1; if($1.flags & R_AB && $3.flags & R_XREG) { w0 |= 0x104000 | $1.ab << 19 | $3.xreg << 18 | $4.sdy << 16; } else if ($1.flags & R_YREG && $3.flags & R_AB && $4.flags & R_AB) { if($1.yreg != 0) yyerror("must use Y0"); if($3.ab == 0 && $4.ab == 0) w0 |= 0x088000; else if($3.ab == 1 && $4.ab == 1) w0 |= 0x098000; else yyerror("illegal R:Y move"); } else { yyerror("illegal R:Y move"); }} ; l_move : LMEM ea ',' regs /* lsd */ {if($4.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } w0 |= 0x40C000 | ($4.lsd & 3) << 16 | ($4.lsd >> 2) << 19;} | regs /* lsd */ ',' LMEM ea {hot_rreg = hot_nreg = hot_mreg = -1; if($1.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } w0 |= 0x404000 | ($1.lsd & 3) << 16 | ($1.lsd >> 2) << 19;} | LMEM abs_short_addr ',' regs /* lsd */ {w0 |= 0x408000 | ($4.lsd & 3) << 16 | ($4.lsd >> 2) << 19; if($4.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } if($2 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); w0 |= ($2 & 0x3F) << 8;} | regs /* lsd */ ',' LMEM abs_short_addr {hot_rreg = hot_nreg = hot_mreg = -1; w0 |= 0x400000 | ($1.lsd & 3) << 16 | ($1.lsd >> 2) << 19; if($1.flags & R_CTL_REG) { yyerror("please use MOVEC for control register moves"); break; } if($4 > 0x003F && pass == 2) yywarning("warning: address operand truncated"); w0 |= ($4 & 0x3F) << 8;} ; xy_move : x_or_y /*XMEM*/ ea /*ea_strange*/ ',' regs YMEM ea /*ea_strange*/ ',' regs {int eax = $2, eay = $6, regx = ($4.flags & R_AB) ? $4.ab | 2 : $4.xreg, regy = ($8.flags & R_AB) ? $8.ab | 2 : $8.yreg; hot_rreg = hot_nreg = hot_mreg = -1; if((eax & 0x400) == (eay & 0x400)) yyerror("registers must be in opposite halves"); if(!($4.flags & (R_AB | R_XREG))) yyerror("invalid X move register"); if(!($8.flags & (R_AB | R_YREG))) yyerror("invalid Y move register"); if($4.flags & R_AB && $8.flags & R_AB && $4.ab == $8.ab) yyerror("duplicate destination register"); w0 = w0 & 0xFF | 0xC08000; /* both write */ w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;} | x_or_y /*XMEM*/ ea /*ea_strange*/ ',' regs regs ',' YMEM ea /*ea_strange*/ {int eax = $2, eay = $8, regx = ($4.flags & R_AB) ? $4.ab | 2 : $4.xreg, regy = ($5.flags & R_AB) ? $5.ab | 2 : $5.yreg; hot_rreg = hot_nreg = hot_mreg = -1; if((eax & 0x400) == (eay & 0x400)) yyerror("registers must be in opposite halves"); if(!($4.flags & (R_AB | R_XREG))) yyerror("invalid X move register"); if(!($5.flags & (R_AB | R_YREG))) yyerror("invalid Y move register"); w0 = w0 & 0xFF | 0x808000; /* X:write, Y:read */ w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;} | regs ',' x_or_y /*XMEM*/ ea /*ea_strange*/ YMEM ea /*ea_strange*/ ',' regs {int eax = $4, eay = $6, regx = ($1.flags & R_AB) ? $1.ab | 2 : $1.xreg, regy = ($8.flags & R_AB) ? $8.ab | 2 : $8.yreg; hot_rreg = hot_nreg = hot_mreg = -1; if((eax & 0x400) == (eay & 0x400)) yyerror("registers must be in opposite halves"); if(!($1.flags & (R_AB | R_XREG))) yyerror("invalid X move register"); if(!($8.flags & (R_AB | R_YREG))) yyerror("invalid Y move register"); w0 = w0 & 0xFF | 0xC00000; /* X:read, Y:write */ w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;} | regs ',' x_or_y /*XMEM*/ ea /*ea_strange*/ regs ',' YMEM ea /*ea_strange*/ {int eax = $4, eay = $8, regx = ($1.flags & R_AB) ? $1.ab | 2 : $1.xreg, regy = ($5.flags & R_AB) ? $5.ab | 2 : $5.yreg; hot_rreg = hot_nreg = hot_mreg = -1; if((eax & 0x400) == (eay & 0x400)) yyerror("registers must be in opposite halves"); if(!($1.flags & (R_AB | R_XREG))) yyerror("invalid X move register"); if(!($5.flags & (R_AB | R_YREG))) yyerror("invalid Y move register"); w0 = w0 & 0xFF | 0x800000; /* both read */ w0 |= eax & 0x1f00 | (eay & 0x300) << 5 | (eay & 0x1800) << 9 | regx << 18 | regy << 16;} ; /*%%%******* absolute address and immediate data fields ************/ num : CHEX {$$ = $1;} | CDEC {$$ = $1;} | FRAC {$$ = $1;} ; ix : '#' expr {$$ = $2; expr_seg = ANY;} | '#' '<' expr {$$.val.i = n2int($3) & 0xFF; $$.type = INT; expr_seg = ANY; long_symbolic_expr = FALSE;} ; ix_long : '#' '>' expr {$$ = $3; expr_seg = ANY;} ; abs_addr : expr {$$ = n2int($1); expr_seg = $1.seg;} ; abs_short_addr : '<' expr {$$ = n2int($2); expr_seg = $2.seg;} ; io_short_addr : SHL expr {$$ = n2int($2); expr_seg = $2.seg;} ; num_or_sym : num {$$ = $1;} | SYM {$$ = sym_ref($1); free($1);} | io_short_addr {$$.type = INT; $$.val.i = $1; $$.seg = expr_seg;} ; num_or_sym_expr : num {$$ = $1; expr_seg = $1.seg;} | SYM {$$ = sym_ref($1); free($1); long_symbolic_expr++; expr_seg = $$.seg; } | CHAR {$$.type = INT; $$.val.i = $1 & 0xFFFFFF; expr_seg = $$.seg = ANY;} | '*' {$$.type = INT; $$.val.i = pc; expr_seg = $$.seg = ANY;} | OP_PI {$$.type = FLT; $$.val.f = acos(-1.0); expr_seg = $$.seg = ANY;} ; expr : OP_INT '(' expr ')' {$$.type = INT; if($3.type == INT) $$.val.i = $3.val.i; else $$.val.i = $3.val.f; $$.seg = $3.seg; } | expr '|' expr {$$ = binary_op($1, '|', $3);} | expr '^' expr {$$ = binary_op($1, '^', $3);} | expr '&' expr {$$ = binary_op($1, '&', $3);} | expr SHR expr {$$ = binary_op($1, SHR, $3);} | expr SHL expr {$$ = binary_op($1, SHL, $3);} | expr '-' expr {$$ = binary_op($1, '-', $3);} | expr '+' expr {$$ = binary_op($1, '+', $3);} | expr '%' expr {$$ = binary_op($1, '%', $3);} | expr '/' expr {$$ = binary_op($1, '/', $3);} | expr '*' expr {$$ = binary_op($1, '*', $3);} | '-' expr %prec '~' {$$ = unary_op('-', $2);} | '~' expr {$$ = unary_op('~', $2);} | OP_SIN '(' expr ')' {$$ = unary_op('s', $3);} | OP_COS '(' expr ')' {$$ = unary_op('c', $3);} | OP_TAN '(' expr ')' {$$ = unary_op('t', $3);} | OP_ASIN '(' expr ')' {$$ = unary_op('S', $3);} | OP_ACOS '(' expr ')' {$$ = unary_op('C', $3);} | OP_ATAN '(' expr ')' {$$ = unary_op('T', $3);} | OP_EXP '(' expr ')' {$$ = unary_op('e', $3);} | OP_LN '(' expr ')' {$$ = unary_op('l', $3);} | OP_LOG '(' expr ')' {$$ = unary_op('L', $3);} | OP_ABS '(' expr ')' {$$ = unary_op('a', $3);} | OP_POW '(' expr ',' expr ')' {$$ = binary_op($3, 'p', $5);} | '(' expr ')' {$$ = $2;} | num_or_sym_expr {$$ = $1;} ; /*%%%****************** end ******************************/ %% #include #include #include int yydebug; struct n binary_op(a1, op, a2) struct n a1, a2; int op; { struct n result; int iarg1, iarg2; double farg1, farg2; if(a1.type == UNDEF || a2.type == UNDEF) { result.type = UNDEF; return result; } iarg1 = a1.type == INT ? a1.val.i : a1.val.f; iarg2 = a2.type == INT ? a2.val.i : a2.val.f; farg1 = a1.type == INT ? a1.val.i : a1.val.f; farg2 = a2.type == INT ? a2.val.i : a2.val.f; /* figure out target segment */ if(a1.seg == a2.seg) result.seg = a1.seg; else if(a1.seg == ANY) result.seg = a2.seg; else if(a2.seg == ANY) result.seg = a1.seg; else result.seg = NONE; /* promote to float automatically */ if(a1.type != a2.type) { if(a1.type == INT) { a1.val.f = a1.val.i; /* truncate */ a1.type = FLT; } else { a2.val.f = a2.val.i; /* truncate */ } } result.type = a1.type; /* do the op */ switch(op) { case '+': if(result.type == INT) result.val.i = a1.val.i + a2.val.i; else result.val.f = a1.val.f + a2.val.f; break; case '-': if(result.type == INT) result.val.i = a1.val.i - a2.val.i; else result.val.f = a1.val.f - a2.val.f; break; case '*': if(result.type == INT) result.val.i = a1.val.i * a2.val.i; else result.val.f = a1.val.f * a2.val.f; break; case '/': if(result.type == INT) result.val.i = a1.val.i / a2.val.i; else result.val.f = a1.val.f / a2.val.f; break; case '%': result.val.i = iarg1 % iarg2; result.type = INT; break; case SHL: result.val.i = iarg1 << iarg2; result.type = INT; break; case SHR: result.val.i = iarg1 >> iarg2; result.type = INT; break; case '|': result.val.i = iarg1 | iarg2; result.type = INT; break; case '&': result.val.i = iarg1 & iarg2; result.type = INT; break; case '^': result.val.i = iarg1 ^ iarg2; result.type = INT; break; case 'p': result.val.f = pow(farg1, farg2); result.type = FLT; } return result; } jmp_buf unary_env; void sigfpu() { longjmp(unary_env, 1); } char *unary_name(op) { switch(op) { case 's': return "sin"; case 'c': return "cos"; case 't': return "tan"; case 'S': return "asin"; case 'C': return "acos"; case 'T': return "atan"; case 'e': return "exp"; case 'l': return "ln"; case 'L': return "log"; case 'a': return "abs"; } } struct n unary_op(op, a1) int op; struct n a1; { struct n result; void (*orig)(); double farg; if(a1.type == UNDEF) { result.type = UNDEF; return result; } result.seg = a1.seg; /* do the op */ orig = signal(SIGFPE, sigfpu); if(setjmp(unary_env)) { yyerror("floating point exception in function %s", unary_name(op)); result.val.i = result.val.f = 0; } else { farg = a1.type == INT ? (double)a1.val.i : a1.val.f; switch(op) { case '-': result.type = a1.type; if(a1.type == INT) result.val.i = -a1.val.i; else result.val.f = -a1.val.f; break; case '~': result.type = a1.type; if(a1.type == INT) result.val.i = ~a1.val.i; else result.val.f = ~(int)a1.val.f; break; case 'a': result.type = a1.type; if(a1.type == INT) result.val.i = a1.val.i < 0 ? -a1.val.i : a1.val.i; else result.val.f = result.val.f = a1.val.f < 0 ? -a1.val.f : a1.val.f; break; case 's': result.type = FLT; result.val.f = sin(farg); break; case 'c': result.type = FLT; result.val.f = cos(farg); break; case 't': result.type = FLT; result.val.f = tan(farg); break; case 'S': result.type = FLT; result.val.f = asin(farg); break; case 'C': result.type = FLT; result.val.f = acos(farg); break; case 'T': result.type = FLT; result.val.f = atan(farg); break; case 'e': result.type = FLT; result.val.f = exp(farg); break; case 'l': result.type = FLT; result.val.f = log(farg); break; case 'L': result.type = FLT; result.val.f = log10(farg); break; } } signal(SIGFPE, orig); return result; } n2int(n) struct n n; { if(n.type == UNDEF) return UNDEF; else if(n.type == INT) return n.val.i; else return n.val.f; } n2frac(n) struct n n; { double adval = n.val.f >= 0.0 ? n.val.f : -n.val.f; if(n.type == UNDEF) return UNDEF; else if(n.type == INT) return n.val.i; else if(n.val.f == -1.0) return 0x800000; adval -= (double)(int)adval; adval *= (double)0x800000; adval += 0.5; if(n.val.f >= 0.0) return adval; else return -adval; } extern struct {int n; char *name;} tok_tab[]; extern int n_tok; char *tok_print(tok) int tok; { int i; static char buf[32]; if(tok == '1') { i = 1; } if(tok < 256) { sprintf(buf, tok < ' ' ? "\\z%02X" : "%c", tok & 0xFF); return buf; } else { for(i = 0; i < n_tok; i++) { if(tok == tok_tab[i].n) return tok_tab[i].name; } } return "*bogus*"; } yyerror(s, a0, a1, a2, a3) char *s, *a0, *a1, *a2, *a3; { extern int error; char buf[1024]; error++; sprintf(buf, s, a0, a1, a2, a3); if(pass == 2) { fprintf(stderr, "%s: line %d: %s (tok=%s)\n", curfile, curline, buf, tok_print(yychar)); fprintf(stderr, "%s\n", cur_line); printf("%s: line %d: %s (tok=%s)\n", curfile, curline, buf, tok_print(yychar)); } } yywarning(s, a0, a1, a2, a3) char *s, *a0, *a1, *a2, *a3; { extern int warning; char buf[1024]; warning++; sprintf(buf, s, a0, a1, a2, a3); if(pass == 2) { fprintf(stderr, "%s: line %d: %s (tok=%s)\n", curfile, curline, buf, tok_print(yychar)); fprintf(stderr, "%s\n", cur_line); printf("%s: line %d: %s (tok=%s)\n", curfile, curline, buf, tok_print(yychar)); } } char *luntab(s) char *s; { static char buf[1024]; int p; strcpy(buf, s); untab(buf); p = strlen(buf); if(buf[p - 1] == '\n') buf[p - 1] = '\0'; return buf; }