ack/mach/ns/as/mach4.c

417 lines
10 KiB
C
Raw Normal View History

1986-12-05 16:58:29 +00:00
#define RCSID4 "$Header$"
/*
* (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
*
* This product is part of the Amsterdam Compiler Kit.
*
* Permission to use, sell, duplicate or disclose this software must be
* obtained in writing. Requests for such permissions may be sent to
*
* Dr. Andrew S. Tanenbaum
* Wiskundig Seminarium
* Vrije Universiteit
* Postbox 7161
* 1007 MC Amsterdam
* The Netherlands
*
*/
/* 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) ) ;}
;