disasm: treat calls and branches differently for state tracking purposes

This commit is contained in:
Devin Acker 2021-08-15 19:41:01 -04:00
parent a632b50acc
commit c593fd0b96
8 changed files with 40 additions and 28 deletions

View file

@ -77,11 +77,13 @@ void SGBDebugger::disassemble_opcode_ex(SGBDebugger::Opcode &opcode, uint24 addr
case 0x18: case 0xc3: case 0xe9:
opcode.flags |= Opcode::FLAG_BRA; break;
case 0x20: case 0x28: case 0x30: case 0x38:
case 0xc2: case 0xc4: case 0xc7: case 0xcc:
case 0xcd: case 0xcf: case 0xd4: case 0xd7:
case 0xdc: case 0xdf: case 0xe7: case 0xef:
case 0xf7: case 0xff:
case 0xc2: case 0xca: case 0xd2: case 0xda:
opcode.flags |= Opcode::FLAG_BRA_CONTINUE; break;
case 0xc4: case 0xc7: case 0xcc: case 0xcd:
case 0xcf: case 0xd4: case 0xd7: case 0xdc:
case 0xdf: case 0xe7: case 0xef: case 0xf7:
case 0xff:
opcode.flags |= Opcode::FLAG_CALL; break;
case 0xc9: case 0xd9:
opcode.flags |= Opcode::FLAG_RETURN; break;
case 0xf1:

View file

@ -5,7 +5,8 @@ struct Opcode {
FLAG_INDIRECT = 0x04, // indirect memory accesses
FLAG_PUSH_F = 0x10, // pushes flags
FLAG_POP_F = 0x20, // pops flags
FLAG_RETURN = 0x40, // returns from call (unconditionally)
FLAG_CALL = 0x40, // performs call
FLAG_RETURN = 0x80, // returns from call (unconditionally)
};
void set(uint16 flags, uint8 optype1, uint8 optype2, const char *opcode, uint8 (&param)[3], uint8 paramsize=0) {
@ -29,6 +30,7 @@ struct Opcode {
inline bool isIndirect() const { return flags & FLAG_INDIRECT; }
inline bool pushesF() const { return flags & FLAG_PUSH_F; }
inline bool popsF() const { return flags & FLAG_POP_F; }
inline bool isCall() const { return flags & FLAG_CALL; }
inline bool returns() const { return flags & FLAG_RETURN; }
uint8 op() {

View file

@ -124,10 +124,12 @@ void CPUcore::disassemble_opcode_ex(CPUcore::Opcode &opcode, uint32 addr, bool e
opcode.flags |= Opcode::FLAG_BRK; break;
case 0x08:
opcode.flags |= Opcode::FLAG_PUSH_P; break;
case 0x10: case 0x20: case 0x22: case 0x30:
case 0x50: case 0x70: case 0x90: case 0xb0:
case 0xd0: case 0xf0: case 0xfc:
case 0x10: case 0x30: case 0x50: case 0x70:
case 0x90: case 0xb0: case 0xd0: case 0xf0:
case 0xfc:
opcode.flags |= Opcode::FLAG_BRA_CONTINUE; break;
case 0x20: case 0x22:
opcode.flags |= Opcode::FLAG_CALL; break;
case 0x28:
opcode.flags |= Opcode::FLAG_POP_P; break;
case 0x40: case 0x60: case 0x6b:

View file

@ -9,7 +9,8 @@ struct Opcode {
FLAG_SET_X = 0x80, // sets X flag
FLAG_PUSH_P = 0x100, // pushes flags
FLAG_POP_P = 0x200, // pops flags
FLAG_RETURN = 0x400, // returns from call
FLAG_CALL = 0x400, // performs call
FLAG_RETURN = 0x800, // returns from call
FLAG_BRK = 0x1000, // software interrupt
FLAG_HALT = 0x2000, // STP
FLAG_RESET_E = 0x8000 // modifies E flag
@ -40,6 +41,7 @@ struct Opcode {
inline bool popsP() const { return flags & FLAG_POP_P; }
inline bool breaks() const { return flags & FLAG_BRK; }
inline bool halts() const { return flags & FLAG_HALT; }
inline bool isCall() const { return flags & FLAG_CALL; }
inline bool returns() const { return flags & FLAG_RETURN; }
uint8 op8(unsigned index = 0) {

View file

@ -65,8 +65,13 @@ uint32_t CPUAnalyst::performAnalysis(uint32_t address, CPUAnalystState &state, b
break;
}
if (op.isBraWithContinue() && !op.isIndirect()) {
if (op.isCall()) {
// analyze the call target, preserving any state changes inside the subroutine
numRoutines += performAnalysis(core.decode(op.optype, op.opall(), address), state);
} else if (op.isBraWithContinue() && !op.isIndirect()) {
// analyze the branch target, not preserving any state changes from when the branch is taken
CPUAnalystState tempState(state);
numRoutines += performAnalysis(core.decode(op.optype, op.opall(), address), tempState);
}
if (op.isBra() && !op.isIndirect()) {

View file

@ -92,23 +92,20 @@ void SMPcore::disassemble_opcode_ex(SMPcore::Opcode &opcode, uint16 addr) {
opcode.set(0, op.mode, op.name, param, SNESSMP::getOpcodeLength(param[0]) - 1);
switch (param[0]) {
case 0x01: case 0x04:
case 0x10: case 0x11: case 0x13:
case 0x21: case 0x23: case 0x2e:
case 0x30: case 0x31: case 0x33: case 0x3f:
case 0x41: case 0x43: case 0x4f:
case 0x50: case 0x51: case 0x53:
case 0x61: case 0x63: case 0x6e:
case 0x70: case 0x71: case 0x73:
case 0x81: case 0x83:
case 0x90: case 0x91: case 0x93:
case 0xa1: case 0xa3:
case 0xb0: case 0xb1: case 0xb3:
case 0xc1: case 0xc3:
case 0xd0: case 0xd1: case 0xd3: case 0xde:
case 0xe1: case 0xe3:
case 0xf0: case 0xf1: case 0xf3: case 0xfe:
case 0x04: case 0x10: case 0x13: case 0x23:
case 0x2e: case 0x30: case 0x33: case 0x43:
case 0x50: case 0x53: case 0x63: case 0x6e:
case 0x70: case 0x73: case 0x83: case 0x90:
case 0x93: case 0xa3: case 0xb0: case 0xb3:
case 0xc3: case 0xd0: case 0xd3: case 0xde:
case 0xe3: case 0xf0: case 0xf3: case 0xfe:
opcode.flags |= Opcode::FLAG_BRA_CONTINUE; break;
case 0x01: case 0x11: case 0x21: case 0x31:
case 0x3f: case 0x41: case 0x4f: case 0x51:
case 0x61: case 0x71: case 0x81: case 0x91:
case 0xa1: case 0xb1: case 0xc1: case 0xd1:
case 0xe1: case 0xf1:
opcode.flags |= Opcode::FLAG_CALL; break;
case 0x0d:
opcode.flags |= Opcode::FLAG_PUSH_P; break;
case 0x0f:

View file

@ -7,7 +7,8 @@ struct Opcode {
FLAG_SET_P = 0x20, // sets P flag
FLAG_PUSH_P = 0x100, // pushes flags
FLAG_POP_P = 0x200, // pops flags
FLAG_RETURN = 0x400, // returns from call
FLAG_CALL = 0x400, // performs call
FLAG_RETURN = 0x800, // returns from call
FLAG_BRK = 0x1000, // software interrupt
FLAG_HALT = 0x2000, // sleep/stop
};
@ -36,6 +37,7 @@ struct Opcode {
inline bool popsP() const { return flags & FLAG_POP_P; }
inline bool breaks() const { return flags & FLAG_BRK; }
inline bool halts() const { return flags & FLAG_HALT; }
inline bool isCall() const { return flags & FLAG_CALL; }
inline bool returns() const { return flags & FLAG_RETURN; }
uint8 op() {

View file

@ -276,7 +276,7 @@ void SgbDisasmProcessor::analyze(uint32_t address) {
SNES::supergameboy.usage(address) |= SNES::SGBDebugger::UsageOpcode;
SNES::supergameboy.disassemble_opcode_ex(op, address);
if (op.isBraWithContinue() && !op.isIndirect()) {
if (op.isCall() || (op.isBraWithContinue() && !op.isIndirect())) {
uint32_t target = decode(op, address);
if (usage(target) == 0) {
// hack: if jumping from fixed to swappable ROM bank, don't continue