From 5b8bf075e51fcae371c61d4f2ebe5f1c33d645c4 Mon Sep 17 00:00:00 2001 From: slack Date: Sat, 16 Aug 2008 04:36:19 +0200 Subject: [PATCH] First (somewhat) working version of wendi, the wenboi disassembler ;) --- GBRom.cc | 3 +- Makefile | 4 +- wendi/CodeBlock.cc | 2 +- wendi/CodeBlock.h | 19 +-- wendi/Instruction.cc | 52 -------- wendi/Instruction.h | 17 ++- wendi/disasm.cc | 302 +++++++++++++++++++++++++----------------- wendi/disasm.h | 1 + wendi/disasm_macros.h | 104 +++++++++------ wendi/wendi.cc | 219 ++++++++++++++++++++++++++++-- 10 files changed, 468 insertions(+), 255 deletions(-) diff --git a/GBRom.cc b/GBRom.cc index 56f5e05..466b7e6 100644 --- a/GBRom.cc +++ b/GBRom.cc @@ -8,7 +8,6 @@ using std::ifstream; using std::ios; -using std::cout; using std::endl; void log_rom_header(GBRom *rom, Logger::log_level level) @@ -62,7 +61,7 @@ GBRom *read_gbrom(std::string filename) is.seekg(0,ios::end); int length = is.tellg(); - cout << "Loading " << filename << " (length=" << length << ")" << endl; + logger.info("Loading ",filename," (length=",length,")"); is.seekg(0,ios::beg); void *buffer = ::operator new(length); diff --git a/Makefile b/Makefile index dbf4e2e..acc44d2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ #CXXFLAGS=-pg -O3 -g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast -CXXFLAGS=-pg -O3 -g -Wall -Weffc++ -Wold-style-cast \ +CXXFLAGS=-pg -g -Wall -Weffc++ -Wold-style-cast \ -Woverloaded-virtual $(shell sdl-config --cflags) LDFLAGS=-pg -g $(shell sdl-config --libs) @@ -39,7 +39,7 @@ tests/test_core: tests/test_core.cc gbcore.o MBC.o GBMemory.o GBRom.o \ wendi/CodeBlock.o: wendi/CodeBlock.cc wendi/CodeBlock.h g++ $(CXXFLAGS) -c -o $@ $< -wendi/disasm.o: wendi/disasm.cc wendi/disasm.h +wendi/disasm.o: wendi/disasm.cc wendi/disasm.h wendi/Instruction.h g++ $(CXXFLAGS) -c -o $@ $< wendi/wendi: wendi/wendi.cc wendi/CodeBlock.o wendi/disasm.o gbcore.o MBC.o \ diff --git a/wendi/CodeBlock.cc b/wendi/CodeBlock.cc index ab0dd7f..06f4698 100644 --- a/wendi/CodeBlock.cc +++ b/wendi/CodeBlock.cc @@ -37,7 +37,7 @@ void CodeBlock::add_instruction(std::string ins, int nbytes) // appends an instr end += nbytes; } -void CodeBlock::add_xref(address addr, JumpType jt) +void CodeBlock::add_xref(address addr, Instruction::InstructionType jt) { xrefs.push_back(std::make_pair(addr, jt)); } diff --git a/wendi/CodeBlock.h b/wendi/CodeBlock.h index dc43cd2..acffda5 100644 --- a/wendi/CodeBlock.h +++ b/wendi/CodeBlock.h @@ -5,27 +5,16 @@ #include #include #include +#include "Instruction.h" #include "../sized_types.h" typedef u16 address; -enum JumpType -{ - JP, - JP_CC, - JR, - CALL, - CALL_CC, - RET, - RETI, - RST, -}; - class CodeBlock { public: typedef std::pair DisassemblyItem; - typedef std::pair XrefsItem; + typedef std::pair XrefsItem; typedef std::list DisassemblyList; typedef std::vector XrefsVector; @@ -44,7 +33,9 @@ class CodeBlock int length() { return end-start; } void add_instruction(std::string ins, int nbytes); // appends an instruction to the end of the block - void add_xref(address addr, JumpType jt); + void add_xref(address addr, Instruction::InstructionType jt); + + bool operator< (const CodeBlock& other) const { return start < other.start; } }; diff --git a/wendi/Instruction.cc b/wendi/Instruction.cc index 1d75a48..8848eae 100644 --- a/wendi/Instruction.cc +++ b/wendi/Instruction.cc @@ -1,54 +1,2 @@ #include "Instruction.h" -#if 0 - // Jumps - dis_inm16(0xC3, "JP") - // JP cc, nn - dis_inm16(0xC2, "JP NZ") - dis_inm16(0xCA, "JP Z") - dis_inm16(0xD2, "JP NC") - dis_inm16(0xDA, "JP C") - case 0xE9: - result << "JP (HL)"; - opcode_str = "JP"; - op1.str="(HL)"; - op2.str=""; - op1.type = Instruction::MEM_INDIRECT; - op1.reg = Instruction::HL; - op2.type = Instruction::NONE; - break; - - dis_JR(0x18, "JR") - dis_JR(0x20, "JR NZ") - dis_JR(0x28, "JR Z") - dis_JR(0x30, "JR NC") - dis_JR(0x38, "JR C") - - // Calls - dis_inm16(0xCD, "CALL") - // CALL cc, nn - dis_inm16(0xC4, "CALL NZ") - dis_inm16(0xCC, "CALL Z") - dis_inm16(0xD4, "CALL NC") - dis_inm16(0xDC, "CALL C") - - // Restarts - dis(0xC7, "RST 0x00") - dis(0xCF, "RST 0x08") - dis(0xD7, "RST 0x10") - dis(0xDF, "RST 0x18") - dis(0xE7, "RST 0x20") - dis(0xEF, "RST 0x28") - dis(0xF7, "RST 0x30") - dis(0xFF, "RST 0x38") - - // Returns - dis(0xC9, "RET") - // RET cc - dis(0xC0, "RET NZ") - dis(0xC8, "RET Z") - dis(0xD0, "RET NC") - dis(0xD8, "RET C") - - dis(0xD9, "RETI") -#endif diff --git a/wendi/Instruction.h b/wendi/Instruction.h index 17816eb..ce463d7 100644 --- a/wendi/Instruction.h +++ b/wendi/Instruction.h @@ -1,16 +1,20 @@ #ifndef INSTRUCTION_H #define INSTRUCTION_H +#include "../sized_types.h" + struct Instruction { enum InstructionType { - JUMP, + UNCONDITIONAL_JUMP=0, + CONDITIONAL_JUMP, CALL, + RET, RESET, ALU, LOAD, - + OTHER }; enum Register { A=0,B,C,D,E,H,L,AF,BC,DE,HL,SP,PC }; @@ -35,10 +39,11 @@ struct Instruction int val; // } - Operand(): str(""), type(NONE) {} + Operand(): str(""), type(NONE), reg(A), val(-1) {} }; int length; + InstructionType type; std::string all; u8 opcode; @@ -46,8 +51,10 @@ struct Instruction std::string str; Operand op1, op2; - Instruction(int length, u8 opcode, u8 sub_opcode, std::string all, std::string opcode_str, Operand op1, Operand op2): - length(length), opcode(opcode), sub_opcode(sub_opcode),all(all), str(opcode_str), op1(op1), op2(op2) + Instruction(int length, InstructionType type, u8 opcode, u8 sub_opcode, + std::string all, std::string opcode_str, Operand op1, Operand op2): + length(length), type(type), all(all), + opcode(opcode), sub_opcode(sub_opcode), str(opcode_str), op1(op1), op2(op2) { } }; diff --git a/wendi/disasm.cc b/wendi/disasm.cc index 37c323a..ddb87d0 100644 --- a/wendi/disasm.cc +++ b/wendi/disasm.cc @@ -62,48 +62,52 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) { u8 opcode, sub_opcode=0xFF; std::ostringstream result; - std::string opcode_str; - Instruction::Operand op1, op2; + Instruction::InstructionType ins_type; + std::string opcode_str; + Instruction::Operand op1, op2; u16 PC = addr; opcode = gb.memory.read(PC++, GBMemory::DONT_WATCH); result << std::hex << std::uppercase << std::setfill('0'); - + + ins_type = Instruction::LOAD; + switch(opcode) { // LD n, nn - dis_for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, "LD", dis_reg_inm) + dis_for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, "LD", Instruction::LOAD, dis_reg_inm) // LD r1,r2 - dis_for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, "LD", dis_A_reg) - dis_for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, "LD", dis_B_reg) - dis_for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, "LD", dis_C_reg) - dis_for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, "LD", dis_D_reg) - dis_for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, "LD", dis_E_reg) - dis_for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, "LD", dis_H_reg) - dis_for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, "LD", dis_L_reg) + dis_for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, "LD", Instruction::LOAD, dis_A_reg) + dis_for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, "LD", Instruction::LOAD, dis_B_reg) + dis_for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, "LD", Instruction::LOAD, dis_C_reg) + dis_for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, "LD", Instruction::LOAD, dis_D_reg) + dis_for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, "LD", Instruction::LOAD, dis_E_reg) + dis_for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, "LD", Instruction::LOAD, dis_H_reg) + dis_for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, "LD", Instruction::LOAD, dis_L_reg) // LD reg, (HL) - dis_for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, "LD", dis_reg__HL_) + dis_for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, "LD", Instruction::LOAD, dis_reg__HL_) // LD (HL), reg - dis_for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, "LD", dis__HL__reg) + dis_for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, "LD", Instruction::LOAD, dis__HL__reg) - dis__reg16__inm(0x36, "LD", HL) + dis__reg16__inm(0x36, "LD", Instruction::LOAD, HL) - dis_reg__reg16_(0x0A, "LD", A, BC) - dis_reg__reg16_(0x1A, "LD", A, DE) - dis_reg__inm_(0xFA, "LD", A) + dis_reg__reg16_(0x0A, "LD", Instruction::LOAD, A, BC) + dis_reg__reg16_(0x1A, "LD", Instruction::LOAD, A, DE) + dis_reg__inm_(0xFA, "LD", Instruction::LOAD, A) - dis__reg16__reg(0x02, "LD", BC, A) - dis__reg16__reg(0x12, "LD", DE, A) - dis__inm__reg(0xEA, "LD", A) + dis__reg16__reg(0x02, "LD", Instruction::LOAD, BC, A) + dis__reg16__reg(0x12, "LD", Instruction::LOAD, DE, A) + dis__inm__reg(0xEA, "LD", Instruction::LOAD, A) // LD A, (C) case 0xF2: result << "LD A, (0xFF00+C)"; opcode_str = "LDH"; + ins_type = Instruction::LOAD; op1.str="A"; op2.str="C"; op1.type=Instruction::REG; @@ -116,6 +120,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) case 0xE2: result << "LD (0xFF00+C), A"; opcode_str = "LDH"; + ins_type = Instruction::LOAD; op1.str="C"; op2.str="A"; op1.type=Instruction::MEM_INDIRECT; @@ -128,6 +133,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) case 0x3A: result << "LD A, (HL-)"; opcode_str = "LDD"; + ins_type = Instruction::LOAD; op1.str="A"; op2.str="(HL)"; op1.type=Instruction::REG; @@ -139,6 +145,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) case 0x32: result << "LD (HL-), A"; opcode_str = "LDD"; + ins_type = Instruction::LOAD; op1.str="(HL)"; op2.str="A"; op1.type=Instruction::MEM_INDIRECT; @@ -150,6 +157,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) case 0x2A: result << "LD A, (HL+)"; opcode_str = "LDI"; + ins_type = Instruction::LOAD; op1.str="A"; op2.str="(HL)"; op1.type=Instruction::REG; @@ -161,6 +169,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) case 0x22: result << "LD (HL+), A"; opcode_str = "LDI"; + ins_type = Instruction::LOAD; op1.str="(HL)"; op2.str="A"; op1.type=Instruction::MEM_INDIRECT; @@ -176,6 +185,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) result << "LD (0xFF" << std::setw(2) << port << "), A" << "\t[" << get_port_name(port) << "]"; opcode_str = "LDH"; + ins_type = Instruction::LOAD; op1.str=std::string("(") + ToString(port) + ")"; op2.str="A"; op1.type=Instruction::MEM_DIRECT; @@ -190,6 +200,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) result << "LD A, (0xFF" << std::setw(2) << port << ")" << "\t[" << get_port_name(port) << "]"; opcode_str = "LDH"; + ins_type = Instruction::LOAD; op1.str="A"; op2.str=std::string("(") + ToString(port) + ")"; op1.type=Instruction::REG; @@ -199,15 +210,16 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) break; } - dis_reg16_inm(0x01, "LD", BC) - dis_reg16_inm(0x11, "LD", DE) - dis_reg16_inm(0x21, "LD", HL) - dis_reg16_inm(0x31, "LD", SP) + dis_reg16_inm(0x01, "LD", Instruction::LOAD, BC) + dis_reg16_inm(0x11, "LD", Instruction::LOAD, DE) + dis_reg16_inm(0x21, "LD", Instruction::LOAD, HL) + dis_reg16_inm(0x31, "LD", Instruction::LOAD, SP) // LD SP, HL case 0xF9: result << "LD SP, HL"; opcode_str = "LD"; + ins_type = Instruction::LOAD; op1.str = "SP"; op2.str = "HL"; op1.type = Instruction::REG; @@ -221,6 +233,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) int n = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); result << "LD HL, SP + 0x"<< std::setw(2) << n; opcode_str = "LD HL, SP+"; + ins_type = Instruction::LOAD; op1.str = ToString(n); op2.str = ""; op1.type = Instruction::INM8; @@ -229,90 +242,90 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) } // LD (nn), SP - dis__inm__reg16(0x08, "LD", SP) + dis__inm__reg16(0x08, "LD", Instruction::LOAD, SP) // PUSH nn - dis_reg16(0xF5, "PUSH", AF) - dis_reg16(0xC5, "PUSH", BC) - dis_reg16(0xD5, "PUSH", DE) - dis_reg16(0xE5, "PUSH", HL) + dis_reg16(0xF5, "PUSH", Instruction::OTHER, AF) + dis_reg16(0xC5, "PUSH", Instruction::OTHER, BC) + dis_reg16(0xD5, "PUSH", Instruction::OTHER, DE) + dis_reg16(0xE5, "PUSH", Instruction::OTHER, HL) // POP nn - dis_reg16(0xF1, "POP", AF) - dis_reg16(0xC1, "POP", BC) - dis_reg16(0xD1, "POP", DE) - dis_reg16(0xE1, "POP", HL) + dis_reg16(0xF1, "POP", Instruction::OTHER, AF) + dis_reg16(0xC1, "POP", Instruction::OTHER, BC) + dis_reg16(0xD1, "POP", Instruction::OTHER, DE) + dis_reg16(0xE1, "POP", Instruction::OTHER, HL) // 8-bit ALU // ADD A,reg - dis_for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, "ADD", dis_A_reg) + dis_for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, "ADD", Instruction::ALU, dis_A_reg) - dis_reg__reg16_(0x86, "ADD", A, HL) - dis_reg_inm(0xC6, "ADD", A) + dis_reg__reg16_(0x86, "ADD", Instruction::ALU, A, HL) + dis_reg_inm(0xC6, "ADD", Instruction::ALU, A) // ADC A, n - dis_for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, "ADC", dis_A_reg) + dis_for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, "ADC", Instruction::ALU, dis_A_reg) - dis_reg__reg16_(0x8E, "ADC", A, HL) - dis_reg_inm(0xCE, "ADC", A) + dis_reg__reg16_(0x8E, "ADC", Instruction::ALU, A, HL) + dis_reg_inm(0xCE, "ADC", Instruction::ALU, A) // SUB n - dis_for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, "SUB", dis_reg) + dis_for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, "SUB", Instruction::ALU, dis_reg) - dis__reg16_(0x96, "SUB", HL) - dis_inm8(0xD6, "SUB") + dis__reg16_(0x96, "SUB", Instruction::ALU, HL) + dis_inm8(0xD6, "SUB", Instruction::ALU) // SBC n - dis_for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, "SBC", dis_reg) + dis_for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, "SBC", Instruction::ALU, dis_reg) - dis__reg16_(0x9E, "SBC", HL) + dis__reg16_(0x9E, "SBC", Instruction::ALU, HL) // AND n - dis_for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, "AND", dis_reg) + dis_for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, "AND", Instruction::ALU, dis_reg) - dis__reg16_(0xA6, "AND", HL) - dis_inm8(0xE6, "AND") + dis__reg16_(0xA6, "AND", Instruction::ALU, HL) + dis_inm8(0xE6, "AND", Instruction::ALU) // OR n - dis_for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, "OR", dis_reg) + dis_for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, "OR", Instruction::ALU, dis_reg) - dis__reg16_(0xB6, "OR", HL) - dis_inm8(0xF6, "OR") + dis__reg16_(0xB6, "OR", Instruction::ALU, HL) + dis_inm8(0xF6, "OR", Instruction::ALU) // XOR n - dis_for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, "XOR", dis_reg) + dis_for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, "XOR", Instruction::ALU, dis_reg) - dis__reg16_(0xAE, "XOR", HL) - dis_inm8(0xEE, "XOR") + dis__reg16_(0xAE, "XOR", Instruction::ALU, HL) + dis_inm8(0xEE, "XOR", Instruction::ALU) // CP n - dis_for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, "CP", dis_reg) + dis_for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, "CP", Instruction::ALU, dis_reg) - dis__reg16_(0xBE, "CP", HL) - dis_inm8(0xFE, "CP") + dis__reg16_(0xBE, "CP", Instruction::ALU, HL) + dis_inm8(0xFE, "CP", Instruction::ALU) // INC n - dis_for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, "INC", dis_reg) + dis_for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, "INC", Instruction::ALU, dis_reg) - dis__reg16_(0x34, "INC", HL) + dis__reg16_(0x34, "INC", Instruction::ALU, HL) // DEC n - dis_for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, "DEC", dis_reg) + dis_for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, "DEC", Instruction::ALU, dis_reg) - dis__reg16_(0x35, "DEC", HL) + dis__reg16_(0x35, "DEC", Instruction::ALU, HL) // 16-bit ALU // ADD HL, n - dis_for_each_register16(0x09, 0x19, 0x29, 0x39, "ADD", dis_HL_reg16) + dis_for_each_register16(0x09, 0x19, 0x29, 0x39, "ADD", Instruction::ALU, dis_HL_reg16) // ADD SP, # - dis_reg16_inm8(0xE8, "ADD", SP) + dis_reg16_inm8(0xE8, "ADD", Instruction::ALU, SP) // INC nn - dis_for_each_register16(0x03, 0x13, 0x23, 0x33, "INC", dis_reg16) + dis_for_each_register16(0x03, 0x13, 0x23, 0x33, "INC", Instruction::ALU, dis_reg16) // DEC nn - dis_for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, "DEC", dis_reg16) + dis_for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, "DEC", Instruction::ALU, dis_reg16) // Miscellaneous instructions case 0xCB: { @@ -320,52 +333,52 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) switch(sub_opcode) { // SWAP n - dis_for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, "SWAP", dis_reg) + dis_for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, "SWAP", Instruction::ALU, dis_reg) // SWAP (HL) - dis__reg16_(0x36, "SWAP", HL) + dis__reg16_(0x36, "SWAP", Instruction::ALU, HL) // RLC n - dis_for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, "RLC", dis_reg) + dis_for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, "RLC", Instruction::ALU, dis_reg) // RLC (HL) - dis__reg16_(0x06, "RLC", HL) + dis__reg16_(0x06, "RLC", Instruction::ALU, HL) // RL n (through carry) - dis_for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, "RL", dis_reg) + dis_for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, "RL", Instruction::ALU, dis_reg) // RL (HL) (through carry) - dis__reg16_(0x16, "RL", HL) + dis__reg16_(0x16, "RL", Instruction::ALU, HL) // RRC n - dis_for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, "RRC", dis_reg) + dis_for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, "RRC", Instruction::ALU, dis_reg) // RRC (HL) - dis__reg16_(0x0E, "RRC", HL) + dis__reg16_(0x0E, "RRC", Instruction::ALU, HL) // RR n (through carry) - dis_for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, "RR", dis_reg) + dis_for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, "RR", Instruction::ALU, dis_reg) // RR (HL) (through carry) - dis__reg16_(0x1E, "RR", HL) + dis__reg16_(0x1E, "RR", Instruction::ALU, HL) // SLA n - dis_for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, "SLA", dis_reg) + dis_for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, "SLA", Instruction::ALU, dis_reg) // SLA (HL) - dis__reg16_(0x26, "SLA", HL) + dis__reg16_(0x26, "SLA", Instruction::ALU, HL) // SRA n - dis_for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, "SRA", dis_reg) + dis_for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, "SRA", Instruction::ALU, dis_reg) // SRA (HL) - dis__reg16_(0x2E, "SRA", HL) + dis__reg16_(0x2E, "SRA", Instruction::ALU, HL) // SRL n - dis_for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, "SRA", dis_reg) + dis_for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, "SRA", Instruction::ALU, dis_reg) // SRL (HL) - dis__reg16_(0x3E, "SRA", HL) + dis__reg16_(0x3E, "SRA", Instruction::ALU, HL) default: { int bit_op = sub_opcode >> 6; @@ -374,6 +387,47 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) const char *bit_ops[4]={"Unknown", "BIT", "RES", "SET"}; const char *regs[8]={"B","C","D","E","H","L","(HL)", "A"}; result << bit_ops[bit_op] << " " << b << ", " << regs[reg]; + opcode_str = bit_ops[bit_op]; + ins_type = Instruction::ALU; + op1.str = ToString(b); + op1.type = Instruction::INM8; + op1.val = b; + op2.str = regs[reg]; + switch(reg) + { + case 0: + op2.type = Instruction::REG; + op2.reg = Instruction::B; + break; + case 1: + op2.type = Instruction::REG; + op2.reg = Instruction::C; + break; + case 2: + op2.type = Instruction::REG; + op2.reg = Instruction::D; + break; + case 3: + op2.type = Instruction::REG; + op2.reg = Instruction::E; + break; + case 4: + op2.type = Instruction::REG; + op2.reg = Instruction::H; + break; + case 5: + op2.type = Instruction::REG; + op2.reg = Instruction::L; + break; + case 6: + op2.type = Instruction::MEM_INDIRECT; + op2.reg = Instruction::HL; + break; + case 7: + op2.type = Instruction::REG; + op2.reg = Instruction::A; + break; + } break; } @@ -381,41 +435,42 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) break; } - dis(0x27, "DAA") + dis(0x27, "DAA", Instruction::ALU) - dis(0x2F, "CPL") + dis(0x2F, "CPL", Instruction::ALU) - dis(0x3F, "CCF") + dis(0x3F, "CCF", Instruction::ALU) - dis(0x37, "SCF") - dis(0x00, "NOP") - dis(0x76, "HALT") + dis(0x37, "SCF", Instruction::ALU) + dis(0x00, "NOP", Instruction::OTHER) + dis(0x76, "HALT", Instruction::OTHER) - dis(0x10, "STOP") + dis(0x10, "STOP", Instruction::OTHER) - dis(0xF3, "DI") + dis(0xF3, "DI", Instruction::OTHER) - dis(0xFB, "EI") + dis(0xFB, "EI", Instruction::OTHER) // Rotates and shifts - dis(0x07, "RLCA") + dis(0x07, "RLCA", Instruction::ALU) - dis(0x17, "RLA") + dis(0x17, "RLA", Instruction::ALU) - dis(0x0F, "RRCA") + dis(0x0F, "RRCA", Instruction::ALU) - dis(0x1F, "RRA") + dis(0x1F, "RRA", Instruction::ALU) // Jumps - dis_inm16(0xC3, "JP") + dis_inm16(0xC3, "JP", Instruction::UNCONDITIONAL_JUMP) // JP cc, nn - dis_inm16(0xC2, "JP NZ") - dis_inm16(0xCA, "JP Z") - dis_inm16(0xD2, "JP NC") - dis_inm16(0xDA, "JP C") + dis_inm16(0xC2, "JP NZ", Instruction::CONDITIONAL_JUMP) + dis_inm16(0xCA, "JP Z", Instruction::CONDITIONAL_JUMP) + dis_inm16(0xD2, "JP NC", Instruction::CONDITIONAL_JUMP) + dis_inm16(0xDA, "JP C", Instruction::CONDITIONAL_JUMP) case 0xE9: result << "JP (HL)"; opcode_str = "JP"; + ins_type = Instruction::UNCONDITIONAL_JUMP; op1.str="(HL)"; op2.str=""; op1.type = Instruction::MEM_INDIRECT; @@ -423,39 +478,39 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) op2.type = Instruction::NONE; break; - dis_JR(0x18, "JR") - dis_JR(0x20, "JR NZ") - dis_JR(0x28, "JR Z") - dis_JR(0x30, "JR NC") - dis_JR(0x38, "JR C") + dis_JR(0x18, "JR", Instruction::UNCONDITIONAL_JUMP) + dis_JR(0x20, "JR NZ", Instruction::CONDITIONAL_JUMP) + dis_JR(0x28, "JR Z", Instruction::CONDITIONAL_JUMP) + dis_JR(0x30, "JR NC", Instruction::CONDITIONAL_JUMP) + dis_JR(0x38, "JR C", Instruction::CONDITIONAL_JUMP) // Calls - dis_inm16(0xCD, "CALL") + dis_inm16(0xCD, "CALL", Instruction::CALL) // CALL cc, nn - dis_inm16(0xC4, "CALL NZ") - dis_inm16(0xCC, "CALL Z") - dis_inm16(0xD4, "CALL NC") - dis_inm16(0xDC, "CALL C") + dis_inm16(0xC4, "CALL NZ", Instruction::CALL) + dis_inm16(0xCC, "CALL Z", Instruction::CALL) + dis_inm16(0xD4, "CALL NC", Instruction::CALL) + dis_inm16(0xDC, "CALL C", Instruction::CALL) // Restarts - dis(0xC7, "RST 0x00") - dis(0xCF, "RST 0x08") - dis(0xD7, "RST 0x10") - dis(0xDF, "RST 0x18") - dis(0xE7, "RST 0x20") - dis(0xEF, "RST 0x28") - dis(0xF7, "RST 0x30") - dis(0xFF, "RST 0x38") + dis(0xC7, "RST 0x00", Instruction::RESET) + dis(0xCF, "RST 0x08", Instruction::RESET) + dis(0xD7, "RST 0x10", Instruction::RESET) + dis(0xDF, "RST 0x18", Instruction::RESET) + dis(0xE7, "RST 0x20", Instruction::RESET) + dis(0xEF, "RST 0x28", Instruction::RESET) + dis(0xF7, "RST 0x30", Instruction::RESET) + dis(0xFF, "RST 0x38", Instruction::RESET) // Returns - dis(0xC9, "RET") + dis(0xC9, "RET", Instruction::RET) // RET cc - dis(0xC0, "RET NZ") - dis(0xC8, "RET Z") - dis(0xD0, "RET NC") - dis(0xD8, "RET C") + dis(0xC0, "RET NZ", Instruction::RET) + dis(0xC8, "RET Z", Instruction::RET) + dis(0xD0, "RET NC", Instruction::RET) + dis(0xD8, "RET C", Instruction::RET) - dis(0xD9, "RETI") + dis(0xD9, "RETI", Instruction::RET) default: std::ostringstream errmsg; @@ -467,6 +522,7 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) } // end switch - return Instruction(PC-addr, opcode, sub_opcode, result.str(), opcode_str, op1, op2); + return Instruction(PC-addr, ins_type, opcode, sub_opcode, + result.str(), opcode_str, op1, op2); } diff --git a/wendi/disasm.h b/wendi/disasm.h index 3cb01eb..2a48463 100644 --- a/wendi/disasm.h +++ b/wendi/disasm.h @@ -2,6 +2,7 @@ #define DISASM_H #include "../gbcore.h" +#include "Instruction.h" #include #include diff --git a/wendi/disasm_macros.h b/wendi/disasm_macros.h index e7d6bdd..1e093b2 100644 --- a/wendi/disasm_macros.h +++ b/wendi/disasm_macros.h @@ -1,25 +1,26 @@ #ifndef DISASM_MACROS_H #define DISASM_MACROS_H -#define dis_for_each_register(opA, opB, opC, opD, opE, opH, opL, name, macro) \ - macro(opA, name, A) \ - macro(opB, name, B) \ - macro(opC, name, C) \ - macro(opD, name, D) \ - macro(opE, name, E) \ - macro(opH, name, H) \ - macro(opL, name, L) - -#define dis_for_each_register16(opBC, opDE, opHL, opSP, name, macro) \ - macro(opBC, name, BC) \ - macro(opDE, name, DE) \ - macro(opHL, name, HL) \ - macro(opSP, name, SP) - -#define dis(opcode, name) \ +#define dis_for_each_register(opA, opB, opC, opD, opE, opH, opL, name, itype, macro) \ + macro(opA, name, itype, A) \ + macro(opB, name, itype, B) \ + macro(opC, name, itype, C) \ + macro(opD, name, itype, D) \ + macro(opE, name, itype, E) \ + macro(opH, name, itype, H) \ + macro(opL, name, itype, L) + +#define dis_for_each_register16(opBC, opDE, opHL, opSP, name, itype, macro) \ + macro(opBC, name, itype, BC) \ + macro(opDE, name, itype, DE) \ + macro(opHL, name, itype, HL) \ + macro(opSP, name, itype, SP) + +#define dis(opcode, name, itype) \ case opcode: \ result << name; \ opcode_str = name; \ + ins_type = itype; \ op1.str=""; \ op2.str=""; \ op1.type=Instruction::NONE; \ @@ -27,10 +28,11 @@ break; // OP reg -#define dis_reg(opcode, name, reg8) \ +#define dis_reg(opcode, name, itype, reg8) \ case opcode: \ result << name << " " << #reg8; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg8; \ op2.str = ""; \ op1.type = Instruction::REG; \ @@ -40,10 +42,11 @@ // OP reg16 -#define dis_reg16(opcode, name, reg16) \ +#define dis_reg16(opcode, name, itype, reg16) \ case opcode: \ result << name << " " << #reg16; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg16; \ op2.str = ""; \ op1.type = Instruction::REG; \ @@ -52,10 +55,11 @@ break; // OP (reg16) -#define dis__reg16_(opcode, name, reg16) \ +#define dis__reg16_(opcode, name, itype, reg16) \ case opcode: \ result << name << " (" << #reg16 << ")"; \ opcode_str = name; \ + ins_type = itype; \ op1.str = std::string("(")+#reg16+")"; \ op2.str = ""; \ op1.type = Instruction::MEM_INDIRECT; \ @@ -64,11 +68,12 @@ break; // OP inm8 -#define dis_inm8(opcode, name) \ +#define dis_inm8(opcode, name, itype) \ case opcode: {\ int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ result << name << " 0x" << std::setw(2) << inm; \ opcode_str = name; \ + ins_type = itype; \ op1.str = ToString(inm); \ op2.str = ""; \ op1.type = Instruction::INM8; \ @@ -78,12 +83,13 @@ } // OP inm16 -#define dis_inm16(opcode, name) \ +#define dis_inm16(opcode, name, itype) \ case opcode: {\ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ PC += 2; \ result << name << " 0x" << std::setw(4) << inm; \ opcode_str = name; \ + ins_type = itype; \ op1.str = ToString(inm); \ op2.str = ""; \ op1.type = Instruction::INM16; \ @@ -92,11 +98,12 @@ break; \ } -#define dis_reg_inm(opcode, name, reg8) \ +#define dis_reg_inm(opcode, name, itype, reg8) \ case opcode: {\ int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ result << name << " " << #reg8 << ", 0x" << std::setw(2) << inm; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg8; \ op2.str = ToString(inm); \ op1.type = Instruction::REG; \ @@ -106,12 +113,13 @@ break; \ } -#define dis_reg16_inm(opcode, name, reg16) \ +#define dis_reg16_inm(opcode, name, itype, reg16) \ case opcode: {\ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ PC += 2; \ result << name << " " << #reg16 << ", 0x" << std::setw(4) << inm; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg16; \ op2.str = ToString(inm); \ op1.type = Instruction::REG; \ @@ -121,11 +129,12 @@ break; \ } -#define dis_reg16_inm8(opcode, name, reg16) \ +#define dis_reg16_inm8(opcode, name, itype, reg16) \ case opcode: {\ int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ result << name << " " << #reg16 << ", 0x" << std::setw(2) << inm; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg16; \ op2.str = ToString(inm); \ op1.type = Instruction::REG; \ @@ -135,10 +144,11 @@ break; \ } -#define dis_reg_reg(opcode, name, reg1, reg2) \ +#define dis_reg_reg(opcode, name, itype, reg1, reg2) \ case opcode: \ result << name << " " << #reg1 << ", " << #reg2; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg1; \ op2.str = #reg2; \ op1.type = Instruction::REG; \ @@ -147,18 +157,19 @@ op2.val = Instruction::reg2; \ break; -#define dis_A_reg(opcode, name, reg2) dis_reg_reg(opcode, name, A, reg2) -#define dis_B_reg(opcode, name, reg2) dis_reg_reg(opcode, name, B, reg2) -#define dis_C_reg(opcode, name, reg2) dis_reg_reg(opcode, name, C, reg2) -#define dis_D_reg(opcode, name, reg2) dis_reg_reg(opcode, name, D, reg2) -#define dis_E_reg(opcode, name, reg2) dis_reg_reg(opcode, name, E, reg2) -#define dis_H_reg(opcode, name, reg2) dis_reg_reg(opcode, name, H, reg2) -#define dis_L_reg(opcode, name, reg2) dis_reg_reg(opcode, name, L, reg2) +#define dis_A_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, A, reg2) +#define dis_B_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, B, reg2) +#define dis_C_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, C, reg2) +#define dis_D_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, D, reg2) +#define dis_E_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, E, reg2) +#define dis_H_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, H, reg2) +#define dis_L_reg(opcode, name, itype, reg2) dis_reg_reg(opcode, name, itype, L, reg2) -#define dis_reg16_reg16(opcode, name, reg16_1, reg16_2) \ +#define dis_reg16_reg16(opcode, name, itype, reg16_1, reg16_2) \ case opcode: \ result << name << " " << #reg16_1 << ", " << #reg16_2; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg16_1; \ op2.str = #reg16_2; \ op1.type = Instruction::REG; \ @@ -167,13 +178,14 @@ op2.val = Instruction::reg16_2; \ break; -#define dis_HL_reg16(opcode, name, reg16_2) dis_reg16_reg16(opcode, name, HL, reg16_2) +#define dis_HL_reg16(opcode, name, itype, reg16_2) dis_reg16_reg16(opcode, name, itype, HL, reg16_2) // OP reg, (reg16) -#define dis_reg__reg16_(opcode, name, reg8, reg16) \ +#define dis_reg__reg16_(opcode, name, itype, reg8, reg16) \ case opcode: \ result << name << " " << #reg8 << ", (" << #reg16 << ")"; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg8; \ op2.str = std::string("(")+ #reg16 + ")"; \ op1.type = Instruction::REG; \ @@ -183,16 +195,17 @@ break; // OP reg, (HL) -#define dis_reg__HL_(opcode, name, reg) dis_reg__reg16_(opcode, name, reg, HL) +#define dis_reg__HL_(opcode, name, itype, reg) dis_reg__reg16_(opcode, name, itype, reg, HL) // OP reg, (inm) -#define dis_reg__inm_(opcode, name, reg8) \ +#define dis_reg__inm_(opcode, name, itype, reg8) \ case opcode: {\ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ PC += 2; \ result << name << " " << #reg8 << ", (0x" << \ std::setw(4) << inm << ")"; \ opcode_str = name; \ + ins_type = itype; \ op1.str = #reg8; \ op2.str = std::string("(") + ToString(inm) + ")"; \ op1.type = Instruction::REG; \ @@ -203,10 +216,11 @@ } // OP (reg16), reg -#define dis__reg16__reg(opcode, name, reg16, reg8) \ +#define dis__reg16__reg(opcode, name, itype, reg16, reg8) \ case opcode: \ result << name << " (" << #reg16 << "), " << #reg8; \ opcode_str = name; \ + ins_type = itype; \ op1.str = std::string("(")+ #reg16 + ")"; \ op2.str = #reg8; \ op1.type = Instruction::MEM_INDIRECT; \ @@ -216,16 +230,17 @@ break; // OP (HL), reg -#define dis__HL__reg(opcode, name, reg) dis__reg16__reg(opcode, name, HL, reg) +#define dis__HL__reg(opcode, name, itype, reg) dis__reg16__reg(opcode, name, itype, HL, reg) // OP (inm), reg -#define dis__inm__reg(opcode, name, reg8) \ +#define dis__inm__reg(opcode, name, itype, reg8) \ case opcode: {\ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ PC += 2; \ result << name << " (0x" << \ std::setw(4) << inm << "), " << #reg8; \ opcode_str = name; \ + ins_type = itype; \ op1.str = std::string("(") + ToString(inm) + ")"; \ op2.str = #reg8; \ op1.type = Instruction::MEM_DIRECT; \ @@ -236,13 +251,14 @@ } // OP (inm), reg16 -#define dis__inm__reg16(opcode, name, reg16) \ +#define dis__inm__reg16(opcode, name, itype, reg16) \ case opcode: {\ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ PC += 2; \ result << name << " (0x" << \ std::setw(4) << inm << "), " << #reg16; \ opcode_str = name; \ + ins_type = itype; \ op1.str = std::string("(") + ToString(inm) + ")"; \ op2.str = #reg16; \ op1.type = Instruction::MEM_DIRECT; \ @@ -253,12 +269,13 @@ } // OP (reg16), inm -#define dis__reg16__inm(opcode, name, reg16) \ +#define dis__reg16__inm(opcode, name, itype, reg16) \ case opcode: {\ int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ result << name << " (" << #reg16 << "), 0x" << \ std::setw(2) << inm; \ opcode_str = name; \ + ins_type = itype; \ op1.str = std::string("(") + #reg16 + ")"; \ op2.str = ToString(inm); \ op1.type = Instruction::MEM_INDIRECT; \ @@ -270,12 +287,13 @@ // Special routine for JR -#define dis_JR(opcode, name) \ +#define dis_JR(opcode, name, itype) \ case opcode: { \ s8 offset = gb.memory.read(PC++); \ result << name << " " << std::dec << int(offset) << "\t[0x" \ << std::hex << std::setw(2) << int(PC+offset) << "]"; \ opcode_str = name; \ + ins_type = itype; \ op1.str = ToString(int(offset)); \ op2.str = ToString(int(PC+offset)); \ op1.type = Instruction::INM8; \ diff --git a/wendi/wendi.cc b/wendi/wendi.cc index d177230..f734df2 100644 --- a/wendi/wendi.cc +++ b/wendi/wendi.cc @@ -1,4 +1,5 @@ #include "../gbcore.h" +#include "../Logger.h" #include "CodeBlock.h" #include "disasm.h" @@ -7,7 +8,9 @@ #include #include #include +#include #include +#include //#include using std::vector; @@ -19,45 +22,235 @@ using std::string; typedef u16 address; list blocks; +list pending; void show_block(const CodeBlock& b) { - std::cout << "block_0x" << std::hex << b.start << ":" << std::endl; + bool is_CALLed = false; + bool is_VBLANK_interrupt_handler = false; + bool is_LCD_STAT_interrupt_handler = false; + bool is_TIMER_interrupt_handler = false; + bool is_SERIAL_interrupt_handler = false; + bool is_JOYPAD_interrupt_handler = false; + std::ostringstream headerstr; + + // Create header, check for CALL xrefs + headerstr << "block_0x" << std::hex << b.start << ":"; + if (!b.xrefs.empty()) + headerstr << "\t;xrefs "; + + for(CodeBlock::XrefsConstIterator i=b.xrefs.begin(); + i!=b.xrefs.end(); + i++) + { + headerstr << std::hex << "0x" << i->first << ","; + if (i->second == Instruction::CALL) + is_CALLed = true; + if (i->first == 0x40) + is_VBLANK_interrupt_handler = true; + if (i->first == 0x48) + is_LCD_STAT_interrupt_handler = true; + if (i->first == 0x50) + is_TIMER_interrupt_handler = true; + if (i->first == 0x58) + is_SERIAL_interrupt_handler = true; + if (i->first == 0x60) + is_JOYPAD_interrupt_handler = true; + } + + headerstr << std::endl; + + // Print header to stdout + if (is_CALLed) + std::cout << std::endl << "-- FUNCTION --------------------------" << std::endl; + if (is_VBLANK_interrupt_handler) + std::cout << std::endl << "-- VBLANK INTERRUPT HANDLER ----------" << std::endl; + if (is_LCD_STAT_interrupt_handler) + std::cout << std::endl << "-- LCD_STAT INTERRUPT HANDLER --------" << std::endl; + if (is_TIMER_interrupt_handler) + std::cout << std::endl << "-- TIMER INTERRUPT HANDLER -----------" << std::endl; + if (is_SERIAL_interrupt_handler) + std::cout << std::endl << "-- SERIAL INTERRUPT HANDLER ----------" << std::endl; + if (is_JOYPAD_interrupt_handler) + std::cout << std::endl << "-- JOYPAD INTERRUPT HANDLER ----------" << std::endl; + + if (b.start == 0x100) + std::cout << std::endl << "-- ENTRYPOINT -----------------" << std::endl; + + std::cout << headerstr.str(); + + // Print disassembly for(CodeBlock::DisassemblyConstIterator i=b.disassembly.begin(); i!=b.disassembly.end(); i++) std::cout << std::hex << "0x" << i->first << "\t" << i->second << std::endl; } +bool is_block_end(const Instruction &ins) +{ + if (ins.type == Instruction::UNCONDITIONAL_JUMP || + ins.type == Instruction::RET) + return true; + + return false; +} + +bool is_jump(const Instruction &ins) +{ + if (ins.type == Instruction::UNCONDITIONAL_JUMP || + ins.type == Instruction::CONDITIONAL_JUMP || + ins.type == Instruction::CALL || + ins.type == Instruction::RESET) + return true; + return false; +} + +address jump_address(const Instruction &ins) +{ + if (ins.type == Instruction::UNCONDITIONAL_JUMP || + ins.type == Instruction::CONDITIONAL_JUMP || + ins.type == Instruction::CALL) + { + if (ins.str.substr(0,2)=="JR") + return ins.op2.val; + else return ins.op1.val; + } + else // RESET + { + switch(ins.opcode) + { + case 0xC7: return 0x00; + case 0xCF: return 0x08; + case 0xD7: return 0x10; + case 0xDF: return 0x18; + case 0xE7: return 0x20; + case 0xEF: return 0x28; + case 0xF7: return 0x30; + case 0xFF: return 0x38; + } + } + + return 0; +} + +list::iterator find_block(list &l, address addr) +{ + //logger.trace("--> find_block()"); + list::iterator i = l.begin(); + while(i != l.end()) + { + //logger.trace("finding block. addr=0x", std::hex, addr, " start=0x", i->start, " end=0x", i->end); + if ((addr >= i->start && addr < i->end) || + (addr == i->start && addr == i->end)) + { + //logger.trace("FOUND!"); + break; + } + i++; + } + //logger.trace("i==l.end()? --> ", i == l.end()); + //logger.trace("<-- find_block()"); + return i; +} int main(int argc, char **argv) { + logger.set_log_level(Logger::TRACE); GameBoy gb(argv[1]); - vector
pending; - pending.push_back(0x100); + list pending; + // pending holds empty CodeBlocks + pending.push_back(CodeBlock(0x100)); // entrypoint + pending.push_back(CodeBlock(0x40)); // interrupt handlers + pending.push_back(CodeBlock(0x48)); + pending.push_back(CodeBlock(0x50)); + pending.push_back(CodeBlock(0x58)); + pending.push_back(CodeBlock(0x60)); while(!pending.empty()) { // Disassemble a block - int addr = pending.back(); - pending.pop_back(); + CodeBlock block = pending.front(); + pending.pop_front(); - blocks.push_back(CodeBlock(addr)); + address addr = block.start; + logger.info("Starting disassembly of block 0x", std::hex, addr); - bool jump_reached = false; - while(!jump_reached) + bool block_end = false; + while(!block_end) { Instruction ins(disassemble_opcode(gb, addr)); - blocks.back().add_instruction(ins.all, ins.length); - addr += ins.length; + block.add_instruction(ins.all, ins.length); - if (ins.is_jump()) jump_reached=true; + if (is_jump(ins)) + { + address dst = jump_address(ins); + logger.info("Found jump. dst address = 0x", std::hex, dst); + if (dst == block.start) // Check if dst is this block's beginning + { + block.add_xref(addr, ins.type); + } + else if (dst > block.start && dst < block.end) // Check if dst is inside this block + { + logger.info("Splitting current block 0x", std::hex, block.start, " at 0x", dst); + CodeBlock newblock(block, dst); + blocks.push_back(block); + block = newblock; + } + else + { + // Check if dst is inside a known block + list::iterator i = find_block(blocks, dst); + if (i != blocks.end()) + { + if (dst == i->start) + { + i->add_xref(addr, ins.type); + } + else + { + logger.info("Splitting block 0x", std::hex, i->start, " at 0x", dst); + blocks.push_back(CodeBlock(*i, dst)); + blocks.back().add_xref(addr, ins.type); + } + + } + else + { + // Check if dst is a pending block + i = find_block(pending, dst); + if (i != pending.end()) + { + logger.info("Adding xref to pending block 0x", std::hex, i->start); + i->add_xref(addr, ins.type); + } + else + { + // dst is a new block + pending.push_back(CodeBlock(dst)); + pending.back().add_xref(addr, ins.type); + logger.info("new block at ", std::hex, "0x", dst); + } + } + } + } + + if (is_block_end(ins)) + { + block_end=true; + } + + addr += ins.length; } + + blocks.push_back(block); } - //std::for_each(blocks, show_block); + vector tmp; for (list::iterator i = blocks.begin(); i != blocks.end(); i++) - show_block(*i); + tmp.push_back(*i); + std::sort(tmp.begin(), tmp.end()); + std::for_each(tmp.begin(), tmp.end(), show_block); + return 0; } -- 2.34.1