#include #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; 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 ); }