New disassembler WIP. Build is completely broken now.
authorslack <slack@codemaniacs.com>
Fri, 15 Aug 2008 13:00:53 +0000 (15:00 +0200)
committerslack <slack@codemaniacs.com>
Fri, 15 Aug 2008 13:00:53 +0000 (15:00 +0200)
Makefile
disasm.h [deleted file]
gbcore.cc
gbcore.h
wendi/CodeBlock.cc [new file with mode: 0644]
wendi/CodeBlock.h [new file with mode: 0644]
wendi/disasm.cc [new file with mode: 0644]
wendi/disasm.h [new file with mode: 0644]
wendi/disasm_macros.h [new file with mode: 0644]
wendi/wendi.cc [new file with mode: 0644]

index b9f3565a114b4b7e1a037dc953508d3743b17768..1883f63b0bcf1ade2268600c7362e35e71dc92a3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ LDFLAGS=-pg -g $(shell sdl-config --libs)
 
 all: tests
 
-tests: tests/test_gbrom tests/test_core
+tests: tests/test_gbrom tests/test_core wendi/wendi
 
 util.o: util.cc util.h
        g++ $(CXXFLAGS) -c -o $@ $<
@@ -36,6 +36,13 @@ tests/test_core: tests/test_core.cc gbcore.o MBC.o GBMemory.o GBRom.o \
        GBVideo.o util.o NoMBC.o MBC1.o
        g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
 
+wendi/CodeBlock.o: wendi/CodeBlock.cc wendi/CodeBlock.h
+       g++ $(CXXFLAGS) -c -o $@ $<
+
+wendi/wendi: wendi/wendi.cc wendi/CodeBlock.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 tests/test_gbrom tests/test_core
 
diff --git a/disasm.h b/disasm.h
deleted file mode 100644 (file)
index d20de97..0000000
--- a/disasm.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#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) \
-       case opcode: \
-               result << name; \
-               break;
-
-// OP reg
-#define dis_reg(opcode, name, reg) \
-       case opcode: \
-               result << name << " " << #reg; \
-               break;
-
-
-// OP reg16
-#define dis_reg16(opcode, name, reg16) \
-       case opcode: \
-               result << name << " " << #reg16; \
-               break;
-
-// OP (reg16)
-#define dis__reg16_(opcode, name, reg16) \
-       case opcode: \
-               result << name << " (" << #reg16 << ")"; \
-               break;
-
-// OP inm8
-#define dis_inm8(opcode, name) \
-       case opcode: \
-               result << name << " 0x" << std::setw(2) << \
-                               int(memory.read(PC++, GBMemory::DONT_WATCH)); \
-               break;
-
-// OP inm16
-#define dis_inm16(opcode, name) \
-       case opcode: \
-               result << name << " 0x" << std::setw(4) << \
-                               int(memory.read16(PC, GBMemory::DONT_WATCH)); \
-               PC += 2; \
-               break;
-
-#define dis_reg_inm(opcode, name, reg) \
-       case opcode: \
-               result << name << " " << #reg << ", 0x" << std::setw(2) << \
-                               int(memory.read(PC++, GBMemory::DONT_WATCH)); \
-               break;
-
-#define dis_reg16_inm(opcode, name, reg16) \
-       case opcode: \
-               result << name << " " << #reg16 << ", 0x" << \
-                               std::setw(4) << \
-                               int(memory.read16(PC, GBMemory::DONT_WATCH)); \
-               PC += 2; \
-               break;
-
-#define dis_reg16_inm8(opcode, name, reg16) \
-       case opcode: \
-               result << name << " " << #reg16 << ", 0x" << \
-                               std::setw(2) << \
-                               int(memory.read(PC++, GBMemory::DONT_WATCH)); \
-               break;
-
-#define dis_reg_reg(opcode, name, reg1, reg2) \
-       case opcode: \
-               result << name << " " << #reg1 << ", " << #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_reg16_reg16(opcode, name, reg16_1, reg16_2) \
-       case opcode: \
-               result << name << " " << #reg16_1 << ", " << #reg16_2; \
-               break;
-
-#define dis_HL_reg16(opcode, name, reg16_2) dis_reg16_reg16(opcode, name, HL, reg16_2)
-
-// OP reg, (reg16)
-#define dis_reg__reg16_(opcode, name, reg, reg16) \
-       case opcode: \
-               result << name << " " << #reg << ", (" << #reg16 << ")"; \
-               break;
-
-// OP reg, (HL)
-#define dis_reg__HL_(opcode, name, reg) dis_reg__reg16_(opcode, name, reg, HL)
-
-// OP reg, (inm)
-#define dis_reg__inm_(opcode, name, reg) \
-       case opcode: \
-               result << name << " " << #reg << ", (0x" << \
-                               std::setw(4) << \
-                               int(memory.read16(PC, GBMemory::DONT_WATCH)) << \
-                               ")"; \
-               PC += 2; \
-               break;
-
-// OP (reg16), reg
-#define dis__reg16__reg(opcode, name, reg16, reg) \
-       case opcode: \
-               result << name << " (" << #reg16 << "), " << #reg; \
-               break;
-
-// OP (HL), reg
-#define dis__HL__reg(opcode, name, reg) dis__reg16__reg(opcode, name, HL, reg)
-
-// OP (inm), reg
-#define dis__inm__reg(opcode, name, reg) \
-       case opcode: \
-               result << name << " (0x" << \
-                               std::setw(4) << \
-                               int(memory.read16(PC, GBMemory::DONT_WATCH)) << \
-                               "), " << #reg; \
-               PC += 2; \
-               break;
-
-// OP (inm), reg16
-#define dis__inm__reg16(opcode, name, reg16) \
-       case opcode: \
-               result << name << " (0x" << \
-                               std::setw(4) << \
-                               int(memory.read16(PC, GBMemory::DONT_WATCH)) << \
-                               "), " << #reg16; \
-               PC += 2; \
-               break;
-
-// OP (reg16), inm
-#define dis__reg16__inm(opcode, name, reg16) \
-       case opcode: \
-               result << name << " (" << #reg16 << "), 0x" << \
-                               std::setw(2) << \
-                               int(memory.read(PC++, GBMemory::DONT_WATCH)); \
-               break;
-
-
-// Special routine for JR
-#define dis_JR(opcode, name) \
-       case opcode: { \
-               s8 offset = memory.read(PC++); \
-               result << name << " " << std::dec << int(offset) << "\t[0x" \
-                                << std::hex << std::setw(2) << int(PC+offset) << "]"; \
-               break; \
-       }
-
-
-////////////////////////////////////////////////////////////
-
-
-
-
-
-
-
-
-
-
-
index 665844db2ef7ef6095a00e8ec3d999b0a6807ffe..0b6695807fbecaf4c05980c4aaf561787bc308e3 100644 (file)
--- a/gbcore.cc
+++ b/gbcore.cc
@@ -1426,59 +1426,6 @@ GameBoy::run_status GameBoy::run()
        return status;
 }
 
