Pristine Ack-5.5
[Ack-5.5.git] / mach / m68020 / ce / as.c
1 #include <string.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 #include "as.h"
5 #include "arg_type.h"
6
7
8 process_label() {}
9
10
11 process_mnemonic( m)
12 char *m;
13 {
14         for ( ; *m != '\0'; m++)
15                 if ( *m == '.')
16                         *m = '_';
17 }
18
19
20 process_operand( str, op)
21 register char *str;
22 register struct t_operand *op;
23 {
24         char *glob_lbl(), *strindex();
25
26         op->type = 0;
27
28         switch ( *str) {
29           case '#' : op->type = IS_IMMEDIATE;
30                      op->expr = str+1;
31
32                      if ( *(op->expr) != '$') {                 /*  #1  */
33                         op->val = atoi( str+1);
34                         if ( 1 <= op->val  &&  op->val <= 8 ) {
35                                 op->type = IS_QUICK;
36                                 op->lbl = NULL;
37                         }
38                      }
39                      else 
40                         if ( arg_type( str+1) == STRING) {      /*  #$1+$2  */
41                                 op->lbl = op->expr;
42                                 *(op->lbl+2) = '\0';
43                                 op->expr = op->lbl+3;
44                         }
45                         else                                    /*  #$1  */
46                                 op->lbl = NULL;
47                      break;
48
49           case '(' : if ( strindex( str+1, ',') == NULL)
50                         if ( is_reg( str+1)) {
51                                 op->reg = reg_val( str+1);
52
53                                 if ( *(str+4) == '+')           /*  (sp)+  */
54                                         op->type = IS_INCR;
55                                 else                            /*  (a0)  */
56                                         op->type = IS_IND_REG;
57                         }
58                         else {
59                                 op->type = IS_IND_MEM;
60                                 op->expr = str+1;
61                                 for ( str++; *++str != ')';)
62                                         ;
63                                 *str = '\0';
64
65                                 if ( *(op->expr) == '$')
66                                         if ( arg_type( op->expr) == STRING) {
67                                                                 /*  ($1+$2)  */
68                                                 op->lbl = op->expr;
69                                                 if ( strlen( op->lbl) == 2) 
70                                                         op->expr = "0";
71                                                 else {
72                                                         *(op->lbl+2) = '\0';
73                                                         op->expr = op->lbl+3;
74                                                 }
75                                         }
76                                         else                    /*  ($1)  */
77                                                 op->lbl = NULL;
78                                 else if ( isdigit( *(op->expr))) /*  (1)  */
79                                         op->lbl = NULL;
80                                 else {                          /*  (.trppc) */
81                                         op->lbl = glob_lbl( op->expr);
82                                         op->expr = "0";
83                                 }
84                         }
85                      else
86                         if ( *(str+1) == '[') {
87                                 op->type = IS_IND_IND;
88                                 op->expr = str+2;
89                                 for ( str += 2; *++str != ',';)
90                                         ;
91                                 *str++ = '\0';
92                                 for ( ; *str == ' '; str++)
93                                         ;
94                                 op->reg = reg_val( str);
95
96                                 for ( ; *str++ != ']';)
97                                         ;
98                                 if ( *str == ')')       /*  ([$1, a6])  */
99                                         op->expr2 = 0;
100                                 else {                  /*  ([8,a6],8)  */
101                                         for ( ; *str++ != ',';)
102                                                 ;
103                                         for ( ; *str == ' '; str++)
104                                                 ;
105                                         op->expr2 = atoi( str);
106                                 }
107                         }
108                         else {
109                                 op->expr = str+1;
110                                 for ( str++; *++str != ',';)
111                                         ;
112                                 *str++ = '\0';
113                                 for ( ; *str == ' '; str++)
114                                         ;
115                                 op->reg = reg_val( str);
116                                 if ( *(str+2) == ')') {         /*  (4, a0)  */
117                                         int i = atoi(op->expr);
118                                         if ((*(op->expr) == '-' ||
119                                              isdigit(*(op->expr))) &&
120                                             i <= 32767 && i >= -32768) {
121                                                 op->type = IS_IND_REG_DISPL;
122                                         }
123                                         else    op->type = IS_IND_REG_EDISPL;
124                                 }
125                                 else {                   /*  (0, sp, d0.l*1)  */
126                                         op->type = IS_3_OPS;
127                                         for ( str++; *++str != ',';)
128                                                 ;
129                                         for ( ; *str == ' '; str++)
130                                                 ;
131                                         op->reg2 = reg_val( str);
132
133                                         for ( ; *str++ != '*';)
134                                                 ;
135                                         op->scale = atoi( str);
136                                 }
137                         }
138                      break;
139
140           case '-' : op->type = IS_DECR;                        /*  -(sp)  */
141                      op->reg = reg_val( str+2);
142                      break;
143
144           case '$' : op->type = IS_GLOB_LBL;                    /*  $1  */
145                      op->lbl = str;
146                      op->expr ="0";
147                      break;
148
149           default  : if ( is_reg( str)) {
150                         op->reg = reg_val( str);
151                         if ( *(str+2) == ':') {                 /*  d2:d1  */
152                                 op->type = IS_REG_PAIR;
153                                 op->reg2 = reg_val( str+3);
154                         }
155                         else                                    /*  a6  */
156                                 op->type = ( *str == 'd' ? IS_D_REG : IS_A_REG);
157                      }
158                      else if ( isdigit( *str)) {                /*  1f  */
159                         op->type = IS_LOC_LBL;
160                         op->lbl = str;
161                         op->expr = "0";
162                         *(str+1) ='\0';
163                      }
164                      else {                                     /*  .strhp  */
165                         op->type = IS_GLOB_LBL;
166                         op->lbl = glob_lbl( str);
167                         *(str+1) ='\0';
168                         op->expr = "0";
169                      }
170         }
171 }
172
173
174 int reg_val( reg)
175 char *reg;
176 {
177         return( *reg == 's' ? 7 : atoi( reg+1));
178 }
179
180 int is_reg( str)
181 register char *str;
182 {
183         switch ( *str) {
184           case 'a' :
185           case 'd' : return( isdigit( *(str+1)));
186
187           case 's' : return( *(str+1) == 'p');
188
189           default  : return( 0);
190         }
191 }
192
193
194 char *glob_lbl( lbl)
195 char *lbl;
196 {
197         char *gl, *Malloc();
198
199         gl = Malloc( strlen( lbl) + 3);
200         sprintf( gl, "\"%s\"", lbl);
201         return( gl);
202 }
203
204
205 /******************************************************************************/
206
207
208 int mode_reg( eaddr)
209 register struct t_operand *eaddr;
210 {
211         switch ( eaddr->type) {
212           case IS_A_REG         : return( 0x08 | eaddr->reg);
213
214           case IS_D_REG         : return( 0x00 | eaddr->reg);
215
216           case IS_IND_REG       : return( 0x10 | eaddr->reg);
217
218           case IS_INCR          : return( 0x18 | eaddr->reg);
219
220           case IS_DECR          : return( 0x20 | eaddr->reg);
221
222           case IS_IND_MEM       : return( 0x39);
223
224           case IS_IND_IND       : return( 0x30 | eaddr->reg);
225
226           case IS_IND_REG_DISPL : return( 0x28 | eaddr->reg);
227
228           case IS_IND_REG_EDISPL: return( 0x30 | eaddr->reg);
229
230           case IS_GLOB_LBL      : return( 0x39);
231
232           case IS_3_OPS         : if ( isdigit( *(eaddr->expr)) &&
233                                                     atoi( eaddr->expr) < 128)
234                                         return( 0x30 | eaddr->reg);
235                                   else
236                                         fprintf( stderr, "FOUT in IS_3_OPS\n");
237                                   break;
238
239           case IS_QUICK         :
240           case IS_IMMEDIATE     : return( 0x3c);
241
242           default               : fprintf( stderr,
243                                            "mode_reg(), wrong operand %d\n",
244                                            eaddr->type);
245                                   abort();
246                                   break;
247         }
248 }
249
250
251 code_extension( eaddr)
252 register struct t_operand *eaddr;
253 {
254
255         switch ( eaddr->type) {
256           case IS_IND_MEM       : if ( eaddr->lbl == NULL) 
257                                         @text4( %$( eaddr->expr));
258                                   else
259                                         @reloc4( %$( eaddr->lbl),
260                                                  %$( eaddr->expr),
261                                                  ABSOLUTE);
262                                   break;
263
264           case IS_IND_IND       : if ( eaddr->expr2 == 0) {
265                                         @text2( 0x161);
266                                         @text2( %$(eaddr->expr));
267                                   }
268                                   else {
269                                         @text2( 0x162);
270                                         @text2( %$(eaddr->expr));
271                                         @text2( %d(eaddr->expr2));
272                                   }
273                                   break;
274
275           case IS_IND_REG_DISPL : @text2( %$( eaddr->expr));
276                                   break;
277
278           case IS_IND_REG_EDISPL :@text2(0x0170);
279                                   @text4( %$( eaddr->expr));
280                                   break;
281
282           case IS_GLOB_LBL      : @reloc4( %$(eaddr->lbl),
283                                            %$(eaddr->expr),
284                                            ABSOLUTE);
285                                   break;
286
287           case IS_3_OPS         : if ( isdigit( *(eaddr->expr)) &&
288                                                     atoi( eaddr->expr) < 128) {
289
290                                         @text2( %d( 0x0800 |
291                                                   ( eaddr->reg2 << 12) |
292                                                   ( two_log( eaddr->scale)<<9) |
293                                                   atoi( eaddr->expr)));
294                                   }
295                                   else
296                                         fprintf( stderr, "FOUT in IS_3_OPS\n");
297                                   break;
298
299           case IS_QUICK         :
300           case IS_IMMEDIATE     : if ( eaddr->lbl != NULL)
301                                         @reloc4( %$(eaddr->lbl),
302                                                  %$(eaddr->expr),
303                                                  ABSOLUTE);
304                                   else
305                                         @text4( %$(eaddr->expr));
306         }
307 }
308
309
310 int reg_mode( eaddr)
311 struct t_operand *eaddr;
312 {
313         int mr;
314
315         mr = mode_reg( eaddr);
316         return( ((mr & 0x7) << 3) | ((mr & 0x38) >> 3));
317 }
318
319
320 code_opcode( opcode, field1, field2, eaddr)
321 int opcode, field1, field2;
322 struct t_operand *eaddr;
323 {
324         @text2( %d(((opcode & 0xf) << 12) | ((field1 & 0x7) << 9) |
325                    ((field2 & 0x7) << 6) | (mode_reg(eaddr) & 0x3f)));
326 }
327
328
329 /* The attempts to optimize the instruction size when it cannot be done
330    at code-expander generation time is actually quite dangerous, because
331    it may not happen between references to and definitions of (corresponding)
332    local labels. The reason for this is that these offsets are computed
333    at code-expander generation time. Unfortunately, no warning is given,
334    so this has to be checked by hand.
335 */
336 code_instr( opcode, field1, field2, eaddr)
337 int opcode, field1, field2;
338 struct t_operand *eaddr;
339 {
340         if (eaddr->type == IS_IND_REG_EDISPL) {
341                 @__instr_code(%d(((opcode & 0xf) << 12) | ((field1 & 0x7) << 9) |
342                                 ((field2 & 0x7) << 6)),
343                               %d(eaddr->reg), %$(eaddr->expr));
344         }
345         else {
346                 code_opcode( opcode, field1, field2, eaddr);
347                 code_extension( eaddr);
348         }
349 }
350
351
352 code_move( size, src, dst)
353 int size;
354 struct t_operand *src, *dst;
355 {
356         if (src->type == IS_IND_REG_EDISPL) {
357                 if (dst->type == IS_IND_REG_EDISPL) {
358                         @__moveXX(%d( ((size & 0x3) << 12)),
359                                  %d(dst->reg), %$(dst->expr),
360                                  %d(src->reg), %$(src->expr));
361                 }
362                 else {
363                         @__instr_code(%d( ((size & 0x3) << 12)|((reg_mode( dst) & 0x3f) << 6)),
364                                  %d(src->reg), %$(src->expr));
365                 }
366         }
367         else if (dst->type == IS_IND_REG_EDISPL) {
368                 @__move_X(%d( ((size & 0x3) << 12) | (mode_reg( src) & 0x3f)),
369                          %d(dst->reg), %$(dst->expr));
370         }
371         else {
372                 @text2( %d( ((size & 0x3) << 12) | ((reg_mode( dst) & 0x3f) << 6) |
373                                            (mode_reg( src) & 0x3f)));
374                 code_extension( src);
375                 code_extension( dst);
376         }
377 }
378
379
380 code_dist4( dst)
381 struct t_operand *dst;
382 {
383         @reloc4( %$(dst->lbl), %$(dst->expr) + 4, PC_REL);
384 }
385
386
387 int two_log( nr)
388 register int nr;
389 {
390         register int log;
391
392         for ( log = 0; nr >= 2; nr >>= 1)
393                 log++;
394
395         return( log);
396 }