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