From: slack Date: Tue, 20 Jan 2009 17:39:00 +0000 (+0100) Subject: Big restructuring in order to switch to CMake X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=104adea8503564d85f1d941973b2cc50c3c6d87a;p=wenboi.git Big restructuring in order to switch to CMake - GameBoy core is now a library - test_core.cc is now the main wenboi program - CMakeLists.txt everywhere Still more changes to come, as I'd like to remove SDL dependencies from the core, abstracting the video driver and creating a dummy one for wendi, and a SDL one based on the existing code. It would be nice too if class GameBoy had a cleaner interface with less public stuff :P --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fd3c3e7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +PROJECT(wenboi) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0) +FIND_PACKAGE(SDL REQUIRED) + +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(wenboi) +ADD_SUBDIRECTORY(wendi) diff --git a/Makefile b/Makefile deleted file mode 100644 index 61f2172..0000000 --- a/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -#CXXFLAGS=-pg -O3 -g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast -CXXFLAGS=-pg -g -Wall -Weffc++ -Wold-style-cast \ - -Woverloaded-virtual $(shell sdl-config --cflags) -LDFLAGS=-pg -g $(shell sdl-config --libs) - -all: tests - -tests: tests/test_gbrom tests/test_core wendi/wendi - -util.o: util.cc util.h - g++ $(CXXFLAGS) -c -o $@ $< - -GBVideo.o: GBVideo.cc GBVideo.h Logger.h util.h gbcore.h - g++ $(CXXFLAGS) -c -o $@ $< - -GBMemory.o: GBMemory.cc GBMemory.h Logger.h MBC.h gbcore.h - g++ $(CXXFLAGS) -c -o $@ $< - -MBC.o: MBC.cc MBC.h Logger.h NoMBC.h MBC1.h - g++ $(CXXFLAGS) -c -o $@ $< - -NoMBC.o: NoMBC.cc NoMBC.h Logger.h - g++ $(CXXFLAGS) -c -o $@ $< - -MBC1.o: MBC1.cc MBC1.h Logger.h - g++ $(CXXFLAGS) -c -o $@ $< - -gbcore.o: gbcore.cc gbcore.h opcodes.h \ - GBRom.h Logger.h MBC.h GBMemory.h GBVideo.h util.h - g++ $(CXXFLAGS) -c -o $@ $< - -tests/test_gbrom: GBRom.cc GBRom.h - g++ $(CXXFLAGS) -DTEST_GBROM -o $@ GBRom.cc $(LDFLAGS) - -tests/test_core: tests/test_core.cc gbcore.o MBC.o GBMemory.o GBRom.o \ - GBVideo.o util.o NoMBC.o MBC1.o wendi/disasm.o - g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS) - -wendi/CodeBlock.o: wendi/CodeBlock.cc wendi/CodeBlock.h - g++ $(CXXFLAGS) -c -o $@ $< - -wendi/disasm.o: wendi/disasm.cc wendi/disasm.h wendi/Instruction.h - g++ $(CXXFLAGS) -c -o $@ $< - -wendi/output_txt.o: wendi/output_txt.cc wendi/output_txt.h wendi/disassembly_output.h - g++ $(CXXFLAGS) -c -o $@ $< - -wendi/output_graph.o: wendi/output_graph.cc wendi/output_graph.h wendi/disassembly_output.h Logger.h - g++ $(CXXFLAGS) -c -o $@ $< - -wendi/wendi: wendi/wendi.cc wendi/CodeBlock.o wendi/disasm.o \ - wendi/output_txt.o wendi/output_graph.o gbcore.o MBC.o \ - GBMemory.o GBRom.o GBVideo.o util.o NoMBC.o MBC1.o - g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS) - -clean: - rm -f *.o wendi/*.o wendi/wendi tests/test_gbrom tests/test_core - -.PHONY: clean tests all diff --git a/Logger.h b/common/Logger.h similarity index 100% rename from Logger.h rename to common/Logger.h diff --git a/Singleton.h b/common/Singleton.h similarity index 100% rename from Singleton.h rename to common/Singleton.h diff --git a/sized_types.h b/common/sized_types.h similarity index 100% rename from sized_types.h rename to common/sized_types.h diff --git a/wendi/disasm.h b/common/toString.h similarity index 78% rename from wendi/disasm.h rename to common/toString.h index 6174354..bf47b03 100644 --- a/wendi/disasm.h +++ b/common/toString.h @@ -14,25 +14,20 @@ You should have received a copy of the GNU General Public License along with wenboi. If not, see . -*/ -#ifndef DISASM_H -#define DISASM_H - -#include "../gbcore.h" -#include "Instruction.h" +*/ +#ifndef TOSTRING_H +#define TOSTRING_H #include #include template -std::string ToString(const T &object) +std::string toString(const T &object) { std::ostringstream os; os << object; return(os.str()); } -Instruction disassemble_opcode(GameBoy &gb, u16 addr); -std::string get_port_name(int port); - #endif + diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt new file mode 100644 index 0000000..982988b --- /dev/null +++ b/core/CMakeLists.txt @@ -0,0 +1,6 @@ +FIND_PACKAGE(SDL REQUIRED) + +ADD_LIBRARY(wenboicore STATIC GameBoy.cc GBMemory.cc GBRom.cc GBVideo.cc MBC.cc NoMBC.cc MBC1.cc util.cc) +TARGET_LINK_LIBRARIES(wenboicore ${SDL_LIBRARY}) +INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR}) + diff --git a/GBMemory.cc b/core/GBMemory.cc similarity index 99% rename from GBMemory.cc rename to core/GBMemory.cc index a1216a7..19c29e6 100644 --- a/GBMemory.cc +++ b/core/GBMemory.cc @@ -16,9 +16,9 @@ along with wenboi. If not, see . */ #include "GBMemory.h" +#include "GameBoy.h" #include "MBC.h" -#include "gbcore.h" -#include "Logger.h" +#include "../common/Logger.h" #include #include #include diff --git a/GBMemory.h b/core/GBMemory.h similarity index 99% rename from GBMemory.h rename to core/GBMemory.h index 4f2a911..def434a 100644 --- a/GBMemory.h +++ b/core/GBMemory.h @@ -18,7 +18,7 @@ #ifndef GBMEMORY_H #define GBMEMORY_H -#include "sized_types.h" +#include "../common/sized_types.h" #include class GameBoy; diff --git a/GBRom.cc b/core/GBRom.cc similarity index 99% rename from GBRom.cc rename to core/GBRom.cc index 23c568f..0c12e49 100644 --- a/GBRom.cc +++ b/core/GBRom.cc @@ -16,7 +16,7 @@ along with wenboi. If not, see . */ #include "GBRom.h" -#include "Logger.h" +#include "../common/Logger.h" #include #include #include diff --git a/GBRom.h b/core/GBRom.h similarity index 98% rename from GBRom.h rename to core/GBRom.h index d2771e5..053395b 100644 --- a/GBRom.h +++ b/core/GBRom.h @@ -18,7 +18,7 @@ #ifndef GBROM_H #define GBROM_H -#include "sized_types.h" +#include "../common/sized_types.h" #include namespace cartridge_types { diff --git a/GBVideo.cc b/core/GBVideo.cc similarity index 99% rename from GBVideo.cc rename to core/GBVideo.cc index 2a6d4b1..2fb2793 100644 --- a/GBVideo.cc +++ b/core/GBVideo.cc @@ -16,8 +16,8 @@ along with wenboi. If not, see . */ #include "GBVideo.h" -#include "gbcore.h" -#include "Logger.h" +#include "GameBoy.h" +#include "../common/Logger.h" #include "util.h" #include #include diff --git a/GBVideo.h b/core/GBVideo.h similarity index 100% rename from GBVideo.h rename to core/GBVideo.h diff --git a/gbcore.cc b/core/GameBoy.cc similarity index 72% rename from gbcore.cc rename to core/GameBoy.cc index 16c8042..a0d7045 100644 --- a/gbcore.cc +++ b/core/GameBoy.cc @@ -15,13 +15,14 @@ You should have received a copy of the GNU General Public License along with wenboi. If not, see . */ -#include "gbcore.h" +#include "GameBoy.h" #include "GBRom.h" #include "MBC.h" -#include "Logger.h" #include "util.h" -#include "wendi/disasm.h" +#include "../common/Logger.h" +#include "../common/toString.h" + #include #include #include @@ -1549,7 +1550,7 @@ GameBoy::run_status GameBoy::run() std::string GameBoy::status_string() { - Instruction ins(disassemble_opcode(*this, regs.PC)); + Instruction ins(disassemble_opcode(regs.PC)); std::ostringstream result; result << "t = " << std::dec << cycle_count << @@ -1604,3 +1605,536 @@ void GameBoy::update_JOYP() memory.high[GBMemory::I_JOYP]=JOYP; } + +////////////////////////////////////////////////// +// OPCODE DISASSEMBLER +////////////////////////////////////////////////// + +#include "disasm_macros.h" + +std::string GameBoy::get_port_name(int port) +{ + std::string port_name; + + switch (port) + { + case 0x00: port_name = "JOYP"; break; + case 0x01: port_name = "SB "; break; + case 0x02: port_name = "SC "; break; + case 0x04: port_name = "DIV "; break; + case 0x05: port_name = "TIMA"; break; + case 0x06: port_name = "TMA "; break; + case 0x07: port_name = "TAC "; break; + case 0x10: port_name = "CH1_ENT"; break; + case 0x11: port_name = "CH1_WAVE"; break; + case 0x12: port_name = "CH1_ENV"; break; + case 0x13: port_name = "CH1_FREQ_LO"; break; + case 0x14: port_name = "CH1_FREQ_HI_KICK"; break; + case 0x16: port_name = "CH2_WAVE"; break; + case 0x17: port_name = "CH2_ENV"; break; + case 0x18: port_name = "CH2_FREQ_LO"; break; + case 0x19: port_name = "CH2_FREQ_HI_KICK"; break; + case 0x1A: port_name = "CH3_ONOFF"; break; + case 0x1C: port_name = "CH3_VOLUME"; break; + case 0x1D: port_name = "CH3_FREQ_LO"; break; + case 0x1E: port_name = "CH3_FREQ_HI_KICK"; break; + case 0x21: port_name = "CH4_ENV"; break; + case 0x22: port_name = "CH4_POLY"; break; + case 0x23: port_name = "CH4_KICK"; break; + case 0x24: port_name = "SND_VIN"; break; + case 0x25: port_name = "SND_STEREO"; break; + case 0x26: port_name = "SND_STAT"; break; + case 0x40: port_name = "LCDC"; break; + case 0x41: port_name = "STAT"; break; + case 0x42: port_name = "SCY "; break; + case 0x43: port_name = "SCX "; break; + case 0x44: port_name = "LY "; break; + case 0x45: port_name = "LYC "; break; + case 0x4A: port_name = "WY "; break; + case 0x4B: port_name = "WX "; break; + case 0x47: port_name = "BGP "; break; + case 0x48: port_name = "OBP0"; break; + case 0x49: port_name = "OBP1"; break; + case 0x46: port_name = "DMA "; break; + case 0x0F: port_name = "IF "; break; + case 0xFF: port_name = "IE "; break; + default: + if (port >= 0x80 && port <= 0xFE) + port_name = "HRAM"; + else if (port >= 0x30 && port <= 0x3F) + port_name = "Wave Pattern RAM"; + + } + return port_name; +} + + +Instruction GameBoy::disassemble_opcode(u16 addr) +{ + u8 opcode, sub_opcode=0xFF; + std::ostringstream result; + Instruction::InstructionType ins_type; + std::string opcode_str; + Instruction::Operand op1, op2; + + u16 PC = addr; + opcode = this->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", Instruction::LOAD, dis_reg_inm) + + // LD r1,r2 + 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", Instruction::LOAD, dis_reg__HL_) + + // LD (HL), reg + dis_for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, "LD", Instruction::LOAD, dis__HL__reg) + + dis__reg16__inm(0x36, "LD", Instruction::LOAD, HL) + + 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", 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; + op1.reg =Instruction::A; + op2.type=Instruction::MEM_INDIRECT; + op2.reg =Instruction::C; + break; + + // LD (C), A + 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; + op1.reg =Instruction::C; + op2.type=Instruction::REG; + op2.reg =Instruction::A; + break; + + // LD A, (HLD); LD A, (HL-); LDD A,(HL); + case 0x3A: + result << "LD A, (HL-)"; + opcode_str = "LDD"; + ins_type = Instruction::LOAD; + op1.str="A"; + op2.str="(HL)"; + op1.type=Instruction::REG; + op1.reg =Instruction::A; + op2.type=Instruction::MEM_INDIRECT; + op2.reg =Instruction::HL; + break; + // LD (HLD), A; LD (HL-), A; LDD (HL), A; + case 0x32: + result << "LD (HL-), A"; + opcode_str = "LDD"; + ins_type = Instruction::LOAD; + op1.str="(HL)"; + op2.str="A"; + op1.type=Instruction::MEM_INDIRECT; + op1.reg =Instruction::HL; + op2.type=Instruction::REG; + op2.reg =Instruction::A; + break; + // LD A, (HLI); LD A, (HL+); LDI A, (HL); + case 0x2A: + result << "LD A, (HL+)"; + opcode_str = "LDI"; + ins_type = Instruction::LOAD; + op1.str="A"; + op2.str="(HL)"; + op1.type=Instruction::REG; + op1.reg =Instruction::A; + op2.type=Instruction::MEM_INDIRECT; + op2.reg =Instruction::HL; + break; + // LD (HLI), A; LD (HL+), A; LDI (HL), A; + case 0x22: + result << "LD (HL+), A"; + opcode_str = "LDI"; + ins_type = Instruction::LOAD; + op1.str="(HL)"; + op2.str="A"; + op1.type=Instruction::MEM_INDIRECT; + op1.reg =Instruction::HL; + op2.type=Instruction::REG; + op2.reg =Instruction::A; + break; + + // LDH (n), A + case 0xE0: { + int port = int(this->memory.read(PC++, GBMemory::DONT_WATCH)); + + 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; + op1.val =0xFF00+port; + op2.type=Instruction::REG; + op2.reg =Instruction::A; + break; + } + // LDH A, (n) + case 0xF0: { + int port = int(this->memory.read(PC++, GBMemory::DONT_WATCH)); + 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; + op1.reg =Instruction::A; + op2.type=Instruction::MEM_DIRECT; + op2.val =0xFF00+port; + break; + } + + 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; + op1.reg = Instruction::SP; + op2.type = Instruction::REG; + op2.reg = Instruction::HL; + + // LD HL, SP+n + // LDHL SP, n + case 0xF8: { + int n = int(this->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; + op1.val = n; + break; + } + + // LD (nn), SP + dis__inm__reg16(0x08, "LD", Instruction::LOAD, SP) + + // PUSH nn + 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", 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", Instruction::ALU, dis_A_reg) + + 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", Instruction::ALU, dis_A_reg) + + 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", Instruction::ALU, dis_reg) + + 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", Instruction::ALU, dis_reg) + + dis__reg16_(0x9E, "SBC", Instruction::ALU, HL) + dis_reg_inm(0xDE, "SBC", Instruction::ALU, A) + + // AND n + dis_for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, "AND", Instruction::ALU, dis_reg) + + 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", Instruction::ALU, dis_reg) + + 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", Instruction::ALU, dis_reg) + + 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", Instruction::ALU, dis_reg) + + 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", Instruction::ALU, dis_reg) + + dis__reg16_(0x34, "INC", Instruction::ALU, HL) + + // DEC n + dis_for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, "DEC", Instruction::ALU, dis_reg) + + dis__reg16_(0x35, "DEC", Instruction::ALU, HL) + + // 16-bit ALU + // ADD HL, n + dis_for_each_register16(0x09, 0x19, 0x29, 0x39, "ADD", Instruction::ALU, dis_HL_reg16) + + // ADD SP, # + dis_reg16_inm8(0xE8, "ADD", Instruction::ALU, SP) + + // INC nn + dis_for_each_register16(0x03, 0x13, 0x23, 0x33, "INC", Instruction::ALU, dis_reg16) + + // DEC nn + dis_for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, "DEC", Instruction::ALU, dis_reg16) + + // Miscellaneous instructions + case 0xCB: { + sub_opcode = this->memory.read(PC++, GBMemory::DONT_WATCH); + switch(sub_opcode) + { + // SWAP n + dis_for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, "SWAP", Instruction::ALU, dis_reg) + + // SWAP (HL) + dis__reg16_(0x36, "SWAP", Instruction::ALU, HL) + + // RLC n + dis_for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, "RLC", Instruction::ALU, dis_reg) + + // 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", Instruction::ALU, dis_reg) + + // RL (HL) (through carry) + dis__reg16_(0x16, "RL", Instruction::ALU, HL) + + // RRC n + dis_for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, "RRC", Instruction::ALU, dis_reg) + + // 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", Instruction::ALU, dis_reg) + + // RR (HL) (through carry) + dis__reg16_(0x1E, "RR", Instruction::ALU, HL) + + // SLA n + dis_for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, "SLA", Instruction::ALU, dis_reg) + + // SLA (HL) + dis__reg16_(0x26, "SLA", Instruction::ALU, HL) + + // SRA n + dis_for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, "SRA", Instruction::ALU, dis_reg) + + // SRA (HL) + dis__reg16_(0x2E, "SRA", Instruction::ALU, HL) + + // SRL n + dis_for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, "SRA", Instruction::ALU, dis_reg) + + // SRL (HL) + dis__reg16_(0x3E, "SRA", Instruction::ALU, HL) + + default: { + int bit_op = sub_opcode >> 6; + int reg = sub_opcode & 7; + int b = (sub_opcode >> 3) & 7; + 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; + } + + } + break; + } + + dis(0x27, "DAA", Instruction::ALU) + + dis(0x2F, "CPL", Instruction::ALU) + + dis(0x3F, "CCF", Instruction::ALU) + + dis(0x37, "SCF", Instruction::ALU) + dis(0x00, "NOP", Instruction::OTHER) + dis(0x76, "HALT", Instruction::OTHER) + + dis(0x10, "STOP", Instruction::OTHER) + + dis(0xF3, "DI", Instruction::OTHER) + + dis(0xFB, "EI", Instruction::OTHER) + + // Rotates and shifts + dis(0x07, "RLCA", Instruction::ALU) + + dis(0x17, "RLA", Instruction::ALU) + + dis(0x0F, "RRCA", Instruction::ALU) + + dis(0x1F, "RRA", Instruction::ALU) + + // Jumps + dis_inm16(0xC3, "JP", Instruction::UNCONDITIONAL_JUMP) + // JP cc, nn + 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; + op1.reg = Instruction::HL; + op2.type = Instruction::NONE; + break; + + 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", Instruction::CALL) + // CALL cc, nn + 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", 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", Instruction::UNCONDITIONAL_RET) + // RET cc + dis(0xC0, "RET NZ", Instruction::CONDITIONAL_RET) + dis(0xC8, "RET Z", Instruction::CONDITIONAL_RET) + dis(0xD0, "RET NC", Instruction::CONDITIONAL_RET) + dis(0xD8, "RET C", Instruction::CONDITIONAL_RET) + + dis(0xD9, "RETI", Instruction::UNCONDITIONAL_RET) + + default: + std::ostringstream errmsg; + errmsg << "Unknown opcode 0x"; + errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; + errmsg << " at 0x" << std::hex << std::setw(4) << PC-1; + logger.trace(errmsg.str()); + break; + + } // end switch + + return Instruction(PC-addr, ins_type, opcode, sub_opcode, + result.str(), opcode_str, op1, op2); +} + diff --git a/gbcore.h b/core/GameBoy.h similarity index 95% rename from gbcore.h rename to core/GameBoy.h index 8d7b328..27381e2 100644 --- a/gbcore.h +++ b/core/GameBoy.h @@ -18,14 +18,16 @@ #ifndef GBCORE_H #define GBCORE_H -#include "sized_types.h" -#include "GBMemory.h" -#include "GBVideo.h" -#include "Logger.h" #include #include #include +#include "GBMemory.h" +#include "GBVideo.h" +#include "Instruction.h" +#include "../common/sized_types.h" +#include "../common/Logger.h" + union GBRom; class GameBoy @@ -149,6 +151,8 @@ class GameBoy void disable_breakpoint(int id); std::string status_string(); + Instruction disassemble_opcode(u16 addr); + static std::string get_port_name(int port); // prevent object copying private: diff --git a/wendi/Instruction.h b/core/Instruction.h similarity index 98% rename from wendi/Instruction.h rename to core/Instruction.h index f7d5316..21e48f8 100644 --- a/wendi/Instruction.h +++ b/core/Instruction.h @@ -18,7 +18,7 @@ #ifndef INSTRUCTION_H #define INSTRUCTION_H -#include "../sized_types.h" +#include "../common/sized_types.h" struct Instruction { diff --git a/MBC.cc b/core/MBC.cc similarity index 97% rename from MBC.cc rename to core/MBC.cc index 07af1b5..689bb0e 100644 --- a/MBC.cc +++ b/core/MBC.cc @@ -19,7 +19,7 @@ #include "NoMBC.h" #include "MBC1.h" -#include "Logger.h" +#include "../common/Logger.h" MBC *create_MBC(GBRom *rom) { diff --git a/MBC.h b/core/MBC.h similarity index 96% rename from MBC.h rename to core/MBC.h index b678677..c265589 100644 --- a/MBC.h +++ b/core/MBC.h @@ -18,7 +18,7 @@ #ifndef MBC_H #define MBC_H -#include "sized_types.h" +#include "../common/sized_types.h" #include "GBRom.h" class MBC diff --git a/MBC1.cc b/core/MBC1.cc similarity index 98% rename from MBC1.cc rename to core/MBC1.cc index dfea2bc..f3a48b0 100644 --- a/MBC1.cc +++ b/core/MBC1.cc @@ -16,7 +16,7 @@ along with wenboi. If not, see . */ #include "MBC1.h" -#include "Logger.h" +#include "../common/Logger.h" #include #include diff --git a/MBC1.h b/core/MBC1.h similarity index 100% rename from MBC1.h rename to core/MBC1.h diff --git a/NoMBC.cc b/core/NoMBC.cc similarity index 98% rename from NoMBC.cc rename to core/NoMBC.cc index 1bdbd0b..2bf5c8e 100644 --- a/NoMBC.cc +++ b/core/NoMBC.cc @@ -16,7 +16,7 @@ along with wenboi. If not, see . */ #include "NoMBC.h" -#include "Logger.h" +#include "../common/Logger.h" #include diff --git a/NoMBC.h b/core/NoMBC.h similarity index 100% rename from NoMBC.h rename to core/NoMBC.h diff --git a/wendi/disasm_macros.h b/core/disasm_macros.h similarity index 88% rename from wendi/disasm_macros.h rename to core/disasm_macros.h index 2721e53..54a203e 100644 --- a/wendi/disasm_macros.h +++ b/core/disasm_macros.h @@ -16,8 +16,7 @@ along with wenboi. If not, see . */ -// Macros to avoid unnecesary repetition in disasm.cc (like opcodes.h for -// gbcore) +// Macros to avoid unnecesary repetition in GameBoy.cc (disassembler) #ifndef DISASM_MACROS_H #define DISASM_MACROS_H @@ -91,11 +90,11 @@ // OP inm8 #define dis_inm8(opcode, name, itype) \ case opcode: {\ - int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ + int inm = int(this->memory.read(PC++, GBMemory::DONT_WATCH)); \ result << name << " 0x" << std::setw(2) << inm; \ opcode_str = name; \ ins_type = itype; \ - op1.str = ToString(inm); \ + op1.str = toString(inm); \ op2.str = ""; \ op1.type = Instruction::INM8; \ op1.val = inm; \ @@ -106,12 +105,12 @@ // OP inm16 #define dis_inm16(opcode, name, itype) \ case opcode: {\ - int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ + int inm = int(this->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); \ + op1.str = toString(inm); \ op2.str = ""; \ op1.type = Instruction::INM16; \ op1.val = inm; \ @@ -121,12 +120,12 @@ #define dis_reg_inm(opcode, name, itype, reg8) \ case opcode: {\ - int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ + int inm = int(this->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); \ + op2.str = toString(inm); \ op1.type = Instruction::REG; \ op1.reg = Instruction::reg8; \ op2.type = Instruction::INM8; \ @@ -136,13 +135,13 @@ #define dis_reg16_inm(opcode, name, itype, reg16) \ case opcode: {\ - int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ + int inm = int(this->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); \ + op2.str = toString(inm); \ op1.type = Instruction::REG; \ op1.reg = Instruction::reg16; \ op2.type = Instruction::INM8; \ @@ -152,12 +151,12 @@ #define dis_reg16_inm8(opcode, name, itype, reg16) \ case opcode: {\ - int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ + int inm = int(this->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); \ + op2.str = toString(inm); \ op1.type = Instruction::REG; \ op1.reg = Instruction::reg16; \ op2.type = Instruction::INM8; \ @@ -221,14 +220,14 @@ // OP reg, (inm) #define dis_reg__inm_(opcode, name, itype, reg8) \ case opcode: {\ - int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ + int inm = int(this->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) + ")"; \ + op2.str = std::string("(") + toString(inm) + ")"; \ op1.type = Instruction::REG; \ op1.reg = Instruction::reg8; \ op2.type = Instruction::MEM_DIRECT; \ @@ -256,13 +255,13 @@ // OP (inm), reg #define dis__inm__reg(opcode, name, itype, reg8) \ case opcode: {\ - int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ + int inm = int(this->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) + ")"; \ + op1.str = std::string("(") + toString(inm) + ")"; \ op2.str = #reg8; \ op1.type = Instruction::MEM_DIRECT; \ op1.val = inm; \ @@ -274,13 +273,13 @@ // OP (inm), reg16 #define dis__inm__reg16(opcode, name, itype, reg16) \ case opcode: {\ - int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \ + int inm = int(this->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) + ")"; \ + op1.str = std::string("(") + toString(inm) + ")"; \ op2.str = #reg16; \ op1.type = Instruction::MEM_DIRECT; \ op1.val = inm; \ @@ -292,13 +291,13 @@ // OP (reg16), inm #define dis__reg16__inm(opcode, name, itype, reg16) \ case opcode: {\ - int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \ + int inm = int(this->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); \ + op2.str = toString(inm); \ op1.type = Instruction::MEM_INDIRECT; \ op1.reg = Instruction::reg16; \ op2.type = Instruction::INM8; \ @@ -310,13 +309,13 @@ // Special routine for JR #define dis_JR(opcode, name, itype) \ case opcode: { \ - s8 offset = gb.memory.read(PC++); \ + s8 offset = this->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.str = toString(int(offset)); \ + op2.str = toString(int(PC+offset)); \ op1.type = Instruction::INM8; \ op1.val = offset; \ op2.type = Instruction::NONE; \ diff --git a/opcodes.h b/core/opcodes.h similarity index 99% rename from opcodes.h rename to core/opcodes.h index f2507d1..6ed1d2c 100644 --- a/opcodes.h +++ b/core/opcodes.h @@ -16,7 +16,7 @@ along with wenboi. If not, see . */ -// Macro definitions to avoid unnecesary repetition in gbcore.cc +// Macro definitions to avoid unnecesary repetition in GameBoy.cc #ifndef OPCODES_H #define OPCODES_H diff --git a/util.cc b/core/util.cc similarity index 100% rename from util.cc rename to core/util.cc diff --git a/util.h b/core/util.h similarity index 96% rename from util.h rename to core/util.h index 5765878..b06b4d7 100644 --- a/util.h +++ b/core/util.h @@ -18,7 +18,7 @@ #ifndef UTIL_H #define UTIL_H -#include "sized_types.h" +#include "../common/sized_types.h" uint32 set_bit(uint32 val, uint32 pos); uint32 reset_bit(uint32 val, uint32 pos); diff --git a/wenboi/CMakeLists.txt b/wenboi/CMakeLists.txt new file mode 100644 index 0000000..de03cf0 --- /dev/null +++ b/wenboi/CMakeLists.txt @@ -0,0 +1,4 @@ +ADD_EXECUTABLE(wenboi wenboi.cc) +TARGET_LINK_LIBRARIES(wenboi wenboicore ${SDL_LIBRARY}) +INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR}) + diff --git a/tests/test_core.cc b/wenboi/wenboi.cc similarity index 98% rename from tests/test_core.cc rename to wenboi/wenboi.cc index c6b60d1..e6c979b 100644 --- a/tests/test_core.cc +++ b/wenboi/wenboi.cc @@ -15,9 +15,8 @@ You should have received a copy of the GNU General Public License along with wenboi. If not, see . */ -#include "../gbcore.h" -#include "../Logger.h" -#include "../wendi/disasm.h" +#include "../core/GameBoy.h" +#include "../common/Logger.h" #include #include #include @@ -181,7 +180,7 @@ int main(int argc, char **argv) pos = start; while (pos < end) { - Instruction ins(disassemble_opcode(gb, pos)); + Instruction ins(gb.disassemble_opcode(pos)); cout << "0x" << std::hex << std::setw(4) << std::setfill('0') << pos << "\t"; for (int i=0; i #include #include -#include "Instruction.h" -#include "../sized_types.h" +#include "../core/Instruction.h" +#include "../common/sized_types.h" typedef u16 address; diff --git a/wendi/disasm.cc b/wendi/disasm.cc deleted file mode 100644 index 888e385..0000000 --- a/wendi/disasm.cc +++ /dev/null @@ -1,549 +0,0 @@ -/* - Copyright 2008 Jorge Gorbe Moya - - This file is part of wenboi - - wenboi is free software: you can redistribute it and/or modify it under the - terms of the GNU General Public License version 3 only, as published by the - Free Software Foundation. - - wenboi is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with wenboi. If not, see . -*/ -#include - -#include "../Logger.h" -#include "disasm.h" -#include "disasm_macros.h" - -std::string get_port_name(int port) -{ - std::string port_name; - - switch (port) - { - case 0x00: port_name = "JOYP"; break; - case 0x01: port_name = "SB "; break; - case 0x02: port_name = "SC "; break; - case 0x04: port_name = "DIV "; break; - case 0x05: port_name = "TIMA"; break; - case 0x06: port_name = "TMA "; break; - case 0x07: port_name = "TAC "; break; - case 0x10: port_name = "CH1_ENT"; break; - case 0x11: port_name = "CH1_WAVE"; break; - case 0x12: port_name = "CH1_ENV"; break; - case 0x13: port_name = "CH1_FREQ_LO"; break; - case 0x14: port_name = "CH1_FREQ_HI_KICK"; break; - case 0x16: port_name = "CH2_WAVE"; break; - case 0x17: port_name = "CH2_ENV"; break; - case 0x18: port_name = "CH2_FREQ_LO"; break; - case 0x19: port_name = "CH2_FREQ_HI_KICK"; break; - case 0x1A: port_name = "CH3_ONOFF"; break; - case 0x1C: port_name = "CH3_VOLUME"; break; - case 0x1D: port_name = "CH3_FREQ_LO"; break; - case 0x1E: port_name = "CH3_FREQ_HI_KICK"; break; - case 0x21: port_name = "CH4_ENV"; break; - case 0x22: port_name = "CH4_POLY"; break; - case 0x23: port_name = "CH4_KICK"; break; - case 0x24: port_name = "SND_VIN"; break; - case 0x25: port_name = "SND_STEREO"; break; - case 0x26: port_name = "SND_STAT"; break; - case 0x40: port_name = "LCDC"; break; - case 0x41: port_name = "STAT"; break; - case 0x42: port_name = "SCY "; break; - case 0x43: port_name = "SCX "; break; - case 0x44: port_name = "LY "; break; - case 0x45: port_name = "LYC "; break; - case 0x4A: port_name = "WY "; break; - case 0x4B: port_name = "WX "; break; - case 0x47: port_name = "BGP "; break; - case 0x48: port_name = "OBP0"; break; - case 0x49: port_name = "OBP1"; break; - case 0x46: port_name = "DMA "; break; - case 0x0F: port_name = "IF "; break; - case 0xFF: port_name = "IE "; break; - default: - if (port >= 0x80 && port <= 0xFE) - port_name = "HRAM"; - else if (port >= 0x30 && port <= 0x3F) - port_name = "Wave Pattern RAM"; - - } - return port_name; -} - - -Instruction disassemble_opcode(GameBoy &gb, u16 addr) -{ - u8 opcode, sub_opcode=0xFF; - std::ostringstream result; - 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", Instruction::LOAD, dis_reg_inm) - - // LD r1,r2 - 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", Instruction::LOAD, dis_reg__HL_) - - // LD (HL), reg - dis_for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, "LD", Instruction::LOAD, dis__HL__reg) - - dis__reg16__inm(0x36, "LD", Instruction::LOAD, HL) - - 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", 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; - op1.reg =Instruction::A; - op2.type=Instruction::MEM_INDIRECT; - op2.reg =Instruction::C; - break; - - // LD (C), A - 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; - op1.reg =Instruction::C; - op2.type=Instruction::REG; - op2.reg =Instruction::A; - break; - - // LD A, (HLD); LD A, (HL-); LDD A,(HL); - case 0x3A: - result << "LD A, (HL-)"; - opcode_str = "LDD"; - ins_type = Instruction::LOAD; - op1.str="A"; - op2.str="(HL)"; - op1.type=Instruction::REG; - op1.reg =Instruction::A; - op2.type=Instruction::MEM_INDIRECT; - op2.reg =Instruction::HL; - break; - // LD (HLD), A; LD (HL-), A; LDD (HL), A; - case 0x32: - result << "LD (HL-), A"; - opcode_str = "LDD"; - ins_type = Instruction::LOAD; - op1.str="(HL)"; - op2.str="A"; - op1.type=Instruction::MEM_INDIRECT; - op1.reg =Instruction::HL; - op2.type=Instruction::REG; - op2.reg =Instruction::A; - break; - // LD A, (HLI); LD A, (HL+); LDI A, (HL); - case 0x2A: - result << "LD A, (HL+)"; - opcode_str = "LDI"; - ins_type = Instruction::LOAD; - op1.str="A"; - op2.str="(HL)"; - op1.type=Instruction::REG; - op1.reg =Instruction::A; - op2.type=Instruction::MEM_INDIRECT; - op2.reg =Instruction::HL; - break; - // LD (HLI), A; LD (HL+), A; LDI (HL), A; - case 0x22: - result << "LD (HL+), A"; - opcode_str = "LDI"; - ins_type = Instruction::LOAD; - op1.str="(HL)"; - op2.str="A"; - op1.type=Instruction::MEM_INDIRECT; - op1.reg =Instruction::HL; - op2.type=Instruction::REG; - op2.reg =Instruction::A; - break; - - // LDH (n), A - case 0xE0: { - int port = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); - - 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; - op1.val =0xFF00+port; - op2.type=Instruction::REG; - op2.reg =Instruction::A; - break; - } - // LDH A, (n) - case 0xF0: { - int port = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); - 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; - op1.reg =Instruction::A; - op2.type=Instruction::MEM_DIRECT; - op2.val =0xFF00+port; - break; - } - - 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; - op1.reg = Instruction::SP; - op2.type = Instruction::REG; - op2.reg = Instruction::HL; - - // LD HL, SP+n - // LDHL SP, n - case 0xF8: { - 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; - op1.val = n; - break; - } - - // LD (nn), SP - dis__inm__reg16(0x08, "LD", Instruction::LOAD, SP) - - // PUSH nn - 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", 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", Instruction::ALU, dis_A_reg) - - 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", Instruction::ALU, dis_A_reg) - - 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", Instruction::ALU, dis_reg) - - 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", Instruction::ALU, dis_reg) - - dis__reg16_(0x9E, "SBC", Instruction::ALU, HL) - dis_reg_inm(0xDE, "SBC", Instruction::ALU, A) - - // AND n - dis_for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, "AND", Instruction::ALU, dis_reg) - - 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", Instruction::ALU, dis_reg) - - 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", Instruction::ALU, dis_reg) - - 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", Instruction::ALU, dis_reg) - - 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", Instruction::ALU, dis_reg) - - dis__reg16_(0x34, "INC", Instruction::ALU, HL) - - // DEC n - dis_for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, "DEC", Instruction::ALU, dis_reg) - - dis__reg16_(0x35, "DEC", Instruction::ALU, HL) - - // 16-bit ALU - // ADD HL, n - dis_for_each_register16(0x09, 0x19, 0x29, 0x39, "ADD", Instruction::ALU, dis_HL_reg16) - - // ADD SP, # - dis_reg16_inm8(0xE8, "ADD", Instruction::ALU, SP) - - // INC nn - dis_for_each_register16(0x03, 0x13, 0x23, 0x33, "INC", Instruction::ALU, dis_reg16) - - // DEC nn - dis_for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, "DEC", Instruction::ALU, dis_reg16) - - // Miscellaneous instructions - case 0xCB: { - sub_opcode = gb.memory.read(PC++, GBMemory::DONT_WATCH); - switch(sub_opcode) - { - // SWAP n - dis_for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, "SWAP", Instruction::ALU, dis_reg) - - // SWAP (HL) - dis__reg16_(0x36, "SWAP", Instruction::ALU, HL) - - // RLC n - dis_for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, "RLC", Instruction::ALU, dis_reg) - - // 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", Instruction::ALU, dis_reg) - - // RL (HL) (through carry) - dis__reg16_(0x16, "RL", Instruction::ALU, HL) - - // RRC n - dis_for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, "RRC", Instruction::ALU, dis_reg) - - // 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", Instruction::ALU, dis_reg) - - // RR (HL) (through carry) - dis__reg16_(0x1E, "RR", Instruction::ALU, HL) - - // SLA n - dis_for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, "SLA", Instruction::ALU, dis_reg) - - // SLA (HL) - dis__reg16_(0x26, "SLA", Instruction::ALU, HL) - - // SRA n - dis_for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, "SRA", Instruction::ALU, dis_reg) - - // SRA (HL) - dis__reg16_(0x2E, "SRA", Instruction::ALU, HL) - - // SRL n - dis_for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, "SRA", Instruction::ALU, dis_reg) - - // SRL (HL) - dis__reg16_(0x3E, "SRA", Instruction::ALU, HL) - - default: { - int bit_op = sub_opcode >> 6; - int reg = sub_opcode & 7; - int b = (sub_opcode >> 3) & 7; - 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; - } - - } - break; - } - - dis(0x27, "DAA", Instruction::ALU) - - dis(0x2F, "CPL", Instruction::ALU) - - dis(0x3F, "CCF", Instruction::ALU) - - dis(0x37, "SCF", Instruction::ALU) - dis(0x00, "NOP", Instruction::OTHER) - dis(0x76, "HALT", Instruction::OTHER) - - dis(0x10, "STOP", Instruction::OTHER) - - dis(0xF3, "DI", Instruction::OTHER) - - dis(0xFB, "EI", Instruction::OTHER) - - // Rotates and shifts - dis(0x07, "RLCA", Instruction::ALU) - - dis(0x17, "RLA", Instruction::ALU) - - dis(0x0F, "RRCA", Instruction::ALU) - - dis(0x1F, "RRA", Instruction::ALU) - - // Jumps - dis_inm16(0xC3, "JP", Instruction::UNCONDITIONAL_JUMP) - // JP cc, nn - 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; - op1.reg = Instruction::HL; - op2.type = Instruction::NONE; - break; - - 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", Instruction::CALL) - // CALL cc, nn - 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", 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", Instruction::UNCONDITIONAL_RET) - // RET cc - dis(0xC0, "RET NZ", Instruction::CONDITIONAL_RET) - dis(0xC8, "RET Z", Instruction::CONDITIONAL_RET) - dis(0xD0, "RET NC", Instruction::CONDITIONAL_RET) - dis(0xD8, "RET C", Instruction::CONDITIONAL_RET) - - dis(0xD9, "RETI", Instruction::UNCONDITIONAL_RET) - - default: - std::ostringstream errmsg; - errmsg << "Unknown opcode 0x"; - errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; - errmsg << " at 0x" << std::hex << std::setw(4) << PC-1; - logger.trace(errmsg.str()); - break; - - } // end switch - - return Instruction(PC-addr, ins_type, opcode, sub_opcode, - result.str(), opcode_str, op1, op2); -} - diff --git a/wendi/disassembly_output.h b/wendi/disassembly_output.h index 0ab845b..bf3e6ee 100644 --- a/wendi/disassembly_output.h +++ b/wendi/disassembly_output.h @@ -18,7 +18,7 @@ #ifndef DISASSEMBLY_OUTPUT_H #define DISASSEMBLY_OUTPUT_H -#include "../gbcore.h" +#include "../core/GameBoy.h" #include "CodeBlock.h" #include diff --git a/wendi/output_graph.cc b/wendi/output_graph.cc index 517f890..27a8863 100644 --- a/wendi/output_graph.cc +++ b/wendi/output_graph.cc @@ -16,9 +16,9 @@ along with wenboi. If not, see . */ #include "output_graph.h" +#include "../common/Logger.h" #include #include -#include "../Logger.h" using std::vector; using std::string; diff --git a/wendi/wendi.cc b/wendi/wendi.cc index 78b87c9..fc42582 100644 --- a/wendi/wendi.cc +++ b/wendi/wendi.cc @@ -18,13 +18,12 @@ // wendi, the WENboi DIsassembler :) -#include "../gbcore.h" -#include "../Logger.h" +#include "../core/GameBoy.h" +#include "../common/Logger.h" #include "disassembly_output.h" #include "output_txt.h" #include "output_graph.h" #include "CodeBlock.h" -#include "disasm.h" #include #include @@ -332,7 +331,7 @@ int main(int argc, char **argv) bool block_end = false; while(!block_end) { - Instruction ins(disassemble_opcode(gb, addr)); + Instruction ins(gb.disassemble_opcode(addr)); block.add_instruction(ins.all, ins.length); if (is_jump(ins))