/* * Motorola 68020 syntax rules */ operation : { instrp = instr; dot_offset = 0; } instruction { emit_instr(); } ; instruction : bcdx DREG ',' DREG { T_EMIT2($1 | $2 | $4<<9,0,0,0);} | bcdx '-' '(' AREG ')' ',' '-' '(' AREG ')' { T_EMIT2($1 | $4 | $9<<9 | 010,0,0,0);} | ADD sizedef ea_ea { add($1, $2);} | AND sizenon ea_ea { and($1, $2);} | SHIFT sizedef ea_ea { shift_op($1, $2);} | SHIFT sizedef ea /* This syntax is also allowed */ { checksize($2, 2); T_EMIT2(($1 & 0177700) | mrg_2,0,0,0); ea_2(SIZE_W, MEM|ALT); } | BR expr { branch($1, $2);} | DBR DREG ',' expr { T_EMIT2($1 | $2,0,0,0); $4.val -= (DOTVAL+dot_offset); fit(fitw($4.val)); T_EMIT2(loww($4.val), $4.typ, RELPC|RELO2, relonami); } | BITOP ea_ea { bitop($1);} | BITFIELD ea off_width { bitfield($1, $3);} | BF_TO_D ea off_width ',' DREG { bitfield($1, $3 | $5<<12);} | BFINS DREG ',' ea off_width { bitfield($1, $5 | $2<<12);} | DIVMUL sizedef ea ',' DREG { checksize($2, 2|4); if ($2 == SIZE_W) { T_EMIT2((0140300^($1<<8))|mrg_2|$5<<9, 0, 0, 0); ea_2(SIZE_W, DTA); } else { /* 32 bit dividend or product */ T_EMIT2((016000 | ($1 & ~1)) | mrg_2, 0, 0, 0); T_EMIT2(($1&1)<<11 | $5<<12 | $5, 0, 0, 0); ea_2(SIZE_L, DTA); } } | DIVMUL sizedef ea ',' DREG ':' DREG { /* 64 bit dividend or product */ checksize($2, 4); T_EMIT2((016000 | ($1 & ~1)) | mrg_2, 0, 0, 0); T_EMIT2(($1&1)<<11 | $7<<12 | $5 | 02000,0,0,0); ea_2(SIZE_L, DTA); } | DIVL sizedef ea ',' DREG ':' DREG { /* 32 bit long division with remainder */ checksize($2, 4); T_EMIT2(($1 & ~1) | mrg_2, 0, 0, 0); T_EMIT2(($1 & 1)<<11 | $7<<12 | $5, 0, 0, 0); ea_2(SIZE_L, DTA); } | LEA ea ',' AREG { T_EMIT2(040700 | mrg_2 | $4<<9,0,0,0); ea_2(SIZE_L, CTR); } | op_ea ea { if (mrg_2==074) serror("bad adressing category"); T_EMIT2(($1&0177700) | mrg_2,0,0,0); ea_2($1&0300, $1&017); } | OP_NOOP { T_EMIT2($1,0,0,0);} | OP_EXT SIZE DREG { checksize($2, ($1 & 0400) ? 4 : (2|4)); T_EMIT2($1 | $2+0100 | $3,0,0,0); } | OP_RANGE sizedef ea ',' reg { T_EMIT2(0300 | ($2<<3) | mrg_2,0,0,0); T_EMIT2($1 | ($5<<12),0,0,0); ea_2($2, CTR); } | TRAPCC SIZE imm { checksize($2, 2|4); T_EMIT2($1 | ($2>>6)+1,0,0,0); ea_2($2, 0); } | TRAPCC { T_EMIT2($1 | 4,0,0,0);} | PACK '-' '(' AREG ')' ',' '-' '(' AREG ')' ',' imm { T_EMIT2($1 | 1 | $4 | $9<<9, 0, 0, 0); ea_2(SIZE_W, 0); } | PACK DREG ',' DREG ',' imm { T_EMIT2($1 | $2 | $4<<9, 0, 0, 0); ea_2(SIZE_W, 0); } | CMP sizedef ea_ea { cmp($2);} | CHK sizedef ea ',' DREG { checksize($2, 2|4); T_EMIT2(040000 | mrg_2 | $5<<9 | ($2==SIZE_W ? 0600 : 0400), 0, 0, 0); ea_2($2, DTA); } | MOVE sizenon ea_ea { move($2);} | MOVEP sizedef ea_ea { movep($2);} | MOVEM sizedef regs ',' notimmreg { movem(0, $2, $3);} | MOVEM sizedef notimmreg ',' regs { movem(1, $2, $5);} | MOVES sizedef ea_ea { if (mrg_1 <= 017) { T_EMIT2(007000 | $2 | mrg_2,0,0,0); T_EMIT2(mrg_1 << 12 | 04000,0,0,0); ea_2($2,ALT|MEM); } else if (mrg_2 <= 017) { T_EMIT2(007000 | $2 | mrg_1,0,0,0); T_EMIT2(mrg_2 << 12,0,0,0); ea_1($2,ALT|MEM); } else badoperand(); } | MOVEC creg ',' reg { T_EMIT2(047172,0,0,0); T_EMIT2($2 | $4<<12,0,0,0); } | MOVEC reg ',' creg { T_EMIT2(047173,0,0,0); T_EMIT2($4 | $2<<12,0,0,0); } | EXG reg ',' reg { if (($2 & 010) == 0) T_EMIT2( (0140500|$4|$2<<9) + (($4&010)<<3) ,0,0,0); else T_EMIT2( (0140600|$2|($4&07)<<9) - (($4&010)<<3) ,0,0,0); } | SWAP DREG { T_EMIT2(044100 | $2,0,0,0);} | STOP imm { T_EMIT2(047162, 0, 0, 0); ea_2(SIZE_W, 0); } | LINK sizenon AREG ',' imm { link($2, $3);} | UNLK AREG { T_EMIT2(047130 | $2,0,0,0);} | TRAP '#' absexp { fit(fit4($3)); T_EMIT2(047100|low4($3),0,0,0); } | RTD imm { T_EMIT2(047164,0,0,0); ea_2(SIZE_W, 0); } | BKPT '#' absexp { fit(($3 & ~07) == 0); T_EMIT2(044110 | low3($3),0,0,0); } | CALLM '#' absexp ',' ea { fit(fitb($3)); T_EMIT2(03300 | mrg_2,0,0,0); T_EMIT2($3,0,0,0); ea_2(SIZE_L, CTR); } | RTM reg { T_EMIT2(03300 | $2, 0, 0, 0);} | CAS sizedef DREG ',' DREG ',' ea { T_EMIT2(04300 | (($2+0100)<<3) | mrg_2,0,0,0); T_EMIT2($5 | ($3<<6),0,0,0); ea_2($2, MEM|ALT); } | CAS2 sizedef DREG ':' DREG ',' DREG ':' DREG ',' '(' reg ')' ':' '(' reg ')' { checksize($2 , 2|4); T_EMIT2(04374 | (($2+0100)<<3),0,0,0); T_EMIT2($3 | ($7<<6) | ($12<<12),0,0,0); T_EMIT2($5 | ($9<<6) | ($16<<12),0,0,0); } | /* Coprocessor instructions; syntax may be changed (please). * No coprocessor defined extension words are emitted. */ CP CPBCC cp_cond expr { cpbcc($2 | $1 | $3, $4); } | CP CPDBCC cp_cond DREG ',' expr { T_EMIT2($2 | $1 | $4,0,0,0); $6.val -= (DOTVAL+dot_offset); fit(fitw($6.val)); T_EMIT2(loww($6.val), $6.typ, RELPC|RELO2, relonami); } | CP CPGEN { T_EMIT2($2 | $1,0,0,0); /* NO COMMAND WORD IS EMITTED; * THIS INSTRUCTIONS IS (STILL) ONE BIG RIDDLE. * NO EFFECTIVE ADDRESS IS CALCULATED (SYNTAX ?) */ } | CP CPRESTORE ea { T_EMIT2($2 | $1 | mrg_2,0,0,0); ea_2(SIZE_W, (mrg_2 & 070)==030 ? 0 : CTR); } | CP CPSAVE ea { T_EMIT2($2 | $1 | mrg_2,0,0,0); ea_2(SIZE_W,(mrg_2 & 070)==020 ? 0 : CTR|ALT); } | CP CPSCC cp_cond ea { T_EMIT2($2 | $1 | mrg_2,0,0,0); T_EMIT2($3,0,0,0); ea_2(SIZE_B,DTA|ALT); } | CP CPTRAPCC cp_cond SIZE imm { checksize($4,2|4); T_EMIT2($2 | $1 | ($4>>6)+1,0,0,0); T_EMIT2($3,0,0,0); ea_2($4, 0); } | CP TRAPCC cp_cond { T_EMIT2($2 | $1 | 4,0,0,0); T_EMIT2($3,0,0,0); } ; cp_cond : '.' absexp { fit(fit6($2)); $$ = low6($2); } ; bcdx : ABCD | ADDX sizedef { $$ = $1 | $2;} ; creg : CREG | SPEC { if ($1 != 075) badoperand(); $$ = 04000; } ; off_width /* note: these should be curly brackets, but that would * leave us without brackets for expressions. */ : '[' abs31 ':' abs31 ']' { $$ = ($2<<6) | $4; } ; abs31 : DREG { $$ = 040 | $1;} | absexp { fit(fit5($1)); $$ = low5($1); } ; op_ea : OP_EA | SZ_EA sizedef { $$ = $1 | $2;} ; regs : rrange | regs '/' rrange { $$ = $1 | $3;} ; rrange : reg { $$ = 1<<$1;} | reg '-' reg { if ($1 > $3) badoperand(); for ($$ = 0; $1 <= $3; $1++) $$ |= (1<<$1); } ; ea : DREG { mrg_2 = $1;} | AREG { mrg_2 = 010 | $1;} | SPEC { mrg_2 = $1;} | { mrg_2 = 0; ffew_2 = 0400; /* initialization */} notimmreg | imm ; notimmreg : '(' AREG ')' { mrg_2 = 020 | $2;} | '(' AREG ')' '+' { mrg_2 = 030 | $2;} | '-' '(' AREG ')' { mrg_2 = 040 | $3;} | '(' expr ')' sizenon { bd_2 = $2; ea7071($4); RELOMOVE(bd_rel2, relonami); } | '(' bd_areg_index ')' { if ((mrg_2 & INDEX) == 0) ffew_2 |= 0100; /* suppress index */ if ( !(mrg_2 & PC_MODE) && (ffew_2 & 0300) == 0100 && bd_2.typ==S_ABS && fitw(bd_2.val) ) mrg_2 = (loww(bd_2.val)?050:020) | $2; else { mrg_2 = (mrg_2&PC_MODE)?073:(060 | $2); ffew_2 |= 060; /* long displacement */ } } | '(' '[' bd_areg_index ']' index_od ')' { switch(mrg_2 & INDEX) { case 0: ffew_2 |= 0163; /* suppress index */ break; case DBL_INDEX: serror("bad indexing"); case PRE_INDEX: ffew_2 |= 063; break; case POST_INDEX: ffew_2 |= 067; break; } mrg_2 = (mrg_2 & PC_MODE) ? 073 : (060 | $3); } ; imm : '#' expr { mrg_2 = 074; bd_2 = $2; RELOMOVE(bd_rel2, relonami); } ; bd_areg_index : /* empty */ { $$ = 0; ffew_2 |= 0200; /* base-reg suppressed */ bd_2.typ = S_ABS; bd_2.val = (valu_t)0; /* zero displacement */ } | expr { $$ = 0; ffew_2 |= 0300; bd_2 = $1; RELOMOVE(bd_rel2, relonami); } | areg_index { bd_2.typ = S_ABS; bd_2.val = (valu_t)0; } | expr ',' areg_index { $$ = $3; bd_2 = $1; RELOMOVE(bd_rel2, relonami); } ; areg_index : areg | index { $$ = 0; ffew_2 |= 0200; /* base-reg suppressed */ mrg_2 |= PRE_INDEX; } | areg ',' index { mrg_2 |= PRE_INDEX; } ; areg : AREG | PC { mrg_2 |= PC_MODE;} | ZPC { mrg_2 |= PC_MODE; ffew_2 |= 0200; /* base-reg suppressed */ } ; index : reg sizedef scale { checksize($2, 2|4); ffew_2 |= $1<<12 | ($2&0200)<<4 | $3; } ; scale : /* empty */ { $$ = 0;} | '*' absexp { $$ = checkscale($2);} ; index_od: /* empty */ { od_2.typ = S_ABS; od_2.val = (valu_t)0;} | ',' index { od_2.typ = S_ABS; od_2.val = (valu_t)0; mrg_2 |= POST_INDEX; } | ',' expr { od_2 = $2; RELOMOVE(od_rel2, relonami); } | ',' index ',' expr { od_2 = $4; mrg_2 |= POST_INDEX; RELOMOVE(od_rel2, relonami); } ; reg : DREG | AREG { $$ = $1 | 010;} ; sizedef : /* empty */ { $$ = SIZE_DEF;} | SIZE ; sizenon : /* empty */ { $$ = SIZE_NON;} | SIZE ; ea_ea : ea ',' { mrg_1 = mrg_2; bd_1 = bd_2; od_1 = od_2; ffew_1 = ffew_2; RELOMOVE(bd_rel1, bd_rel2); RELOMOVE(od_rel1, od_rel2); } ea ;