xref: /original-bsd/old/as.tahoe/ascode.c (revision 5133e8a4)
1 /*
2  *	Copyright (c) 1982 Regents of the University of California
3  */
4 #ifndef lint
5 static char sccsid[] = "@(#)ascode.c 4.11 6/30/83";
6 #endif not lint
7 
8 #include <stdio.h>
9 #include "as.h"
10 #include "assyms.h"
11 
12 insout(opcode, ap, nact)
13 	u_char	opcode;
14 	struct	arg	*ap;
15 	int	nact;
16 {
17 	int	jxxflg;
18 	reg	struct	instab	*ip;		/* the instruction */
19 	reg	struct	arg	*ap_walk;	/* actual param walk */
20 	reg	int	i;
21 	reg	int	ap_type;		/* actual param type */
22 	reg	int	ap_type_mask;		/* masked actual param */
23 	reg	int	argtype;
24 
25 	jxxflg = nact;
26 	if (nact < 0)
27 		nact = -nact;
28 	if (passno == 1) {
29 		ip = ITABFETCH(opcode & 0xFF);
30 		if (nact < ip->i_nargs)
31 			yyerror("Too few arguments");
32 		if (nact > ip->i_nargs) {
33 			yyerror("Too many arguments");
34 			nact = ip->i_nargs;
35 		}
36 	    /*
37 	     *	Check argument compatability with instruction template
38 	     */
39 	    for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){
40 		ap_type = ap_walk->a_atype;
41 		ap_type_mask = ap_type & AMASK;
42 		/*
43 		 *	The switch value is >> by TYPLG so that the switch
44 		 *	code is dense, not implemented as a sequence
45 		 *	of branches but implemented as a casel.
46 		 *	In addition, cases ACCI and ACCR are added to force
47 		 *	dense switch code.
48 		 *	switch on the type of fp
49 		 */
50 		argtype = fetcharg(ip, i-1);
51 		switch( (argtype & ACCESSMASK) >> TYPLG){
52 		case ACCI >> TYPLG:
53 			break;
54 		case ACCR >> TYPLG:
55 			if ((argtype == A_RQ) &&
56 			   (ap_type_mask == AREG) &&
57 			   (ap_walk->a_areg1 & 0x01)) {
58 				yyerror("arg %d, register must be even",i);
59 				return;
60 			}
61 			if (ap_type_mask == ADECR)
62 			{
63 				 yyerror("arg %d, a source arg cant be auto decrement",i);
64 				 return;
65 			}
66 			if (argtype == A_RD)
67 			{
68 				if (ap_type_mask == AIMM)
69 				   if ( !(ap_type&ASTAR))
70 				{
71 					 yyerror("arg %d, cant be immediate data",i);
72 					 return;
73 				}
74 				if ((argtype == A_RD) &&
75 				   ((ap_type_mask == AINCR) ||
76 				   (ap_type_mask == ADECR)))
77 				{
78 					 yyerror("arg %d, cant be auto increment/decrement",i);
79 					 return;
80 				}
81 				if ((argtype == A_RD) &&
82 				   (ap_type_mask == AREG) &&
83 				   (ap_walk->a_areg1 & 0x01)) {
84 					yyerror("arg %d, register must be even",i);
85 					return;
86 				}
87 			}
88 			break;
89 		case ACCB >> TYPLG:
90 			if ( ap_type_mask != AEXP)
91 			{
92 				yyerror("arg %d, branch displacement must be an expression",i);
93 				return;
94 			}
95 			break;
96 		case ACCA >> TYPLG:
97 			switch(ap_type_mask){
98 			case AREG:	yyerror("arg %d, addressing a register",i);
99 					return;
100 			case AIMM:	if ( !(ap_type & ASTAR) ){
101 					 yyerror("arg %d, addressing an immediate operand",i);
102 					 return;
103 					}
104 			}
105 			break;
106 		case ACCM >> TYPLG:
107 		case ACCW >> TYPLG:
108 			if ((argtype == A_WQ) &&
109 			   (ap_type_mask == AREG) &&
110 			   (ap_walk->a_areg1 & 0x01)) {
111 				yyerror("arg %d, register must be even",i);
112 				return;
113 			}
114 			switch(ap_type_mask){
115 			case AIMM:	if (!(ap_type&ASTAR)) {
116 					 yyerror("arg %d, modifying a constant",i);
117 					 return;
118 					}
119 			case AINCR:
120 				 yyerror("arg %d, a destination arg cant be auto increment",i);
121 				 return;
122 			}
123 			break;
124 		}	/* end of the switch on fp_type */
125 		if (ap_type & AINDX) {
126 			if (ap_walk->a_areg2==0xF) {
127 				yyerror("arg %d, PC used as index",i);
128 				return;
129 			}
130 			if (ap_walk->a_areg2==0xE) {
131 				yyerror("arg %d, SP used as index",i);
132 				return;
133 			}
134 			switch(ap_type_mask){
135 			case AREG:	yyerror("arg %d, indexing the register file",i);
136 					return;
137 			case AIMM:	yyerror("arg %d, indexing a constant",i);
138 					return;
139 			case ADECR:
140 			case AINCR:	if (ap_walk->a_areg1==ap_walk->a_areg2) {
141 						yyerror("arg %d, indexing with modified register",i);
142 						return;
143 					}
144 					break;
145 			}	/* end of switch on ap_type_mask */
146 		} /* end of AINDX */
147 	   }
148 	} /* both passes here */
149 	if (jxxflg < 0)
150 		ijxout(opcode, ap, nact);
151 	else
152 		putins(opcode, ap, nact);
153 }
154 
155 extern	int d124;
156 
157 putins(opcode, ap, n)
158 	u_char	opcode;
159 	register struct arg *ap;
160 	int	n;			/* Must be positive */
161 {
162 	reg	struct exp 	*xp;
163 	reg	int 	argtype;
164 		int 	i;
165 		int	reloc_how;
166 
167 #ifdef DEBUG
168 	fflush(stdout);
169 #endif
170 	if (passno == 2)
171 		goto PASS2;
172 
173 	dotp->e_xvalue += n+1;		/* at least one byte per arg */
174 
175 	for (i=0; i<n; i++,ap++) {	/* some args take more than 1 byte */
176 	    argtype = ap->a_atype;
177 	    if (argtype & AINDX)
178 		dotp->e_xvalue++;
179 	    /*
180 	     *	This switch has been fixed by enumerating the no action
181 	     *	alternatives (those that have 1 one byte of code)
182 	     *	so that a casel instruction is emitted.
183 	     */
184 	    switch (argtype&~(AINDX|ASTAR)) {
185 		case AREG:
186 		case ABASE:
187 		case ADECR:
188 		case AINCR:
189 			break;
190 		case AEXP:
191 			argtype = fetcharg(ITABFETCH(opcode), i);
192 			if (argtype == A_BB)
193 				break;
194 			if (argtype == A_BW){
195 				dotp->e_xvalue++;
196 				break;
197 			}
198 			/*
199 			 *	Reduces to PC relative
200 			 */
201 			dotp->e_xvalue += ap->a_dispsize;
202 			break;
203 
204 		case ADISP:
205 			xp=ap->a_xp;
206 			if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
207 				dotp->e_xvalue += ap->a_dispsize;
208 				break;
209 			}
210 			if (xp->e_xvalue==0 && !(argtype&ASTAR))
211 				break;
212 			dotp->e_xvalue ++;
213 			if (ISBYTE(xp->e_xvalue))
214 				break;
215 			dotp->e_xvalue ++;
216 			if (ISWORD(xp->e_xvalue))
217 				break;
218 			dotp->e_xvalue += 2;
219 			break;
220 
221 		case AIMM:
222 			if (ap->a_atype&ASTAR) {
223 				argtype=TYPL;
224 			} else {
225 				argtype = fetcharg(ITABFETCH(opcode), i);
226 				if (argtype&ACCA)
227 					argtype = TYPL;
228 				else
229 					argtype &= TYPMASK;
230 				xp = ap->a_xp;
231 				if (   ((xp->e_xtype&XTYPE)==XABS)
232 				    && (!(xp->e_xtype&XFORW))
233 				    && (argtype != TYPD)
234 				    && (argtype != TYPF))
235 				{
236 				    if ((xp->e_xvalue>=0)
237 				    && (xp->e_xvalue<=63))
238 						break;
239 				    if (ISBYTE(xp->e_xvalue))
240 					argtype = TYPB;
241 				    else
242 					if (ISWORD(xp->e_xvalue))
243 						argtype = TYPW;
244 					else
245 						argtype = TYPL;
246 				}
247 				else
248 					argtype = TYPL;
249 			}
250 			switch (argtype) {
251 			case TYPD:
252 			case TYPF:
253 				    if (!(slitflt(xp)))
254 					return;
255 			case TYPQ:
256 			case TYPL:
257 			case TYPW:
258 			case TYPB:
259 					dotp->e_xvalue += ty_nbyte[argtype];
260 					break;
261 			}	/*end of the switch on argtype*/
262 	    }	/*end of the switch on the type*/
263 	}	/*end of looping for all arguments*/
264 	return;
265 
266 PASS2:
267 	/*
268 	 *	Output the opcode
269 	 */
270 	Outb(opcode);
271 	if ((passno == 2) && liston)
272 	{
273 		byte_out (opcode);
274 		*layoutpos++ = ' ';
275 	}
276 
277 	for (i=0; i<n; i++,ap++) {/* now for the arguments */
278 		argtype=ap->a_atype;
279 		xp=ap->a_xp;
280 		reloc_how = TYPNONE;
281 		if (argtype&AINDX) {
282 			{ Outb(0x40 | ap->a_areg2);
283 			  if ((passno == 2) && liston)
284 			  	byte_out (0x40 | ap->a_areg2); }
285 			argtype &= ~AINDX;
286 		}
287 		if (argtype&ASTAR) {
288 			ap->a_areg1 |= 0x10;
289 			argtype &= ~ASTAR;
290 		}
291 		switch (argtype) {
292 		case AREG:		/* %r */
293 			ap->a_areg1 |= 0x50;
294 			break;
295 		case ABASE:		/* (%r) */
296 			ap->a_areg1 |= 0x60;
297 			break;
298 		case ADECR: 		/* -(%r) */
299 			ap->a_areg1 |= 0x70;
300 			break;
301 		case AINCR:		/* (%r)+ */
302 			ap->a_areg1 |= 0x80;
303 			break;
304 		case AEXP: /* expr */
305 			argtype = fetcharg(ITABFETCH(opcode), i);
306 			if (argtype == A_BB) {
307 				ap->a_areg1 = argtype =
308 					xp->e_xvalue - (dotp->e_xvalue + 1);
309 				if (xp->e_xtype & XXTRN)
310 					yywarning("%s: destination label is external",
311 						FETCHNAME(ITABFETCH(opcode)));
312 				if (!ISBYTE(argtype) && !jxxxJUMP)
313 					yyerror("%s: Branch too far(%db): try -J flag",
314 						FETCHNAME(ITABFETCH(opcode)),
315 						argtype);
316 				break;
317 			}
318 			if (argtype == A_BW) {
319 				ap->a_areg1 = argtype = xp->e_xvalue
320 					-= dotp->e_xvalue + 2;
321 				if (xp->e_xtype & XXTRN)
322 					yywarning("%s: destination label is external",
323 						FETCHNAME(ITABFETCH(opcode)));
324 				xp->e_xtype = XABS;
325 				if (!ISWORD(argtype) && !jxxxJUMP)
326 					yyerror("%s: Branch too far(%db): try -J flag",
327 						FETCHNAME(ITABFETCH(opcode)),
328 						argtype);
329 				reloc_how = TYPB;
330 				ap->a_areg1 = argtype>>8;
331 				xp->e_xvalue = argtype;
332 				break;
333 			}
334 			/* reduces to expr(pc) mode */
335 			ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]);
336 			reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL;
337 			break;
338 
339 		case ADISP: /* expr(%r) */
340 			ap->a_areg1 |= 0xA0;
341 			if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
342 				ap->a_areg1 += mod124[ap->a_dispsize];
343 				reloc_how = type_124[ap->a_dispsize];
344 				break;
345 			}
346 			if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) {
347 				ap->a_areg1 ^= 0xC0;
348 				break;
349 			}
350 			reloc_how = TYPB;
351 			if (ISBYTE(xp->e_xvalue))
352 				break;
353 			ap->a_areg1 += 0x20;
354 			reloc_how = TYPW;
355 			if (ISWORD(xp->e_xvalue))
356 				break;
357 			ap->a_areg1 += 0x20;
358 			reloc_how = TYPL;
359 			break;
360 
361 		case AIMM:  /* $expr */
362 			if (ap->a_atype&ASTAR) {
363 				argtype=TYPL;
364 				ap->a_areg1 |= 0x8F;
365 			} else {
366 				argtype = fetcharg(ITABFETCH(opcode), i);
367 				if (argtype&ACCA)
368 					argtype = TYPL;
369 				else
370 					argtype &= TYPMASK;
371 				if (    ( (xp->e_xtype&XTYPE) == XABS)
372 				    && !(xp->e_xtype&XFORW)
373 				    &&  (argtype != TYPF)
374 				    &&  (argtype != TYPD)
375  				  )
376 				{
377 				    if  ((xp->e_xvalue <= 63)
378 				    &&  (xp->e_xvalue >= 0))
379 				     {
380 					ap->a_areg1 = xp->e_xvalue;
381 					break;
382 				     }
383 			else
384 				if (ISBYTE (xp->e_xvalue))
385 				{
386 					ap->a_areg1 = 0x88;
387 					argtype = TYPB;
388 				}
389 				else
390 					if (ISWORD (xp->e_xvalue))
391 					{
392 						ap->a_areg1 = 0x89;
393 						argtype = TYPW;
394 			 		}
395 					else
396 					{
397 						ap->a_areg1 = 0x8F;
398 						argtype = TYPL;
399 			 		}
400 			}
401 			else
402 			{
403 				ap->a_areg1 = 0x8F;
404 				argtype = TYPL;
405 			 }
406 			}
407 			reloc_how = argtype;
408 			if (reloc_how == TYPD || reloc_how == TYPF){
409 				if (   ((xp->e_xtype&XTYPE)==XABS)
410 				    && (!(xp->e_xtype&XFORW))
411 				    && (slitflt(xp))
412 				){
413 					reloc_how = TYPNONE;
414 					ap->a_areg1=extlitflt(xp);
415 				}
416 			}
417 			break;
418 
419 		}	/*end of the switch on argtype*/
420 		/*
421 		 *	use the first byte to describe the argument
422 		 */
423 		Outb(ap->a_areg1);
424 		if ((passno == 2) && liston)
425 			byte_out (ap->a_areg1);
426 		if (reloc_how != TYPNONE)
427 			outrel(xp, reloc_how);
428 		if ((passno == 2) && liston)
429 			*layoutpos++ = ' ';
430 	}	/*end of the for to pick up all arguments*/
431 }
432