ack/mach/z8000/as/mach4.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 "$Id$"
/*
** 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( offset<<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( offset<<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( offset<<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( offset<<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( offset<<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;
offset = $3;
}
;