Browse Source

Simplify and fix index bit instructions in disassembler.

master
Ben Kurtovic 8 years ago
parent
commit
c14ad04c48
3 changed files with 115 additions and 66 deletions
  1. +83
    -58
      src/disassembler/arguments.c
  2. +1
    -1
      src/disassembler/mnemonics.c
  3. +31
    -7
      src/z80_ops.inc.c

+ 83
- 58
src/disassembler/arguments.c View File

@@ -9,6 +9,8 @@


#define MAX_ARG_SIZE 256 #define MAX_ARG_SIZE 256


/* Internal structs, enums, etc. */

typedef enum { typedef enum {
AT_NONE = 0, AT_NONE = 0,
/* Register */ /* Register */
@@ -28,6 +30,15 @@ typedef enum {
AT_PORT_C, AT_PORT_IM, AT_PORT_0 AT_PORT_C, AT_PORT_IM, AT_PORT_0
} ArgType; } ArgType;


typedef ArgType ArgTable[3][256];

typedef struct {
uint8_t index, opcode, arg1, arg2;
ArgTable *table;
} Instr;

/* Temporary aliases to make table definitions concise */

#define __ AT_NONE #define __ AT_NONE
#define A_ AT_REG_A #define A_ AT_REG_A
#define B_ AT_REG_B #define B_ AT_REG_B
@@ -72,7 +83,9 @@ typedef enum {
#define PM AT_PORT_IM #define PM AT_PORT_IM
#define R0 AT_PORT_0 #define R0 AT_PORT_0


static ArgType instr_args[3][256] = {
/* Argument tables */

static ArgTable instr_args = {
{ {
__, BC, NB, BC, B_, B_, B_, __, AF, HL, A_, BC, C_, C_, C_, __, __, BC, NB, BC, B_, B_, B_, __, AF, HL, A_, BC, C_, C_, C_, __,
ML, DE, ND, DE, D_, D_, D_, __, ML, HL, A_, DE, E_, E_, E_, __, ML, DE, ND, DE, D_, D_, D_, __, ML, HL, A_, DE, E_, E_, E_, __,
@@ -112,7 +125,7 @@ static ArgType instr_args[3][256] = {
{ __ } { __ }
}; };


static ArgType instr_args_extended[3][256] = {
static ArgTable instr_args_extended = {
{ {
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
@@ -152,7 +165,7 @@ static ArgType instr_args_extended[3][256] = {
{ __ } { __ }
}; };


static ArgType instr_args_bits[3][256] = {
static ArgTable instr_args_bits = {
{ {
B_, C_, D_, E_, H_, L_, NH, A_, B_, C_, D_, E_, H_, L_, NH, A_, B_, C_, D_, E_, H_, L_, NH, A_, B_, C_, D_, E_, H_, L_, NH, A_,
B_, C_, D_, E_, H_, L_, NH, A_, B_, C_, D_, E_, H_, L_, NH, A_, B_, C_, D_, E_, H_, L_, NH, A_, B_, C_, D_, E_, H_, L_, NH, A_,
@@ -192,7 +205,7 @@ static ArgType instr_args_bits[3][256] = {
{ __ } { __ }
}; };


static ArgType instr_args_index[3][256] = {
static ArgTable instr_args_index = {
{ {
__, __, __, __, __, __, __, __, __, XY, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, XY, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, XY, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, XY, __, __, __, __, __, __,
@@ -232,7 +245,7 @@ static ArgType instr_args_index[3][256] = {
{ __ } { __ }
}; };


static ArgType instr_args_index_bits[3][256] = {
static ArgTable instr_args_index_bits = {
{ {
II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II,
II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II, II,
@@ -289,6 +302,8 @@ static ArgType instr_args_index_bits[3][256] = {
} }
}; };


/* Remove temporary aliases */

#undef __ #undef __
#undef A_ #undef A_
#undef B_ #undef B_
@@ -336,52 +351,50 @@ static ArgType instr_args_index_bits[3][256] = {
/* /*
Decode an immediate argument. Decode an immediate argument.
*/ */
static void decode_immediate(
char *arg, ArgType type, const uint8_t *bytes, size_t shift)
static void decode_immediate(char *arg, Instr *instr, ArgType type)
{ {
char *format;
size_t take;
uint8_t b = bytes[shift];
uint8_t op = instr->opcode, take;
bool ix = instr->index == 0xDD;


switch (type) { switch (type) {
case AT_IMM_U16: // 16-bit immediate case AT_IMM_U16: // 16-bit immediate
sprintf(arg, "$%04X", bytes[shift + 1] + (bytes[shift + 2] << 8));
sprintf(arg, "$%04X", instr->arg1 + (instr->arg2 << 8));
break; break;
case AT_IMM_U8: // 8-bit unsigned immediate case AT_IMM_U8: // 8-bit unsigned immediate
if ((bytes[0] == 0xDD || bytes[0] == 0xFD) && bytes[1] == 0x36)
take = 2;
if (instr->index != 0x00 && op == 0x36)
take = instr->arg2;
else else
take = 1;
sprintf(arg, "$%02X", bytes[shift + take]);
take = instr->arg1;
sprintf(arg, "$%02X", take);
break; break;
case AT_IMM_REL: // 8-bit relative offset (JP and DJNZ) case AT_IMM_REL: // 8-bit relative offset (JP and DJNZ)
sprintf(arg, "%hhd", (int8_t) (bytes[shift + 1] + 2));
sprintf(arg, "%hhd", (int8_t) (instr->arg1 + 2));
break; break;
case AT_IMM_BIT: // Bit position case AT_IMM_BIT: // Bit position
sprintf(arg, "%d", (b & 0x38) >> 3);
sprintf(arg, "%d", (op & 0x38) >> 3);
break; break;
case AT_IMM_RST: // Reset case AT_IMM_RST: // Reset
sprintf(arg, "$%02X", b & 0x38);
sprintf(arg, "$%02X", op & 0x38);
break; break;
case AT_IMM_IM: // Interrupt mode case AT_IMM_IM: // Interrupt mode
sprintf(arg, "%d", !(b & (1 << 4)) ? 0 : !(b & (1 << 3)) ? 1 : 2);
sprintf(arg, "%d", !(op & (1 << 4)) ? 0 : !(op & (1 << 3)) ? 1 : 2);
break; break;
case AT_IDR_IMM: // Indirect immediate case AT_IDR_IMM: // Indirect immediate
sprintf(arg, "($%04X)", bytes[shift + 1] + (bytes[shift + 2] << 8));
sprintf(arg, "($%04X)", instr->arg1 + (instr->arg2 << 8));
break; break;
case AT_IX_IY: // Indexed offset case AT_IX_IY: // Indexed offset
if (bytes[shift + 1]) {
format = bytes[0] == 0xDD ? "(ix%+hhd)" : "(iy%+hhd)";
sprintf(arg, format, (int8_t) bytes[shift + 1]);
if (instr->arg1) {
char *format = ix ? "(ix%+hhd)" : "(iy%+hhd)";
sprintf(arg, format, (int8_t) instr->arg1);
} else { } else {
sprintf(arg, bytes[0] == 0xDD ? "(ix)" : "(iy)");
sprintf(arg, ix ? "(ix)" : "(iy)");
} }
break; break;
case AT_PORT_IM: // Immediate port case AT_PORT_IM: // Immediate port
sprintf(arg, "($%02X)", bytes[shift + 1]);
sprintf(arg, "($%02X)", instr->arg1);
break; break;
default: default:
FATAL("invalid call: decode_immediate(arg, %d, ...)", type)
FATAL("invalid call: decode_immediate(arg, ..., %d)", type)
return; return;
} }
} }
@@ -389,10 +402,10 @@ static void decode_immediate(
/* /*
Decode a single argument, given its type. Decode a single argument, given its type.
*/ */
static void decode_argument(
char *arg, ArgType type, const uint8_t *bytes, size_t shift)
static void decode_argument(char *arg, Instr *instr, ArgType type)
{ {
const char *value; const char *value;
bool ix = instr->index == 0xDD;


switch (type) { switch (type) {
case AT_NONE: case AT_NONE:
@@ -427,10 +440,10 @@ static void decode_argument(
case AT_COND_M: value = "m"; break; case AT_COND_M: value = "m"; break;
case AT_PORT_C: value = "(c)"; break; case AT_PORT_C: value = "(c)"; break;
case AT_PORT_0: value = "0"; break; case AT_PORT_0: value = "0"; break;
case AT_REG_IXY: value = (bytes[0] == 0xDD) ? "ix" : "iy"; break;
case AT_REG_IH: value = (bytes[0] == 0xDD) ? "ixh" : "iyh"; break;
case AT_REG_IL: value = (bytes[0] == 0xDD) ? "ixl" : "iyl"; break;
case AT_IDR_IXY: value = (bytes[0] == 0xDD) ? "(ix)" : "(iy)"; break;
case AT_REG_IXY: value = ix ? "ix" : "iy"; break;
case AT_REG_IH: value = ix ? "ixh" : "iyh"; break;
case AT_REG_IL: value = ix ? "ixl" : "iyl"; break;
case AT_IDR_IXY: value = ix ? "(ix)" : "(iy)"; break;
case AT_IMM_U16: case AT_IMM_U16:
case AT_IMM_U8: case AT_IMM_U8:
case AT_IMM_REL: case AT_IMM_REL:
@@ -440,40 +453,51 @@ static void decode_argument(
case AT_IDR_IMM: case AT_IDR_IMM:
case AT_IX_IY: case AT_IX_IY:
case AT_PORT_IM: case AT_PORT_IM:
decode_immediate(arg, type, bytes, shift);
decode_immediate(arg, instr, type);
return; return;
default: default:
FATAL("invalid call: decode_argument(arg, %d, ...)", type)
FATAL("invalid call: decode_argument(arg, ..., %d)", type)
return; return;
} }
strcpy(arg, value); strcpy(arg, value);
} }


/* /*
Return the appropriate argument table for the given instruction.

This function also adds the number of instruction bytes to skip to its
shift argument (corresponding to any prefix bits), so bytes[*shift] will
always be the instruction opcode.

This function return type is ridiculous, but it returns a pointer to an
array of 3 arrays of 256 ArgTypes.
Fill an Instruction object with the appropriate fields.
*/ */
static inline ArgType (*get_table_and_shift(
const uint8_t *bytes, size_t *shift))[3][256]
static inline void load_instr(Instr *instr, const uint8_t *bytes)
{ {
uint8_t b = bytes[0]; uint8_t b = bytes[0];
bool extend = b == 0xED;
bool bit = b == 0xCB;
bool index = b == 0xDD || b == 0xFD;
bool indexbit = index && bytes[1] == 0xCB;

instr->index = index ? b : 0x00;


if (b == 0xED)
return (*shift)++, &instr_args_extended;
if (b == 0xCB)
return (*shift)++, &instr_args_bits;
if (b == 0xDD || b == 0xFD) {
if (bytes[1] == 0xCB)
return (*shift) += 2, &instr_args_index_bits;
return (*shift)++, &instr_args_index;
if (indexbit) {
instr->opcode = bytes[3];
instr->arg1 = bytes[2];
} else if (extend || bit || index) {
instr->opcode = bytes[1];
instr->arg1 = bytes[2];
instr->arg2 = bytes[3];
} else {
instr->opcode = bytes[0];
instr->arg1 = bytes[1];
instr->arg2 = bytes[2];
} }
return &instr_args;

if (extend)
instr->table = &instr_args_extended;
else if (bit)
instr->table = &instr_args_bits;
else if (indexbit)
instr->table = &instr_args_index_bits;
else if (index)
instr->table = &instr_args_index;
else
instr->table = &instr_args;
} }


/* /*
@@ -484,13 +508,14 @@ static inline ArgType (*get_table_and_shift(
char* decode_arguments(const uint8_t *bytes) char* decode_arguments(const uint8_t *bytes)
{ {
char args[3][MAX_ARG_SIZE], *result; char args[3][MAX_ARG_SIZE], *result;
ArgType (*table)[3][256], type;
size_t shift = 0, i, len;
Instr instr;
ArgType type;
size_t i, len;


table = get_table_and_shift(bytes, &shift);
load_instr(&instr, bytes);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
type = (*table)[i][bytes[shift]];
decode_argument(args[i], type, bytes, shift);
type = (*instr.table)[i][instr.opcode];
decode_argument(args[i], &instr, type);
} }


if (!*args[0]) if (!*args[0])


+ 1
- 1
src/disassembler/mnemonics.c View File

@@ -158,7 +158,7 @@ char* decode_mnemonic(const uint8_t *bytes)
return instr_mnemonics_bits[bytes[1]]; return instr_mnemonics_bits[bytes[1]];
if (b == 0xDD || b == 0xFD) { if (b == 0xDD || b == 0xFD) {
if (bytes[1] == 0xCB) if (bytes[1] == 0xCB)
return instr_mnemonics_bits[bytes[2]];
return instr_mnemonics_bits[bytes[3]];
return instr_mnemonics_index[bytes[1]]; return instr_mnemonics_index[bytes[1]];
} }
return instr_mnemonics[b]; return instr_mnemonics[b];


+ 31
- 7
src/z80_ops.inc.c View File

@@ -936,17 +936,41 @@ static uint8_t z80_inst_dec_ss(Z80 *z80, uint8_t opcode)


// RLC (IXY+d) // RLC (IXY+d)


// RL m
// RL r


// RRC m
// RL (HL)


// RR m
// RL (IXY+d)


// SLA m
// RRC r


// SRA m
// RRC (HL)


// SRL m
// RRC (IXY+d)

// RR r

// RR (HL)

// RR (IXY+d)

// SLA r

// SLA (HL)

// SLA (IXY+d)

// SRA r

// SRA (HL)

// SRA (IXY+d)

// SRL r

// SRL (HL)

// SRL (IXY+d)


// RLD // RLD


@@ -1408,7 +1432,7 @@ static uint8_t z80_prefix_index(Z80 *z80, uint8_t opcode)
*/ */
static uint8_t z80_prefix_index_bits(Z80 *z80, uint8_t opcode) static uint8_t z80_prefix_index_bits(Z80 *z80, uint8_t opcode)
{ {
opcode = mmu_read_byte(z80->mmu, ++z80->regfile.pc);
opcode = mmu_read_byte(z80->mmu, z80->regfile.pc += 2);
return (*instruction_table_index_bits[opcode])(z80, opcode); return (*instruction_table_index_bits[opcode])(z80, opcode);
} }




Loading…
Cancel
Save