binutils-gdb/opcodes/z8k-dis.c

520 lines
14 KiB
C

#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;
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%s\t", 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 );
}