15822Srrh /*
2*18714Sdist * Copyright (c) 1982 Regents of the University of California.
3*18714Sdist * All rights reserved. The Berkeley software License Agreement
4*18714Sdist * specifies the terms and conditions for redistribution.
55822Srrh */
6*18714Sdist
75822Srrh #ifndef lint
8*18714Sdist static char sccsid[] = "@(#)ascode.c 5.1 (Berkeley) 04/24/85";
95822Srrh #endif not lint
105822Srrh
11592Sbill #include <stdio.h>
12592Sbill #include "as.h"
13592Sbill #include "assyms.h"
14592Sbill
155822Srrh insout(opcode, ap, nact)
165822Srrh struct Opcode opcode;
175822Srrh struct arg *ap;
185822Srrh int nact;
195822Srrh {
205822Srrh int jxxflg;
215822Srrh reg struct instab *ip; /* the instruction */
225822Srrh reg struct arg *ap_walk; /* actual param walk */
235822Srrh reg int i;
245822Srrh reg int ap_type; /* actual param type */
255822Srrh reg int ap_type_mask; /* masked actual param */
26673Shenry
27592Sbill jxxflg = nact;
28592Sbill if (nact < 0)
29592Sbill nact = -nact;
30592Sbill if (passno == 1) {
315822Srrh if (!(ITABCHECK(opcode)))
325822Srrh panic("Botched reference into itab");
335822Srrh ip = ITABFETCH(opcode);
345822Srrh if (nact < ip->i_nargs)
355822Srrh yyerror("Too few arguments");
365822Srrh if (nact > ip->i_nargs) {
375822Srrh yyerror("Too many arguments");
385822Srrh nact = ip->i_nargs;
395822Srrh }
40667Shenry /*
41667Shenry * Check argument compatability with instruction template
42667Shenry */
43667Shenry for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){
44673Shenry ap_type = ap_walk->a_atype;
45667Shenry ap_type_mask = ap_type & AMASK;
461746Shenry /*
475822Srrh * The switch value is >> by TYPLG so that the switch
481746Shenry * code is dense, not implemented as a sequence
491746Shenry * of branches but implemented as a casel.
501746Shenry * In addition, cases ACCI and ACCR are added to force
511746Shenry * dense switch code.
525822Srrh * switch on the type of fp
531746Shenry */
545822Srrh switch( ((fetcharg(ip, i-1)) & ACCESSMASK) >> TYPLG){
555822Srrh case ACCI >> TYPLG:
565822Srrh case ACCR >> TYPLG:
571746Shenry break;
585822Srrh case ACCB >> TYPLG:
59667Shenry if ( !((ap_type_mask == AEXP) || (ap_type_mask == AIMM)) ){
60667Shenry yyerror("arg %d, branch displacement must be an expression",i);
61667Shenry return;
62667Shenry }
63667Shenry break;
645822Srrh case ACCA >> TYPLG:
65667Shenry switch(ap_type_mask){
66667Shenry case AREG: yyerror("arg %d, addressing a register",i);
67667Shenry return;
68667Shenry case AIMM: if ( !(ap_type & ASTAR) ){
69667Shenry yyerror("arg %d, addressing an immediate operand",i);
70667Shenry return;
71667Shenry }
72667Shenry }
73667Shenry break;
745822Srrh case ACCM >> TYPLG:
755822Srrh case ACCW >> TYPLG:
76667Shenry switch(ap_type_mask){
77667Shenry case AIMM: if (!(ap_type&ASTAR)) {
78667Shenry yyerror("arg %d, modifying a constant",i);
79667Shenry return;
80667Shenry }
81667Shenry }
82667Shenry break;
83667Shenry } /* end of the switch on fp_type */
84667Shenry if (ap_type & AINDX) {
85667Shenry if (ap_walk->a_areg2==0xF) {
86667Shenry yyerror("arg %d, PC used as index",i);
87667Shenry return;
88667Shenry }
89667Shenry switch(ap_type_mask){
90667Shenry case AREG: yyerror("arg %d, indexing the register file",i);
91667Shenry return;
92667Shenry case AIMM: yyerror("arg %d, indexing a constant",i);
93667Shenry return;
94673Shenry case ADECR:
95673Shenry case AINCR: if (ap_walk->a_areg1==ap_walk->a_areg2) {
96667Shenry yyerror("arg %d, indexing with modified register",i);
97667Shenry return;
98667Shenry }
99667Shenry break;
100667Shenry } /* end of switch on ap_type_mask */
101667Shenry } /* end of AINDX */
102667Shenry }
103667Shenry } /* both passes here */
104592Sbill if (jxxflg < 0)
1055822Srrh ijxout(opcode, ap, nact);
1065822Srrh else
1075822Srrh putins(opcode, ap, nact);
108592Sbill }
109592Sbill
110592Sbill extern int d124;
111592Sbill
1125822Srrh putins(opcode, ap, n)
1135822Srrh struct Opcode opcode;
114592Sbill register struct arg *ap;
1155822Srrh int n; /* Must be positive */
116592Sbill {
1175822Srrh reg struct exp *xp;
1185822Srrh reg int argtype;
1195822Srrh int i;
1205822Srrh int reloc_how;
1215822Srrh int value;
122592Sbill
123592Sbill #ifdef DEBUG
124592Sbill fflush(stdout);
125592Sbill #endif
126592Sbill if (passno == 2)
127592Sbill goto PASS2;
128592Sbill
1295822Srrh dotp->e_xvalue += n; /* at least one byte per arg */
1305822Srrh switch(opcode.Op_eopcode){
1315822Srrh case NEW:
1325822Srrh case CORE:
1335822Srrh dotp->e_xvalue += 1; /* 1 byte opcode */
1345822Srrh break;
1355822Srrh case ESCD:
1365822Srrh case ESCF:
1375822Srrh dotp->e_xvalue += 2; /* 2 byte opcode */
1385822Srrh break;
1395822Srrh default:
1405822Srrh panic("Bad escape opcode");
1415822Srrh }
1425822Srrh
143629Shenry for (i=0; i<n; i++,ap++) { /* some args take more than 1 byte */
144853Shenry argtype = ap->a_atype;
145853Shenry if (argtype & AINDX)
146629Shenry dotp->e_xvalue++;
1471746Shenry /*
1481746Shenry * This switch has been fixed by enumerating the no action
1491746Shenry * alternatives (those that have 1 one byte of code)
1501746Shenry * so that a casel instruction is emitted.
1511746Shenry */
152853Shenry switch (argtype&~(AINDX|ASTAR)) {
1531746Shenry case AREG:
1541746Shenry case ABASE:
1551746Shenry case ADECR:
1561746Shenry case AINCR:
1571746Shenry break;
158592Sbill case AEXP:
1595822Srrh argtype = fetcharg(ITABFETCH(opcode), i);
1605822Srrh if (argtype == A_BB)
161592Sbill break;
1625822Srrh if (argtype == A_BW){
163629Shenry dotp->e_xvalue++;
164592Sbill break;
165592Sbill }
166592Sbill /*
167592Sbill * Reduces to PC relative
168592Sbill */
169629Shenry dotp->e_xvalue += ap->a_dispsize;
170592Sbill break;
171592Sbill
172592Sbill case ADISP:
173629Shenry xp=ap->a_xp;
174629Shenry if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
175629Shenry dotp->e_xvalue += ap->a_dispsize;
176592Sbill break;
177592Sbill }
178853Shenry if (xp->e_xvalue==0 && !(argtype&ASTAR))
179592Sbill break;
1805822Srrh dotp->e_xvalue += 1;
1815822Srrh if (ISBYTE(xp->e_xvalue))
1825822Srrh break;
1835822Srrh dotp->e_xvalue += 1;
1845822Srrh if (ISWORD(xp->e_xvalue))
1855822Srrh break;
1865822Srrh dotp->e_xvalue += 2;
187592Sbill break;
188592Sbill
189592Sbill case AIMM:
1905822Srrh if (ap->a_atype&ASTAR) {
1915822Srrh argtype=TYPL;
1925822Srrh } else {
1935822Srrh argtype = fetcharg(ITABFETCH(opcode), i);
194853Shenry if (argtype&ACCA)
195853Shenry argtype = TYPL;
196592Sbill else
197853Shenry argtype &= TYPMASK;
198629Shenry xp = ap->a_xp;
1995822Srrh if (immconstant(ap->a_xp, argtype, &value))
2005822Srrh break;
201592Sbill }
2025822Srrh dotp->e_xvalue += ty_nbyte[argtype];
203592Sbill } /*end of the switch on the type*/
204592Sbill } /*end of looping for all arguments*/
205592Sbill return;
206592Sbill
207592Sbill PASS2:
2085822Srrh /*
2095822Srrh * Output the opcode
2105822Srrh */
2115822Srrh switch(opcode.Op_eopcode){
2125822Srrh case NEW:
2135822Srrh nnewopcodes++;
2145822Srrh break;
2155822Srrh case ESCD:
2165822Srrh case ESCF:
2175822Srrh nGHopcodes++;
2185822Srrh Outb(opcode.Op_eopcode);
2195822Srrh break;
2205822Srrh case CORE:
2215822Srrh break;
2225822Srrh default:
2235822Srrh panic("Bad escape opcode");
2245822Srrh }
2255822Srrh Outb(opcode.Op_popcode);
226592Sbill
227592Sbill for (i=0; i<n; i++,ap++) {/* now for the arguments */
228853Shenry argtype=ap->a_atype;
229629Shenry xp=ap->a_xp;
230673Shenry reloc_how = TYPNONE;
231853Shenry if (argtype&AINDX) {
2325822Srrh { Outb(0x40 | ap->a_areg2); }
233853Shenry argtype &= ~AINDX;
234592Sbill }
235853Shenry if (argtype&ASTAR) {
236629Shenry ap->a_areg1 |= 0x10;
237853Shenry argtype &= ~ASTAR;
238592Sbill }
239853Shenry switch (argtype) {
240592Sbill case AREG: /* %r */
241629Shenry ap->a_areg1 |= 0x50;
242592Sbill break;
243592Sbill case ABASE: /* (%r) */
244629Shenry ap->a_areg1 |= 0x60;
245592Sbill break;
246592Sbill case ADECR: /* -(%r) */
247629Shenry ap->a_areg1 |= 0x70;
248592Sbill break;
249665Shenry case AINCR: /* (%r)+ */
250629Shenry ap->a_areg1 |= 0x80;
251592Sbill break;
252592Sbill case AEXP: /* expr */
2535822Srrh argtype = fetcharg(ITABFETCH(opcode), i);
2545822Srrh if (argtype == A_BB) {
255853Shenry ap->a_areg1 = argtype =
256629Shenry xp->e_xvalue - (dotp->e_xvalue + 1);
25716764Sralph if ((xp->e_xtype & XTYPE) == XUNDEF)
2585822Srrh yywarning("%s: destination label is external",
25913511Srrh FETCHNAME(ITABFETCH(opcode)));
2605822Srrh if (!ISBYTE(argtype))
26113083Srrh yyerror("%s: Branch too far(%db): try -J flag",
26213511Srrh FETCHNAME(ITABFETCH(opcode)),
2635822Srrh argtype);
2645822Srrh break;
265592Sbill }
2665822Srrh if (argtype == A_BW) {
267853Shenry ap->a_areg1 = argtype = xp->e_xvalue
268629Shenry -= dotp->e_xvalue + 2;
26916764Sralph if ((xp->e_xtype & XTYPE) == XUNDEF)
2705822Srrh yywarning("%s: destination label is external",
27113511Srrh FETCHNAME(ITABFETCH(opcode)));
272629Shenry xp->e_xtype = XABS;
2735822Srrh if (!ISWORD(argtype))
27413083Srrh yyerror("%s: Branch too far(%db): try -J flag",
27513511Srrh FETCHNAME(ITABFETCH(opcode)),
2765822Srrh argtype);
277853Shenry xp->e_xvalue = argtype>>8;
278673Shenry reloc_how = TYPB;
279592Sbill break;
280592Sbill }
281592Sbill /* reduces to expr(pc) mode */
282629Shenry ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]);
283673Shenry reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL;
284592Sbill break;
285592Sbill
286592Sbill case ADISP: /* expr(%r) */
287629Shenry ap->a_areg1 |= 0xA0;
288629Shenry if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
289629Shenry ap->a_areg1 += mod124[ap->a_dispsize];
290673Shenry reloc_how = type_124[ap->a_dispsize];
291592Sbill break;
292592Sbill }
293629Shenry if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) {
294629Shenry ap->a_areg1 ^= 0xC0;
295592Sbill break;
296592Sbill }
297673Shenry reloc_how = TYPB;
2985822Srrh if (ISBYTE(xp->e_xvalue))
2995822Srrh break;
3005822Srrh ap->a_areg1 += 0x20;
3015822Srrh reloc_how = TYPW;
3025822Srrh if (ISWORD(xp->e_xvalue))
3035822Srrh break;
3045822Srrh ap->a_areg1 += 0x20;
3055822Srrh reloc_how = TYPL;
306592Sbill break;
307592Sbill
308592Sbill case AIMM: /* $expr */
3095822Srrh if (ap->a_atype&ASTAR) {
310853Shenry argtype=TYPL;
3115822Srrh } else {
3125822Srrh argtype = fetcharg(ITABFETCH(opcode), i);
313853Shenry if (argtype&ACCA)
3145822Srrh argtype = TYPL;
315592Sbill else
316853Shenry argtype &= TYPMASK;
3175822Srrh if (immconstant(xp, argtype, &value)){
3185822Srrh reloc_how = TYPNONE;
3195822Srrh ap->a_areg1 = value;
320592Sbill break;
321592Sbill }
322592Sbill }
323629Shenry ap->a_areg1 |= 0x8F;
324853Shenry reloc_how = argtype;
325592Sbill break;
326592Sbill
327853Shenry } /*end of the switch on argtype*/
328592Sbill /*
329592Sbill * use the first byte to describe the argument
330592Sbill */
3315822Srrh Outb(ap->a_areg1);
332673Shenry if (reloc_how != TYPNONE)
333673Shenry outrel(xp, reloc_how);
334592Sbill } /*end of the for to pick up all arguments*/
335592Sbill }
3365822Srrh /*
3375822Srrh * Is xp an immediate constant?
3385822Srrh * argtype: how the instruction will interpret the bytes
3395822Srrh * xp->e_number.num_tag ("numtype"): the kind of number given
3405822Srrh *
3415822Srrh * Use the following table:
3425822Srrh * float: TYPF, TYPD, TYPG, TYPH
3435822Srrh * quad: TYPQ, TYPO
3445822Srrh * int: TYPG, TYPW, TYPL
3455822Srrh *
3465822Srrh * numtype
3475822Srrh * argtype float quad int
3485822Srrh *
3495822Srrh * float slitflt slitflt slitflt
3505822Srrh * quad 0 0 0
3515822Srrh * int 0..63 0 0..63
3525822Srrh *
3535822Srrh * Where the table entry implies the predicate to return.
3545822Srrh */
3555822Srrh #define IMMFLT 1 /* these flags are not used by anybody (yet) */
3565822Srrh #define IMMINT 2
3575822Srrh
immconstant(xp,argtype,valuep)3585822Srrh int immconstant(xp, argtype, valuep)
3595822Srrh reg struct exp *xp;
3605822Srrh int argtype;
3615822Srrh int *valuep;
3625822Srrh {
3635822Srrh reg int back = 0;
3645822Srrh int numtype;
3655822Srrh reg int fits;
3665822Srrh
3675822Srrh if ((xp->e_xtype & XTYPE) != XABS)
3685822Srrh return(0);
3695822Srrh if ((xp->e_xtype & XFORW) != 0)
3705822Srrh return(0);
3715822Srrh numtype = xp->e_number.num_tag;
3725822Srrh
3735822Srrh fits = 1;
3745822Srrh if (passno == 2) switch(argtype){
3755822Srrh case TYPB:
3765822Srrh switch(numtype){
3775822Srrh default: fits = 0; break;
3785822Srrh case TYPB: fits = 1; break;
3795822Srrh case TYPW:
3805822Srrh case TYPL:
3815822Srrh fits = ISBYTE(xp->e_xvalue) || ISUBYTE(xp->e_xvalue);
3825822Srrh break;
3835822Srrh }
3845822Srrh break;
3855822Srrh case TYPW:
3865822Srrh switch(numtype){
3875822Srrh default: fits = 0; break;
3885822Srrh case TYPB:
3895822Srrh case TYPW: fits = 1; break;
3905822Srrh case TYPL:
3915822Srrh fits = ISWORD(xp->e_xvalue) || ISUWORD(xp->e_xvalue);
3925822Srrh break;
3935822Srrh }
3945822Srrh break;
3955822Srrh case TYPF:
3965822Srrh if (numtype == TYPD){ /* same format for first 32 bits */
3975822Srrh fits = 1;
3985822Srrh break;
3995822Srrh }
4005822Srrh /*FALLTHROUGH*/
4015822Srrh default:
4025822Srrh fits = ty_nbyte[argtype] >= ty_nbyte[numtype];
4035822Srrh }
4045822Srrh if (!fits){
4055822Srrh yywarning("Immediate constant type %s mismatches instruction type %s",
4065822Srrh ty_string[numtype],
4075822Srrh ty_string[argtype]);
4085822Srrh }
4095822Srrh
4105822Srrh switch(argtype){
4115822Srrh case TYPF:
4125822Srrh case TYPG:
4135822Srrh case TYPD:
4145822Srrh case TYPH:
4155822Srrh back = slitflt(xp->e_number, argtype, valuep);
4165822Srrh break;
4175822Srrh case TYPO:
4185822Srrh case TYPQ:
4195822Srrh back = 0;
4205822Srrh break;
4215822Srrh case TYPB:
4225822Srrh case TYPW:
4235822Srrh case TYPL:
4245822Srrh switch(numtype){
4255822Srrh case TYPO:
4265822Srrh case TYPQ:
4275822Srrh back = 0;
4285822Srrh break;
4295822Srrh default:
4305822Srrh *valuep = xp->e_xvalue;
4315822Srrh back = ISLIT(xp->e_xvalue);
4325822Srrh break;
4335822Srrh }
4345822Srrh break;
4355822Srrh }
4365822Srrh return(back);
4375822Srrh }
438