#define RCSID4 "$Id$" /* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". * */ /* * Zilog Z80 parsing rules */ operation : NOOPOP { emit1($1);} | LDOP ldargs | PSHPOP R16 { switch ($2) { case BC: emit1($1); break; case DE: emit1($1 | 020); break; case AF: emit1($1 | 060); break; case HL: case IX: case IY: xyreg($2,$1 | 040); break; default: serror("register error"); } } | EXOP R16 ',' R16 { if ($2==DE && $4==HL) emit1(0353); else if ($2==AF && $4==AF2) emit1(010); else serror("register error"); } | EXOP '(' R16 ')' ',' R16 { if ($3!=SP) serror("register error"); xyreg($6,$1); } | E_ED { emit1(0355); emit1($1);} | ADDOP R16 ',' R16 { if ($4 == $2) xyreg($2,051); else { if ($4==HL || $4>SP) serror("register error"); xyreg($2,011 | $4<<4); } } | ADCSBC R16 ',' R16 { if ($2!=HL || $4>SP) serror("register error"); emit1(0355); emit1(($1==0210 ? 0112 : 0102) | ($4<<4)); } | INCDEC R16 { switch ($2) { case BC: case DE: case SP: emit1(($1==04 ? 03 : 013) | $2<<4); break; case HL: case IX: case IY: xyreg($2,$1==04 ? 043 : 053); break; default: serror("register error"); } } | INCDEC r8 { emit1($1 | $2<<3);} | INCDEC ind { xymem($2,$1 | 060);} | ari8 r8 { emit1($1 | $2);} | ari8 expr { emit1($1 | 0106); emit1($2.val);} | ari8 ind { xymem($2,$1 | 06);} | IMOP absexp { emit1(0355); switch ($2) { case 0: emit1(0106); break; case 1: emit1(0126); break; case 2: emit1(0136); break; default: serror("range 0..2"); } } | ROTATE r8 { emit1(0313); emit1($1 | $2);} | ROTATE ind { xymem($2,0313); emit1($1 | 06);} | BITS absexp ',' r8 { fit(fit3($2)); emit1(0313); emit1($1 | low3($2)<<3 | $4); } | BITS absexp ',' ind { fit(fit3($2)); xymem($4,0313); emit1($1 | low3($2)<<3 | 06); } | JP expr { emit1($1); #ifdef RELOCATION newrelo($2.typ, RELO2); #endif emit2($2.val); } | JP coco ',' expr { emit1(0302 | $2<<3); #ifdef RELOCATION newrelo($4.typ, RELO2); #endif emit2($4.val); } | JP indir { xyreg($2,0351);} | JR expr { branch($1,$2);} | JR coco ',' expr { if ($2 > 3) serror("bad condition code"); branch(040 | ($2<<3), $4); } | DJNZ expr { branch($1,$2);} | CALL expr { emit1($1); #ifdef RELOCATION newrelo($2.typ, RELO2); #endif emit2($2.val); } | CALL coco ',' expr { emit1(0304 | $2<<3); #ifdef RELOCATION newrelo($4.typ, RELO2); #endif emit2($4.val); } | RET { emit1($1);} | RET coco { emit1(0300 | $2<<3);} | RST absexp { if (($2&070)!=$2) serror("rst expression out of range"); emit1($1 | $2); } | IN R8 ',' expr { if ($2 != A) serror("register error"); emit1($1); #ifdef RELOCATION newrelo($4.typ, RELO1); #endif emit1($4.val); } | IN R8 ',' R8 { if ($4 != C) serror("register error"); emit1(0355); emit1(0100 | $2<<3); } | OUT expr ',' R8 { if ($4 != A) serror("register error"); emit1($1); #ifdef RELOCATION newrelo($2.typ, RELO1); #endif emit1($2.val); } | OUT R8 ',' R8 { if ($2 != C) serror("register error"); emit1(0355); emit1(0101 | $4<<3); } ; ari8 : ARI8 | ADDOP R8 ',' { if ($2 != A) serror("register error");} | ADCSBC R8 ',' { if ($2 != A) serror("register error");} ; ldargs : R8 ',' R8 { if ($1==F || $3==F) serror("register error"); if ($1<=A && $3<=A) emit1(0100 | $1<<3 | $3); else { emit1(0355); if ((($1==A) ^ ($3==A)) == 0) serror("register error"); emit1( 0107 | ($1==R||$3==R)<<3 | ($1==A)<<4 ); } } | R8 ',' expr { if ($1==F || $1==I || $1==R) serror("register error"); emit1(06 | $1<<3); #ifdef RELOCATION newrelo($3.typ, RELO1); #endif emit1($3.val); } | R8 ',' indir { if ($1==F || $1==I || $1==R) serror("register error"); if ($1==A && ($3==BC || $3==DE)) emit1($3==BC ? 012 : 032); else xymem($3,0106 | $1<<3); } | R8 ',' index { if ($1==F || $1==I || $1==R) serror("register error"); xymem($3,0106 | $1<<3); } | R8 ',' '(' expr ')' { if ($1!=A) serror("register error"); emit1(072); #ifdef RELOCATION newrelo($4.typ, RELO2); #endif emit2($4.val); } | indir ',' r8 { if ($3==A && ($1==BC || $1==DE)) emit1($1==BC ? 02 : 022); else xymem($1,0160 | $3); } | index ',' r8 { xymem($1,0160 | $3);} | indir ',' expr { xymem($1,066); #ifdef RELOCATION newrelo($3.typ, RELO1); #endif emit1($3.val); } | index ',' expr { xymem($1,066); #ifdef RELOCATION newrelo($3.typ, RELO1); #endif emit1($3.val); } | R16 ',' expr { switch ($1) { case BC: case DE: case HL: case SP: emit1(01 | $1<<4); break; case IX: case IY: xyreg($1,041); break; default: serror("register error"); } #ifdef RELOCATION newrelo($3.typ, RELO2); #endif emit2($3.val); } | R16 ',' R16 { if ($1!=SP) serror("register error"); xyreg($3,0371); } | R16 ',' '(' expr ')' { switch ($1) { case BC: case DE: case SP: emit1(0355); emit1(0113 | $1<<4); break; case HL: case IX: case IY: xyreg($1,052); break; default: serror("register error"); } #ifdef RELOCATION newrelo($4.typ, RELO2); #endif emit2($4.val); } | '(' expr ')' ',' R8 { if ($5!=A) serror("register error"); emit1(062); #ifdef RELOCATION newrelo($2.typ, RELO2); #endif emit2($2.val); } | '(' expr ')' ',' R16 { switch ($5) { case BC: case DE: case SP: emit1(0355); emit1(0103 | $5<<4); break; case HL: case IX: case IY: xyreg($5,042); break; default: serror("register error"); } #ifdef RELOCATION newrelo($2.typ, RELO2); #endif emit2($2.val); } ; r8 : R8 { if ($1==F || $1==I || $1==R) serror("register error"); } ; indir : '(' R16 ')' { if ($2>=SP && $2!=IX && $2!=IY) serror("register error"); exp_ind.typ = S_ABS; exp_ind.val = 0; $$ = $2; } ; index : '(' R16 '+' expr ')' { if ($2!=IX && $2!=IY) serror("register error"); exp_ind = $4; RELOMOVE(rel_ind, relonami); $$ = $2; } | '(' R16 '-' expr ')' { if ($2!=IX && $2!=IY) serror("register error"); fit(fitb($4.val)); exp_ind = $4; RELOMOVE(rel_ind, relonami); $$ = $2; } ; ind : indir | index ; coco : CC | R8 { if ($1 != C) serror("bad condition code"); $$ = 3; } ;