aboutsummaryrefslogtreecommitdiff
path: root/opcodes/z8k-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/z8k-dis.c')
-rw-r--r--opcodes/z8k-dis.c519
1 files changed, 519 insertions, 0 deletions
diff --git a/opcodes/z8k-dis.c b/opcodes/z8k-dis.c
new file mode 100644
index 0000000..eb62d8f
--- /dev/null
+++ b/opcodes/z8k-dis.c
@@ -0,0 +1,519 @@
+#include <stdio.h>
+#define DEFINE_TABLE
+#include "z8k-opc.h"
+
+static void fetch_data();
+static void fetch_instr();
+static unsigned long get_val();
+static int is_segmented();
+static int lookup_instr();
+static void output_instr();
+static void unpack_instr();
+static void unparse_instr();
+
+typedef struct {
+ unsigned char instr_buf[24];
+ unsigned long bytes_fetched;
+ unsigned long tabl_index;
+ unsigned char instr_asmsrc[80];
+ unsigned long arg_reg[0x0f];
+ unsigned long immediate;
+ unsigned long displacement;
+ unsigned long address;
+ unsigned long cond_code;
+ unsigned long ctrl_code;
+ unsigned long flags;
+ unsigned long interrupts;
+} instr_data_s;
+
+
+static char *codes[16] =
+{
+ "f",
+ "lt",
+ "le",
+ "ule",
+ "ov/pe",
+ "mi",
+ "eq",
+ "c/ult",
+ "t",
+ "ge",
+ "gt",
+ "ugt",
+ "nov/po",
+ "pl",
+ "ne",
+ "nc/uge"
+};
+
+
+int print_insn_z8k(addr, in_buf, stream)
+unsigned long addr;
+unsigned char *in_buf;
+FILE *stream;
+{
+ instr_data_s instr_data;
+
+ fetch_instr( &in_buf, &instr_data );
+ if ( lookup_instr( &instr_data ))
+ {
+ fetch_data( &in_buf, &instr_data );
+ unpack_instr( &instr_data );
+ unparse_instr( &instr_data );
+ output_instr( &instr_data, addr, stream );
+ return instr_data.bytes_fetched;
+ }
+ else {
+ fprintf(stream,".word %02x%02x", in_buf[0], in_buf[1]);
+ return 2;
+ }
+
+}
+
+
+static void fetch_data( in_buf, instr_data )
+unsigned char **in_buf;
+instr_data_s *instr_data;
+{
+ int bytes_2fetch;
+
+ bytes_2fetch = z8k_table[instr_data->tabl_index].length -
+ instr_data->bytes_fetched;
+ while( bytes_2fetch-- )
+ instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
+}
+
+static void fetch_instr( in_buf, instr_data )
+unsigned char **in_buf;
+instr_data_s *instr_data;
+{
+ unsigned int loop = 2;
+
+ instr_data->bytes_fetched = 0;
+ while( loop-- )
+ instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
+
+}
+
+static unsigned long get_val( instr_buf, start_nibl, nibls_long )
+unsigned char (*instr_buf)[];
+unsigned int start_nibl, nibls_long;
+{
+ unsigned long ret_val;
+ unsigned char byte_val, nibl_val;
+ unsigned int nibl_index, nibl_lim;
+ unsigned int byte_index;
+ unsigned int which_nibl;
+
+ ret_val = 0;
+ nibl_lim = start_nibl + nibls_long;
+ for( nibl_index = start_nibl; nibl_index < nibl_lim; nibl_index++ )
+ {
+ byte_index = nibl_index / 2;
+ which_nibl = nibl_index % 2;
+ switch( which_nibl )
+ {
+ case 0:
+ byte_val = (*instr_buf)[byte_index];
+ nibl_val = (byte_val >> 4) & 0x0f;
+ break;
+ case 1:
+ nibl_val = byte_val & 0x0f;
+ break;
+ }
+ ret_val = (ret_val << 4) | nibl_val;
+ }
+
+ return ret_val;
+
+}
+
+static int is_segmented()
+{
+ return 1;
+}
+
+static
+int lookup_instr( instr_data )
+instr_data_s *instr_data;
+{
+
+ int nibl_index, tabl_index;
+ int tablent_found, nibl_matched;
+ unsigned short instr_nibl;
+ unsigned short tabl_datum, datum_class, datum_value;
+
+ nibl_matched = 0;
+ tabl_index = 0;
+ while( ! nibl_matched && z8k_table[tabl_index].name)
+ {
+ nibl_matched = 1;
+ for( nibl_index = 0; nibl_index < 4 && nibl_matched; nibl_index++ )
+ {
+ instr_nibl = get_val( instr_data->instr_buf, nibl_index, 1 );
+
+ tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
+ datum_class = tabl_datum & CLASS_MASK;
+ datum_value = ~CLASS_MASK & tabl_datum;
+
+ switch( datum_class )
+ {
+ case CLASS_BIT:
+ if( datum_value != instr_nibl ) nibl_matched = 0;
+ break;
+ case CLASS_00II:
+ if( ! ((~instr_nibl) & 0x4) ) nibl_matched = 0;
+ break;
+ case CLASS_01II:
+ if( ! (instr_nibl & 0x4) ) nibl_matched = 0;
+ break;
+ case CLASS_0CCC:
+ if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
+ break;
+ case CLASS_1CCC:
+ if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
+ break;
+ case CLASS_0DISP7:
+ if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
+ nibl_index += 1;
+ break;
+ case CLASS_1DISP7:
+ if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
+ nibl_index += 1;
+ break;
+ case CLASS_REGN0:
+ if( instr_nibl == 0 ) nibl_matched = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ tabl_index++;
+ }
+
+
+ instr_data->tabl_index = tabl_index;
+
+ return nibl_matched;
+
+}
+
+static void output_instr( instr_data, addr, stream )
+instr_data_s *instr_data;
+unsigned long addr;
+FILE *stream;
+{
+ int loop, loop_limit;
+ unsigned long word_val;
+ char tmp_str[20];
+ char out_str[100];
+
+ strcpy( out_str, "" );
+
+ loop_limit = z8k_table[instr_data->tabl_index].length / 2;
+ for( loop = 0; loop < loop_limit; loop++ )
+ {
+ word_val = get_val( instr_data->instr_buf, loop * 4, 4 );
+ sprintf( tmp_str, "%04x ", word_val );
+ strcat( out_str, tmp_str );
+ }
+
+ while( loop++ < 5 )
+ {
+ strcat( out_str, " " );
+ }
+
+ strcat( out_str, instr_data->instr_asmsrc );
+
+ fprintf( stream, "%s", out_str );
+}
+
+static void unpack_instr( instr_data )
+instr_data_s *instr_data;
+{
+ int nibl_index, word_index;
+ int nibl_count, loop;
+ unsigned short instr_nibl, instr_byte, instr_word, instr_long;
+ unsigned short tabl_datum, datum_class, datum_value;
+
+ nibl_count = 0;
+ loop = 0;
+ while( z8k_table[instr_data->tabl_index].byte_info[loop] != 0 )
+ {
+ word_index = (int) nibl_count / 4;
+ nibl_index = (int) nibl_count % 4;
+
+ switch( nibl_index )
+ {
+ case 0:
+ instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
+ instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
+ instr_word = get_val( instr_data->instr_buf, nibl_count, 4 );
+ instr_long = get_val( instr_data->instr_buf, nibl_count, 8 );
+ break;
+ case 1:
+ instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
+ break;
+ case 2:
+ instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
+ instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
+ break;
+ case 3:
+ instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
+ break;
+ default:
+ break;
+ }
+
+ tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
+ datum_class = tabl_datum & CLASS_MASK;
+ datum_value = tabl_datum & ~CLASS_MASK;
+
+ switch( datum_class )
+ {
+ case CLASS_X:
+ instr_data->address = instr_nibl;
+ break;
+ case CLASS_BA:
+ instr_data->displacement = instr_nibl;
+ break;
+ case CLASS_BX:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_DISP:
+ switch( datum_value )
+ {
+ case ARG_DISP16:
+ instr_data->displacement = instr_word;
+ nibl_count += 3;
+ break;
+ case ARG_DISP12:
+ instr_data->displacement = instr_word & 0x0fff;
+ nibl_count += 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case CLASS_IMM:
+ switch( datum_value )
+ {
+ case ARG_IMM4:
+ instr_data->immediate = instr_nibl;
+ break;
+ case ARG_IMM8:
+ instr_data->immediate = instr_byte;
+ nibl_count += 1;
+ break;
+ case ARG_IMM16:
+ instr_data->immediate = instr_word;
+ nibl_count += 3;
+ break;
+ case ARG_IMM32:
+ instr_data->immediate = instr_long;
+ nibl_count += 7;
+ break;
+ case ARG_IMMN:
+ instr_data->immediate = instr_nibl -1;
+ break;
+ /* ????? */
+ /* missing ARG_IMMNMINUS1 */
+ case ARG_IMM_1:
+ instr_data->immediate = 1;
+ break;
+ case ARG_IMM_2:
+ instr_data->immediate = 2;
+ break;
+ case ARG_NIM16:
+ instr_data->immediate = (- instr_word);
+ nibl_count += 3;
+ break;
+ case ARG_IMM2:
+ instr_data->immediate = instr_nibl & 0x3;
+ break;
+ default:
+ break;
+ }
+ break;
+ case CLASS_CC:
+ instr_data->cond_code = instr_nibl;
+ break;
+ case CLASS_CTRL:
+ instr_data->ctrl_code = instr_nibl;
+ break;
+ case CLASS_DA:
+ case CLASS_ADDRESS:
+ if( is_segmented() )
+ {
+ if( instr_nibl & 0x8 )
+ {
+ instr_data->address = ((instr_word & 0x7f00) << 8) +
+ (instr_long & 0xffff);
+ nibl_count += 7;
+ }
+ else
+ {
+ instr_data->address = ((instr_word & 0x7f00) << 8) +
+ (instr_word & 0x00ff);
+ nibl_count += 3;
+ }
+ }
+ else
+ {
+ instr_data->address = instr_word;
+ nibl_count += 3;
+ }
+ break;
+ case CLASS_0CCC:
+ instr_data->cond_code = instr_nibl & 0x7;
+ break;
+ case CLASS_1CCC:
+ instr_data->cond_code = instr_nibl & 0x7;
+ break;
+ case CLASS_0DISP7:
+ instr_data->displacement = instr_byte & 0x7f;
+ nibl_count += 1;
+ break;
+ case CLASS_1DISP7:
+ instr_data->displacement = instr_byte & 0x7f;
+ nibl_count += 1;
+ break;
+ case CLASS_01II:
+ instr_data->interrupts = instr_nibl & 0x3;
+ break;
+ case CLASS_00II:
+ instr_data->interrupts = instr_nibl & 0x3;
+ break;
+ case CLASS_BIT:
+ /* do nothing */
+ break;
+ case CLASS_IR:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_FLAGS:
+ instr_data->flags = instr_nibl;
+ break;
+ case CLASS_REG:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_BYTE:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_WORD:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_QUAD:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_LONG:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REGN0:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ default:
+ break;
+ }
+
+ loop += 1;
+ nibl_count += 1;
+ }
+}
+
+static void unparse_instr( instr_data )
+instr_data_s *instr_data;
+{
+ unsigned short tabl_datum, datum_class, datum_value;
+ int loop, loop_limit;
+ char out_str[80], tmp_str[25];
+
+ sprintf( out_str, "\t%-10s", z8k_table[instr_data->tabl_index].name );
+
+ loop_limit = z8k_table[instr_data->tabl_index].noperands;
+ for( loop = 0; loop < loop_limit; loop++ )
+ {
+ if( loop )
+ strcat( out_str, "," );
+
+ tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
+ datum_class = tabl_datum & CLASS_MASK;
+ datum_value = tabl_datum & ~CLASS_MASK;
+
+ switch( datum_class )
+ {
+ case CLASS_X:
+ sprintf( tmp_str, "0x%0x(R%d)", instr_data->address,
+ instr_data->arg_reg[datum_value] );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_BA:
+ sprintf( tmp_str, "r%d(#%x)", instr_data->arg_reg[datum_value],
+ instr_data->displacement);
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_BX:
+ sprintf( tmp_str, "r%d(R%d)", instr_data->arg_reg[datum_value],
+ instr_data->arg_reg[ARG_RX] );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_DISP:
+ sprintf( tmp_str, "#0x%0x", instr_data->displacement );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_IMM:
+ sprintf( tmp_str, "#0x%0x", instr_data->immediate );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_CC:
+ sprintf( tmp_str, "%s", codes[instr_data->cond_code] );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_CTRL:
+ sprintf( tmp_str, "0x%0x", instr_data->ctrl_code );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_DA:
+ case CLASS_ADDRESS:
+ sprintf( tmp_str, "#0x%0x", instr_data->address );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_IR:
+ sprintf( tmp_str, "@R%d", instr_data->arg_reg[datum_value] );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_FLAGS:
+ sprintf( tmp_str, "0x%0x", instr_data->flags );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_REG_BYTE:
+ if( instr_data->arg_reg[datum_value] >= 0x8 )
+ {
+ sprintf( tmp_str, "rl%d",
+ instr_data->arg_reg[datum_value] - 0x8 );
+ }
+ else
+ {
+ sprintf( tmp_str, "rh%d", instr_data->arg_reg[datum_value] );
+ }
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_REG_WORD:
+ sprintf( tmp_str, "r%d", instr_data->arg_reg[datum_value] );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_REG_QUAD:
+ sprintf( tmp_str, "rq%d", instr_data->arg_reg[datum_value] );
+ strcat( out_str, tmp_str );
+ break;
+ case CLASS_REG_LONG:
+ sprintf( tmp_str, "rr%d", instr_data->arg_reg[datum_value] );
+ strcat( out_str, tmp_str );
+ break;
+ default:
+ break;
+ }
+ }
+
+ strcpy( instr_data->instr_asmsrc, out_str );
+}