mirror of
https://github.com/pevans/erc-c.git
synced 2025-01-03 00:29:38 +00:00
Disassembler now outputs more idiomatic code
It also no longer prints out register and address state
This commit is contained in:
parent
0d1e22a348
commit
395ac4a841
@ -30,15 +30,9 @@
|
||||
#include "mos6502.dis.h"
|
||||
#include "mos6502.enums.h"
|
||||
|
||||
static char s_inst[4],
|
||||
s_addr[5],
|
||||
s_oper[10],
|
||||
s_value[3],
|
||||
s_label[13],
|
||||
s_state[63],
|
||||
s_bytes[12];
|
||||
|
||||
static vm_8bit jump_table[MOS6502_MEMSIZE];
|
||||
static char s_bytes[9],
|
||||
s_inst[4],
|
||||
s_operand[11];
|
||||
|
||||
static char *instruction_strings[] = {
|
||||
"ADC",
|
||||
@ -127,7 +121,6 @@ mos6502_dis_operand(mos6502 *cpu,
|
||||
vm_16bit value)
|
||||
{
|
||||
int rel_address;
|
||||
int ind_address;
|
||||
vm_8bit eff_value = 0;
|
||||
mos6502_address_resolver resolv;
|
||||
|
||||
@ -141,41 +134,27 @@ mos6502_dis_operand(mos6502 *cpu,
|
||||
break;
|
||||
case ABS:
|
||||
snprintf(str, len, "$%04X", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case ABX:
|
||||
snprintf(str, len, "$%04X,X", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case ABY:
|
||||
snprintf(str, len, "$%04X,Y", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case IMM:
|
||||
snprintf(str, len, "#$%02X", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case IMP:
|
||||
snprintf(s_value, sizeof(s_value), "%02x", 0);
|
||||
snprintf(str, len, "");
|
||||
break;
|
||||
case IND:
|
||||
ind_address = mos6502_get(cpu, value + 1) << 8;
|
||||
ind_address |= mos6502_get(cpu, value);
|
||||
if (jump_table[ind_address]) {
|
||||
mos6502_dis_label(str, len, ind_address);
|
||||
snprintf(s_value, sizeof(s_value), "%02X", 0);
|
||||
} else {
|
||||
snprintf(str, len, "($%04X)", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
}
|
||||
snprintf(str, len, "($%04X)", value);
|
||||
break;
|
||||
case IDX:
|
||||
snprintf(str, len, "($%02X,X)", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case IDY:
|
||||
snprintf(str, len, "($%02X),Y", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case REL:
|
||||
rel_address = address + value;
|
||||
@ -183,26 +162,20 @@ mos6502_dis_operand(mos6502 *cpu,
|
||||
rel_address -= 256;
|
||||
}
|
||||
|
||||
mos6502_dis_label(str, len, rel_address);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
snprintf(str, len, "<%04x>", rel_address);
|
||||
break;
|
||||
case ZPG:
|
||||
// We add a couple of spaces here to help our output
|
||||
// comments line up.
|
||||
snprintf(str, len, "$%02X", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case ZPX:
|
||||
snprintf(str, len, "$%02X,X", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
case ZPY:
|
||||
snprintf(str, len, "$%02X,Y", value);
|
||||
snprintf(s_value, sizeof(s_value), "%02x", eff_value);
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(s_addr, sizeof(s_addr), "%04x", cpu->eff_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -324,77 +297,34 @@ mos6502_dis_opcode(mos6502 *cpu, FILE *stream, int address)
|
||||
break;
|
||||
}
|
||||
|
||||
// If the stream is NULL, we're doing some kind of lookahead.
|
||||
// Furthermore, if this is an instruction that would switch control
|
||||
// to a different spot in the program, then let's label this in the
|
||||
// jump table.
|
||||
if (stream == NULL && mos6502_would_jump(inst_code)) {
|
||||
mos6502_dis_jump_label(cpu, operand, address, addr_mode);
|
||||
}
|
||||
|
||||
// It's totally possible that we are not expected to print out the
|
||||
// contents of our inspection of the opcode. (For example, we may
|
||||
// just want to set the jump table in a lookahead operation.)
|
||||
if (stream) {
|
||||
s_label[0] = '\0';
|
||||
s_oper[0] = '\0';
|
||||
s_value[0] = '\0';
|
||||
|
||||
// Hey! We might have a label at this position in the code. If
|
||||
// so, let's print out the label.
|
||||
if (jump_table[address]) {
|
||||
// This will print out just the label itself.
|
||||
mos6502_dis_label(s_label, sizeof(s_label) - 3, address);
|
||||
|
||||
// But to actually define the label, we need a colon to
|
||||
// complete the notation. (We don't _need_ a newline, but it
|
||||
// looks nicer to my arbitrary sensibilities. Don't @ me!)
|
||||
snprintf(s_label + 9, sizeof(s_label) - 9, ":\n");
|
||||
}
|
||||
|
||||
// Print out the instruction code that our opcode represents.
|
||||
mos6502_dis_instruction(s_inst, sizeof(s_inst), inst_code);
|
||||
|
||||
if (expected) {
|
||||
// Print out the operand given the proper address mode.
|
||||
mos6502_dis_operand(cpu, s_oper, sizeof(s_oper), address, addr_mode, operand);
|
||||
mos6502_dis_operand(cpu, s_operand, sizeof(s_operand),
|
||||
address, addr_mode, operand);
|
||||
}
|
||||
|
||||
// Here we just want to show a few pieces of information; one,
|
||||
// what the PC was at the point of this opcode sequence; two,
|
||||
// the opcode;
|
||||
snprintf(s_state, sizeof(s_state) - 1,
|
||||
"pc:%02x%02x cy:%02d addr:%4s val:%2s a:%02x x:%02x y:%02x p:%c%c-%c%c%c%c s:%02x",
|
||||
cpu->PC >> 8, cpu->PC & 0xff,
|
||||
mos6502_cycles(cpu, opcode), s_addr, s_value,
|
||||
cpu->A, cpu->X, cpu->Y,
|
||||
cpu->P & MOS_NEGATIVE ? 'N' : 'n',
|
||||
cpu->P & MOS_OVERFLOW ? 'O' : 'o',
|
||||
cpu->P & MOS_DECIMAL ? 'D' : 'd',
|
||||
cpu->P & MOS_INTERRUPT ? 'I' : 'i',
|
||||
cpu->P & MOS_ZERO ? 'Z' : 'z',
|
||||
cpu->P & MOS_CARRY ? 'C' : 'c',
|
||||
cpu->S);
|
||||
|
||||
// And three, the operand, if any. Remembering that the operand
|
||||
// should be shown in little-endian order.
|
||||
if (expected == 2) {
|
||||
snprintf(s_bytes, sizeof(s_bytes) - 1, "%02x %02x %02x",
|
||||
snprintf(s_bytes, sizeof(s_bytes) - 1, "%02X %02X %02X",
|
||||
opcode, operand & 0xff, operand >> 8);
|
||||
} else if (expected == 1) {
|
||||
snprintf(s_bytes, sizeof(s_bytes) - 1, "%02x %02x",
|
||||
snprintf(s_bytes, sizeof(s_bytes) - 1, "%02X %02X",
|
||||
opcode, operand & 0xff);
|
||||
} else {
|
||||
snprintf(s_bytes, sizeof(s_bytes) - 1, "%02x", opcode);
|
||||
snprintf(s_bytes, sizeof(s_bytes) - 1, "%02X", opcode);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stream, "%s %4s %-9s ; %-60s | %s\n",
|
||||
s_label, s_inst, s_oper, s_state, s_bytes);
|
||||
|
||||
if (mos6502_would_jump(inst_code)) {
|
||||
fprintf(stream, ";;;\n\n");
|
||||
}
|
||||
fprintf(stream, "%04X:%-9s%20s %s\n",
|
||||
cpu->PC, s_bytes, s_inst, s_operand);
|
||||
|
||||
// The expected number of bytes here is for the operand, but we need
|
||||
// to add one for the opcode to return the true number that this
|
||||
@ -413,80 +343,3 @@ mos6502_dis_scan(mos6502 *cpu, FILE *stream, int pos, int end)
|
||||
pos += mos6502_dis_opcode(cpu, stream, pos);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Associate a label with a given address or operand, depending on the
|
||||
* address mode. For example, with REL, the jump label will be based on
|
||||
* the address but added to or subtracted with the operand. Whereas in
|
||||
* IND, the address is wholly dependent on the operand.
|
||||
*/
|
||||
void
|
||||
mos6502_dis_jump_label(mos6502 *cpu,
|
||||
vm_16bit operand,
|
||||
int address,
|
||||
int addr_mode)
|
||||
{
|
||||
int jump_loc;
|
||||
|
||||
switch (addr_mode) {
|
||||
case ABS:
|
||||
jump_loc = operand;
|
||||
break;
|
||||
|
||||
// With indirect address mode, the address we want to jump to is
|
||||
// not the literal operand, but a 16-bit address that is
|
||||
// _pointed to_ by the address represented by the operand. Think
|
||||
// of the operand as a kind of double pointer, or just re-watch
|
||||
// Inception.
|
||||
case IND:
|
||||
jump_loc = mos6502_get(cpu, operand + 1) << 8;
|
||||
jump_loc |= mos6502_get(cpu, operand);
|
||||
break;
|
||||
|
||||
// In relative address mode, the jump location will be a
|
||||
// number -- well -- relative to the address. If the 8th bit
|
||||
// of the operand is 1, then we treat the number as a
|
||||
// negative; otherwise, positive or zero.
|
||||
case REL:
|
||||
jump_loc = address + operand;
|
||||
|
||||
if (operand > 127) {
|
||||
jump_loc -= 256;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
jump_table[jump_loc] = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the form of our label to the given file stream. This is
|
||||
* fairly dumb; it'll print out whatever address you give to it.
|
||||
*/
|
||||
inline void
|
||||
mos6502_dis_label(char *str, int len, int address)
|
||||
{
|
||||
snprintf(str, len, "ADDR_%04x", address);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the previously-set label in the jump table for a given
|
||||
* address.
|
||||
*/
|
||||
inline void
|
||||
mos6502_dis_jump_unlabel(int address)
|
||||
{
|
||||
jump_table[address] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the given address has a jump label associated with it.
|
||||
*/
|
||||
inline bool
|
||||
mos6502_dis_is_jump_label(int address)
|
||||
{
|
||||
return jump_table[address] == 1;
|
||||
}
|
||||
|
@ -91,12 +91,6 @@ Test(mos6502_dis, operand)
|
||||
// jump-labeled version.
|
||||
mos6502_dis_operand(cpu, buf, sizeof(buf), 0, IND, 0x1234);
|
||||
assert_buf("($1234)");
|
||||
mos6502_dis_jump_label(cpu, 0x1234, 0, IND);
|
||||
mos6502_dis_operand(cpu, buf, sizeof(buf), 0, IND, 0x1234);
|
||||
assert_buf("ADDR_3448");
|
||||
|
||||
// Let's undo our label above...
|
||||
mos6502_dis_jump_unlabel(0x1234);
|
||||
|
||||
mos6502_dis_operand(cpu, buf, sizeof(buf), 0, IDX, 0x12);
|
||||
assert_buf("($12,X)");
|
||||
@ -241,37 +235,3 @@ Test(mos6502_dis, scan)
|
||||
";;;\n\n"
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* These tests are all contained within the jump_label test below.
|
||||
* Test(mos6502_dis, jump_unlabel)
|
||||
* Test(mos6502_dis, is_jump_label)
|
||||
*/
|
||||
Test(mos6502_dis, jump_label)
|
||||
{
|
||||
cr_assert_eq(mos6502_dis_is_jump_label(123), false);
|
||||
|
||||
mos6502_set(cpu, 123, 5);
|
||||
mos6502_set(cpu, 124, 0);
|
||||
|
||||
mos6502_dis_jump_label(cpu, 123, 0, IND);
|
||||
cr_assert_eq(mos6502_dis_is_jump_label(5), true);
|
||||
mos6502_dis_jump_unlabel(123);
|
||||
cr_assert_eq(mos6502_dis_is_jump_label(123), false);
|
||||
|
||||
// Testing forward relative
|
||||
mos6502_dis_jump_label(cpu, 123, 10, REL);
|
||||
cr_assert_eq(mos6502_dis_is_jump_label(123 + 10), true);
|
||||
mos6502_dis_jump_unlabel(123 + 10);
|
||||
|
||||
// Testing backward relative
|
||||
mos6502_dis_jump_label(cpu, 133, 1000, REL);
|
||||
cr_assert_eq(mos6502_dis_is_jump_label(133 + 1000 - 256), true);
|
||||
mos6502_dis_jump_unlabel(133 + 1000 - 256);
|
||||
}
|
||||
|
||||
Test(mos6502_dis, label)
|
||||
{
|
||||
mos6502_dis_label(buf, sizeof(buf) - 1, 123);
|
||||
assert_buf("ADDR_007b");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user