574 lines
13 KiB
C
574 lines
13 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
#define RCSID4 "$Header$"
|
|
|
|
/*
|
|
** Zilog z8000 yacc parsing rules
|
|
*/
|
|
operation
|
|
: f1
|
|
| f2
|
|
| f3
|
|
| f4
|
|
| f5
|
|
| f6
|
|
| f7
|
|
| f8
|
|
| f9
|
|
;
|
|
|
|
|
|
f1 : F1_1F2_3 dst
|
|
{ switch( ($1 & 0x0F00)>>8 ) {
|
|
case 9: case 0xF: chtype( DST, TYPE_11a23 ); break;
|
|
case 0xC: case 0xD: chtype( DST, TYPE_11b23 ); break;
|
|
}
|
|
emit2( mode | $1 | $2<<4 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
| F1_1a reg
|
|
{ chreg( $1, $2 );
|
|
emit2( $1 | $2<<4 );
|
|
}
|
|
| F1_1b reg option
|
|
{ if ( $3 != 1 && $3 != 2 ) argerr();
|
|
emit2( $1 | $2<<4 | ($3-1)<<1 );
|
|
}
|
|
| F1_2 dst option
|
|
{ chtype( DST, TYPE_12 );
|
|
fit(fit4($3-1));
|
|
emit2( mode | $1 | $2<<4 | $3-1 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
| LDK reg ',' imexpr
|
|
{ fit(fit4($4));
|
|
emit2( $1 | $2<<4 | $4 );
|
|
}
|
|
| F1_2F6_3 dst ',' src
|
|
{ if ( oprtype[ DST ] == REG && oprtype[ SRC ] == REG )
|
|
{ emit2( $1 | $4 );
|
|
emit2( $2<<8 );
|
|
}
|
|
else if ( oprtype[ SRC ] == IM )
|
|
{ chtype( DST, TYPE_1263 );
|
|
if ((immed.typ & ~S_EXT) != S_ABS) {
|
|
serror("must be absolute");
|
|
}
|
|
if ( bitset($1,8) ) /* word */ fit(fit4(immed.val));
|
|
else /* byte */ fit(fit3(immed.val));
|
|
emit2( mode | $1 | $2<<4 | (int)immed.val );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
else argerr();
|
|
}
|
|
| JP coco1 dst
|
|
{ chtype( DST, TYPE_jp );
|
|
emit2( mode | $1 | $3<<4 | $2 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
| TCC coco1 reg
|
|
{ emit2( $1 | $3<<4 | $2 ); }
|
|
;
|
|
|
|
|
|
f2 : F2_1 reg ',' src
|
|
{ switch( ($1 & 0xF000)>>12 )
|
|
{ case 2: chtype( SRC, TYPE_21a ); break;
|
|
case 3: chtype( SRC, TYPE_21b ); break;
|
|
}
|
|
emit2( mode | $1 | $4<<4 | $2 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
| F2_1F5_1 dst ',' src
|
|
{ switch( oprtype[ DST ] )
|
|
{ case REG: chtype( SRC, TYPE_2151 );
|
|
chreg( $1, $2 );
|
|
emit2( mode | $1 | $4<<4 | $2 );
|
|
break;
|
|
case IR: case DA: case X:
|
|
if ( oprtype[ SRC ] == IM
|
|
&& ( $1 == 0x0B00 || $1 == 0x0A00 ) )
|
|
/* cp or cpb */
|
|
{ setmode( DST );
|
|
emit2( mode | $1 + 0x201 | $2<<4 );
|
|
break;
|
|
}
|
|
default: argerr();
|
|
}
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
if ( oprtype[ SRC ] == IM )
|
|
{ if (bitset($1,8)) /* word */ {
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO2|RELBR);
|
|
#endif
|
|
emit2( (int)immed.val );
|
|
}
|
|
else if (bitset($1,12)) /* long */ {
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO4|RELWR|RELBR);
|
|
#endif
|
|
emit4( immed.val );
|
|
}
|
|
else /* byte */ {
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO1);
|
|
#endif
|
|
emit1((int) immed.val);
|
|
/* emit1((int) immed.val); ??? twice ??? */
|
|
}
|
|
}
|
|
}
|
|
| LDA R32 ',' src
|
|
{ switch( oprtype[ SRC ] )
|
|
{ case DA: case X: emit2( 0x7600 | $4<<4 | $2 );
|
|
emit_ad( addr_inf );
|
|
break;
|
|
case BA: emit2( 0x3400 | $4<<4 | $2 );
|
|
#ifdef RELOCATION
|
|
newrelo(displ.typ,RELO2|RELBR);
|
|
#endif
|
|
emit2( (int) displ.val ); break;
|
|
case BX: emit2( 0x7400 | $4<<4 | $2 );
|
|
emit2( index<<8 ); break;
|
|
default: argerr();
|
|
}
|
|
}
|
|
| POP dst ',' ir
|
|
{ chtype( DST, TYPE_pop );
|
|
emit2( mode | $1 | $4<<4 | $2 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
| PUSH ir ',' src
|
|
{ chtype( SRC, TYPE_push );
|
|
switch ( oprtype[ SRC ] )
|
|
{ case IM: if ( $1 == 0x1100 ) /* pushl */ argerr();
|
|
/* { emit2( 0x9109 | $2<<4 );
|
|
** emit4( immed );
|
|
** }
|
|
*/
|
|
else
|
|
{ emit2( 0x0D09 | $2<<4 );
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO2|RELBR);
|
|
#endif
|
|
emit2( (int)immed.val );
|
|
}
|
|
break;
|
|
default: emit2( mode | $1 | $2<<4 | $4 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
}
|
|
}
|
|
| LD dst ',' src
|
|
{ if ( oprtype[ DST ] == REG )
|
|
{ switch( oprtype[ SRC ] )
|
|
{ case IM:
|
|
if ( $1 == 0 ) /* ldb: F3.2 */
|
|
{ /* fit(fits8(immed)); */
|
|
emit1( 0xC000 | $2<<8);
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO1);
|
|
#endif
|
|
emit1((int) immed.val);
|
|
}
|
|
else
|
|
{ /*fit(fits16(immed));*/
|
|
emit2( 0x2100 | $2 );
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO2|RELBR);
|
|
#endif
|
|
emit2( (int)immed.val );
|
|
}
|
|
break;
|
|
case REG: case IR: case DA: case X:
|
|
setmode( SRC );
|
|
emit2( mode | 0x2000 | $1 | $4<<4 | $2 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
break;
|
|
case BA: emit2( 0x3000 | $1 | $4<<4 | $2 );
|
|
#ifdef RELOCATION
|
|
newrelo(displ.typ,RELO2|RELBR);
|
|
#endif
|
|
emit2( (int) displ.val );
|
|
break;
|
|
case BX: emit2( 0x7000 | $1 | $4<<4 | $2 );
|
|
emit2( index<<8 );
|
|
break;
|
|
default: argerr();
|
|
}
|
|
break;
|
|
}
|
|
if ( oprtype[ SRC ] == REG )
|
|
{ switch( oprtype[ DST ] )
|
|
{ case IR: case DA: case X:
|
|
setmode( DST );
|
|
emit2( mode | 0x2E00 | $1 | $2<<4 | $4 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
break;
|
|
case BA: emit2( 0x3200 | $1 | $2<<4 | $4 );
|
|
#ifdef RELOCATION
|
|
newrelo(displ.typ,RELO2|RELBR);
|
|
#endif
|
|
emit2( (int) displ.val );
|
|
break;
|
|
case BX: emit2( 0x7200 | $1 | $2<<4 | $4 );
|
|
emit2( index<<8 );
|
|
break;
|
|
default: argerr();
|
|
}
|
|
break;
|
|
}
|
|
if ( oprtype[ SRC ] == IM ) /* F5.1 */
|
|
{ chtype( DST, TYPE_ld );
|
|
emit2( mode | 0xC05 | $1 | $2<<4 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
if ( $1 == 0 ) /* ldb */
|
|
{ /* fit(fits8(immed)); */
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO1);
|
|
#endif
|
|
emit1((int) immed.val);
|
|
/* emit1((int) immed.val); ??? twice ??? */
|
|
}
|
|
else /* ld */
|
|
{ /*fit(fits16(immed));*/
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO2 | RELBR);
|
|
#endif
|
|
emit2( (int)immed.val );
|
|
}
|
|
break;
|
|
}
|
|
argerr();
|
|
}
|
|
| LDL dst ',' src
|
|
{ if ( oprtype[ DST ] == REG )
|
|
{ switch( oprtype[ SRC ] )
|
|
{ case IM: emit2( 0x1400 | $2 );
|
|
#ifdef RELOCATION
|
|
newrelo(immed.typ, RELO4|RELBR|RELWR);
|
|
#endif
|
|
emit4( immed.val );
|
|
break;
|
|
case REG: case IR: case DA: case X:
|
|
setmode( SRC );
|
|
emit2( mode | 0x1400 | $4<<4 | $2 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
break;
|
|
case BA: emit2( 0x3500 | $4<<4 | $2 );
|
|
#ifdef RELOCATION
|
|
newrelo(displ.typ,RELO2|RELBR);
|
|
#endif
|
|
emit2((int) displ.val );
|
|
break;
|
|
case BX: emit2( 0x7500 | $4<<4 | $2 );
|
|
emit2( index<<8 );
|
|
break;
|
|
default: argerr();
|
|
}
|
|
break;
|
|
}
|
|
if ( oprtype[ SRC ] == REG )
|
|
{ switch( oprtype[ DST ] )
|
|
{ case IR: case DA: case X:
|
|
setmode( DST );
|
|
emit2( mode | 0x1D00 | $2<<4 | $4 );
|
|
if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
break;
|
|
case BA: emit2( 0x3700 | $2<<4 | $4 );
|
|
#ifdef RELOCATION
|
|
newrelo(displ.typ,RELO2|RELBR);
|
|
#endif
|
|
emit2( (int) displ.val );
|
|
break;
|
|
case BX: emit2( 0x7700 | $2<<4 | $4 );
|
|
emit2( index<<8 );
|
|
break;
|
|
default: argerr();
|
|
}
|
|
break;
|
|
}
|
|
/* if ( oprtype[ SRC ] == IM )
|
|
** { chtype( DST, TYPE_ld );
|
|
** emit2( mode | 0xD07 | $2<<4 );
|
|
** if ( mode>>12 == 4 ) emit_ad( addr_inf );
|
|
** emit4( immed );
|
|
** break;
|
|
** }
|
|
*/
|
|
argerr();
|
|
}
|
|
;
|
|
|
|
|
|
f3 : DJNZ reg ',' ra
|
|
{ branch( $1 | $2<<8, $4 ); }
|
|
| JR coco1 ra
|
|
{ branch( $1 | $2<<8, $3 ); }
|
|
| CALR ra
|
|
{ branch( $1, $2 ); }
|
|
;
|
|
|
|
|
|
f4 : LDR reg ',' ra
|
|
{ ldrel( $1 | $2, $4 ); }
|
|
| LDR ra ',' reg
|
|
{ ldrel( $1 | 0x200 | $4, $2 ); }
|
|
| LDAR R32 ',' ra
|
|
{ ldrel( $1 | $2, $4 ); }
|
|
;
|
|
|
|
|
|
f5 : F5_1L reg option
|
|
{ if ( $3 < 0 )
|
|
{ warning( "neg src results in a right shift!" );
|
|
warning( "warning only");
|
|
}
|
|
shiftcode( $1 | $2<<4, $3 );
|
|
}
|
|
| F5_1R reg option2
|
|
{ if ( $3 > 0 )
|
|
{ warning( "pos src results in a left shift!" );
|
|
warning( "warning only");
|
|
}
|
|
shiftcode( $1 | $2<<4, $3 );
|
|
}
|
|
;
|
|
|
|
option2 : ',' imexpr
|
|
{ $$ = $2; }
|
|
| /* empty */
|
|
{ $$ = -1; }
|
|
;
|
|
|
|
f6 : LDM dst ',' src ',' imexpr
|
|
{ switch( oprtype[ DST ] )
|
|
{ case REG: chtype( SRC, TYPE_ldm );
|
|
ldmcode( $1 | $4<<4, $2, $6 );
|
|
break;
|
|
default: switch( oprtype[ SRC ] )
|
|
{ case REG: chtype( DST, TYPE_ldm );
|
|
ldmcode($1+8 | $2<<4, $4, $6);
|
|
break;
|
|
default: argerr();
|
|
}
|
|
}
|
|
}
|
|
| F6_4 ir ',' ir ',' R16
|
|
{ /* For translate instructions the roles of $2 and $4
|
|
** are interchanged with respect to the other
|
|
** instructions of this group.
|
|
*/
|
|
if ( ($1 & 0xB8FF) == $1 )
|
|
{ /* translate instruction */
|
|
emit2( ($1 & ~0xF0) | $2<<4 );
|
|
emit2( ($1 & 0xF0)>>4 | $6<<8 | $4<<4 );
|
|
}
|
|
else
|
|
{ emit2( ($1 & ~0xF0) | $4<<4 );
|
|
emit2( ($1 & 0xF0)>>4 | $6<<8 | $2<<4 );
|
|
}
|
|
}
|
|
| F6_5 dst ',' ir ',' R16 coco2
|
|
{ switch( oprtype[ DST ] )
|
|
{ case REG: if ( bitset($1,1) ) argerr(); break;
|
|
case IR : if ( !bitset($1,1) ) argerr(); break;
|
|
default : argerr();
|
|
}
|
|
emit2( $1 | $4<<4 );
|
|
emit2( $6<<8 | $2<<4 | $7 );
|
|
}
|
|
| F6_6 reg ',' R16
|
|
{ emit2( $1 | $2<<4 );
|
|
emit2( $4<<8 );
|
|
}
|
|
;
|
|
|
|
|
|
f7 : IN reg ',' da
|
|
{ emit2( $1 | 0xA04 | $2<<4 );
|
|
#ifdef RELOCATION
|
|
newrelo(adr_inf.typ, RELO2|RELBR);
|
|
#endif
|
|
emit2( (short)addr_inf.val ); /* i/o address */
|
|
}
|
|
| OUT da ',' reg
|
|
{ emit2( $1 | 0xA06 | $4<<4 );
|
|
#ifdef RELOCATION
|
|
newrelo(adr_inf.typ, RELO2|RELBR);
|
|
#endif
|
|
emit2( (short)addr_inf.val ); /* i/o address */
|
|
}
|
|
| IN reg ',' ir
|
|
{ if ( bitset($1,0) ) argerr();
|
|
emit2( $1 | 0xC00 | $4<<4 | $2 );
|
|
}
|
|
| OUT ir ',' reg
|
|
{ if ( bitset($1,0) ) argerr();
|
|
emit2( $1 | 0xE00 | $2<<4 | $4 );
|
|
}
|
|
;
|
|
|
|
|
|
f8 : LDCTL ctlargs
|
|
{ emit2( $1 | $2 ); }
|
|
| LDCTLB ctlbargs
|
|
{ emit2( $1 | $2 ); }
|
|
| MREQ reg
|
|
{ emit2( $1 | $2<<4 ); }
|
|
;
|
|
ctlargs : CTLR ',' R16
|
|
{ $$ = $3<<4 | $1 | 8; }
|
|
| R16 ',' CTLR
|
|
{ $$ = $1<<4 | $3; }
|
|
;
|
|
ctlbargs: CTLRFLAGS ',' R8
|
|
{ $$ = $3<<4 | $1 | 8;}
|
|
| R8 ',' CTLRFLAGS
|
|
{ $$ = $1<<4 | $3; }
|
|
;
|
|
|
|
|
|
|
|
|
|
f9 : F9_1 flags
|
|
{ emit2( $1 | $2 ); }
|
|
| F9_2 ints
|
|
{ emit2( $1 | $2 ); }
|
|
| F9_3
|
|
{ emit2( $1 ); }
|
|
| RET
|
|
{ emit2( $1 | 8 ); }
|
|
| RET CC
|
|
{ emit2( $1 | $2 ); }
|
|
| SC imexpr
|
|
{ fit(fit8($2));
|
|
emit2( $1 | $2 );
|
|
}
|
|
;
|
|
flags : flags ',' FLAG
|
|
{ $$ = $1 | $3; }
|
|
| FLAG
|
|
{ $$ = $1; }
|
|
;
|
|
ints : ints ',' INTCB
|
|
{ $$ = $1 | $3; }
|
|
| INTCB
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
|
|
|
|
|
|
coco1 : CC ','
|
|
{ $$ = $1; }
|
|
| /* empty */
|
|
{ $$ = 8; }
|
|
;
|
|
coco2 : ',' CC
|
|
{ $$ = $2; }
|
|
| /* empty */
|
|
{ $$ = 8; }
|
|
;
|
|
option : ',' imexpr
|
|
{ $$ = $2; }
|
|
| /* empty */
|
|
{ $$ = 1; }
|
|
;
|
|
/* `imexpr', just as `im', is used to implement immediate data.
|
|
** But `imexpr' is used in those cases where the immediate value
|
|
** always will fit into 16 bits, so (long) `immed' is not needed.
|
|
** Those cases are in `option', `option2', f9-`SC', f6-`LDM' and
|
|
** f1-`LDK'.
|
|
*/
|
|
imexpr : '$' absexp
|
|
{ $$ = $2; }
|
|
;
|
|
/* Destination (dst) as well as source (src) operands never
|
|
** have RA as addressing mode, except for some instructions of the
|
|
** F3 and F4 instruction format group. In those cases RA is even
|
|
** the only addressing mode which is allowed. This is why `ra'
|
|
** has a yacc-rule not being part of `opr'.
|
|
*/
|
|
ra : expr
|
|
{ $$ = $1; }
|
|
;
|
|
dst : { operand = DST;}
|
|
opr
|
|
{ $$ = $2; }
|
|
;
|
|
src : { operand = SRC;}
|
|
opr
|
|
{ $$ = $2; }
|
|
;
|
|
opr : reg
|
|
{ settype( REG ); }
|
|
| im
|
|
{ settype( IM ); }
|
|
| ir
|
|
{ settype( IR ); }
|
|
| da
|
|
{ settype( DA ); }
|
|
| x
|
|
{ settype( X ); }
|
|
| ba
|
|
{ settype( BA ); }
|
|
| bx
|
|
{ settype( BX ); }
|
|
;
|
|
reg : R8
|
|
| R16
|
|
| R32
|
|
| R64
|
|
;
|
|
im : '$' expr
|
|
{ $$ = 0;
|
|
immed = $2;
|
|
}
|
|
| '$' '<' '<' expr '>' '>' expr
|
|
{ $$ = 0;
|
|
immed.typ = combine($4.typ, $7.typ, '+');
|
|
immed.val = $4.val<<16 | $7.val;
|
|
}
|
|
;
|
|
ir : '*' R32
|
|
{ if ( $2 == 0 ) regerr();
|
|
$$ = $2;
|
|
}
|
|
;
|
|
da : expr
|
|
{ $$ = 0;
|
|
addr_inf = $1;
|
|
}
|
|
| '<' '<' expr '>' '>' expr
|
|
{ $$ = 0;
|
|
addr_inf.typ = combine( $3.typ, $6.typ, '+' );
|
|
addr_inf.val = $3.val<<16 | $6.val;
|
|
}
|
|
;
|
|
x : expr '(' R16 ')'
|
|
{ if ( $3 == 0 ) regerr();
|
|
$$ = $3;
|
|
addr_inf = $1;
|
|
}
|
|
| '<' '<' expr '>' '>' expr '(' R16 ')'
|
|
{ if ( $8 == 0 ) regerr();
|
|
$$ = $8;
|
|
addr_inf.typ = combine( $3.typ, $6.typ, '+' );
|
|
addr_inf.val = $3.val<<16 | $6.val;
|
|
}
|
|
;
|
|
ba : R32 '(' '$' expr ')'
|
|
{ if ( $1 == 0 ) regerr();
|
|
$$ = $1;
|
|
displ = $4;
|
|
}
|
|
;
|
|
bx : R32 '(' R16 ')'
|
|
{ if ( $1 == 0 || $3 == 0 ) regerr();
|
|
$$ = $1;
|
|
index = $3;
|
|
}
|
|
;
|