diff options
Diffstat (limited to 'opcodes/z8k-dis.c')
-rw-r--r-- | opcodes/z8k-dis.c | 519 |
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 ); +} |