/* Copyright (c) 1980 Regents of the University of California */
static char sccsid
[] = "@(#)ascode.c 4.7 11/5/80";
* Loader reference types (plust PCREL) to bytes and lg bytes
/* LEN1 LEN1+PC LEN2 LEN2+PC LEN4 LEN4+PC LEN8 LEN8+PC*/
int reflen
[] = /* {LEN*+PCREL} ==> number of bytes */
{0, 0, 1, 1, 2, 2, 4, 4, 8, 8};
int lgreflen
[] = /* {LEN*+PCREL} ==> lg number of bytes */
{-1, -1, 0, 0, 1, 1, 2, 2, 3, 3};
* Sizes to Loader reference types and type flags
int len124
[] = /* {1,2,4,8} ==> {LEN1, LEN2, LEN4, LEN8} */
{0, LEN1
, LEN2
, 0, LEN4
, 0, 0, 0, LEN8
};
char mod124
[] = /* {1,2,4,8} ==> {bits to construct operands */
{0, 0x00, 0x20, 0, 0x40, 0, 0, 0, 0};
int type_124
[] = /* {1,2,4,8} ==> {TYPB, TYPW, TYPL, TYPQ} */
{0, TYPB
, TYPW
, 0, TYPL
, 0, 0, 0, TYPQ
};
* type flags to Loader reference and byte lengths
/*TYPB TYPW TYPL TYPQ TYPF TYPD*/
int ty_NORELOC
[] = /* {TYPB..TYPD} ==> {1 if relocation not OK */
int ty_LEN
[] = /* {TYPB..TYPD} ==> {LEN1..LEN8} */
{LEN1
, LEN2
, LEN4
, LEN8
, LEN4
, LEN8
};
int ty_nbyte
[] = /* {TYPB..TYPD} ==> {1,2,4,8} */
int ty_nlg
[] = /* {TYPB..TYPD} ==> lg{1,2,4,8} */
register struct instab
*ip
; /* the instruction */
register struct arg
*ap_walk
; /* actual param walk */
register int ap_type
; /* actual param type */
register int ap_type_mask
; /* masked actual param */
yyerror("Too few arguments");
if (nact
> ip
->i_nargs
) {
yyerror("Too many arguments");
* Check argument compatability with instruction template
for (ap_walk
= ap
, i
= 1; i
<= nact
; ap_walk
++, i
++){
ap_type
= ap_walk
->a_atype
;
ap_type_mask
= ap_type
& AMASK
;
* The switch value is >> by 3 so that the switch
* code is dense, not implemented as a sequence
* of branches but implemented as a casel.
* In addition, cases ACCI and ACCR are added to force
switch( ((fetcharg(ip
, i
-1)) & ACCESSMASK
)>>3){ /* type of fp */
if ( !((ap_type_mask
== AEXP
) || (ap_type_mask
== AIMM
)) ){
yyerror("arg %d, branch displacement must be an expression",i
);
case AREG
: yyerror("arg %d, addressing a register",i
);
case AIMM
: if ( !(ap_type
& ASTAR
) ){
yyerror("arg %d, addressing an immediate operand",i
);
case AIMM
: if (!(ap_type
&ASTAR
)) {
yyerror("arg %d, modifying a constant",i
);
} /* end of the switch on fp_type */
if (ap_walk
->a_areg2
==0xF) {
yyerror("arg %d, PC used as index",i
);
case AREG
: yyerror("arg %d, indexing the register file",i
);
case AIMM
: yyerror("arg %d, indexing a constant",i
);
case AINCR
: if (ap_walk
->a_areg1
==ap_walk
->a_areg2
) {
yyerror("arg %d, indexing with modified register",i
);
} /* end of switch on ap_type_mask */
else putins(op
, ap
, nact
);
* n had better be positive
dotp
->e_xvalue
+= n
+1; /* 1 for the opcode, at least 1 per arg */
for (i
=0; i
<n
; i
++,ap
++) { /* some args take more than 1 byte */
* This switch has been fixed by enumerating the no action
* alternatives (those that have 1 one byte of code)
* so that a casel instruction is emitted.
switch (argtype
&~(AINDX
|ASTAR
)) {
argtype
= fetcharg(itab
[op
], i
);
if (argtype
== ACCB
+TYPB
)
dotp
->e_xvalue
+= ap
->a_dispsize
;
if ((xp
->e_xtype
&XTYPE
)!=XABS
|| xp
->e_xtype
&XFORW
){
dotp
->e_xvalue
+= ap
->a_dispsize
;
if (xp
->e_xvalue
==0 && !(argtype
&ASTAR
))
if ((xp
->e_xvalue
<MINBYTE
) || (xp
->e_xvalue
>MAXBYTE
))
if ((xp
->e_xvalue
<MINWORD
) || (xp
->e_xvalue
>MAXWORD
))
if (ap
->a_atype
&ASTAR
) argtype
=TYPL
;
argtype
= fetcharg(itab
[op
], i
);
if ( ((xp
->e_xtype
&XTYPE
)==XABS
)
&& (!(xp
->e_xtype
&XFORW
))
if ( !(((xp
->e_xtype
&XTYPE
)==XABS
)
&& (!(xp
->e_xtype
&XFORW
))
dotp
->e_xvalue
+= ((argtype
==TYPF
)?
dotp
->e_xvalue
+= 8;break;
dotp
->e_xvalue
+= 4;break;
dotp
->e_xvalue
+= 2;break;
dotp
->e_xvalue
+= 1;break;
} /*end of the switch on argtype*/
} /*end of the switch on the type*/
} /*end of looping for all arguments*/
outb(op
); /* the opcode */
*vms_obj_ptr
++ = -1; *vms_obj_ptr
++ = (char)op
;
for (i
=0; i
<n
; i
++,ap
++) {/* now for the arguments */
{ outb(0x40 | ap
->a_areg2
); }
*vms_obj_ptr
++ = (0x40 | ap
->a_areg2
);
argtype
= fetcharg(itab
[op
], i
);
if (argtype
== ACCB
+TYPB
) {
xp
->e_xvalue
- (dotp
->e_xvalue
+ 1);
if (argtype
<MINBYTE
|| argtype
>MAXBYTE
)
yyerror("Branch too far"); break;
if (argtype
== ACCB
+TYPW
) {
ap
->a_areg1
= argtype
= xp
->e_xvalue
if (argtype
<MINWORD
|| argtype
>MAXWORD
)
yyerror("Branch too far");
xp
->e_xvalue
= argtype
>>8;
/* reduces to expr(pc) mode */
ap
->a_areg1
|= (0xAF + mod124
[ap
->a_dispsize
]);
reloc_how
= type_124
[ap
->a_dispsize
] + RELOC_PCREL
;
case ADISP
: /* expr(%r) */
if ((xp
->e_xtype
&XTYPE
)!=XABS
|| xp
->e_xtype
&XFORW
){
ap
->a_areg1
+= mod124
[ap
->a_dispsize
];
reloc_how
= type_124
[ap
->a_dispsize
];
if (xp
->e_xvalue
==0 && !(ap
->a_areg1
&0x10)) {
if ((xp
->e_xvalue
<MINBYTE
) || (xp
->e_xvalue
>MAXBYTE
)){
if ((xp
->e_xvalue
<MINWORD
) || (xp
->e_xvalue
>MAXWORD
)){
argtype
= fetcharg(itab
[op
], i
);
if ( ( (xp
->e_xtype
&XTYPE
) == XABS
)
ap
->a_areg1
= xp
->e_xvalue
;
if (reloc_how
== TYPD
|| reloc_how
== TYPF
){
if ( ((xp
->e_xtype
&XTYPE
)==XABS
)
&& (!(xp
->e_xtype
&XFORW
))
ap
->a_areg1
=extlitflt(xp
);
} /*end of the switch on argtype*/
* use the first byte to describe the argument
*vms_obj_ptr
++ = -1; *vms_obj_ptr
++ = (char)(ap
->a_areg1
);
if ((vms_obj_ptr
-sobuf
) > 400) {
write(objfil
,sobuf
,vms_obj_ptr
-sobuf
);
if (reloc_how
!= TYPNONE
)
} /*end of the for to pick up all arguments*/