* configure.in: Add ncr* configuration.
[platform/upstream/binutils.git] / opcodes / z8k-dis.c
1 #include <stdio.h>
2 #define DEFINE_TABLE
3 #include "z8k-opc.h"
4
5 static void fetch_data();
6 static void fetch_instr();
7 static unsigned long get_val();
8 static int is_segmented();
9 static int lookup_instr();
10 static void output_instr();
11 static void unpack_instr();
12 static void unparse_instr();
13
14 typedef struct {
15    unsigned char instr_buf[24];
16    unsigned long bytes_fetched;
17    unsigned long tabl_index;
18    char instr_asmsrc[80];
19    unsigned long arg_reg[0x0f];
20    unsigned long immediate;
21    unsigned long displacement;
22    unsigned long address;
23    unsigned long cond_code;
24    unsigned long ctrl_code;
25    unsigned long flags;
26    unsigned long interrupts;
27 } instr_data_s;
28
29
30 static char *codes[16] = 
31 {
32   "f",
33   "lt",
34   "le",
35   "ule",
36   "ov/pe",
37   "mi",
38   "eq",
39   "c/ult",
40   "t",
41   "ge",
42   "gt",
43   "ugt",
44   "nov/po",
45   "pl",
46   "ne",
47   "nc/uge"
48 };
49
50
51 int print_insn_z8k(addr, in_buf, stream)
52 unsigned long addr;
53 unsigned char *in_buf;
54 FILE *stream;
55 {
56   instr_data_s  instr_data;
57
58   fetch_instr( &in_buf, &instr_data );
59   if (  lookup_instr( &instr_data )) 
60   {
61     fetch_data( &in_buf, &instr_data );
62     unpack_instr( &instr_data );
63     unparse_instr( &instr_data );
64     output_instr( &instr_data, addr, stream );
65     return instr_data.bytes_fetched;
66   }
67   else {
68     fprintf(stream,".word %02x%02x", in_buf[0], in_buf[1]);
69     return 2;
70   }
71
72 }
73
74
75 static void fetch_data( in_buf, instr_data )
76 unsigned char **in_buf;
77 instr_data_s *instr_data;
78 {
79    int bytes_2fetch;
80
81    bytes_2fetch = z8k_table[instr_data->tabl_index].length -
82                   instr_data->bytes_fetched;
83    while( bytes_2fetch-- )
84       instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
85 }
86
87 static void fetch_instr( in_buf, instr_data )
88 unsigned char **in_buf;
89 instr_data_s  *instr_data;
90 {
91    unsigned int loop = 2;
92
93    instr_data->bytes_fetched = 0;
94    while( loop-- )
95       instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
96
97 }
98
99 static unsigned long get_val( instr_buf, start_nibl, nibls_long )
100 unsigned char (*instr_buf)[];
101 unsigned int start_nibl, nibls_long;
102 {
103    unsigned long ret_val;
104    unsigned char byte_val, nibl_val;
105    unsigned int  nibl_index, nibl_lim;
106    unsigned int byte_index;
107    unsigned int which_nibl;
108
109    ret_val = 0;
110    nibl_lim = start_nibl + nibls_long;
111    for( nibl_index = start_nibl; nibl_index < nibl_lim; nibl_index++ )
112    {
113       byte_index = nibl_index / 2;
114       which_nibl = nibl_index % 2;
115       switch( which_nibl )
116       {
117          case 0:
118             byte_val = (*instr_buf)[byte_index];
119             nibl_val = (byte_val >> 4) & 0x0f;
120             break;
121          case 1:
122             nibl_val = byte_val & 0x0f;
123             break;
124       }
125       ret_val = (ret_val << 4) | nibl_val;
126    }
127
128    return ret_val;
129
130 }
131
132 static int is_segmented()
133 {
134    return 1;
135 }
136
137 static 
138 int lookup_instr( instr_data )
139 instr_data_s *instr_data;
140 {
141
142   int            nibl_index, tabl_index;
143   int            tablent_found, nibl_matched;
144   unsigned short instr_nibl;
145   unsigned short tabl_datum, datum_class, datum_value;
146
147   nibl_matched = 0;
148   tabl_index = 0;
149   while( ! nibl_matched && z8k_table[tabl_index].name)
150   {
151     nibl_matched = 1;
152     for( nibl_index = 0; nibl_index < 4 && nibl_matched; nibl_index++ )
153     {
154       instr_nibl =  get_val( instr_data->instr_buf, nibl_index, 1 );
155
156       tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
157       datum_class = tabl_datum & CLASS_MASK;
158       datum_value = ~CLASS_MASK & tabl_datum;
159
160       switch( datum_class )
161       {
162        case CLASS_BIT:
163         if( datum_value != instr_nibl ) nibl_matched = 0;
164         break;
165        case CLASS_00II:
166         if( ! ((~instr_nibl) & 0x4) ) nibl_matched = 0;
167         break;
168        case CLASS_01II:
169         if( ! (instr_nibl & 0x4) ) nibl_matched = 0;
170         break;
171        case CLASS_0CCC:
172         if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
173         break;
174        case CLASS_1CCC:
175         if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
176         break;
177        case CLASS_0DISP7:
178         if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
179         nibl_index += 1;
180         break;
181        case CLASS_1DISP7:
182         if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
183         nibl_index += 1;
184         break;
185        case CLASS_REGN0:
186         if( instr_nibl == 0 ) nibl_matched = 0;
187         break;
188        default:
189         break;
190       }
191     }
192     tabl_index++;
193   }
194
195
196   instr_data->tabl_index = tabl_index;
197
198   return   nibl_matched;
199
200 }
201
202 static void output_instr( instr_data, addr, stream )
203 instr_data_s  *instr_data;
204 unsigned long addr;
205 FILE *stream;
206 {
207    int            loop, loop_limit;
208    unsigned long  word_val;
209    char           tmp_str[20];
210    char           out_str[100];
211
212    strcpy( out_str, "" );
213
214    loop_limit = z8k_table[instr_data->tabl_index].length / 2;
215    for( loop = 0; loop < loop_limit; loop++ )
216    {
217       word_val = get_val( instr_data->instr_buf, loop * 4, 4 );
218       sprintf( tmp_str,  "%04x ", word_val );
219       strcat( out_str, tmp_str );
220    }
221
222    while( loop++ < 5 )
223    {
224       strcat( out_str, "     " );
225    }
226
227    strcat( out_str, instr_data->instr_asmsrc );
228
229    fprintf( stream, "%s", out_str );
230 }
231
232 static void unpack_instr( instr_data )
233 instr_data_s  *instr_data;
234 {
235    int            nibl_index, word_index;
236    int            nibl_count, loop;
237    unsigned short instr_nibl, instr_byte, instr_word, instr_long;
238    unsigned short tabl_datum, datum_class, datum_value;
239
240    nibl_count = 0;
241    loop = 0;
242    while( z8k_table[instr_data->tabl_index].byte_info[loop] != 0 )
243    {
244       word_index = (int) nibl_count / 4;
245       nibl_index = (int) nibl_count % 4;
246
247       switch( nibl_index )
248       {
249          case 0:
250             instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
251             instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
252             instr_word = get_val( instr_data->instr_buf, nibl_count, 4 );
253             instr_long = get_val( instr_data->instr_buf, nibl_count, 8 );
254             break;
255          case 1:
256             instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
257             break;
258          case 2:
259             instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
260             instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
261             break;
262          case 3:
263             instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
264             break;
265          default:
266             break;
267       }
268
269       tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
270       datum_class = tabl_datum & CLASS_MASK;
271       datum_value = tabl_datum & ~CLASS_MASK;
272
273       switch( datum_class )
274       {
275          case CLASS_X:
276             instr_data->address = instr_nibl;
277             break;
278          case CLASS_BA:
279             instr_data->displacement = instr_nibl;
280             break;
281          case CLASS_BX:
282             instr_data->arg_reg[datum_value] = instr_nibl;
283             break;
284          case CLASS_DISP:
285             switch( datum_value )
286             {
287                case ARG_DISP16:
288                   instr_data->displacement = instr_word;
289                   nibl_count += 3;
290                   break;
291                case ARG_DISP12:
292                   instr_data->displacement = instr_word & 0x0fff;
293                   nibl_count += 2;
294                   break;
295                default:
296                   break;
297             }
298             break;
299          case CLASS_IMM:
300             switch( datum_value )
301             {
302                case ARG_IMM4:
303                   instr_data->immediate = instr_nibl;
304                   break;
305                case ARG_IMM8:
306                   instr_data->immediate = instr_byte;
307                   nibl_count += 1;
308                   break;
309                case ARG_IMM16:
310                   instr_data->immediate = instr_word;
311                   nibl_count += 3;
312                   break;
313                case ARG_IMM32:
314                   instr_data->immediate = instr_long;
315                   nibl_count += 7;
316                   break;
317                case ARG_IMMN:
318                   instr_data->immediate = instr_nibl -1;
319                   break;
320                /* ????? */
321                /* missing ARG_IMMNMINUS1 */
322                case ARG_IMM_1:
323                   instr_data->immediate = 1;
324                   break;
325                case ARG_IMM_2:
326                   instr_data->immediate = 2;
327                   break;
328                case ARG_NIM16:
329                   instr_data->immediate = (- instr_word);
330                   nibl_count += 3;
331                   break;
332                case ARG_IMM2:
333                   instr_data->immediate = instr_nibl & 0x3;
334                   break;
335                default:
336                   break;
337             }
338             break;
339          case CLASS_CC:
340             instr_data->cond_code = instr_nibl;
341             break;
342          case CLASS_CTRL:
343             instr_data->ctrl_code = instr_nibl;
344             break;
345          case CLASS_DA:
346          case CLASS_ADDRESS:
347             if( is_segmented() )
348             {
349                if( instr_nibl & 0x8 )
350                {
351                   instr_data->address = ((instr_word & 0x7f00) << 8) +
352                                         (instr_long & 0xffff);
353                   nibl_count += 7;
354                }
355                else
356                {
357                   instr_data->address = ((instr_word & 0x7f00) << 8) +
358                                         (instr_word  & 0x00ff);
359                   nibl_count += 3;
360                }
361             }
362             else
363             {
364                instr_data->address = instr_word;
365                nibl_count += 3;
366             }
367             break;
368          case CLASS_0CCC:
369             instr_data->cond_code = instr_nibl & 0x7;
370             break;
371          case CLASS_1CCC:
372             instr_data->cond_code = instr_nibl & 0x7;
373             break;
374          case CLASS_0DISP7:
375             instr_data->displacement = instr_byte & 0x7f;
376             nibl_count += 1;
377             break;
378          case CLASS_1DISP7:
379             instr_data->displacement = instr_byte & 0x7f;
380             nibl_count += 1;
381             break;
382          case CLASS_01II:
383             instr_data->interrupts = instr_nibl & 0x3;
384             break;
385          case CLASS_00II:
386             instr_data->interrupts = instr_nibl & 0x3;
387             break;
388          case CLASS_BIT:
389             /* do nothing */
390             break;
391          case CLASS_IR:
392             instr_data->arg_reg[datum_value] = instr_nibl;
393             break;
394          case CLASS_FLAGS:
395             instr_data->flags = instr_nibl;
396             break;
397          case CLASS_REG:
398             instr_data->arg_reg[datum_value] = instr_nibl;
399             break;
400          case CLASS_REG_BYTE:
401             instr_data->arg_reg[datum_value] = instr_nibl;
402             break;
403          case CLASS_REG_WORD:
404             instr_data->arg_reg[datum_value] = instr_nibl;
405             break;
406          case CLASS_REG_QUAD:
407             instr_data->arg_reg[datum_value] = instr_nibl;
408             break;
409          case CLASS_REG_LONG:
410             instr_data->arg_reg[datum_value] = instr_nibl;
411             break;
412          case CLASS_REGN0:
413             instr_data->arg_reg[datum_value] = instr_nibl;
414             break;
415          default:
416             break;
417       }
418
419       loop += 1;
420       nibl_count += 1;
421    }
422 }
423
424 static void unparse_instr( instr_data )
425 instr_data_s  *instr_data;
426 {
427    unsigned short tabl_datum, datum_class, datum_value;
428    int            loop, loop_limit;
429    char           out_str[80], tmp_str[25];
430
431    sprintf( out_str, "\t%-10s", z8k_table[instr_data->tabl_index].name );
432
433    loop_limit = z8k_table[instr_data->tabl_index].noperands;
434    for( loop = 0; loop < loop_limit; loop++ )
435    {
436       if( loop )
437          strcat( out_str, "," );
438
439       tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
440       datum_class = tabl_datum & CLASS_MASK;
441       datum_value = tabl_datum & ~CLASS_MASK;
442
443       switch( datum_class )
444       {
445          case CLASS_X:
446             sprintf( tmp_str, "0x%0x(R%d)", instr_data->address,
447                      instr_data->arg_reg[datum_value] );
448             strcat( out_str, tmp_str );
449             break;
450          case CLASS_BA:
451             sprintf( tmp_str, "r%d(#%x)", instr_data->arg_reg[datum_value],
452                      instr_data->displacement);
453             strcat( out_str, tmp_str );
454             break;
455          case CLASS_BX:
456             sprintf( tmp_str, "r%d(R%d)", instr_data->arg_reg[datum_value],
457                      instr_data->arg_reg[ARG_RX] );
458             strcat( out_str, tmp_str );
459             break;
460          case CLASS_DISP:
461             sprintf( tmp_str, "#0x%0x", instr_data->displacement );
462             strcat( out_str, tmp_str );
463             break;
464          case CLASS_IMM:
465             sprintf( tmp_str, "#0x%0x", instr_data->immediate );
466             strcat( out_str, tmp_str );
467             break;
468          case CLASS_CC:
469             sprintf( tmp_str, "%s", codes[instr_data->cond_code] );
470             strcat( out_str, tmp_str );
471             break;
472          case CLASS_CTRL:
473             sprintf( tmp_str, "0x%0x", instr_data->ctrl_code );
474             strcat( out_str, tmp_str );
475             break;
476          case CLASS_DA:
477          case CLASS_ADDRESS:
478             sprintf( tmp_str, "#0x%0x", instr_data->address );
479             strcat( out_str, tmp_str );
480             break;
481          case CLASS_IR:
482             sprintf( tmp_str, "@R%d", instr_data->arg_reg[datum_value] );
483             strcat( out_str, tmp_str );
484             break;
485          case CLASS_FLAGS:
486             sprintf( tmp_str, "0x%0x", instr_data->flags );
487             strcat( out_str, tmp_str );
488             break;
489          case CLASS_REG_BYTE:
490             if( instr_data->arg_reg[datum_value] >= 0x8 )
491             {
492                sprintf( tmp_str, "rl%d",
493                         instr_data->arg_reg[datum_value] - 0x8 );
494             }
495             else
496             {
497                sprintf( tmp_str, "rh%d", instr_data->arg_reg[datum_value] );
498             } 
499             strcat( out_str, tmp_str );
500             break;
501          case CLASS_REG_WORD:
502             sprintf( tmp_str, "r%d", instr_data->arg_reg[datum_value] );
503             strcat( out_str, tmp_str );
504             break;
505          case CLASS_REG_QUAD:
506             sprintf( tmp_str, "rq%d", instr_data->arg_reg[datum_value] );
507             strcat( out_str, tmp_str );
508             break;
509          case CLASS_REG_LONG:
510             sprintf( tmp_str, "rr%d", instr_data->arg_reg[datum_value] );
511             strcat( out_str, tmp_str );
512             break;
513          default:
514             break;
515       }
516    }
517
518    strcpy( instr_data->instr_asmsrc, out_str );
519 }