-std::string GameBoy::get_port_name(int port) const
-{
-       std::string port_name;
-
-       switch (port)
-       {
-               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;
-}
-
 std::string GameBoy::status_string()
 {
        std::string disassembled_instruction;
@@ -1553,13 +1500,13 @@ void GameBoy::disassemble_opcode(u16 addr, std::string &instruction, int &length
                dis(0xE2, "LD (0xFF00+C), A")
 
                // LD A, (HLD); LD A, (HL-); LDD A,(HL);
-               dis(0x3A, "LD A, (HL-)")
+               dis(0x3A, "LDD A, (HL)")
                // LD (HLD), A; LD (HL-), A; LDD (HL), A;
-               dis(0x32, "LD (HL-), A")
+               dis(0x32, "LDD (HL), A")
                // LD A, (HLI); LD A, (HL+); LDI A, (HL);
-               dis(0x2A, "LD A, (HL+)")
+               dis(0x2A, "LDI A, (HL)")
                // LD (HLI), A; LD (HL+), A; LDI (HL), A;
-               dis(0x22, "LD (HL+), A")
+               dis(0x22, "LDI (HL), A")
 
                // LDH (n), A
                case 0xE0: {
index 5201b66e8f008e63e6d8007327f2131cafe3891a..48808ea576994cc9efe43c8a023b95acff2e3c23 100644 (file)
--- a/gbcore.h
+++ b/gbcore.h
@@ -117,7 +117,6 @@ class GameBoy
        void disable_breakpoint(int id);
 
        std::string status_string();
-       std::string get_port_name(int port) const;
 
        // prevent object copying
        private:
diff --git a/wendi/CodeBlock.cc b/wendi/CodeBlock.cc
new file mode 100644 (file)
index 0000000..ab0dd7f
--- /dev/null
@@ -0,0 +1,46 @@
+#include "CodeBlock.h"
+
+#include <algorithm>
+#include <ext/functional>
+
+CodeBlock::CodeBlock(address start): //< creates an empty CodeBlock 
+       start(start),
+       end(start),
+       disassembly(),
+       xrefs()
+{}
+
+CodeBlock::CodeBlock(CodeBlock &block, address addr): //< removes [addr,end[ from the block creating a new one
+       start(addr),
+       end(block.end),
+       disassembly(),
+       xrefs()
+{
+       using std::bind2nd;
+       using __gnu_cxx::select1st;
+       using std::equal_to;
+       block.end = addr;
+
+       // HAHA! I'M USING STL EXTENSIONS!!!1
+       DisassemblyIterator first = std::find_if(block.disassembly.begin(),
+                       block.disassembly.end(),
+                       compose1(bind2nd(equal_to<address>(), addr),
+                               select1st<DisassemblyItem>()));
+       DisassemblyIterator last  = block.disassembly.end();
+       disassembly.splice(disassembly.end(), block.disassembly, first, last);
+}
+
+
+void CodeBlock::add_instruction(std::string ins, int nbytes) // appends an instruction to the end of the block
+{
+       disassembly.push_back(std::make_pair(end,ins));
+       end += nbytes;
+}
+
+void CodeBlock::add_xref(address addr, JumpType jt)
+{
+       xrefs.push_back(std::make_pair(addr, jt));
+}
+
+
+
diff --git a/wendi/CodeBlock.h b/wendi/CodeBlock.h
new file mode 100644 (file)
index 0000000..dc43cd2
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef CODEBLOCK_H
+#define CODEBLOCK_H
+
+#include <vector>
+#include <utility>
+#include <string>
+#include <list>
+#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<address, std::string> DisassemblyItem;
+       typedef std::pair<address, JumpType>    XrefsItem;
+       typedef std::list<DisassemblyItem>      DisassemblyList;
+       typedef std::vector<XrefsItem>          XrefsVector;
+       
+       typedef DisassemblyList::iterator       DisassemblyIterator;
+       typedef DisassemblyList::const_iterator DisassemblyConstIterator;
+       typedef XrefsVector::iterator           XrefsIterator;
+       typedef XrefsVector::const_iterator     XrefsConstIterator;
+
+       address start, end;  // block is [start, end[
+       DisassemblyList disassembly;
+       XrefsVector xrefs;
+
+
+       CodeBlock(address start); //< creates an empty CodeBlock 
+       CodeBlock(CodeBlock &block, address addr); //< removes [addr,end[ from the block creating a new one
+
+       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);
+};
+
+
+
+#endif
+
diff --git a/wendi/disasm.cc b/wendi/disasm.cc
new file mode 100644 (file)
index 0000000..3f56883
--- /dev/null
@@ -0,0 +1,381 @@
+#include "disasm.h"
+#include "disasm_macros.h"
+
+std::string get_port_name(int port)
+{
+       std::string port_name;
+
+       switch (port)
+       {
+               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;
+}
+
+
+void disassemble_opcode(GameBoy &gb, u16 addr, std::string &instruction, int &length)
+{
+       int opcode;
+       std::ostringstream result;
+       std::string              opcode_str, op1_str, op2_str;
+       Instruction::OperandType op1_type, op2_type;
+       Instruction::Operand     op1, op2;
+
+       u16 PC = addr;
+       opcode = gb.memory.read(PC++, GBMemory::DONT_WATCH);
+
+       result << std::hex << std::uppercase << std::setfill('0');
+       
+       switch(opcode)
+       {
+               // LD n, nn
+               dis_for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, "LD", 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)
+               
+               // LD reg, (HL)
+               dis_for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, "LD", dis_reg__HL_)
+
+               // LD (HL), reg
+               dis_for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, "LD", dis__HL__reg)
+       
+               dis__reg16__inm(0x36, "LD", HL)
+               
+               dis_reg__reg16_(0x0A, "LD", A, BC)
+               dis_reg__reg16_(0x1A, "LD", A, DE)
+               dis_reg__inm_(0xFA, "LD", A)
+
+               dis__reg16__reg(0x02, "LD", BC, A)
+               dis__reg16__reg(0x12, "LD", DE, A)
+               dis__inm__reg(0xEA, "LD", A)
+
+               // LD A, (C)
+               dis(0xF2, "LD A, (0xFF00+C)")
+               // LD (C), A
+               dis(0xE2, "LD (0xFF00+C), A")
+
+               // LD A, (HLD); LD A, (HL-); LDD A,(HL);
+               dis(0x3A, "LDD A, (HL)")
+               // LD (HLD), A; LD (HL-), A; LDD (HL), A;
+               dis(0x32, "LDD (HL), A")
+               // LD A, (HLI); LD A, (HL+); LDI A, (HL);
+               dis(0x2A, "LDI A, (HL)")
+               // LD (HLI), A; LD (HL+), A; LDI (HL), A;
+               dis(0x22, "LDI (HL), A")
+
+               // 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) << "]";
+                       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) << "]";
+                       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)
+               
+               // LD SP, HL
+               dis(0xF9, "LD SP, HL")
+
+               // LD HL, SP+n
+               // LDHL SP, n
+               case 0xF8: 
+                       result << "LD HL, SP + 0x"<< std::setw(2) << int(gb.memory.read(PC++, GBMemory::DONT_WATCH));
+                       break; 
+
+               // LD (nn), SP
+               dis__inm__reg16(0x08, "LD", SP)
+
+               // PUSH nn
+               dis_reg16(0xF5, "PUSH", AF)
+               dis_reg16(0xC5, "PUSH", BC)
+               dis_reg16(0xD5, "PUSH", DE)
+               dis_reg16(0xE5, "PUSH", HL)
+
+               // POP nn
+               dis_reg16(0xF1, "POP", AF)
+               dis_reg16(0xC1, "POP", BC)
+               dis_reg16(0xD1, "POP", DE)
+               dis_reg16(0xE1, "POP", HL)
+
+               // 8-bit ALU
+               // ADD A,reg
+               dis_for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, "ADD", dis_A_reg)
+
+               dis_reg__reg16_(0x86, "ADD", A, HL)
+               dis_reg_inm(0xC6, "ADD", A)
+               
+               // ADC A, n
+               dis_for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, "ADC", dis_A_reg)
+               
+               dis_reg__reg16_(0x8E, "ADC", A, HL)
+               dis_reg_inm(0xCE, "ADC", A)
+
+               // SUB n
+               dis_for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, "SUB", dis_reg)
+               
+               dis__reg16_(0x96, "SUB", HL)
+               dis_inm8(0xD6, "SUB")   
+               
+               // SBC n
+               dis_for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, "SBC", dis_reg)
+
+               dis__reg16_(0x9E, "SBC", HL)
+
+               // AND n
+               dis_for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, "AND", dis_reg)
+
+               dis__reg16_(0xA6, "AND", HL)
+               dis_inm8(0xE6, "AND")
+               
+               // OR n
+               dis_for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, "OR", dis_reg)
+               
+               dis__reg16_(0xB6, "OR", HL)
+               dis_inm8(0xF6, "OR")
+
+               // XOR n
+               dis_for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, "XOR", dis_reg)
+
+               dis__reg16_(0xAE, "XOR", HL)
+               dis_inm8(0xEE, "XOR")
+               
+               // CP n
+               dis_for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, "CP", dis_reg)
+               
+               dis__reg16_(0xBE, "CP", HL)
+               dis_inm8(0xFE, "CP")
+
+               // INC n
+               dis_for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, "INC", dis_reg)
+
+               dis__reg16_(0x34, "INC", HL)
+               
+               // DEC n
+               dis_for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, "DEC", dis_reg)
+
+               dis__reg16_(0x35, "DEC", HL)
+               
+               // 16-bit ALU
+               // ADD HL, n
+               dis_for_each_register16(0x09, 0x19, 0x29, 0x39, "ADD", dis_HL_reg16)
+
+               // ADD SP, #
+               dis_reg16_inm8(0xE8, "ADD", SP)
+               
+               // INC nn
+               dis_for_each_register16(0x03, 0x13, 0x23, 0x33, "INC", dis_reg16)
+
+               // DEC nn
+               dis_for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, "DEC", dis_reg16)
+
+               // Miscellaneous instructions
+               case 0xCB: {
+                       int 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", dis_reg)
+
+                               // SWAP (HL)
+                               dis__reg16_(0x36, "SWAP", HL)
+
+                               // RLC n
+                               dis_for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, "RLC", dis_reg)
+
+                               // RLC (HL)
+                               dis__reg16_(0x06, "RLC", HL)
+
+                               // RL n (through carry)
+                               dis_for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, "RL", dis_reg)
+
+                               // RL (HL) (through carry)
+                               dis__reg16_(0x16, "RL", HL)
+
+                               // RRC n
+                               dis_for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, "RRC", dis_reg)
+
+                               // RRC (HL)
+                               dis__reg16_(0x0E, "RRC", HL)
+
+                               // RR n (through carry)
+                               dis_for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, "RR", dis_reg)
+
+                               // RR (HL) (through carry)
+                               dis__reg16_(0x1E, "RR", HL)
+
+                               // SLA n
+                               dis_for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, "SLA", dis_reg)
+
+                               // SLA (HL)
+                               dis__reg16_(0x26, "SLA", HL)
+
+                               // SRA n
+                               dis_for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, "SRA", dis_reg)
+                               
+                               // SRA (HL)
+                               dis__reg16_(0x2E, "SRA", HL)
+
+                               // SRL n
+                               dis_for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, "SRA", dis_reg)
+                               
+                               // SRL (HL)
+                               dis__reg16_(0x3E, "SRA", 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];
+                                       break;
+                               }
+                               
+                       }
+                       break;
+               }
+
+               dis(0x27, "DAA")
+
+               dis(0x2F, "CPL")
+
+               dis(0x3F, "CCF")
+
+               dis(0x37, "SCF")
+               dis(0x00, "NOP")
+               dis(0x76, "HALT")
+
+               dis(0x10, "STOP")
+               
+               dis(0xF3, "DI")
+
+               dis(0xFB, "EI")
+                          
+               // Rotates and shifts
+               dis(0x07, "RLCA")
+
+               dis(0x17, "RLA")
+               
+               dis(0x0F, "RRCA")
+
+               dis(0x1F, "RRA")
+               
+               // TODO: Bit instructions
+               
+               // 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")
+               dis(0xE9, "JP (HL)")
+               
+               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")
+
+               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
+       
+       instruction = result.str();
+       length = PC - addr;
+}
+
diff --git a/wendi/disasm.h b/wendi/disasm.h
new file mode 100644 (file)
index 0000000..c0bd640
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DISASM_H
+#define DISASM_H
+
+#include <string>
+#include <sstream>
+
+struct Instruction
+{
+       enum Register { A=0,B,C,D,E,H,L,AF,BC,DE,HL,SP,PC };
+
+       enum OperandType
+       {
+               NONE=0,
+               REG,
+               MEM_DIRECT,
+               MEM_INDIRECT,
+               INM8,
+               INM16
+       };
+
+       union Operand {
+               Register reg;
+               int      val;
+       };
+
+       int length;
+       std::string all;
+
+       std::string opcode_str, op1_str, op2_str;
+       OperandType op1_type, op2_type;
+       Operand     op1, op2;
+};
+
+template <class T> 
+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/wendi/disasm_macros.h b/wendi/disasm_macros.h
new file mode 100644 (file)
index 0000000..b9315d4
--- /dev/null
@@ -0,0 +1,295 @@
+#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) \
+       case opcode: \
+               result << name; \
+               break;
+
+// OP reg
+#define dis_reg(opcode, name, reg) \
+       case opcode: \
+               result << name << " " << #reg; \
+               opcode_str = name; \
+               op1_str  = #reg; \
+               op2_str  = ""; \
+               op1_type = REG; \
+               op1.reg  = reg; \
+               op2.type = NONE; \
+               break;
+
+
+// OP reg16
+#define dis_reg16(opcode, name, reg16) \
+       case opcode: \
+               result << name << " " << #reg16; \
+               opcode_str = name; \
+               op1_str  = #reg16; \
+               op2_str  = ""; \
+               op1_type = REG; \
+               op1.reg  = reg16; \
+               op2.type = NONE; \
+               break;
+
+// OP (reg16)
+#define dis__reg16_(opcode, name, reg16) \
+       case opcode: \
+               result << name << " (" << #reg16 << ")"; \
+               opcode_str = name; \
+               op1_str  = std::string("(")+#reg16+")"; \
+               op2_str  = ""; \
+               op1_type = MEM_INDIRECT; \
+               op1.reg  = reg16; \
+               op2.type = NONE; \
+               break;
+
+// OP inm8
+#define dis_inm8(opcode, name) \
+       case opcode: {\
+               int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+               result << name << " 0x" << std::setw(2) << inm; \
+               opcode_str = name; \
+               op1_str  = ToString(inm); \
+               op2_str  = ""; \
+               op1_type = INM8; \
+               op1.val  = inm; \
+               op2.type = NONE; \
+               break; \
+       }
+
+// OP inm16
+#define dis_inm16(opcode, name) \
+       case opcode: {\
+               int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+        PC += 2; \
+               result << name << " 0x" << std::setw(4) << inm; \
+               opcode_str = name; \
+               op1_str  = ToString(inm); \
+               op2_str  = ""; \
+               op1_type = INM16; \
+               op1.val  = inm; \
+               op2.type = NONE; \
+               break; \
+       }
+
+#define dis_reg_inm(opcode, name, reg) \
+       case opcode: {\
+               int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+               result << name << " " << #reg << ", 0x" << std::setw(2) << inm; \
+               opcode_str = name; \
+               op1_str  = #reg; \
+               op2_str  = ToString(inm); \
+               op1_type = REG; \
+               op1.reg  = reg; \
+               op2.type = INM8; \
+               op2.val  = inm; \
+               break; \
+       }
+
+#define dis_reg16_inm(opcode, name, reg16) \
+       case opcode: {\
+               int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+               PC += 2; \
+               result << name << " " << #reg16 << ", 0x" << std::setw(4) << inm; \
+               opcode_str = name; \
+               op1_str  = #reg16; \
+               op2_str  = ToString(inm); \
+               op1_type = REG; \
+               op1.reg  = reg16; \
+               op2.type = INM8; \
+               op2.val  = inm; \
+               break; \
+       }
+
+#define dis_reg16_inm8(opcode, name, reg16) \
+       case opcode: {\
+               int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+               result << name << " " << #reg16 << ", 0x" << std::setw(2) << inm; \
+               opcode_str = name; \
+               op1_str  = #reg; \
+               op2_str  = ToString(inm); \
+               op1_type = REG; \
+               op1.reg  = reg; \
+               op2.type = INM8; \
+               op2.val  = inm; \
+               break; \
+       }
+
+#define dis_reg_reg(opcode, name, reg1, reg2) \
+       case opcode: \
+               result << name << " " << #reg1 << ", " << #reg2; \
+               opcode_str = name; \
+               op1_str  = #reg1; \
+               op2_str  = #reg2; \
+               op1_type = REG; \
+               op1.reg  = reg1; \
+               op2.type = REG; \
+               op2.val  = 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_reg16_reg16(opcode, name, reg16_1, reg16_2) \
+       case opcode: \
+               result << name << " " << #reg16_1 << ", " << #reg16_2; \
+               opcode_str = name; \
+               op1_str  = #reg16_1; \
+               op2_str  = #reg16_2; \
+               op1_type = REG; \
+               op1.reg  = reg16_1; \
+               op2.type = REG; \
+               op2.val  = reg16_2; \
+               break;
+
+#define dis_HL_reg16(opcode, name, reg16_2) dis_reg16_reg16(opcode, name, HL, reg16_2)
+
+// OP reg, (reg16)
+#define dis_reg__reg16_(opcode, name, reg, reg16) \
+       case opcode: \
+               result << name << " " << #reg << ", (" << #reg16 << ")"; \
+               opcode_str = name; \
+               op1_str  = #reg; \
+               op2_str  = std::string("(")+ #reg16 + ")"; \
+               op1_type = REG; \
+               op1.reg  = reg; \
+               op2.type = MEM_INDIRECT; \
+               op2.val  = reg16; \
+               break;
+
+// OP reg, (HL)
+#define dis_reg__HL_(opcode, name, reg) dis_reg__reg16_(opcode, name, reg, HL)
+
+// OP reg, (inm)
+#define dis_reg__inm_(opcode, name, reg) \
+       case opcode: {\
+               int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+        PC += 2; \
+               result << name << " " << #reg << ", (0x" << \
+                               std::setw(4) << inm << ")"; \
+               opcode_str = name; \
+               op1_str  = #reg; \
+               op2_str  = std::string("(") + ToString(inm) + ")"; \
+               op1_type = REG; \
+               op1.reg  = reg; \
+               op2.type = MEM_DIRECT; \
+               op2.val  = inm; \
+               break; \
+       }
+
+// OP (reg16), reg
+#define dis__reg16__reg(opcode, name, reg16, reg) \
+       case opcode: \
+               result << name << " (" << #reg16 << "), " << #reg; \
+               opcode_str = name; \
+               op1_str  = std::string("(")+ #reg16 + ")"; \
+               op2_str  = #reg; \
+               op1.type = MEM_INDIRECT; \
+               op1.val  = reg16; \
+               op2_type = REG; \
+               op2.reg  = reg; \
+               break;
+
+// OP (HL), reg
+#define dis__HL__reg(opcode, name, reg) dis__reg16__reg(opcode, name, HL, reg)
+
+// OP (inm), reg
+#define dis__inm__reg(opcode, name, reg) \
+       case opcode: {\
+               int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+        PC += 2; \
+               result << name << " (0x" << \
+                               std::setw(4) << inm << "), " << #reg; \
+               opcode_str = name; \
+               op1_str  = std::string("(") + ToString(inm) + ")"; \
+               op2_str  = #reg; \
+               op1.type = MEM_DIRECT; \
+               op1.val  = inm; \
+               op2_type = REG; \
+               op2.reg  = reg; \
+               break; \
+       }
+
+// OP (inm), reg16
+#define dis__inm__reg16(opcode, name, reg16) \
+       case opcode: {\
+               int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+        PC += 2; \
+               result << name << " (0x" << \
+                               std::setw(4) << inm << "), " << #reg16; \
+               opcode_str = name; \
+               op1_str  = std::string("(") + ToString(inm) + ")"; \
+               op2_str  = #reg; \
+               op1.type = MEM_DIRECT; \
+               op1.val  = inm; \
+               op2_type = REG; \
+               op2.reg  = reg16; \
+               break; \
+       }
+
+// OP (reg16), inm
+#define dis__reg16__inm(opcode, name, reg16) \
+       case opcode: {\
+               int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+               result << name << " (" << #reg16 << "), 0x" << \
+                               std::setw(2) << inm; \
+               opcode_str = name; \
+               op1_str  = std::string("(") + #reg16 + ")"; \
+               op2_str  = ToString(inm); \
+               op1.type = MEM_INDIRECT; \
+               op1.reg  = reg16; \
+               op2.type = INM8; \
+               op2.val  = inm; \
+               break; \
+       }
+
+
+// Special routine for JR
+#define dis_JR(opcode, name) \
+       case opcode: { \
+               s8 offset = memory.read(PC++); \
+               result << name << " " << std::dec << int(offset) << "\t[0x" \
+                                << std::hex << std::setw(2) << int(PC+offset) << "]"; \
+               opcode_str = name; \
+               op1_str  = ToString(int(offset)); \
+               op2_str  = ToString(int(PC+offset)); \
+               op1.type = INM8; \
+               op1.reg  = offset; \
+               op2.type = NONE; \
+               op2.val  = int(PC+offset); \
+               break; \
+       }
+
+
+////////////////////////////////////////////////////////////
+
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/wendi/wendi.cc b/wendi/wendi.cc
new file mode 100644 (file)
index 0000000..75c0d17
--- /dev/null
@@ -0,0 +1,56 @@
+#include "../gbcore.h"
+#include "CodeBlock.h"
+
+#include <vector>
+#include <utility>
+#include <string>
+#include <list>
+#include <iostream>
+#include <tr1/unordered_map>
+
+using std::vector;
+using std::list;
+using std::pair;
+using std::string;
+using std::tr1::unordered_map;
+
+typedef u16 address;
+
+list<CodeBlock> blocks;
+
+void show_block(const CodeBlock& b)
+{
+       std::cout << "block_0x" << std::hex << b.start << ":" << std::endl;
+       for(CodeBlock::DisassemblyConstIterator i=b.disassembly.begin();
+                       i!=b.disassembly.end();
+                       i++)
+               std::cout << std::hex << "0x" << i->first << "\t" << i->second << std::endl;
+}
+
+
+int main(int argc, char **argv)
+{
+       GameBoy gb(argv[1]);
+
+       vector<address> pending;
+       pending.push_back(0x100);
+
+       while(!pending.empty())
+       {
+               // Disassemble a block
+               int addr = pending.back();
+               pending.pop_back();
+
+               blocks.push_back(CodeBlock(addr));
+
+               bool jump_reached = false;
+               while(!jump_reached)
+               {
+                       string ins;
+                       int len;
+                       gb.disassemble_opcode(addr, ins, len);
+                       blocks.back().add_instruction(ins, len);
+                       addr += len;
+               }
+       }
+}