#define RCSID4 "$Header$" /* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". * */ /* Author: Ed Keizer */ operation: BR expr /* format 0 */ { dot_adjust(&$2) ; form0($1) ; disp(&$2, RELPC) ;} | WAIT /* format 1 */ { form1($1) ;} | BSR expr /* format 1 */ { dot_adjust(&$2) ; form1($1) ; disp(&$2, RELPC) ;} | RET expr /* format 1 */ { form1($1) ; disp(&$2, 0) ;} | SAVE reg_list /* format 1 */ { form1($1) ; emit1(reg_list($2,id_op($1)!=0x6)) ;} | ENTER reg_list ',' expr /* format 1 */ { form1($1) ; emit1(reg_list($2,0)) ; disp(&$4, 0) ;} | LPR AREG ',' gen1 /* format 2 */ { if ( id_op($1)==0x2 ) not_imm(&mode1) ; form2($1,$2) ; gen1($1) ; } | SEQ gen1 /* format 2 */ { form2($1,id_cc($1)) ; gen1($1) ; not_imm(&mode1) ;} | MOVQ absexp ',' gen1 /* format 2 */ { if ( !fit4($2) ) { serror("Constant too large") ; } form2($1,low4($2)) ; gen1($1) ; if ( id_op($1)!=0x1 ) not_imm(&mode1) ; /* !cmp */ } | ACB absexp ',' gen1 ',' expr /* format 2 */ { dot_adjust(&$6) ; if (!fit4($2) ) { serror("Constant too large") ; } form2($1,low4($2)) ; gen1($1) ; not_imm(&mode1) ; disp(&$6, RELPC) ; } | ADJSP gen1 /* format 3 */ { if ( id_op($1)==0 ) not_imm(&mode1) ; /* cxpd */ form3($1) ; gen1($1) ;} | JSR gen1 /* format 3 */ { #ifndef NO_OPTIM if ( mode1.m_mode==0x15 ) { /* Absolute */ dot_adjust(&mode1.m_expr1) ; RELOMOVE(relonami, mode1.m_rel1); form1(0) ; disp(&mode1.m_expr1, RELPC) ; /* bsr */ } else #endif { form3($1) ; gen1($1) ; } not_imm(&mode1) ; } | JUMP gen1 /* format 3 */ { #ifndef NO_OPTIM if ( mode1.m_mode==0x15 ) { /* Absolute */ dot_adjust(&mode1.m_expr1) ; RELOMOVE(relonami, mode1.m_rel1); form0(B_TRUE) ; disp(&mode1.m_expr1, RELPC) ; /* br */ } else #endif { form3($1) ; gen1($1) ; } not_imm(&mode1) ; } | ADD_I gen1 ',' gen2 /* format 4 */ { register opc ; opc=id_op($1) ; if ( opc==0x9 ) not_imm(&mode1) ; /* addr */ if ( opc!=0x1 ) not_imm(&mode2) ; /* !cmp */ #ifndef NO_OPTIM if ( mode1.m_mode==0x14 && /* Immediate */ (mode1.m_expr1.typ & ~S_EXT) == S_ABS && ( (fit4(mode1.m_expr1.val) && (opc==0 || opc==1 || opc==5)) || (fit4(-mode1.m_expr1.val) && (opc==8)) ) ) { /* Warning, an absolute expression derived from a symbol that is defined after use might - if the value now suddenly fits - cause failed assertions in newlabel */ /* add, cmp, mov */ /* added: the subtract of a signed * short is the same as the add * of the negation of that short * so: subi short,x == addqi -short,x * 19/04/85 h.m.kodden,m.j.a.leliveld */ if (opc==8) /* do the negate */ mode1.m_expr1.val = (~mode1.m_expr1.val+1)&0xF; opc=low4(mode1.m_expr1.val) ; mode1= mode2 ; form2($1,opc) ; gen1($1) ; } else #endif { form4($1) ; gengen($1) ; } } | SETCFG cpu_opts /* format 5 */ { form5($1,$2) ;} | MOVS string_opts /* format 5 */ { form5($1,($2)|id_cc($1)) ;} | COM gen1 ',' gen2 /* format 6 */ { form6($1) ; gengen($1) ; not_imm(&mode2) ;} | MUL_I gen1 ',' gen2 /* format 7 */ { if ( id_op($1)==0x9 || id_op($1)==0xB ) { /* mei or dei */ switch ( mode2.m_mode ) { case 1 : case 3 : case 5 : case 7 : serror("register must be even") ; } } form7($1) ; gengen($1) ; not_imm(&mode2) ; } | MOVID gen1 ',' gen2 /* format 7 */ { form7x($1,id_g1($1)) ; gengen($1) ; not_imm(&mode2) ;} | MOVM gen1 ',' gen2 ',' expr /* format 7 */ { register s_size ; s_size= id_g1($1)+1 ; /* $6.val= $6.val*s_size - s_size ; */ $6.val= $6.val -1 ; form7($1) ; gengen($1) ; disp(&$6, 0) ; not_imm(&mode1) ; not_imm(&mode2) ; } | INSS gen1 ',' gen2 ',' absexp ',' absexp /* format 7 */ { if ( ( $6<0 || $6>7 || $8<1 || $8>32 ) ) { serror("Constant out of bounds") ; } form7($1) ; gengen($1) ; if ( id_op($1)==0x3 ) not_imm(&mode1) ; /* exts */ not_imm(&mode2) ; emit1((((int)$6)<<5)+(int)$8-1) ; } | FFS gen1 ',' gen2 /* format 8 */ { form8($1,id_cc($1)) ; gengen($1) ; not_imm(&mode2) ;} | CHECK REG ',' gen1 ',' gen2 /* format 8 */ { form8($1,$2) ; gengen($1) ; if ( id_op($1)!=0x4 ) { not_imm(&mode1) ; /* check, cvtp */ if ( id_op($1)==0x1 ) not_imm(&mode2) ;/*cvtp */ } } | INS REG ',' gen1 ',' gen2 ',' expr /* format 8 */ { form8($1,$2) ; gengen($1) ; disp(&$8, 0) ; if ( id_op($1)==0x0 ) not_imm(&mode1) ; not_imm(&mode2) ; } | MOVIF gen1 ',' fgen2 /* format 9 */ { assert( id_t1($1)==T_INT && id_t2($1)==T_FL ) ; form9($1,id_g1($1),id_g2($1)) ; gengen($1) ; not_imm(&mode2) ; } | MOVFL fgen1 ',' fgen2 /* format 9 */ { assert( id_t1($1)==T_FL && id_t2($1)==T_FL ) ; form9($1,id_g1($1),( id_g2($1)==F_LONG?3:2 )) ; gengen($1) ; not_imm(&mode2) ; } | TRUNC fgen1 ',' gen2 /* format 9 */ { assert( id_t1($1)==T_FL && id_t2($1)==T_INT ) ; form9($1,id_g2($1),id_g1($1)) ; gengen($1) ; not_imm(&mode2) ; } | LFSR gen1 /* format 9 */ { if ( id_op($1)==6 ) { /* SFSR */ not_imm(&mode1) ; mode2.m_mode=mode1.m_mode ; mode1.m_mode=0 ; } else { mode2.m_mode=0 ; } form9($1,0,0) ; if ( id_op($1)==6 ) { mode1.m_mode=mode2.m_mode ; } gen1($1) ; } | ADD_F fgen1 ',' fgen2 /* format 11 */ { if ( id_op($1)!=0x2 ) not_imm(&mode2) ; /* !CMPF */ form11($1) ; gengen($1) ; } | RDVAL gen1 /* format 14 */ { form14($1,0) ; gen1($1) ; not_imm(&mode1) ;} | LMR MREG ',' gen1 /* format 14 */ { form14($1,$2) ; gen1($1) ; if ( id_op($1)==0x3 ) not_imm(&mode1) ; } /* All remaining categories are not checked for illegal immediates */ | LCR CREG ',' gen1 /* format 15.0 */ { frm15_0($1,$2) ; gen1($1) ;} | CATST gen1 /* format 15.0 */ { frm15_0($1,0) ; gen1($1) ;} | LCSR gen1 /* format 15.1 */ /* Sure? */ { mode2.m_mode=0 ; frm15_1($1,0,0) ; gen1($1) ;} | CCVIS gen1 ',' gen2 /* format 15.1 */ { assert( id_t1($1)==T_INT && id_t2($1)==T_SLAVE ) ; frm15_1($1,id_g1($1),id_g2($1)) ; gengen($1) ; } | CCVSI gen1 ',' gen2 /* format 15.1 */ { assert( id_t1($1)==T_SLAVE && id_t2($1)==T_INT ) ; frm15_1($1,id_g2($1),id_g1($1)) ; gengen($1) ; } | CCVSS gen1 ',' gen2 /* format 15.1 */ { assert( id_t1($1)==T_SLAVE && id_t2($1)==T_SLAVE ) ; frm15_1($1,0,0) ; gengen($1) ; /* Sure? */ } | CMOV gen1 ',' gen2 /* format 15.5 */ { frm15_5($1) ; gengen($1) ;} ; gen1 : { mode_ptr= &mode1 ; clrmode() ; } gen ; gen2 : { mode_ptr= &mode2 ; clrmode() ; } gen ; fgen1 : { mode_ptr= &mode1 ; clrmode() ; } fgen ; fgen2 : { mode_ptr= &mode2 ; clrmode() ; } fgen ; gen : gen_not_reg /* Every mode except register */ | REG { mode_ptr->m_mode= $1 ; } ; fgen : gen_not_reg /* Every mode except register */ | FREG { mode_ptr->m_mode= $1 ; } ; gen_not_reg: gen_a /* general mode with eff. address */ | REG { mode_ptr->m_mode=$1 ;} index /* The register is supposed to contain the address */ | gen_a index /* As above, but indexed */ | expr /* Immediate */ { mode_ptr->m_mode= 0x14 ; mode_ptr->m_expr1= $1 ; RELOMOVE(mode_ptr->m_rel1, relonami); } ; gen_a : expr '(' REG ')' /* Register relative */ { mode_ptr->m_mode= 0x8 + $3 ; mode_ptr->m_ndisp= 1 ; mode_ptr->m_expr1= $1 ; RELOMOVE(mode_ptr->m_rel1, relonami); } | expr '(' AREG ')' /* Memory space */ { if ( $3<0x8 || $3>0xA ) badsyntax() ; mode_ptr->m_mode= 0x18 + ($3&3) ; mode_ptr->m_ndisp= 1 ; mode_ptr->m_expr1= $1 ; RELOMOVE(mode_ptr->m_rel1, relonami); } | expr '(' PC ')' /* Memory space */ { mode_ptr->m_mode= 0x1B ; mode_ptr->m_ndisp= 1 ; mode_ptr->m_expr1= $1 ; RELOMOVE(mode_ptr->m_rel1, relonami); dot_adjust(&mode_ptr->m_expr1) ; } | expr '(' { mode_ptr->m_expr2 = $1; RELOMOVE(mode_ptr->m_rel2, relonami); } expr '(' AREG ')' ')' /* Memory relative */ { if ( $6<0x8 || $6>0xA ) badsyntax() ; mode_ptr->m_mode= 0x10 + ($6&3) ; mode_ptr->m_ndisp= 2 ; mode_ptr->m_expr1= $4 ; RELOMOVE(mode_ptr->m_rel1, relonami); } | '@' expr /* Absolute */ { mode_ptr->m_mode= 0x15 ; mode_ptr->m_ndisp= 1 ; mode_ptr->m_expr1= $2 ; RELOMOVE(mode_ptr->m_rel1, relonami); } | EXTERNAL '(' expr ')' { mode_ptr->m_mode= 0x16 ; mode_ptr->m_ndisp= 2 ; mode_ptr->m_expr1= $3 ; RELOMOVE(mode_ptr->m_rel1, relonami); } '+' expr /* External */ { mode_ptr->m_expr2= $7 ; RELOMOVE(mode_ptr->m_rel2, relonami); } | TOS /* Top Of Stack */ { mode_ptr->m_mode= 0x17 ; } ; index : '[' REG ':' INDICATOR ']' /* Indexed postfix */ { mode_ptr->m_index= (mode_ptr->m_mode<<3) | $2 ; mode_ptr->m_mode= ind_mode( $4 ) ; } ; cpu_opts: '[' ']' { $$=0 ;} | '[' cpu_list ']' { $$= $2 ;} ; cpu_list: INDICATOR { $$=cpu_opt($1) ; } | cpu_list ',' INDICATOR { $$= ($1) | cpu_opt($3) ;} ; string_opts: { $$=0 ;} | INDICATOR { $$= string_opt($1) ; } | INDICATOR ',' INDICATOR { if ( $1 != 'b' || ( $3 != 'u' && $3 != 'w' ) ) { serror("illegal string options") ; } $$ = string_opt($1)|string_opt($3) ; } ; reg_list: '[' ']' { $$=0 ;} | '[' reg_items ']' { $$= $2 ;} ; reg_items: REG { $$= 1<<($1) ; } | reg_items ',' REG { $$= ($1) | ( 1<<($3) ) ;} ;