Change two switches to get casel instruction
[unix-history] / usr / src / old / as.vax / ascode.c
... / ...
CommitLineData
1/* Copyright (c) 1980 Regents of the University of California */
2static char sccsid[] = "@(#)ascode.c 4.7 %G%";
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*/
11int reflen[] = /* {LEN*+PCREL} ==> number of bytes */
12{0, 0, 1, 1, 2, 2, 4, 4, 8, 8};
13int 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*/
20int len124[] = /* {1,2,4,8} ==> {LEN1, LEN2, LEN4, LEN8} */
21{0, LEN1, LEN2, 0, LEN4, 0, 0, 0, LEN8};
22char mod124[] = /* {1,2,4,8} ==> {bits to construct operands */
23{0, 0x00, 0x20, 0, 0x40, 0, 0, 0, 0};
24int 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*/
31int ty_NORELOC[] = /* {TYPB..TYPD} ==> {1 if relocation not OK */
32{0, 0, 0, 1, 1, 1};
33int ty_LEN[] = /* {TYPB..TYPD} ==> {LEN1..LEN8} */
34{LEN1, LEN2, LEN4, LEN8, LEN4, LEN8};
35int ty_nbyte[] = /* {TYPB..TYPD} ==> {1,2,4,8} */
36{1, 2, 4, 8, 4, 8};
37int ty_nlg[] = /* {TYPB..TYPD} ==> lg{1,2,4,8} */
38{0, 1, 2, 3, 2, 3};
39
40insout(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
129extern int d124;
130
131putins(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
237PASS2:
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}