Change two switches to get casel instruction
[unix-history] / usr / src / old / as.vax / ascode.c
CommitLineData
cb3898cb 1/* Copyright (c) 1980 Regents of the University of California */
10973e2e 2static char sccsid[] = "@(#)ascode.c 4.7 %G%";
cb3898cb 3#include <stdio.h>
cb3898cb
BJ
4#include "as.h"
5#include "assyms.h"
6
5b3c350a
RH
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
cb3898cb
BJ
40insout(op, ap, nact)
41 struct arg *ap;
42{
a264a1b2
RH
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 */
cb3898cb
BJ
49 op &= 0xFF;
50 jxxflg = nact;
51 if (nact < 0)
52 nact = -nact;
53 if (passno == 1) {
a264a1b2
RH
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++){
5b3c350a 65 ap_type = ap_walk->a_atype;
a264a1b2 66 ap_type_mask = ap_type & AMASK;
10973e2e
RH
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:
a264a1b2
RH
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;
10973e2e 84 case ACCA >> 3:
a264a1b2
RH
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;
10973e2e
RH
94 case ACCM >> 3:
95 case ACCW >> 3:
a264a1b2
RH
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;
5b3c350a
RH
114 case ADECR:
115 case AINCR: if (ap_walk->a_areg1==ap_walk->a_areg2) {
a264a1b2
RH
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 */
cb3898cb
BJ
124 if (jxxflg < 0)
125 ijxout(op, ap, nact);
126 else putins(op, ap, nact);
127}
128
cb3898cb 129extern int d124;
cb3898cb
BJ
130
131putins(op, ap, n)
132 /*
133 * n had better be positive
134 */
135 register struct arg *ap;
136{
137 register struct exp *xp;
1e967e62 138 register int argtype;
5b3c350a
RH
139 int i;
140 int reloc_how;
cb3898cb
BJ
141
142#ifdef DEBUG
143 fflush(stdout);
144#endif
145 if (passno == 2)
146 goto PASS2;
147
451260e7
RH
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 */
1e967e62
RH
150 argtype = ap->a_atype;
151 if (argtype & AINDX)
451260e7 152 dotp->e_xvalue++;
10973e2e
RH
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 */
1e967e62 158 switch (argtype&~(AINDX|ASTAR)) {
10973e2e
RH
159 case AREG:
160 case ABASE:
161 case ADECR:
162 case AINCR:
163 break;
cb3898cb 164 case AEXP:
1e967e62
RH
165 argtype = fetcharg(itab[op], i);
166 if (argtype == ACCB+TYPB)
cb3898cb 167 break;
1e967e62 168 if (argtype==ACCB+TYPW){
451260e7 169 dotp->e_xvalue++;
cb3898cb
BJ
170 break;
171 }
172 /*
173 * Reduces to PC relative
174 */
451260e7 175 dotp->e_xvalue += ap->a_dispsize;
cb3898cb
BJ
176 break;
177
178 case ADISP:
451260e7
RH
179 xp=ap->a_xp;
180 if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
181 dotp->e_xvalue += ap->a_dispsize;
cb3898cb
BJ
182 break;
183 }
1e967e62 184 if (xp->e_xvalue==0 && !(argtype&ASTAR))
cb3898cb 185 break;
451260e7
RH
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;
cb3898cb
BJ
191 break;
192
193 case AIMM:
1e967e62 194 if (ap->a_atype&ASTAR) argtype=TYPL;
cb3898cb 195 else {
1e967e62
RH
196 argtype = fetcharg(itab[op], i);
197 if (argtype&ACCA)
198 argtype = TYPL;
cb3898cb 199 else
1e967e62 200 argtype &= TYPMASK;
451260e7
RH
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)
1e967e62
RH
207 && (argtype != TYPD)
208 && (argtype != TYPF)
cb3898cb
BJ
209 )
210 break;
211 }
1e967e62 212 switch (argtype) {
cb3898cb
BJ
213 case TYPD:
214 case TYPF:
451260e7
RH
215 if ( !(((xp->e_xtype&XTYPE)==XABS)
216 && (!(xp->e_xtype&XFORW))
cb3898cb
BJ
217 && (slitflt(xp)))
218 ){
219 /* it is NOT short */
1e967e62 220 dotp->e_xvalue += ((argtype==TYPF)?
cb3898cb
BJ
221 4 : 8);
222 }
223 break;
224 case TYPQ:
451260e7 225 dotp->e_xvalue += 8;break;
cb3898cb 226 case TYPL:
451260e7 227 dotp->e_xvalue += 4;break;
cb3898cb 228 case TYPW:
451260e7 229 dotp->e_xvalue += 2;break;
cb3898cb 230 case TYPB:
451260e7 231 dotp->e_xvalue += 1;break;
1e967e62 232 } /*end of the switch on argtype*/
cb3898cb
BJ
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;
451260e7 244 dotp->e_xvalue += 1;
cb3898cb
BJ
245#endif VMS
246
247 for (i=0; i<n; i++,ap++) {/* now for the arguments */
1e967e62 248 argtype=ap->a_atype;
451260e7 249 xp=ap->a_xp;
5b3c350a 250 reloc_how = TYPNONE;
1e967e62 251 if (argtype&AINDX) {
cb3898cb 252#ifdef UNIX
451260e7 253 { outb(0x40 | ap->a_areg2); }
cb3898cb
BJ
254#endif UNIX
255#ifdef VMS
256 { *vms_obj_ptr++ = -1;
451260e7
RH
257 *vms_obj_ptr++ = (0x40 | ap->a_areg2);
258 dotp->e_xvalue += 1; }
cb3898cb 259#endif VMS
1e967e62 260 argtype &= ~AINDX;
cb3898cb 261 }
1e967e62 262 if (argtype&ASTAR) {
451260e7 263 ap->a_areg1 |= 0x10;
1e967e62 264 argtype &= ~ASTAR;
cb3898cb 265 }
1e967e62 266 switch (argtype) {
cb3898cb 267 case AREG: /* %r */
451260e7 268 ap->a_areg1 |= 0x50;
cb3898cb
BJ
269 break;
270 case ABASE: /* (%r) */
451260e7 271 ap->a_areg1 |= 0x60;
cb3898cb
BJ
272 break;
273 case ADECR: /* -(%r) */
451260e7 274 ap->a_areg1 |= 0x70;
cb3898cb 275 break;
593d71c1 276 case AINCR: /* (%r)+ */
451260e7 277 ap->a_areg1 |= 0x80;
cb3898cb
BJ
278 break;
279 case AEXP: /* expr */
1e967e62
RH
280 argtype = fetcharg(itab[op], i);
281 if (argtype == ACCB+TYPB) {
282 ap->a_areg1 = argtype =
451260e7 283 xp->e_xvalue - (dotp->e_xvalue + 1);
1e967e62 284 if (argtype<MINBYTE || argtype>MAXBYTE)
cb3898cb
BJ
285 yyerror("Branch too far"); break;
286 }
1e967e62
RH
287 if (argtype == ACCB+TYPW) {
288 ap->a_areg1 = argtype = xp->e_xvalue
451260e7
RH
289 -= dotp->e_xvalue + 2;
290 xp->e_xtype = XABS;
1e967e62 291 if (argtype<MINWORD || argtype>MAXWORD)
cb3898cb 292 yyerror("Branch too far");
1e967e62 293 xp->e_xvalue = argtype>>8;
5b3c350a 294 reloc_how = TYPB;
cb3898cb
BJ
295 break;
296 }
297 /* reduces to expr(pc) mode */
451260e7 298 ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]);
5b3c350a 299 reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL;
cb3898cb
BJ
300 break;
301
302 case ADISP: /* expr(%r) */
451260e7
RH
303 ap->a_areg1 |= 0xA0;
304 if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
305 ap->a_areg1 += mod124[ap->a_dispsize];
5b3c350a 306 reloc_how = type_124[ap->a_dispsize];
cb3898cb
BJ
307 break;
308 }
451260e7
RH
309 if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) {
310 ap->a_areg1 ^= 0xC0;
cb3898cb
BJ
311 break;
312 }
5b3c350a 313 reloc_how = TYPB;
451260e7
RH
314 if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)){
315 ap->a_areg1 += 0x20;
5b3c350a 316 reloc_how = TYPW;
cb3898cb 317 }
451260e7
RH
318 if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)){
319 ap->a_areg1 += 0x20;
5b3c350a 320 reloc_how = TYPL;
cb3898cb
BJ
321 }
322 break;
323
324 case AIMM: /* $expr */
451260e7 325 if (ap->a_atype&ASTAR)
1e967e62 326 argtype=TYPL;
cb3898cb 327 else {
1e967e62
RH
328 argtype = fetcharg(itab[op], i);
329 if (argtype&ACCA)
330 argtype=TYPL;
cb3898cb 331 else
1e967e62 332 argtype &= TYPMASK;
451260e7
RH
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)
1e967e62
RH
338 && (argtype != TYPF)
339 && (argtype != TYPD) ) {
451260e7 340 ap->a_areg1 = xp->e_xvalue;
cb3898cb
BJ
341 break;
342 }
343 }
451260e7 344 ap->a_areg1 |= 0x8F;
1e967e62 345 reloc_how = argtype;
5b3c350a 346 if (reloc_how == TYPD || reloc_how == TYPF){
451260e7
RH
347 if ( ((xp->e_xtype&XTYPE)==XABS)
348 && (!(xp->e_xtype&XFORW))
cb3898cb
BJ
349 && (slitflt(xp))
350 ){
5b3c350a 351 reloc_how = TYPNONE;
451260e7 352 ap->a_areg1=extlitflt(xp);
cb3898cb 353 }
cb3898cb
BJ
354 }
355 break;
356
1e967e62 357 } /*end of the switch on argtype*/
cb3898cb
BJ
358 /*
359 * use the first byte to describe the argument
360 */
361#ifdef UNIX
451260e7 362 outb(ap->a_areg1);
cb3898cb
BJ
363#endif UNIX
364#ifdef VMS
451260e7
RH
365 *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)(ap->a_areg1);
366 dotp->e_xvalue += 1;
cb3898cb
BJ
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
5b3c350a
RH
372 if (reloc_how != TYPNONE)
373 outrel(xp, reloc_how);
cb3898cb
BJ
374 } /*end of the for to pick up all arguments*/
375}