Pristine Ack-5.5
[Ack-5.5.git] / mach / vax4 / as / mach5.c
1 /*
2  * (c) copyright 1990 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 #define RCSID5 "$Id: mach5.c,v 1.4 1994/06/24 13:41:21 ceriel Exp $"
6
7 /*
8  * VAX-11 Machine dependent C declarations
9  */
10
11 /* Opcode of branch on reversed condition. */
12 #define rev_cond_branch(opc)    ((opc) ^ 1)
13
14 /* Process one operand. */
15 static
16 oprnd(p)
17         register struct operand *p;
18 {
19         int     sm;
20
21         if (p->index_reg >= 0 && p->mode != DISPL) {
22                 /* Indexed mode; emit */
23                 emit1((INDEX_MODE << 4) | p->index_reg);
24         }
25
26         switch(p->mode) {
27         case REG_MODE:
28                 if (p->size == -2 && p->index_reg < 0) {
29                         serror("register mode not allowed here");
30                 }
31                 emit1((REG_MODE << 4) | p->reg);
32                 break;
33         case REGDEF_MODE:
34                 emit1((REGDEF_MODE << 4) | p->reg);
35                 break;
36         case AI_MODE:
37                 emit1((AI_MODE << 4) | p->reg);
38                 break;
39         case AI_DEF_MODE:
40                 emit1((AI_DEF_MODE << 4) | p->reg);
41                 break;
42         case AD_MODE:
43                 emit1((AD_MODE << 4) | p->reg);
44                 break;
45         case DISPLL_MODE:
46         case DISPLL_DEF_MODE:
47                 /* Three possible sizes: 1, 2, and 4 (and 0, but this is
48                    not implemented). Therefore, we need two bits in the
49                    optimize table.
50                 */
51                 if (small(p->exp.typ == S_ABS && fitw(p->exp.val), 2)) {
52                         /* We gained two bytes; see if we can gain another. */
53                         if (small(fitb(p->exp.val), 1)) {
54                                 /* DISPLB_MODE or DISPLB_DEF_MODE */
55                                 emit1(((p->mode-4)<<4) | p->reg);
56                                 emit1((int)(p->exp.val));
57                         }
58                         else {
59                                 /* DISPLW_MODE or DISPLW_DEF_MODE */
60                                 emit1(((p->mode-2)<<4) | p->reg);
61                                 emit2((int)(p->exp.val));
62                         }
63                 }
64                 else {  /* We need 4 bytes here. */
65                         small(0, 1);    /* dummy call too keep bits in sync */
66                         emit1((p->mode<<4) | p->reg);
67 #ifdef RELOCATION
68                         RELOMOVE(relonami, p->relo);
69                         newrelo(p->exp.typ, RELO4);
70 #endif
71                         emit4((long) p->exp.val);
72                 }
73                 break;
74         case DISPL:
75                 /* A displacement. The p->size field contains the size. */
76                 p->exp.val -= (DOTVAL + p->size);
77                 if ((pass == PASS_2) &&
78                     (p->exp.val > 0) &&
79                     ((p->exp.typ & S_DOT) == 0)
80                    ) {
81                         p->exp.val -= DOTGAIN;
82                 }
83                 if (p->size == 1) sm = fitb(p->exp.val);
84                 else if (p->size == 2) sm = fitw(p->exp.val);
85                 else sm = 1;
86                 if (pass >= PASS_2 &&
87                     ((p->exp.typ & ~S_DOT) != DOTTYP || !sm)) {
88                         serror("label too far");
89                 }
90                 if (p->size == 1) emit1((int)(p->exp.val));
91                 else if (p->size == 2) emit2((int)(p->exp.val));
92                 else {
93 #ifdef RELOCATION
94                         RELOMOVE(relonami, p->relo);
95                         newrelo(p->exp.typ, RELO4|RELPC);
96 #endif
97                         emit4(p->exp.val);
98                 }
99                 break;
100         case IMM:
101                 /* Immediate mode; either literal mode or auto-increment
102                    of program counter.
103                 */
104                 if (p->size < 0) {
105                         serror("immediate mode not allowed here");
106                         p->size = 4;
107                 }
108                 else if (p->size == 0) {
109                         serror("this immediate mode is not implemented");
110                         p->size = 4;
111                 }
112                 if (small(p->exp.typ == S_ABS && literal(p->exp.val), p->size)){
113                         emit1((int)(p->exp.val));
114                 }
115                 else {
116                         emit1((AI_MODE << 4) | PC);
117                         RELOMOVE(relonami, p->relo);
118                         switch(p->size) {
119                         case 1:
120 #ifdef RELOCATION
121                                 newrelo(p->exp.typ, RELO1);
122 #endif
123                                 emit1((int)(p->exp.val));
124                                 break;
125                         case 2:
126 #ifdef RELOCATION
127                                 newrelo(p->exp.typ, RELO2);
128 #endif
129                                 emit2((int)(p->exp.val));
130                                 break;
131                         case 4:
132 #ifdef RELOCATION
133                                 newrelo(p->exp.typ, RELO4);
134 #endif
135                                 emit4(p->exp.val);
136                                 break;
137                         default:
138                                 assert(0);
139                         }
140                 }
141                 break;
142         case ABS:
143                 /* Absolute mode (is auto-increment deferred with respect
144                    to the program counter).
145                 */
146                 emit1((AI_DEF_MODE << 4) | PC);
147 #ifdef RELOCATION
148                 RELOMOVE(relonami, p->relo);
149                 newrelo(p->exp.typ, RELO4);
150 #endif
151                 emit4(p->exp.val);
152                 break;
153         case REL:
154         case REL_DEF:
155                 /* Relative or relative deferred is actually displacement
156                    or displacement deferred, but relative to program counter.
157                 */
158                 if (p->mode == REL) p->mode = DISPLL_MODE;
159                 else p->mode = DISPLL_DEF_MODE;
160                 p->reg = PC;
161                 p->exp.val -= (DOTVAL + 2);
162                 if ((pass == PASS_2)
163                     &&
164                     (p->exp.val > 0)
165                     &&
166                     ((p->exp.typ & S_DOT) == 0)
167                    ) {
168                         p->exp.val -= DOTGAIN;
169                 }
170                 /* Why test for exp.val - 1? Well, if we need a word for
171                    the offset, we actually generate one byte more, and this
172                    is reflected in the value of the program counter.
173                 */
174                 sm = fitw(p->exp.val - 1);
175                 if ((p->exp.typ & ~S_DOT) != DOTTYP) sm = 0;
176                 if (small(sm, 2)) {
177                         if (small(fitb(p->exp.val), 1)) {
178                                 /* DISPLB_MODE or DISPLB_DEF_MODE */
179                                 emit1(((p->mode-4)<<4) | p->reg);
180                                 emit1((int)(p->exp.val));
181                         }
182                         else {
183                                 /* DISPLW_MODE or DISPLW_DEF_MODE */
184                                 emit1(((p->mode-2)<<4) | p->reg);
185                                 /* exp.val - 1: see comment above */
186                                 emit2((int)(p->exp.val - 1));
187                         }
188                 }
189                 else {
190                         small(0, 1);    /* dummy call */
191                         emit1((p->mode<<4) | p->reg);
192 #ifdef RELOCATION
193                         RELOMOVE(relonami, p->relo);
194                         newrelo(p->exp.typ, RELO4|RELPC);
195 #endif
196                         /* exp.val - 3: see comment above */
197                         emit4((long) p->exp.val - 3);
198                 }
199                 break;
200         default:
201                 assert(0);
202         }
203 }
204
205 /* Give an upper bound on the size of the operands */
206 static int
207 size_ops()
208 {
209         register struct operand *p = &opnd[0];
210         register int i;
211         register int sz = 0;
212
213         for (i = op_ind; i > 0; i--) {
214                 if (p->index_reg >= 0 && p->mode != DISPL) {
215                         sz++;
216                 }
217                 switch(p->mode) {
218                 case REG_MODE:
219                 case REGDEF_MODE:
220                 case AI_MODE:
221                 case AI_DEF_MODE:
222                 case AD_MODE:
223                         sz++;
224                         break;
225                 case DISPLL_MODE:
226                 case DISPLL_DEF_MODE:
227                 case REL:
228                 case REL_DEF:
229                 case IMM:
230                         sz += 5;
231                         break;
232                 case DISPL:
233                         sz += p->size;
234                         break;
235                 default:
236                         assert(0);
237                 }
238                 p++;
239         }
240         return sz;
241 }
242
243 /* Branch with byte or word offset  */
244 branch(opc, exp)
245         expr_t exp;
246 {
247         exp.val -= (DOTVAL + 2);
248         if ((pass == PASS_2) &&
249             (exp.val > 0) &&
250             ((exp.typ & S_DOT) == 0)
251            ) {
252                 exp.val -= DOTGAIN;
253         }
254         /* For the reason of exp.val-1, see the comment at the generation
255            of the RELative addressing mode.
256         */
257         if (pass >= PASS_2 &&
258             ((exp.typ & ~S_DOT) != DOTTYP || ! fitw(exp.val - 1))) {
259                 serror("label too far");
260         }
261         if (small(fitb(exp.val) && ((exp.typ & ~S_DOT) == DOTTYP), 1)) {
262                 emit1(opc);
263                 emit1((int) exp.val);
264         }
265         else {
266                 emit1(opc|0x20);
267                 emit2((int) (exp.val - 1));
268         }
269 }
270
271 /* Extended conditional branch instructions: if offset is too far,
272    they are replaced by a reversed conditional branch over a word-branch or
273    jump.
274 */
275 ext_branch(opc, exp)
276         expr_t exp;
277 {
278         int sm;
279         int gain = opc == BRB ? 1 : 3;
280         valu_t  val, d2 = DOTVAL + 2;
281
282         exp.val -= d2;
283         if ((pass == PASS_2) &&
284             (exp.val > 0) &&
285             ((exp.typ & S_DOT) == 0)
286            ) {
287                 exp.val -= DOTGAIN;
288         }
289         /* We have not generated the operands yet and cannot do so
290            because we don't know the opcode yet and have to generate that
291            first. Therefore, we make a conservative guess of the size
292            of the operands in case the branch is backwards. If it is
293            forwards, the (sizes of the) operands do not matter.
294         */
295         if (exp.val < 0) val = exp.val - size_ops();
296         else val = exp.val;
297         sm = fitw(val);
298         if ((exp.typ & ~S_DOT) != DOTTYP) sm = 0;
299         /* We gain three bytes if the offset fits in a word; for a
300            jump we also need an addressing mode byte.
301         */
302         if (small(sm, 3)) {
303                 /* Here we can gain 3 bytes if the extended branch is
304                    conditional and the offset fits in a byte. Otherwise,
305                    if the offset fits in a byte we gain 1 byte.
306                 */
307                 if (small(fitb(val), gain)) {
308                         emit1(opc);
309                         operands();
310                         /* Adjust exp.val for operand sizes. Keep into account
311                            that we already generated the opcode(!). This
312                            accounts for the "+ 1" instead of "+ 2".
313                         */
314                         emit1((int) (exp.val - (DOTVAL + 1 - d2)));
315                 }
316                 else {
317                         if (opc != BRB) {
318                                 emit1(rev_cond_branch(opc));
319                                 operands();
320                                 emit1(3);
321                         }
322                         emit1(BRW);
323                         emit2((int) (exp.val - (DOTVAL + 2 - d2)));
324                 }
325         }
326         else {
327                 small(0, gain); /* dummy call to keep bittab in sync */
328                 if (opc != BRB) {
329                         emit1(rev_cond_branch(opc));
330                         operands();
331                         emit1(6);
332                 }
333                 emit1(JMP);
334                 emit1((DISPLL_MODE << 4) | PC);
335 #ifdef RELOCATION
336                 newrelo(exp.typ, RELO4|RELPC);
337 #endif
338                 emit4(exp.val - (DOTVAL + 4 - d2));
339         }
340 }
341
342 /* Generate code for the operands */
343 operands()
344 {
345         register int i;
346
347         for (i = 0; i < op_ind; i++) {
348                 oprnd(&opnd[i]);
349         }
350 }