Pristine Ack-5.5
[Ack-5.5.git] / mach / m68020 / as / mach5.c
1 /* $Id: mach5.c,v 1.11 1994/06/24 13:05:54 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  */
6 /*
7  * Motorola 68020 auxiliary functions
8  */
9
10 /* With pc-relative modes the offset is calulated from the address of the 
11  * extension word. This address is not known until the instruction opcode(s)
12  * have been emitted. Since this address is unknown, the offset from pc
13  * cannot be calculated correctly, so it cannot immediately be decided whether
14  * to use mode 072 (pc-relative with 16 bit offset) or mode 073 (pc_relative
15  * with possibly 32 bit offset) Because of this, instruction opcodes
16  * are not really emitted right away, but temporarily stored. This way
17  * the address of the extension word is known so the offset can be calculated
18  * correctly and it then can be decided to use mode 072 or 073; this can be
19  * altered in the instruction opcode, if necessary. For the sake of consistency
20  * the effective address(es) are also stored temporarily. The instruction is
21  * then emitted in one go, by emit_instr().
22  */
23
24 emit_instr()
25 {
26         register instr_t *ip;
27
28         for (ip=instr; ip<instrp; emit2((ip++)->i_word)) {
29 #ifdef RELOCATION
30                 RELOMOVE(relonami, ip->i_relonami);
31                 if (ip->i_reloinfo)
32                         newrelo(ip->i_relotype, ip->i_reloinfo | RELBR | RELWR);
33 #endif
34         }
35 }
36
37
38 #ifdef RELOCATION
39 t_emit2(word, relotype, reloinfo, relnm)
40 short word;
41 short relotype;
42 valu_t relnm;
43 #else
44 t_emit2(word)
45 short word;
46 #endif
47 {
48 #ifdef RELOCATION
49         if (instrp->i_reloinfo = reloinfo) {
50                 RELOMOVE(instrp->i_relonami, relnm);
51                 instrp->i_relotype = relotype;
52         }
53 #endif
54         instrp->i_word = word;
55         instrp++;
56         dot_offset += 2;
57 }
58
59 #ifdef RELOCATION
60 t_emit4(words, relotype, reloinfo, relnm)
61 long words;
62 short relotype;
63 valu_t relnm;
64 #else
65 t_emit4(words)
66 long words;
67 #endif
68 {
69         T_EMIT2((short)(words>>16), relotype, reloinfo, relnm);
70         T_EMIT2((short)(words), 0, 0, 0);
71 }
72
73 ea_1(sz, bits)
74 {
75                 /* Because displacements come in three sizes (null displacement,
76                  * word and long displacement), each displacement requires
77                  * two bits in the bittable, so two calls to small. Sometimes
78                  * one of these calls is a dummy call.
79                  */
80
81         register flag;
82         register sm, sm1, sm2;
83
84         if (mrg_1 > 074)
85                 serror("no specials");
86         if ((flag = eamode[mrg_1>>3]) == 0)
87                 if ((flag = eamode[010 + (mrg_1&07)]) == 0)
88                         flag = eamode[015 + (sz>>6)];
89         if ((mrg_1 & 070) == 010)
90                 checksize(sz, 2|4);
91         bits &= ~flag;
92         if (bits)
93                 serror("bad addressing category");
94         if (mrg_1==073 && (ffew_1 & 0200) == 0 && (bd_1.typ & ~S_DOT) == DOTTYP)
95                 bd_1.val -= (DOTVAL + dot_offset);
96
97         if ( (mrg_1==073) || (mrg_1&070)==060 ) {
98                 sm = (
99                         (mrg_1==073 && (bd_1.typ & ~S_DOT)==DOTTYP)
100                       ||
101                         (bd_1.typ == S_ABS)
102                      );
103                 if (small(sm && fitw(bd_1.val), 2)) {
104                         sm = (
105                                 (sm1 = ((ffew_1 & 0307)==0 && fitb(bd_1.val)))
106                               ||
107                                 (sm2 = ((ffew_1 & 0307)==0100 && mrg_1==073))
108                               ||
109                                 (bd_1.val==0)
110                              );
111                         if (small(sm,2)) {
112                                 if (sm1) {      /* brief format extension */
113                                     T_EMIT2((ffew_1&0177000) | lowb(bd_1.val),
114                                                                     0, 0, 0);
115                                     return;
116                                 }
117                                 if (sm2) {
118                                         /* change mode to 072 in opcode word */
119                                     instr->i_word &= ~1;
120                                     T_EMIT2(loww(bd_1.val), 0, 0, 0);
121                                     return;
122                                 }
123                                 ffew_1 &= ~040; /* null displacement */
124                         }
125                         else
126                                 ffew_1 &= ~020;         /* word displacement */
127                 } else
128                         sm = small(0,2); /* dummy call */
129
130                 if (ffew_1 & 3) {
131                         sm = (od_1.typ == S_ABS);
132                         if (small(sm && fitw(od_1.val), 2))
133                                 ffew_1 &= small(od_1.val==0, 2) ? ~2 : ~1;
134                         else
135                                 sm = small(0,2); /* dummy call */
136                 }
137
138                 assert((ffew_1 & 0410) == 0400);
139                 T_EMIT2(ffew_1, 0, 0, 0);
140
141                 assert(ffew_1 & 060);
142                 switch(ffew_1 & 060) {
143                 case 020:
144                         break;
145                 case 040:
146                         T_EMIT2(loww(bd_1.val), 0, 0, 0);
147                         break;
148                 case 060:
149                         T_EMIT4(    bd_1.val,
150                                     bd_1.typ,
151                                     (mrg_1 == 073 && (ffew_1 & 0200) == 0)
152                                         ? RELPC|RELO4
153                                         : RELO4,
154                                     bd_rel1
155                                 );
156                 }
157
158                 if (ffew_1 & 3) {
159                         switch(ffew_1 & 3) {
160                         case 1:
161                                 break;
162                         case 2:
163                                 T_EMIT2(loww(od_1.val), 0, 0, 0);
164                                 break;
165                         case 3:
166                                 T_EMIT4(od_1.val, od_1.typ, RELO4, od_rel1);
167                         }
168                 }
169                 return; /* mode 060 and 073 have been dealt with */
170         }
171
172         if (flag & FITW)
173                 if (
174                         ! fitw(bd_1.val)
175                         &&
176                         (mrg_1 != 074 || ! fit16(bd_1.val))
177                 )
178                         nofit();
179         if (flag & FITB) {
180                 if (
181                         ! fitb(bd_1.val)
182                         &&
183                         (mrg_1 != 074 || ! fit8(bd_1.val))
184                 )
185                         nofit();
186                 if (mrg_1 == 074)
187                         bd_1.val &= 0xFF;
188         }
189         if (flag & PUTL)
190                 T_EMIT4(bd_1.val, bd_1.typ, (flag>>8), bd_rel1);
191         if (flag & PUTW)
192                 T_EMIT2(loww(bd_1.val), bd_1.typ, (flag>>8), bd_rel1);
193 }
194
195 ea_2(sz, bits)
196
197         mrg_1  = mrg_2;
198         bd_1   = bd_2;
199         od_1   = od_2;
200         ffew_1 = ffew_2;
201         RELOMOVE(bd_rel1, bd_rel2);
202         RELOMOVE(od_rel1, od_rel2);
203         ea_1(sz, bits);
204 }
205
206 checksize(sz, bits)
207 {
208         if ((bits & (1 << (sz>>6))) == 0)
209                 serror("bad size");
210 }
211
212 check_fsize(sz, size)
213 {
214         if (sz != size)
215                 serror("bad size");
216 }
217
218 ch_sz_dreg(size, mode)
219 {
220         if (mode == 0 &&
221             (size == FSIZE_X || size == FSIZE_P || size == FSIZE_D))
222                 serror("illegal size for data register");
223 }
224
225 checkscale(val)
226 valu_t val;
227 {
228         int v = val;
229
230         if (v != val) v = 0;
231         switch(v) {
232         case 1:         return 0;
233         case 2:         return 1<<9;
234         case 4:         return 2<<9;
235         case 8:         return 3<<9;
236         default:        serror("bad scale"); return 0;
237         }
238 }
239
240 badoperand()
241 {
242         serror("bad operand(s)");
243 }
244
245 shift_op(opc, sz)
246 {
247         if (mrg_1 < 010 && mrg_2 < 010) {
248                 T_EMIT2((opc & 0170470) | sz | mrg_1<<9 | mrg_2, 0, 0, 0);
249                 return;
250         }
251         if (bd_1.typ != S_ABS || mrg_1 != 074) {
252                 badoperand();
253                 return;
254         }
255         if (mrg_2 < 010) {
256                 fit(fit3(bd_1.val));
257                 T_EMIT2((opc & 0170430) | sz | low3(bd_1.val)<<9 | mrg_2,0,0,0);
258                 return;
259         }
260         checksize(sz, 2);
261         fit(bd_1.val == 1);
262         T_EMIT2((opc & 0177700) | mrg_2, 0, 0, 0);
263         ea_2(SIZE_W, MEM|ALT);
264 }
265
266 bitop(opc)
267 {
268         register bits;
269
270         bits = DTA|ALT;
271         if (opc == 0 && (mrg_1 < 010 || mrg_2 != 074))
272                 bits = DTA;
273         if (mrg_1 < 010) {
274                 T_EMIT2(opc | 0400 | mrg_1<<9 | mrg_2, 0, 0, 0);
275                 ea_2(0, bits);
276                 return;
277         }
278         if (mrg_1 == 074) {
279                 T_EMIT2(opc | 04000 | mrg_2, 0, 0, 0);
280                 ea_1(SIZE_W, 0);
281                 ea_2(0, bits);
282                 return;
283         }
284         badoperand();
285 }
286
287 bitfield(opc, extension)
288 {
289         T_EMIT2(opc | mrg_2, 0, 0, 0);
290         T_EMIT2(extension, 0, 0, 0);
291         ea_2(SIZE_L, (mrg_2 < 010) ? 0 : (CTR | ALT));
292 }
293
294 add(opc, sz)
295 {
296         if ((mrg_2 & 070) == 010)
297                 checksize(sz, 2|4);
298         if (
299                 mrg_1 == 074
300                 &&
301                 small(
302                         bd_1.typ==S_ABS && fit3(bd_1.val),
303                         sz==SIZE_L ? 4 : 2
304                      )
305            ) {
306                 T_EMIT2((opc&0400) | 050000 | low3(bd_1.val)<<9 | sz | mrg_2,
307                                                                 0, 0, 0);
308                 ea_2(sz, ALT);
309                 return;
310         }
311         if (mrg_1 == 074 && (mrg_2 & 070) != 010) {
312                 T_EMIT2((opc&03000) | sz | mrg_2, 0, 0, 0);
313                 ea_1(sz, 0);
314                 ea_2(sz, DTA|ALT);
315                 return;
316         }
317         if ((mrg_2 & 070) == 010) {
318                 T_EMIT2((opc&0170300) | (mrg_2&7)<<9 | sz<<1 | mrg_1, 0, 0, 0);
319                 ea_1(sz, 0);
320                 return;
321         }
322         if (to_dreg(opc, sz, 0))
323                 return;
324         if (from_dreg(opc, sz, ALT|MEM))
325                 return;
326         badoperand();
327 }
328
329 and(opc, sz)
330 {
331         if (mrg_1 == 074 && mrg_2 >= 076) {     /* ccr or sr */
332                 if (sz != SIZE_NON)
333                         checksize(sz, mrg_2==076 ? 1 : 2);
334                 else
335                         sz = (mrg_2==076 ? SIZE_B : SIZE_W);
336                 T_EMIT2((opc&07400) | sz | 074, 0, 0, 0);
337                 ea_1(sz, 0);
338                 return;
339         }
340         if (sz == SIZE_NON)
341                 sz = SIZE_DEF;
342         if (mrg_1 == 074) {
343                 T_EMIT2((opc&07400) | sz | mrg_2, 0, 0, 0);
344                 ea_1(sz, 0);
345                 ea_2(sz, DTA|ALT);
346                 return;
347         }
348         if ((opc & 010000) == 0 && to_dreg(opc, sz, DTA))
349                 return;
350         if (from_dreg(opc, sz, (opc & 010000) ? DTA|ALT : ALT|MEM))
351                 return;
352         badoperand();
353 }
354
355 to_dreg(opc, sz, bits)
356 {
357         if ((mrg_2 & 070) != 000)
358                 return(0);
359         T_EMIT2((opc & 0170000) | sz | (mrg_2&7)<<9 | mrg_1, 0, 0, 0);
360         ea_1(sz, bits);
361         return(1);
362 }
363
364 from_dreg(opc, sz, bits)
365 {
366         if ((mrg_1 & 070) != 000)
367                 return(0);
368         T_EMIT2((opc & 0170000) | sz | (mrg_1&7)<<9 | 0400 | mrg_2, 0, 0, 0);
369         ea_2(sz, bits);
370         return(1);
371 }
372
373 cmp(sz)
374 {
375         register opc;
376
377         if ((mrg_1&070) == 030 && (mrg_2&070) == 030) {
378                 T_EMIT2(0130410 | sz | (mrg_1&7) | (mrg_2&7)<<9, 0, 0, 0);
379                 return;
380         }
381         if (mrg_1 == 074 && (mrg_2 & 070) != 010) {
382                 if (mrg_2==074)
383                         badoperand();
384                 T_EMIT2(06000 | sz | mrg_2, 0, 0, 0);
385                 ea_1(sz, 0);
386                 ea_2(sz, DTA);
387                 return;
388         }
389         if (mrg_2 < 020) {
390                 if (mrg_2 >= 010) {
391                         checksize(sz, 2|4);
392                         opc = 0130300 | sz<<1;
393                         mrg_2 &= 7;
394                 } else
395                         opc = 0130000 | sz;
396                 T_EMIT2(opc | mrg_2<<9 | mrg_1, 0, 0, 0);
397                 ea_1(sz, 0);
398                 return;
399         }
400         badoperand();
401 }
402
403 link_instr(sz, areg)
404 {
405         if (sz == SIZE_NON) {
406                 if (bd_2.typ == S_ABS && fitw(bd_2.val))
407                         sz = SIZE_W;
408                 else
409                         sz = SIZE_L;
410         }
411         checksize(sz, 2|4);
412         if (sz == SIZE_W)
413                 T_EMIT2(047120 | areg, 0, 0, 0);
414         else /* sz == SIZE_L */
415                 T_EMIT2(044010 | areg, 0, 0, 0);
416         ea_2(sz, 0);
417 }
418
419 move(sz)
420 {
421         register opc;
422
423         if (mrg_1 > 074 || mrg_2 > 074) {
424                 move_special(sz);
425                 return;
426         }
427         if (sz == SIZE_NON)
428                 sz = SIZE_DEF;
429         if (
430                 mrg_2<010
431                 &&
432                 mrg_1==074
433                 &&
434                 sz==SIZE_L
435                 &&
436                 small(bd_1.typ==S_ABS && fitb(bd_1.val), 4)
437         ) {
438                 T_EMIT2(070000 | mrg_2<<9 | lowb(bd_1.val), 0, 0, 0);
439                 return;
440         }
441         switch (sz) {
442         case SIZE_B:    opc = 010000; break;
443         case SIZE_W:    opc = 030000; break;
444         case SIZE_L:    opc = 020000; break;
445         }
446         T_EMIT2(opc | mrg_1 | (mrg_2&7)<<9 | (mrg_2&070)<<3, 0, 0, 0);
447         ea_1(sz, 0);
448         ea_2(sz, ALT);
449 }
450
451 move_special(sz)
452 {
453         if (mrg_2 >= 076) {
454                 if (sz != SIZE_NON)
455                         checksize(sz, 2);
456                 T_EMIT2(042300 | (mrg_2==076?0:01000) | mrg_1, 0, 0, 0);
457                 ea_1(SIZE_W, DTA);
458                 return;
459         }
460         if (mrg_1 >= 076) {
461                 if (sz != SIZE_NON)
462                         checksize(sz, 2);
463                 T_EMIT2(040300 | (mrg_1==076?01000:0) | mrg_2, 0, 0, 0);
464                 ea_2(SIZE_W, DTA|ALT);
465                 return;
466         }
467         if (sz != SIZE_NON)
468                 checksize(sz, 4);
469         if (mrg_1==075 && (mrg_2&070)==010) {
470                 T_EMIT2(047150 | (mrg_2&7), 0, 0, 0);
471                 return;
472         }
473         if (mrg_2==075 && (mrg_1&070)==010) {
474                 T_EMIT2(047140 | (mrg_1&7), 0, 0, 0);
475                 return;
476         }
477         badoperand();
478 }
479
480 movem(dr, sz, regs)
481 {
482         register i;
483
484         if ((mrg_2>>3) == 04) {
485                 regs = reverse(regs, 16);
486         }
487         checksize(sz, 2|4);
488         if ((mrg_2>>3)-3 == dr)
489                 badoperand();
490         T_EMIT2(044200 | dr<<10 | (sz & 0200) >> 1 | mrg_2, 0, 0, 0);
491         T_EMIT2(regs, 0, 0, 0);
492         i = CTR;
493         if (dr == 0 && (mrg_2&070) == 040)
494                 i = MEM;
495         if (dr != 0 && (mrg_2&070) == 030)
496                 i = MEM;
497         if (dr == 0)
498                 i |= ALT;
499         ea_2(sz, i);
500 }
501
502 reverse(regs, max)
503         register int regs;
504 {
505         register int r, i;
506
507         r = regs; regs = 0;
508         for (i = max; i > 0; i--) {
509                 regs <<= 1;
510                 if (r & 1)
511                         regs++;
512                 r >>= 1;
513         }
514         return regs;
515 }
516
517 movep(sz)
518 {
519         checksize(sz, 2|4);
520         if (mrg_1<010 && (mrg_2&070)==050) {
521                 T_EMIT2(0610 | (sz & 0200)>>1 | mrg_1<<9 | (mrg_2&7), 0, 0, 0);
522                 ea_2(sz, 0);
523                 return;
524         }
525         if (mrg_2<010 && (mrg_1&070)==050) {
526                 T_EMIT2(0410 | (sz & 0200)>>1 | mrg_2<<9 | (mrg_1&7), 0, 0, 0);
527                 ea_1(sz, 0);
528                 return;
529         }
530         badoperand();
531 }
532
533 branch(opc, exp)
534 expr_t exp;
535 {
536         register sm;
537
538         exp.val -= (DOTVAL + 2);
539         if ((pass == PASS_2) 
540             &&
541             (exp.val > 0)
542             &&
543             ((exp.typ & S_DOT) == 0)
544            )
545                 exp.val -= DOTGAIN;
546         sm = fitw(exp.val);
547         if ((exp.typ & ~S_DOT) != DOTTYP)
548                 sm = 0;
549         if (small(sm,2)) {
550                 if (small(fitb(exp.val),2)) {
551                         if (exp.val == 0)
552                                 T_EMIT2(047161, 0, 0, 0);       /* NOP */
553                         else if (exp.val == -1) {
554                                 T_EMIT2(047161, 0, 0, 0);
555                                 serror("bad branch offset");
556                         } else
557                                 T_EMIT2(opc | lowb(exp.val), 0, 0, 0);
558                 } else {
559                         T_EMIT2(opc, 0, 0, 0);
560                         T_EMIT2(loww(exp.val), 0, 0, 0);
561                 }
562                 return;
563         }
564         sm = small(0,2);        /* dummy call; two calls to small per branch */
565         T_EMIT2(opc | 0377, 0, 0, 0); /* 4 byte offset */
566         T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami);
567 }
568
569 cpbcc(opc, exp)
570 expr_t exp;
571 {
572         register sm;
573
574         exp.val -= (DOTVAL + 2);
575         if ((pass == PASS_2) 
576             &&
577             (exp.val > 0)
578             &&
579             ((exp.typ & S_DOT) == 0)
580            )
581                 exp.val -= DOTGAIN;
582         sm = fitw(exp.val);
583         if ((exp.typ & ~S_DOT) != DOTTYP)
584                 sm = 0;
585         if (small(sm,2)) {
586                 T_EMIT2(opc, 0, 0, 0);
587                 T_EMIT2(loww(exp.val), 0, 0, 0);
588                 return;
589         }
590         
591         T_EMIT2(opc | 0100, 0, 0, 0); /* 4 byte offset */
592                 /* NB: no coprocessor defined extension words are emitted */
593         T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami);
594 }
595
596 ea7071(sz)
597 {
598         mrg_2 = 071;
599         switch (sz) {
600         case SIZE_B:
601                 badoperand();
602         case SIZE_W:
603                 mrg_2 = 070;
604         case SIZE_L:
605                 return;
606         case SIZE_NON:
607                 break;
608         }
609                 /* If this absolute address is in program space, and if we
610                  * can assume that the only references to program space are made
611                  * by instructins like 'jsr', 'jmp', 'lea' and 'pea', it might
612                  * be possible to use a (PC,d16) effective address mode instead
613                  * of absolute long. This is done here. If this scheme is in
614                  * some way undesirable (e.g. when references to program space
615                  * are made by instructions with more than one opcode word or by
616                  * second effective addresses in instructions), the rest
617                  * of this routine can simply be removed and replaced by the
618                  * next two lines (which of course are in comment brackets now).
619         if (small(bd_2.typ == S_ABS && fitw(bd_2.val), 2))
620                 mrg_2 = 070;
621                  */
622         if (pass == PASS_1) {
623                         /* Reserve a bit in the bittable; in the following
624                          * passes one call to small() will be done, but know yet
625                          * which one, because bd_2.typ cannot be trusted yet.
626                          */
627                 small(0, 2);
628                 return;
629         }
630         if ((bd_2.typ & ~S_DOT) == DOTTYP) {
631                         /* the "off" variable fixes the problem described above,
632                          * e.g., when references to program space are made by
633                          * instructions with more than one opcode word.
634                          */
635                 int off = 2;
636
637                 switch(curr_instr) {
638                 case MOVEM:
639                 case FMOVE:
640                 case FMOVEM:
641                 case FDYADIC:
642                 case FMONADIC:
643                 case FSINCOS:
644                 case FSCC:
645                 case FTST:
646                 case DIVL:
647                 case OP_RANGE:
648                 case CALLM:
649                 case CAS:
650                 case CPSCC:
651                 case CPTRAPCC:
652                 case PFLUSH:
653                 case PTEST:
654                 case PMOVE:
655                 case PLOAD:
656                         off = 4;
657                         break;
658                 case MOVESP:
659                         if (curr_size != 0) off = 4;
660                         break;
661                 case DIVMUL:
662                         if (curr_size != SIZE_W) off = 4;
663                         break;
664                 }
665                 if (small(fitw(bd_2.val-(DOTVAL+off)), 2)) {
666                         bd_2.val -= (DOTVAL+off);
667                         mrg_2 = 072;
668                 }
669         } else
670                 if (small(bd_2.typ == S_ABS && fitw(bd_2.val), 2))
671                         mrg_2 = 070;
672 }
673
674 fbranch(opc, exp)
675 expr_t exp;
676 {
677         register sm;
678
679         exp.val -= (DOTVAL + 2);
680         if ((pass == PASS_2) 
681             &&
682             (exp.val > 0)
683             &&
684             ((exp.typ & S_DOT) == 0)
685            )
686                 exp.val -= DOTGAIN;
687         sm = fitw(exp.val);
688         if ((exp.typ & ~S_DOT) != DOTTYP)
689                 sm = 0;
690         if (small(sm,2)) {
691                 T_EMIT2(0170200|co_id|opc, 0, 0, 0);
692                 T_EMIT2(loww(exp.val), 0, 0, 0);
693                 return;
694         }
695         T_EMIT2(0170300|co_id|opc, 0, 0, 0); /* 4 byte offset */
696         T_EMIT4(exp.val, exp.typ, RELPC|RELO4, relonami);
697 }