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