#include <cstdlib>
+extern "C"
int main(int argc, char *argv[])
{
if (argc != 2) {
void GBVideo::DMA_OAM (const u16 src)
{
+ logger.trace("DMA OAM from 0x",std::hex,src);
for (u16 i=0; i<160; i++)
{
OAM.raw[i] = core->memory.read(src+i);
for (int i=0; i<40; i++)
{
int y_orig = OAM.sprites[i].y - 16;
+ //logger.trace("sprite #", i, "y_orig = ", y_orig);
if (LY >= y_orig && LY < y_orig+sprite_height)
v.push_back(OAM.sprites[i]);
}
// sort sprites
std::stable_sort(v.begin(), v.end());
+ //logger.trace("LY=",LY," sprites=",v.size());
// draw sprites
u16 tile_data_addr = 0x0000;
int cur_x = 0;
int tile_data_base = (tile_data_addr == 0x0800) ? -128 : 0;
for (int row=0; row < 32; row++)
{
- logger.trace("bgmap row=", row);
+ logger.trace("window map row=", row);
for (int col=0; col < 32; col++)
{
int ty = row*8;
pallette[3] = (BGP>>6) & 3;
u16 tile_map_addr = check_bit(LCDC,6) ? 0x1C00 : 0x1800;
u16 tile_data_addr = 0x0000;
- int tile_data_base = (tile_data_addr == 0x0800) ? -128 : 0;
+ int tile_data_base = 0;
for (int row=0; row < 32; row++)
{
logger.trace("bgmap row=", row);
MBC1.o: MBC1.cc MBC1.h Logger.h
g++ $(CXXFLAGS) -c -o $@ $<
-gbcore.o: gbcore.cc gbcore.h opcodes.h disasm.h \
+gbcore.o: gbcore.cc gbcore.h opcodes.h \
GBRom.h Logger.h MBC.h GBMemory.h GBVideo.h util.h
g++ $(CXXFLAGS) -c -o $@ $<
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
+wendi/disasm.o: wendi/disasm.cc wendi/disasm.h
+ g++ $(CXXFLAGS) -c -o $@ $<
+
+wendi/wendi: wendi/wendi.cc wendi/CodeBlock.o wendi/disasm.o gbcore.o MBC.o \
+ GBMemory.o GBRom.o GBVideo.o util.o NoMBC.o MBC1.o
g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
clean:
std::string GameBoy::status_string()
{
std::string disassembled_instruction;
- int length;
- disassemble_opcode(regs.PC, disassembled_instruction, length);
+ //int length;
+ //disassemble_opcode(regs.PC, disassembled_instruction, length);
std::ostringstream result;
result << "t = " << std::dec << cycle_count <<
return result.str();
}
-#include "disasm.h"
-void GameBoy::disassemble_opcode(u16 addr, std::string &instruction, int &length)
-{
- int opcode;
- u16 PC = addr;
- opcode = memory.read(PC++, GBMemory::DONT_WATCH);
- std::ostringstream result;
-
- 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(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(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(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 = 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;
-}
-
run_status run();
// debug methods
- void disassemble_opcode(u16 addr, std::string &instruction, int &length);
-
int set_breakpoint (u16 addr);
void delete_breakpoint (int id);
void enable_breakpoint (int id);
{
break;
}
+ /*
else if (command == "disasm" || command == "d")
{
int start, end, pos;
}
}
+ */
else if (command == "x")
{
int addr = str2int(arguments[0]);
--- /dev/null
+#include "Instruction.h"
+
+#if 0
+ // Jumps
+ dis_inm16(0xC3, "JP")
+ // JP cc, nn
+ dis_inm16(0xC2, "JP NZ")
+ dis_inm16(0xCA, "JP Z")
+ dis_inm16(0xD2, "JP NC")
+ dis_inm16(0xDA, "JP C")
+ case 0xE9:
+ result << "JP (HL)";
+ opcode_str = "JP";
+ op1.str="(HL)";
+ op2.str="";
+ op1.type = Instruction::MEM_INDIRECT;
+ op1.reg = Instruction::HL;
+ op2.type = Instruction::NONE;
+ break;
+
+ dis_JR(0x18, "JR")
+ dis_JR(0x20, "JR NZ")
+ dis_JR(0x28, "JR Z")
+ dis_JR(0x30, "JR NC")
+ dis_JR(0x38, "JR C")
+
+ // Calls
+ dis_inm16(0xCD, "CALL")
+ // CALL cc, nn
+ dis_inm16(0xC4, "CALL NZ")
+ dis_inm16(0xCC, "CALL Z")
+ dis_inm16(0xD4, "CALL NC")
+ dis_inm16(0xDC, "CALL C")
+
+ // Restarts
+ dis(0xC7, "RST 0x00")
+ dis(0xCF, "RST 0x08")
+ dis(0xD7, "RST 0x10")
+ dis(0xDF, "RST 0x18")
+ dis(0xE7, "RST 0x20")
+ dis(0xEF, "RST 0x28")
+ dis(0xF7, "RST 0x30")
+ dis(0xFF, "RST 0x38")
+
+ // Returns
+ dis(0xC9, "RET")
+ // RET cc
+ dis(0xC0, "RET NZ")
+ dis(0xC8, "RET Z")
+ dis(0xD0, "RET NC")
+ dis(0xD8, "RET C")
+
+ dis(0xD9, "RETI")
+#endif
--- /dev/null
+#ifndef INSTRUCTION_H
+#define INSTRUCTION_H
+
+struct Instruction
+{
+ enum InstructionType
+ {
+ JUMP,
+ CALL,
+ RESET,
+ ALU,
+ LOAD,
+
+ };
+
+ 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
+ };
+
+ struct Operand
+ {
+ std::string str;
+ OperandType type;
+ // FIXME: An anonymous union doesn't work here :(
+ // union {
+ Register reg;
+ int val;
+ // }
+
+ Operand(): str(""), type(NONE) {}
+ };
+
+ int length;
+ std::string all;
+
+ u8 opcode;
+ u8 sub_opcode;
+ std::string str;
+ Operand op1, op2;
+
+ Instruction(int length, u8 opcode, u8 sub_opcode, std::string all, std::string opcode_str, Operand op1, Operand op2):
+ length(length), opcode(opcode), sub_opcode(sub_opcode),all(all), str(opcode_str), op1(op1), op2(op2)
+ {
+ }
+};
+
+#endif
+
+#include <iomanip>
+
+#include "../Logger.h"
#include "disasm.h"
#include "disasm_macros.h"
}
-void disassemble_opcode(GameBoy &gb, u16 addr, std::string &instruction, int &length)
+Instruction disassemble_opcode(GameBoy &gb, u16 addr)
{
- int opcode;
+ u8 opcode, sub_opcode=0xFF;
std::ostringstream result;
- std::string opcode_str, op1_str, op2_str;
- Instruction::OperandType op1_type, op2_type;
+ std::string opcode_str;
Instruction::Operand op1, op2;
u16 PC = addr;
dis__inm__reg(0xEA, "LD", A)
// LD A, (C)
- dis(0xF2, "LD A, (0xFF00+C)")
+ case 0xF2:
+ result << "LD A, (0xFF00+C)";
+ opcode_str = "LDH";
+ 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
- dis(0xE2, "LD (0xFF00+C), A")
+ case 0xE2:
+ result << "LD (0xFF00+C), A";
+ opcode_str = "LDH";
+ 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);
- dis(0x3A, "LDD A, (HL)")
+ case 0x3A:
+ result << "LD A, (HL-)";
+ opcode_str = "LDD";
+ 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;
- dis(0x32, "LDD (HL), A")
+ case 0x32:
+ result << "LD (HL-), A";
+ opcode_str = "LDD";
+ 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);
- dis(0x2A, "LDI A, (HL)")
+ case 0x2A:
+ result << "LD A, (HL+)";
+ opcode_str = "LDI";
+ 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;
- dis(0x22, "LDI (HL), A")
+ case 0x22:
+ result << "LD (HL+), A";
+ opcode_str = "LDI";
+ 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: {
result << "LD (0xFF" <<
std::setw(2) << port << "), A" << "\t[" << get_port_name(port) << "]";
+ opcode_str = "LDH";
+ 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)
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";
+ 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(0x31, "LD", SP)
// LD SP, HL
- dis(0xF9, "LD SP, HL")
+ case 0xF9:
+ result << "LD SP, HL";
+ opcode_str = "LD";
+ 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:
- result << "LD HL, SP + 0x"<< std::setw(2) << int(gb.memory.read(PC++, GBMemory::DONT_WATCH));
+ 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+";
+ op1.str = ToString(n);
+ op2.str = "";
+ op1.type = Instruction::INM8;
+ op1.val = n;
break;
+ }
// LD (nn), SP
dis__inm__reg16(0x08, "LD", SP)
// Miscellaneous instructions
case 0xCB: {
- int sub_opcode = gb.memory.read(PC++, GBMemory::DONT_WATCH);
+ sub_opcode = gb.memory.read(PC++, GBMemory::DONT_WATCH);
switch(sub_opcode)
{
// SWAP n
dis(0x1F, "RRA")
- // TODO: Bit instructions
-
// Jumps
dis_inm16(0xC3, "JP")
// JP cc, nn
dis_inm16(0xCA, "JP Z")
dis_inm16(0xD2, "JP NC")
dis_inm16(0xDA, "JP C")
- dis(0xE9, "JP (HL)")
+ case 0xE9:
+ result << "JP (HL)";
+ opcode_str = "JP";
+ op1.str="(HL)";
+ op2.str="";
+ op1.type = Instruction::MEM_INDIRECT;
+ op1.reg = Instruction::HL;
+ op2.type = Instruction::NONE;
+ break;
dis_JR(0x18, "JR")
dis_JR(0x20, "JR NZ")
break;
} // end switch
-
- instruction = result.str();
- length = PC - addr;
+
+ return Instruction(PC-addr, opcode, sub_opcode, result.str(), opcode_str, op1, op2);
}
#ifndef DISASM_H
#define DISASM_H
+#include "../gbcore.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)
{
#define dis(opcode, name) \
case opcode: \
result << name; \
+ opcode_str = name; \
+ op1.str=""; \
+ op2.str=""; \
+ op1.type=Instruction::NONE; \
+ op2.type=Instruction::NONE; \
break;
// OP reg
-#define dis_reg(opcode, name, reg) \
+#define dis_reg(opcode, name, reg8) \
case opcode: \
- result << name << " " << #reg; \
+ result << name << " " << #reg8; \
opcode_str = name; \
- op1_str = #reg; \
- op2_str = ""; \
- op1_type = REG; \
- op1.reg = reg; \
- op2.type = NONE; \
+ op1.str = #reg8; \
+ op2.str = ""; \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg8; \
+ op2.type = Instruction::NONE; \
break;
case opcode: \
result << name << " " << #reg16; \
opcode_str = name; \
- op1_str = #reg16; \
- op2_str = ""; \
- op1_type = REG; \
- op1.reg = reg16; \
- op2.type = NONE; \
+ op1.str = #reg16; \
+ op2.str = ""; \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg16; \
+ op2.type = Instruction::NONE; \
break;
// OP (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; \
+ op1.str = std::string("(")+#reg16+")"; \
+ op2.str = ""; \
+ op1.type = Instruction::MEM_INDIRECT; \
+ op1.reg = Instruction::reg16; \
+ op2.type = Instruction::NONE; \
break;
// OP inm8
#define dis_inm8(opcode, name) \
case opcode: {\
- int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.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.str = ToString(inm); \
+ op2.str = ""; \
+ op1.type = Instruction::INM8; \
op1.val = inm; \
- op2.type = NONE; \
+ op2.type = Instruction::NONE; \
break; \
}
// OP inm16
#define dis_inm16(opcode, name) \
case opcode: {\
- int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.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.str = ToString(inm); \
+ op2.str = ""; \
+ op1.type = Instruction::INM16; \
op1.val = inm; \
- op2.type = NONE; \
+ op2.type = Instruction::NONE; \
break; \
}
-#define dis_reg_inm(opcode, name, reg) \
+#define dis_reg_inm(opcode, name, reg8) \
case opcode: {\
- int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
- result << name << " " << #reg << ", 0x" << std::setw(2) << inm; \
+ int inm = int(gb.memory.read(PC++, GBMemory::DONT_WATCH)); \
+ result << name << " " << #reg8 << ", 0x" << std::setw(2) << inm; \
opcode_str = name; \
- op1_str = #reg; \
- op2_str = ToString(inm); \
- op1_type = REG; \
- op1.reg = reg; \
- op2.type = INM8; \
+ op1.str = #reg8; \
+ op2.str = ToString(inm); \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg8; \
+ op2.type = Instruction::INM8; \
op2.val = inm; \
break; \
}
#define dis_reg16_inm(opcode, name, reg16) \
case opcode: {\
- int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.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; \
+ op1.str = #reg16; \
+ op2.str = ToString(inm); \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg16; \
+ op2.type = Instruction::INM8; \
op2.val = inm; \
break; \
}
#define dis_reg16_inm8(opcode, name, reg16) \
case opcode: {\
- int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.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; \
+ op1.str = #reg16; \
+ op2.str = ToString(inm); \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg16; \
+ op2.type = Instruction::INM8; \
op2.val = inm; \
break; \
}
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; \
+ op1.str = #reg1; \
+ op2.str = #reg2; \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg1; \
+ op2.type = Instruction::REG; \
+ op2.val = Instruction::reg2; \
break;
#define dis_A_reg(opcode, name, reg2) dis_reg_reg(opcode, name, A, reg2)
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; \
+ op1.str = #reg16_1; \
+ op2.str = #reg16_2; \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg16_1; \
+ op2.type = Instruction::REG; \
+ op2.val = Instruction::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) \
+#define dis_reg__reg16_(opcode, name, reg8, reg16) \
case opcode: \
- result << name << " " << #reg << ", (" << #reg16 << ")"; \
+ result << name << " " << #reg8 << ", (" << #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; \
+ op1.str = #reg8; \
+ op2.str = std::string("(")+ #reg16 + ")"; \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg8; \
+ op2.type = Instruction::MEM_INDIRECT; \
+ op2.val = Instruction::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) \
+#define dis_reg__inm_(opcode, name, reg8) \
case opcode: {\
- int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \
PC += 2; \
- result << name << " " << #reg << ", (0x" << \
+ result << name << " " << #reg8 << ", (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; \
+ op1.str = #reg8; \
+ op2.str = std::string("(") + ToString(inm) + ")"; \
+ op1.type = Instruction::REG; \
+ op1.reg = Instruction::reg8; \
+ op2.type = Instruction::MEM_DIRECT; \
op2.val = inm; \
break; \
}
// OP (reg16), reg
-#define dis__reg16__reg(opcode, name, reg16, reg) \
+#define dis__reg16__reg(opcode, name, reg16, reg8) \
case opcode: \
- result << name << " (" << #reg16 << "), " << #reg; \
+ result << name << " (" << #reg16 << "), " << #reg8; \
opcode_str = name; \
- op1_str = std::string("(")+ #reg16 + ")"; \
- op2_str = #reg; \
- op1.type = MEM_INDIRECT; \
- op1.val = reg16; \
- op2_type = REG; \
- op2.reg = reg; \
+ op1.str = std::string("(")+ #reg16 + ")"; \
+ op2.str = #reg8; \
+ op1.type = Instruction::MEM_INDIRECT; \
+ op1.val = Instruction::reg16; \
+ op2.type = Instruction::REG; \
+ op2.reg = Instruction::reg8; \
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) \
+#define dis__inm__reg(opcode, name, reg8) \
case opcode: {\
- int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.memory.read16(PC, GBMemory::DONT_WATCH)); \
PC += 2; \
result << name << " (0x" << \
- std::setw(4) << inm << "), " << #reg; \
+ std::setw(4) << inm << "), " << #reg8; \
opcode_str = name; \
- op1_str = std::string("(") + ToString(inm) + ")"; \
- op2_str = #reg; \
- op1.type = MEM_DIRECT; \
+ op1.str = std::string("(") + ToString(inm) + ")"; \
+ op2.str = #reg8; \
+ op1.type = Instruction::MEM_DIRECT; \
op1.val = inm; \
- op2_type = REG; \
- op2.reg = reg; \
+ op2.type = Instruction::REG; \
+ op2.reg = Instruction::reg8; \
break; \
}
// OP (inm), reg16
#define dis__inm__reg16(opcode, name, reg16) \
case opcode: {\
- int inm = int(memory.read16(PC, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.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.str = std::string("(") + ToString(inm) + ")"; \
+ op2.str = #reg16; \
+ op1.type = Instruction::MEM_DIRECT; \
op1.val = inm; \
- op2_type = REG; \
- op2.reg = reg16; \
+ op2.type = Instruction::REG; \
+ op2.reg = Instruction::reg16; \
break; \
}
// OP (reg16), inm
#define dis__reg16__inm(opcode, name, reg16) \
case opcode: {\
- int inm = int(memory.read(PC++, GBMemory::DONT_WATCH)); \
+ int inm = int(gb.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; \
+ op1.str = std::string("(") + #reg16 + ")"; \
+ op2.str = ToString(inm); \
+ op1.type = Instruction::MEM_INDIRECT; \
+ op1.reg = Instruction::reg16; \
+ op2.type = Instruction::INM8; \
op2.val = inm; \
break; \
}
// Special routine for JR
#define dis_JR(opcode, name) \
case opcode: { \
- s8 offset = memory.read(PC++); \
+ s8 offset = gb.memory.read(PC++); \
result << name << " " << std::dec << int(offset) << "\t[0x" \
<< std::hex << std::setw(2) << int(PC+offset) << "]"; \
opcode_str = name; \
- op1_str = ToString(int(offset)); \
- op2_str = ToString(int(PC+offset)); \
- op1.type = INM8; \
- op1.reg = offset; \
- op2.type = NONE; \
+ op1.str = ToString(int(offset)); \
+ op2.str = ToString(int(PC+offset)); \
+ op1.type = Instruction::INM8; \
+ op1.val = offset; \
+ op2.type = Instruction::NONE; \
op2.val = int(PC+offset); \
break; \
}
#include "../gbcore.h"
#include "CodeBlock.h"
+#include "disasm.h"
#include <vector>
#include <utility>
#include <string>
#include <list>
#include <iostream>
-#include <tr1/unordered_map>
+#include <algorithm>
+//#include <tr1/unordered_map>
using std::vector;
using std::list;
using std::pair;
using std::string;
-using std::tr1::unordered_map;
+//using std::tr1::unordered_map;
typedef u16 address;
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;
+ Instruction ins(disassemble_opcode(gb, addr));
+ blocks.back().add_instruction(ins.all, ins.length);
+ addr += ins.length;
+
+ if (ins.is_jump()) jump_reached=true;
}
}
+
+ //std::for_each(blocks, show_block);
+ for (list<CodeBlock>::iterator i = blocks.begin(); i != blocks.end(); i++)
+ show_block(*i);
+ return 0;
}