xref: /original-bsd/old/as.vax/ascode.c (revision 6c57d260)
1 /* Copyright (c) 1980 Regents of the University of California */
2 static	char sccsid[] = "@(#)ascode.c 4.7 11/05/80";
3 #include <stdio.h>
4 #include "as.h"
5 #include "assyms.h"
6 
7 /*
8  *	Loader reference types  (plust PCREL) to bytes and lg bytes
9  */
10 /*		LEN1	LEN1+PC	LEN2	LEN2+PC	LEN4	LEN4+PC	LEN8	LEN8+PC*/
11 int	reflen[] = 	/* {LEN*+PCREL} ==> number of bytes */
12 {0,	0,	1,	1,	2,	2,	4,	4,	8,	8};
13 int	lgreflen[] =	/* {LEN*+PCREL} ==> lg number of bytes */
14 {-1,	-1,	0,	0,	1,	1,	2,	2,	3,	3};
15 
16 /*
17  *	Sizes to Loader reference types and type flags
18  */
19 /*0	1	2	3	4	5	6	7	8*/
20 int	len124[] = 	/* {1,2,4,8} ==> {LEN1, LEN2, LEN4, LEN8} */
21 {0,	LEN1,	LEN2,	0,	LEN4,	0,	0,	0,	LEN8};
22 char	mod124[] = 	/* {1,2,4,8} ==> {bits to construct operands */
23 {0,	0x00,	0x20,	0,	0x40,	0,	0,	0,	0};
24 int	type_124[] =	/* {1,2,4,8} ==> {TYPB, TYPW, TYPL, TYPQ} */
25 {0,	 TYPB,	TYPW,	 0,	 TYPL,	 0,	 0,	 0,	 TYPQ};
26 
27 /*
28  *	type flags to Loader reference and byte lengths
29  */
30 /*TYPB	TYPW	TYPL	TYPQ	TYPF	TYPD*/
31 int	ty_NORELOC[] =	/* {TYPB..TYPD} ==> {1 if relocation not OK */
32 {0,	0,	0,	1,	1,	1};
33 int	ty_LEN[] =	/* {TYPB..TYPD} ==> {LEN1..LEN8} */
34 {LEN1,	LEN2,	LEN4,	LEN8,	LEN4,	LEN8};
35 int	ty_nbyte[] =	/* {TYPB..TYPD} ==> {1,2,4,8} */
36 {1,	2,	4,	8,	4,	8};
37 int	ty_nlg[] =	/* {TYPB..TYPD} ==> lg{1,2,4,8} */
38 {0,	1,	2,	3,	2,	3};
39 
40 insout(op, ap, nact)
41 	struct arg *ap;
42 {
43 	int		jxxflg;
44 	register	struct	instab	*ip;		/* the instruction */
45 	register	struct	arg	*ap_walk;	/* actual param walk */
46 	register	int	i;
47 	register	int	ap_type;		/* actual param type */
48 	register	int	ap_type_mask;		/* masked actual param */
49 	op &= 0xFF;
50 	jxxflg = nact;
51 	if (nact < 0)
52 		nact = -nact;
53 	if (passno == 1) {
54 	    ip = itab[op];
55 	    if (nact < ip->i_nargs)
56 		yyerror("Too few arguments");
57 	    if (nact > ip->i_nargs) {
58 		yyerror("Too many arguments");
59 		nact = ip->i_nargs;
60 	    }
61 	    /*
62 	     *	Check argument compatability with instruction template
63 	     */
64 	    for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){
65 		ap_type = ap_walk->a_atype;
66 		ap_type_mask = ap_type & AMASK;
67 		/*
68 		 *	The switch value is >> by 3 so that the switch
69 		 *	code is dense, not implemented as a sequence
70 		 *	of branches but implemented as a casel.
71 		 *	In addition, cases ACCI and ACCR are added to force
72 		 *	dense switch code.
73 		 */
74 		switch( ((fetcharg(ip, i-1)) & ACCESSMASK)>>3){	/* type of fp */
75 		case ACCI >> 3:
76 		case ACCR >> 3:
77 			break;
78 		case ACCB >> 3:
79 			if ( !((ap_type_mask == AEXP) || (ap_type_mask == AIMM)) ){
80 				yyerror("arg %d, branch displacement must be an expression",i);
81 				return;
82 			}
83 			break;
84 		case ACCA >> 3:
85 			switch(ap_type_mask){
86 			case AREG:	yyerror("arg %d, addressing a register",i);
87 					return;
88 			case AIMM:	if ( !(ap_type & ASTAR) ){
89 					 yyerror("arg %d, addressing an immediate operand",i);
90 					 return;
91 					}
92 			}
93 			break;
94 		case ACCM >> 3:
95 		case ACCW >> 3:
96 			switch(ap_type_mask){
97 			case AIMM:	if (!(ap_type&ASTAR)) {
98 					 yyerror("arg %d, modifying a constant",i);
99 					 return;
100 					}
101 			}
102 			break;
103 		}	/* end of the switch on fp_type */
104 		if (ap_type & AINDX) {
105 			if (ap_walk->a_areg2==0xF) {
106 				yyerror("arg %d, PC used as index",i);
107 				return;
108 			}
109 			switch(ap_type_mask){
110 			case AREG:	yyerror("arg %d, indexing the register file",i);
111 					return;
112 			case AIMM:	yyerror("arg %d, indexing a constant",i);
113 					return;
114 			case ADECR:
115 			case AINCR:	if (ap_walk->a_areg1==ap_walk->a_areg2) {
116 						yyerror("arg %d, indexing with modified register",i);
117 						return;
118 					}
119 					break;
120 			}	/* end of switch on ap_type_mask */
121 		} /* end of AINDX */
122 	   }
123 	} /* both passes here */
124 	if (jxxflg < 0)
125 		ijxout(op, ap, nact);
126 	else putins(op, ap, nact);
127 }
128 
129 extern	int d124;
130 
131 putins(op, ap, n)
132 	/*
133 	 *	n had better be positive
134 	 */
135 	register struct arg *ap;
136 {
137 	register struct exp 	*xp;
138 	register int 		argtype;
139 	int 			i;
140 	int			reloc_how;
141 
142 #ifdef DEBUG
143 	fflush(stdout);
144 #endif
145 	if (passno == 2)
146 		goto PASS2;
147 
148 	dotp->e_xvalue += n+1;		/* 1 for the opcode, at least 1 per arg */
149 	for (i=0; i<n; i++,ap++) {	/* some args take more than 1 byte */
150 	    argtype = ap->a_atype;
151 	    if (argtype & AINDX)
152 		dotp->e_xvalue++;
153 	    /*
154 	     *	This switch has been fixed by enumerating the no action
155 	     *	alternatives (those that have 1 one byte of code)
156 	     *	so that a casel instruction is emitted.
157 	     */
158 	    switch (argtype&~(AINDX|ASTAR)) {
159 		case AREG:
160 		case ABASE:
161 		case ADECR:
162 		case AINCR:
163 			break;
164 		case AEXP:
165 			argtype = fetcharg(itab[op], i);
166 			if (argtype == ACCB+TYPB)
167 				break;
168 			if (argtype==ACCB+TYPW){
169 				dotp->e_xvalue++;
170 				break;
171 			}
172 			/*
173 			 *	Reduces to PC relative
174 			 */
175 			dotp->e_xvalue += ap->a_dispsize;
176 			break;
177 
178 		case ADISP:
179 			xp=ap->a_xp;
180 			if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
181 				dotp->e_xvalue += ap->a_dispsize;
182 				break;
183 			}
184 			if (xp->e_xvalue==0 && !(argtype&ASTAR))
185 				break;
186 			dotp->e_xvalue++;
187 			if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE))
188 				dotp->e_xvalue++;
189 			if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD))
190 				dotp->e_xvalue += 2;
191 			break;
192 
193 		case AIMM:
194 			if (ap->a_atype&ASTAR) argtype=TYPL;
195 			else {
196 				argtype = fetcharg(itab[op], i);
197 				if (argtype&ACCA)
198 					argtype = TYPL;
199 				else
200 					argtype &= TYPMASK;
201 				xp = ap->a_xp;
202 				if (   ((xp->e_xtype&XTYPE)==XABS)
203 				    && (!(xp->e_xtype&XFORW))
204 				    && (xp->e_xvalue>=0)
205 				    && (xp->e_xvalue<=63)
206 				    && (xp->e_yvalue == 0)
207 				    && (argtype != TYPD)
208 				    && (argtype != TYPF)
209 				)
210 						break;
211 			}
212 			switch (argtype) {
213 			case TYPD:
214 			case TYPF:
215 				if (   !(((xp->e_xtype&XTYPE)==XABS)
216 				    && (!(xp->e_xtype&XFORW))
217 				    && (slitflt(xp)))
218 				){
219 				/* it is NOT short */
220 					dotp->e_xvalue += ((argtype==TYPF)?
221 						4 : 8);
222 				}
223 				break;
224 			case TYPQ:
225 				dotp->e_xvalue += 8;break;
226 			case TYPL:
227 				dotp->e_xvalue += 4;break;
228 			case TYPW:
229 				dotp->e_xvalue += 2;break;
230 			case TYPB:
231 				dotp->e_xvalue += 1;break;
232 			}	/*end of the switch on argtype*/
233 	    }	/*end of the switch on the type*/
234 	}	/*end of looping for all arguments*/
235 	return;
236 
237 PASS2:
238 
239 #ifdef UNIX
240 	outb(op); /* the opcode */
241 #endif UNIX
242 #ifdef VMS
243 	*vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)op;
244 	dotp->e_xvalue += 1;
245 #endif VMS
246 
247 	for (i=0; i<n; i++,ap++) {/* now for the arguments */
248 		argtype=ap->a_atype;
249 		xp=ap->a_xp;
250 		reloc_how = TYPNONE;
251 		if (argtype&AINDX) {
252 #ifdef UNIX
253 			{ outb(0x40 | ap->a_areg2); }
254 #endif UNIX
255 #ifdef VMS
256 			{ *vms_obj_ptr++ = -1;
257 			  *vms_obj_ptr++ = (0x40 | ap->a_areg2);
258 			  dotp->e_xvalue += 1; }
259 #endif VMS
260 			argtype &= ~AINDX;
261 		}
262 		if (argtype&ASTAR) {
263 			ap->a_areg1 |= 0x10;
264 			argtype &= ~ASTAR;
265 		}
266 		switch (argtype) {
267 		case AREG:		/* %r */
268 			ap->a_areg1 |= 0x50;
269 			break;
270 		case ABASE:		/* (%r) */
271 			ap->a_areg1 |= 0x60;
272 			break;
273 		case ADECR: 		/* -(%r) */
274 			ap->a_areg1 |= 0x70;
275 			break;
276 		case AINCR:		/* (%r)+ */
277 			ap->a_areg1 |= 0x80;
278 			break;
279 		case AEXP: /* expr */
280 			argtype = fetcharg(itab[op], i);
281 			if (argtype == ACCB+TYPB) {
282 				ap->a_areg1 = argtype =
283 					xp->e_xvalue - (dotp->e_xvalue + 1);
284 				if (argtype<MINBYTE || argtype>MAXBYTE)
285 					yyerror("Branch too far"); break;
286 			}
287 			if (argtype == ACCB+TYPW) {
288 				ap->a_areg1 = argtype = xp->e_xvalue
289 					-= dotp->e_xvalue + 2;
290 				xp->e_xtype = XABS;
291 				if (argtype<MINWORD || argtype>MAXWORD)
292 					yyerror("Branch too far");
293 				xp->e_xvalue = argtype>>8;
294 				reloc_how = TYPB;
295 				break;
296 			}
297 			/* reduces to expr(pc) mode */
298 			ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]);
299 			reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL;
300 			break;
301 
302 		case ADISP: /* expr(%r) */
303 			ap->a_areg1 |= 0xA0;
304 			if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
305 				ap->a_areg1 += mod124[ap->a_dispsize];
306 				reloc_how = type_124[ap->a_dispsize];
307 				break;
308 			}
309 			if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) {
310 				ap->a_areg1 ^= 0xC0;
311 				break;
312 			}
313 			reloc_how = TYPB;
314 			if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)){
315 				ap->a_areg1 += 0x20;
316 				reloc_how = TYPW;
317 			}
318 			if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)){
319 				ap->a_areg1 += 0x20;
320 				reloc_how = TYPL;
321 			}
322 			break;
323 
324 		case AIMM:  /* $expr */
325 			if (ap->a_atype&ASTAR)
326 				argtype=TYPL;
327 			else {
328 				argtype = fetcharg(itab[op], i);
329 				if (argtype&ACCA)
330 					argtype=TYPL;
331 				else
332 					argtype &= TYPMASK;
333 				if (    ( (xp->e_xtype&XTYPE) == XABS)
334 				    && !(xp->e_xtype&XFORW)
335 				    &&  (xp->e_xvalue >= 0)
336 				    &&  (xp->e_xvalue <= 63)
337 				    &&  (xp->e_yvalue == 0)
338 				    &&  (argtype != TYPF)
339 				    &&  (argtype != TYPD) ) {
340 					ap->a_areg1 = xp->e_xvalue;
341 					break;
342 				}
343 			}
344 			ap->a_areg1 |= 0x8F;
345 			reloc_how = argtype;
346 			if (reloc_how == TYPD || reloc_how == TYPF){
347 				if (   ((xp->e_xtype&XTYPE)==XABS)
348 				    && (!(xp->e_xtype&XFORW))
349 				    && (slitflt(xp))
350 				){
351 					reloc_how = TYPNONE;
352 					ap->a_areg1=extlitflt(xp);
353 				}
354 			}
355 			break;
356 
357 		}	/*end of the switch on argtype*/
358 		/*
359 		 *	use the first byte to describe the argument
360 		 */
361 #ifdef UNIX
362 		outb(ap->a_areg1);
363 #endif UNIX
364 #ifdef VMS
365 		*vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)(ap->a_areg1);
366 		dotp->e_xvalue += 1;
367 		if ((vms_obj_ptr-sobuf) > 400) {
368 			write(objfil,sobuf,vms_obj_ptr-sobuf);
369 			vms_obj_ptr=sobuf+1;
370 		}
371 #endif VMS
372 		if (reloc_how != TYPNONE)
373 			outrel(xp, reloc_how);
374 	}	/*end of the for to pick up all arguments*/
375 }
376