xref: /csrg-svn/old/as.vax/ascode.c (revision 1746)
1592Sbill /* Copyright (c) 1980 Regents of the University of California */
2*1746Shenry static	char sccsid[] = "@(#)ascode.c 4.7 11/05/80";
3592Sbill #include <stdio.h>
4592Sbill #include "as.h"
5592Sbill #include "assyms.h"
6592Sbill 
7673Shenry /*
8673Shenry  *	Loader reference types  (plust PCREL) to bytes and lg bytes
9673Shenry  */
10673Shenry /*		LEN1	LEN1+PC	LEN2	LEN2+PC	LEN4	LEN4+PC	LEN8	LEN8+PC*/
11673Shenry int	reflen[] = 	/* {LEN*+PCREL} ==> number of bytes */
12673Shenry {0,	0,	1,	1,	2,	2,	4,	4,	8,	8};
13673Shenry int	lgreflen[] =	/* {LEN*+PCREL} ==> lg number of bytes */
14673Shenry {-1,	-1,	0,	0,	1,	1,	2,	2,	3,	3};
15673Shenry 
16673Shenry /*
17673Shenry  *	Sizes to Loader reference types and type flags
18673Shenry  */
19673Shenry /*0	1	2	3	4	5	6	7	8*/
20673Shenry int	len124[] = 	/* {1,2,4,8} ==> {LEN1, LEN2, LEN4, LEN8} */
21673Shenry {0,	LEN1,	LEN2,	0,	LEN4,	0,	0,	0,	LEN8};
22673Shenry char	mod124[] = 	/* {1,2,4,8} ==> {bits to construct operands */
23673Shenry {0,	0x00,	0x20,	0,	0x40,	0,	0,	0,	0};
24673Shenry int	type_124[] =	/* {1,2,4,8} ==> {TYPB, TYPW, TYPL, TYPQ} */
25673Shenry {0,	 TYPB,	TYPW,	 0,	 TYPL,	 0,	 0,	 0,	 TYPQ};
26673Shenry 
27673Shenry /*
28673Shenry  *	type flags to Loader reference and byte lengths
29673Shenry  */
30673Shenry /*TYPB	TYPW	TYPL	TYPQ	TYPF	TYPD*/
31673Shenry int	ty_NORELOC[] =	/* {TYPB..TYPD} ==> {1 if relocation not OK */
32673Shenry {0,	0,	0,	1,	1,	1};
33673Shenry int	ty_LEN[] =	/* {TYPB..TYPD} ==> {LEN1..LEN8} */
34673Shenry {LEN1,	LEN2,	LEN4,	LEN8,	LEN4,	LEN8};
35673Shenry int	ty_nbyte[] =	/* {TYPB..TYPD} ==> {1,2,4,8} */
36673Shenry {1,	2,	4,	8,	4,	8};
37673Shenry int	ty_nlg[] =	/* {TYPB..TYPD} ==> lg{1,2,4,8} */
38673Shenry {0,	1,	2,	3,	2,	3};
39673Shenry 
40592Sbill insout(op, ap, nact)
41592Sbill 	struct arg *ap;
42592Sbill {
43667Shenry 	int		jxxflg;
44667Shenry 	register	struct	instab	*ip;		/* the instruction */
45667Shenry 	register	struct	arg	*ap_walk;	/* actual param walk */
46667Shenry 	register	int	i;
47667Shenry 	register	int	ap_type;		/* actual param type */
48667Shenry 	register	int	ap_type_mask;		/* masked actual param */
49592Sbill 	op &= 0xFF;
50592Sbill 	jxxflg = nact;
51592Sbill 	if (nact < 0)
52592Sbill 		nact = -nact;
53592Sbill 	if (passno == 1) {
54667Shenry 	    ip = itab[op];
55667Shenry 	    if (nact < ip->i_nargs)
56667Shenry 		yyerror("Too few arguments");
57667Shenry 	    if (nact > ip->i_nargs) {
58667Shenry 		yyerror("Too many arguments");
59667Shenry 		nact = ip->i_nargs;
60667Shenry 	    }
61667Shenry 	    /*
62667Shenry 	     *	Check argument compatability with instruction template
63667Shenry 	     */
64667Shenry 	    for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){
65673Shenry 		ap_type = ap_walk->a_atype;
66667Shenry 		ap_type_mask = ap_type & AMASK;
67*1746Shenry 		/*
68*1746Shenry 		 *	The switch value is >> by 3 so that the switch
69*1746Shenry 		 *	code is dense, not implemented as a sequence
70*1746Shenry 		 *	of branches but implemented as a casel.
71*1746Shenry 		 *	In addition, cases ACCI and ACCR are added to force
72*1746Shenry 		 *	dense switch code.
73*1746Shenry 		 */
74*1746Shenry 		switch( ((fetcharg(ip, i-1)) & ACCESSMASK)>>3){	/* type of fp */
75*1746Shenry 		case ACCI >> 3:
76*1746Shenry 		case ACCR >> 3:
77*1746Shenry 			break;
78*1746Shenry 		case ACCB >> 3:
79667Shenry 			if ( !((ap_type_mask == AEXP) || (ap_type_mask == AIMM)) ){
80667Shenry 				yyerror("arg %d, branch displacement must be an expression",i);
81667Shenry 				return;
82667Shenry 			}
83667Shenry 			break;
84*1746Shenry 		case ACCA >> 3:
85667Shenry 			switch(ap_type_mask){
86667Shenry 			case AREG:	yyerror("arg %d, addressing a register",i);
87667Shenry 					return;
88667Shenry 			case AIMM:	if ( !(ap_type & ASTAR) ){
89667Shenry 					 yyerror("arg %d, addressing an immediate operand",i);
90667Shenry 					 return;
91667Shenry 					}
92667Shenry 			}
93667Shenry 			break;
94*1746Shenry 		case ACCM >> 3:
95*1746Shenry 		case ACCW >> 3:
96667Shenry 			switch(ap_type_mask){
97667Shenry 			case AIMM:	if (!(ap_type&ASTAR)) {
98667Shenry 					 yyerror("arg %d, modifying a constant",i);
99667Shenry 					 return;
100667Shenry 					}
101667Shenry 			}
102667Shenry 			break;
103667Shenry 		}	/* end of the switch on fp_type */
104667Shenry 		if (ap_type & AINDX) {
105667Shenry 			if (ap_walk->a_areg2==0xF) {
106667Shenry 				yyerror("arg %d, PC used as index",i);
107667Shenry 				return;
108667Shenry 			}
109667Shenry 			switch(ap_type_mask){
110667Shenry 			case AREG:	yyerror("arg %d, indexing the register file",i);
111667Shenry 					return;
112667Shenry 			case AIMM:	yyerror("arg %d, indexing a constant",i);
113667Shenry 					return;
114673Shenry 			case ADECR:
115673Shenry 			case AINCR:	if (ap_walk->a_areg1==ap_walk->a_areg2) {
116667Shenry 						yyerror("arg %d, indexing with modified register",i);
117667Shenry 						return;
118667Shenry 					}
119667Shenry 					break;
120667Shenry 			}	/* end of switch on ap_type_mask */
121667Shenry 		} /* end of AINDX */
122667Shenry 	   }
123667Shenry 	} /* both passes here */
124592Sbill 	if (jxxflg < 0)
125592Sbill 		ijxout(op, ap, nact);
126592Sbill 	else putins(op, ap, nact);
127592Sbill }
128592Sbill 
129592Sbill extern	int d124;
130592Sbill 
131592Sbill putins(op, ap, n)
132592Sbill 	/*
133592Sbill 	 *	n had better be positive
134592Sbill 	 */
135592Sbill 	register struct arg *ap;
136592Sbill {
137592Sbill 	register struct exp 	*xp;
138853Shenry 	register int 		argtype;
139673Shenry 	int 			i;
140673Shenry 	int			reloc_how;
141592Sbill 
142592Sbill #ifdef DEBUG
143592Sbill 	fflush(stdout);
144592Sbill #endif
145592Sbill 	if (passno == 2)
146592Sbill 		goto PASS2;
147592Sbill 
148629Shenry 	dotp->e_xvalue += n+1;		/* 1 for the opcode, at least 1 per arg */
149629Shenry 	for (i=0; i<n; i++,ap++) {	/* some args take more than 1 byte */
150853Shenry 	    argtype = ap->a_atype;
151853Shenry 	    if (argtype & AINDX)
152629Shenry 		dotp->e_xvalue++;
153*1746Shenry 	    /*
154*1746Shenry 	     *	This switch has been fixed by enumerating the no action
155*1746Shenry 	     *	alternatives (those that have 1 one byte of code)
156*1746Shenry 	     *	so that a casel instruction is emitted.
157*1746Shenry 	     */
158853Shenry 	    switch (argtype&~(AINDX|ASTAR)) {
159*1746Shenry 		case AREG:
160*1746Shenry 		case ABASE:
161*1746Shenry 		case ADECR:
162*1746Shenry 		case AINCR:
163*1746Shenry 			break;
164592Sbill 		case AEXP:
165853Shenry 			argtype = fetcharg(itab[op], i);
166853Shenry 			if (argtype == ACCB+TYPB)
167592Sbill 				break;
168853Shenry 			if (argtype==ACCB+TYPW){
169629Shenry 				dotp->e_xvalue++;
170592Sbill 				break;
171592Sbill 			}
172592Sbill 			/*
173592Sbill 			 *	Reduces to PC relative
174592Sbill 			 */
175629Shenry 			dotp->e_xvalue += ap->a_dispsize;
176592Sbill 			break;
177592Sbill 
178592Sbill 		case ADISP:
179629Shenry 			xp=ap->a_xp;
180629Shenry 			if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
181629Shenry 				dotp->e_xvalue += ap->a_dispsize;
182592Sbill 				break;
183592Sbill 			}
184853Shenry 			if (xp->e_xvalue==0 && !(argtype&ASTAR))
185592Sbill 				break;
186629Shenry 			dotp->e_xvalue++;
187629Shenry 			if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE))
188629Shenry 				dotp->e_xvalue++;
189629Shenry 			if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD))
190629Shenry 				dotp->e_xvalue += 2;
191592Sbill 			break;
192592Sbill 
193592Sbill 		case AIMM:
194853Shenry 			if (ap->a_atype&ASTAR) argtype=TYPL;
195592Sbill 			else {
196853Shenry 				argtype = fetcharg(itab[op], i);
197853Shenry 				if (argtype&ACCA)
198853Shenry 					argtype = TYPL;
199592Sbill 				else
200853Shenry 					argtype &= TYPMASK;
201629Shenry 				xp = ap->a_xp;
202629Shenry 				if (   ((xp->e_xtype&XTYPE)==XABS)
203629Shenry 				    && (!(xp->e_xtype&XFORW))
204629Shenry 				    && (xp->e_xvalue>=0)
205629Shenry 				    && (xp->e_xvalue<=63)
206629Shenry 				    && (xp->e_yvalue == 0)
207853Shenry 				    && (argtype != TYPD)
208853Shenry 				    && (argtype != TYPF)
209592Sbill 				)
210592Sbill 						break;
211592Sbill 			}
212853Shenry 			switch (argtype) {
213592Sbill 			case TYPD:
214592Sbill 			case TYPF:
215629Shenry 				if (   !(((xp->e_xtype&XTYPE)==XABS)
216629Shenry 				    && (!(xp->e_xtype&XFORW))
217592Sbill 				    && (slitflt(xp)))
218592Sbill 				){
219592Sbill 				/* it is NOT short */
220853Shenry 					dotp->e_xvalue += ((argtype==TYPF)?
221592Sbill 						4 : 8);
222592Sbill 				}
223592Sbill 				break;
224592Sbill 			case TYPQ:
225629Shenry 				dotp->e_xvalue += 8;break;
226592Sbill 			case TYPL:
227629Shenry 				dotp->e_xvalue += 4;break;
228592Sbill 			case TYPW:
229629Shenry 				dotp->e_xvalue += 2;break;
230592Sbill 			case TYPB:
231629Shenry 				dotp->e_xvalue += 1;break;
232853Shenry 			}	/*end of the switch on argtype*/
233592Sbill 	    }	/*end of the switch on the type*/
234592Sbill 	}	/*end of looping for all arguments*/
235592Sbill 	return;
236592Sbill 
237592Sbill PASS2:
238592Sbill 
239592Sbill #ifdef UNIX
240592Sbill 	outb(op); /* the opcode */
241592Sbill #endif UNIX
242592Sbill #ifdef VMS
243592Sbill 	*vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)op;
244629Shenry 	dotp->e_xvalue += 1;
245592Sbill #endif VMS
246592Sbill 
247592Sbill 	for (i=0; i<n; i++,ap++) {/* now for the arguments */
248853Shenry 		argtype=ap->a_atype;
249629Shenry 		xp=ap->a_xp;
250673Shenry 		reloc_how = TYPNONE;
251853Shenry 		if (argtype&AINDX) {
252592Sbill #ifdef UNIX
253629Shenry 			{ outb(0x40 | ap->a_areg2); }
254592Sbill #endif UNIX
255592Sbill #ifdef VMS
256592Sbill 			{ *vms_obj_ptr++ = -1;
257629Shenry 			  *vms_obj_ptr++ = (0x40 | ap->a_areg2);
258629Shenry 			  dotp->e_xvalue += 1; }
259592Sbill #endif VMS
260853Shenry 			argtype &= ~AINDX;
261592Sbill 		}
262853Shenry 		if (argtype&ASTAR) {
263629Shenry 			ap->a_areg1 |= 0x10;
264853Shenry 			argtype &= ~ASTAR;
265592Sbill 		}
266853Shenry 		switch (argtype) {
267592Sbill 		case AREG:		/* %r */
268629Shenry 			ap->a_areg1 |= 0x50;
269592Sbill 			break;
270592Sbill 		case ABASE:		/* (%r) */
271629Shenry 			ap->a_areg1 |= 0x60;
272592Sbill 			break;
273592Sbill 		case ADECR: 		/* -(%r) */
274629Shenry 			ap->a_areg1 |= 0x70;
275592Sbill 			break;
276665Shenry 		case AINCR:		/* (%r)+ */
277629Shenry 			ap->a_areg1 |= 0x80;
278592Sbill 			break;
279592Sbill 		case AEXP: /* expr */
280853Shenry 			argtype = fetcharg(itab[op], i);
281853Shenry 			if (argtype == ACCB+TYPB) {
282853Shenry 				ap->a_areg1 = argtype =
283629Shenry 					xp->e_xvalue - (dotp->e_xvalue + 1);
284853Shenry 				if (argtype<MINBYTE || argtype>MAXBYTE)
285592Sbill 					yyerror("Branch too far"); break;
286592Sbill 			}
287853Shenry 			if (argtype == ACCB+TYPW) {
288853Shenry 				ap->a_areg1 = argtype = xp->e_xvalue
289629Shenry 					-= dotp->e_xvalue + 2;
290629Shenry 				xp->e_xtype = XABS;
291853Shenry 				if (argtype<MINWORD || argtype>MAXWORD)
292592Sbill 					yyerror("Branch too far");
293853Shenry 				xp->e_xvalue = argtype>>8;
294673Shenry 				reloc_how = TYPB;
295592Sbill 				break;
296592Sbill 			}
297592Sbill 			/* reduces to expr(pc) mode */
298629Shenry 			ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]);
299673Shenry 			reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL;
300592Sbill 			break;
301592Sbill 
302592Sbill 		case ADISP: /* expr(%r) */
303629Shenry 			ap->a_areg1 |= 0xA0;
304629Shenry 			if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
305629Shenry 				ap->a_areg1 += mod124[ap->a_dispsize];
306673Shenry 				reloc_how = type_124[ap->a_dispsize];
307592Sbill 				break;
308592Sbill 			}
309629Shenry 			if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) {
310629Shenry 				ap->a_areg1 ^= 0xC0;
311592Sbill 				break;
312592Sbill 			}
313673Shenry 			reloc_how = TYPB;
314629Shenry 			if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)){
315629Shenry 				ap->a_areg1 += 0x20;
316673Shenry 				reloc_how = TYPW;
317592Sbill 			}
318629Shenry 			if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)){
319629Shenry 				ap->a_areg1 += 0x20;
320673Shenry 				reloc_how = TYPL;
321592Sbill 			}
322592Sbill 			break;
323592Sbill 
324592Sbill 		case AIMM:  /* $expr */
325629Shenry 			if (ap->a_atype&ASTAR)
326853Shenry 				argtype=TYPL;
327592Sbill 			else {
328853Shenry 				argtype = fetcharg(itab[op], i);
329853Shenry 				if (argtype&ACCA)
330853Shenry 					argtype=TYPL;
331592Sbill 				else
332853Shenry 					argtype &= TYPMASK;
333629Shenry 				if (    ( (xp->e_xtype&XTYPE) == XABS)
334629Shenry 				    && !(xp->e_xtype&XFORW)
335629Shenry 				    &&  (xp->e_xvalue >= 0)
336629Shenry 				    &&  (xp->e_xvalue <= 63)
337629Shenry 				    &&  (xp->e_yvalue == 0)
338853Shenry 				    &&  (argtype != TYPF)
339853Shenry 				    &&  (argtype != TYPD) ) {
340629Shenry 					ap->a_areg1 = xp->e_xvalue;
341592Sbill 					break;
342592Sbill 				}
343592Sbill 			}
344629Shenry 			ap->a_areg1 |= 0x8F;
345853Shenry 			reloc_how = argtype;
346673Shenry 			if (reloc_how == TYPD || reloc_how == TYPF){
347629Shenry 				if (   ((xp->e_xtype&XTYPE)==XABS)
348629Shenry 				    && (!(xp->e_xtype&XFORW))
349592Sbill 				    && (slitflt(xp))
350592Sbill 				){
351673Shenry 					reloc_how = TYPNONE;
352629Shenry 					ap->a_areg1=extlitflt(xp);
353592Sbill 				}
354592Sbill 			}
355592Sbill 			break;
356592Sbill 
357853Shenry 		}	/*end of the switch on argtype*/
358592Sbill 		/*
359592Sbill 		 *	use the first byte to describe the argument
360592Sbill 		 */
361592Sbill #ifdef UNIX
362629Shenry 		outb(ap->a_areg1);
363592Sbill #endif UNIX
364592Sbill #ifdef VMS
365629Shenry 		*vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)(ap->a_areg1);
366629Shenry 		dotp->e_xvalue += 1;
367592Sbill 		if ((vms_obj_ptr-sobuf) > 400) {
368592Sbill 			write(objfil,sobuf,vms_obj_ptr-sobuf);
369592Sbill 			vms_obj_ptr=sobuf+1;
370592Sbill 		}
371592Sbill #endif VMS
372673Shenry 		if (reloc_how != TYPNONE)
373673Shenry 			outrel(xp, reloc_how);
374592Sbill 	}	/*end of the for to pick up all arguments*/
375592Sbill }
376