#include "../common/toString.h"
QtBoiDisassemblyWindow::QtBoiDisassemblyWindow(QWidget *parent, GameBoy *gb, QHash<u32,QString> *tags)
- :QWidget(parent), gb(gb), tags(tags), history(), historyPosition(-1)
+:QWidget(parent), gb(gb), tags(tags), history(), historyPosition(-1)
{
- setFocusPolicy(Qt::NoFocus);
-
- browser = new QTextBrowser(this);
- browser->setOpenLinks(false);
- browser->setFont(QFont("courier"));
- browser->setFocusPolicy(Qt::NoFocus);
- browser->setMinimumSize(500,500);
- connect(browser, SIGNAL(anchorClicked(const QUrl&)), this, SIGNAL(anchorClicked(const QUrl &)));
-
-
- backButton = new QPushButton("Back", this);
- backButton->setEnabled(false);
- backButton->setFocusPolicy(Qt::NoFocus);
- forwardButton = new QPushButton("Forward", this);
- forwardButton->setEnabled(false);
- forwardButton->setFocusPolicy(Qt::NoFocus);
- connect(backButton, SIGNAL(clicked()), this, SLOT(historyBack()));
- connect(forwardButton, SIGNAL(clicked()), this, SLOT(historyForward()));
-
- //backButton->setIcon(QIcon("../icons/go-next.svg"));
- //forwardButton->setIcon(QIcon("../icons/go-previous.svg"));
-
- QHBoxLayout *buttons = new QHBoxLayout();
- buttons->addWidget(backButton);
- buttons->addWidget(forwardButton);
-
- QVBoxLayout *vbox = new QVBoxLayout;
- vbox->addWidget(browser);
- vbox->addLayout(buttons);
-
- setLayout(vbox);
+ setFocusPolicy(Qt::NoFocus);
+
+ browser = new QTextBrowser(this);
+ browser->setOpenLinks(false);
+ browser->setFont(QFont("courier"));
+ browser->setFocusPolicy(Qt::NoFocus);
+ browser->setMinimumSize(500,500);
+ connect(browser, SIGNAL(anchorClicked(const QUrl&)), this, SIGNAL(anchorClicked(const QUrl &)));
+
+
+ backButton = new QPushButton("Back", this);
+ backButton->setEnabled(false);
+ backButton->setFocusPolicy(Qt::NoFocus);
+ forwardButton = new QPushButton("Forward", this);
+ forwardButton->setEnabled(false);
+ forwardButton->setFocusPolicy(Qt::NoFocus);
+ connect(backButton, SIGNAL(clicked()), this, SLOT(historyBack()));
+ connect(forwardButton, SIGNAL(clicked()), this, SLOT(historyForward()));
+
+ //backButton->setIcon(QIcon("../icons/go-next.svg"));
+ //forwardButton->setIcon(QIcon("../icons/go-previous.svg"));
+
+ QHBoxLayout *buttons = new QHBoxLayout();
+ buttons->addWidget(backButton);
+ buttons->addWidget(forwardButton);
+
+ QVBoxLayout *vbox = new QVBoxLayout;
+ vbox->addWidget(browser);
+ vbox->addLayout(buttons);
+
+ setLayout(vbox);
}
QtBoiDisassemblyWindow::~QtBoiDisassemblyWindow()
std::string QtBoiDisassemblyWindow::htmlLinkMem(u32 addr)
{
- std::string result("<a href=\"gotoaddr:");
- result += toString(addr);
- result += "\">";
- if (tags->value(addr) != "")
- result += tags->value(addr).toStdString();
- else
- result += toStringHex(addr, 4);
- result += "</a>";
-
- return result;
+ std::string result("<a href=\"gotoaddr:");
+ result += toString(addr);
+ result += "\">";
+ if (tags->value(addr) != "")
+ result += tags->value(addr).toStdString();
+ else
+ result += toStringHex(addr, 4);
+ result += "</a>";
+
+ return result;
}
std::string QtBoiDisassemblyWindow::operandToHtml(const Instruction::Operand &op)
{
- std::string result;
- switch(op.type)
- {
- case Instruction::MEM_DIRECT:
- result += "(";
- result += htmlLinkMem(op.val);
- result += ")";
- break;
-
- case Instruction::INM16:
- result += toStringHex(op.val,4);
- break;
-
- default:
- return op.str;
- }
-
- return result;
+ std::string result;
+ switch(op.type)
+ {
+ case Instruction::MEM_DIRECT:
+ result += "(";
+ result += htmlLinkMem(op.val);
+ result += ")";
+ break;
+
+ case Instruction::INM16:
+ result += toStringHex(op.val,4);
+ break;
+
+ default:
+ return op.str;
+ }
+
+ return result;
}
std::string QtBoiDisassemblyWindow::insToHtml(const Instruction &ins)
{
- std::string result;
-
- if (ins.type == Instruction::RESET)
- {
- result += "RST ";
- result += htmlLinkMem(strtol(ins.str.substr(4).c_str(), 0, 16));
- }
- else
- {
- result += ins.str;
- result += " ";
- if (ins.str.substr(0,2)=="JR")
- {
- result += operandToHtml(ins.op1);
- result += " [";
- result += htmlLinkMem(ins.op2.val);
- result += "]";
- }
- else if ((ins.str.substr(0,2)=="JP" && ins.op1.type == Instruction::INM16)
- || ins.str.substr(0,4)=="CALL")
- {
- result += htmlLinkMem(ins.op1.val);
- }
- else
- {
- result += operandToHtml(ins.op1);
- if (ins.op2.type != Instruction::NONE)
- {
- result += ", ";
- result += operandToHtml(ins.op2);
- }
- }
- }
- return result;
+ std::string result;
+
+ if (ins.type == Instruction::RESET)
+ {
+ result += "RST ";
+ result += htmlLinkMem(strtol(ins.str.substr(4).c_str(), 0, 16));
+ }
+ else
+ {
+ result += ins.str;
+ result += " ";
+ if (ins.str.substr(0,2)=="JR")
+ {
+ result += operandToHtml(ins.op1);
+ result += " [";
+ result += htmlLinkMem(ins.op2.val);
+ result += "]";
+ }
+ else if ((ins.str.substr(0,2)=="JP" && ins.op1.type == Instruction::INM16)
+ || ins.str.substr(0,4)=="CALL")
+ {
+ result += htmlLinkMem(ins.op1.val);
+ }
+ else
+ {
+ result += operandToHtml(ins.op1);
+ if (ins.op2.type != Instruction::NONE)
+ {
+ result += ", ";
+ result += operandToHtml(ins.op2);
+ }
+ }
+ }
+ if (ins.str.substr(0,3)=="LDH") {
+ int port;
+ if (ins.op1.type == Instruction::MEM_DIRECT)
+ port = ins.op1.val - 0xFF00;
+ else
+ port = ins.op2.val - 0xFF00;
+ result += " ["+GameBoy::get_port_name(port)+"]";
+ }
+ return result;
}
void QtBoiDisassemblyWindow::gotoAddress(u16 addr)
{
- int start = addr;
- int end = start+200;
- int pos = start;
+ GameBoy::BreakpointMap bpmap = gb->get_breakpoints();
- if (end > 0xFFFF) end = 0xFFFF;
- std::ostringstream str;
-
- str << "<html><head><title>Disassembly</title></head><body>";
- str << "<table cellpadding=0 cellspacing=0>";
- str << "<tr bgcolor=#c0ffc0><td width=25%>Labels</td><td width=15%>Addr</td><td width=15%>Opcodes</td><td>Instruction</td></tr>";
+ int start = addr;
+ int end = start+200;
+ int pos = start;
- bool hilightBG=true;
+ if (end > 0xFFFF) end = 0xFFFF;
+ std::ostringstream str;
- while (pos < end)
- {
- Instruction ins(gb->disassemble_opcode(pos));
- str << "<tr bgcolor=" << (pos == gb->regs.PC ? "#ffc0c0" : (hilightBG ? "#d0d0d0" : "#ffffff")) << ">" <<
- "<td>" << tags->value(pos).toStdString() << "</td>" <<
- "<td><a href=\"newtag:" << std::dec << pos << "\">0x" << std::hex << std::setw(4) << std::setfill('0') <<
- pos << "</a></td><td>";
- for (int i=0; i<ins.length; i++)
- str << std::setw(2) << int(gb->memory.read(pos+i)) << " ";
+ str << "<html><head><title>Disassembly</title></head><body>";
+ str << "<table cellpadding=0 cellspacing=0>";
+ str << "<tr bgcolor=#c0ffc0><td width=25%>Labels</td><td> BP </td><td width=15%>Addr</td><td width=15%>Opcodes</td><td>Instruction</td></tr>";
- str << "</td><td>";
+ bool hilightBG=true;
- str << insToHtml(ins) << "</td></tr>";
- pos += ins.length;
+ while (pos < end)
+ {
+ bool isBP=false;
- hilightBG = !hilightBG;
+ for (GameBoy::BreakpointMap::iterator i = bpmap.begin(); i != bpmap.end(); i++) {
+ if (i->second.addr == pos) {
+ isBP=true;
+ break;
+ }
}
- str << "</table></body></html>";
-
- browser->setHtml(QString(str.str().c_str()));
- currentAddress=addr;
-
- // If there are "forward" history elements
- // - check if we are going forwards or backwards
- // - else, delete forward history and insert the new address
- if (historyPosition < history.size()-1 && history[historyPosition+1] == addr)
- historyPosition++;
- else if (historyPosition > 0 && history[historyPosition-1] == addr)
- historyPosition--;
- else
- {
- while (history.size() > historyPosition+1)
- history.pop_back();
- history.push_back(addr);
- historyPosition++;
- }
-
- // enable/disable navigation buttons
- if (historyPosition >= 1) backButton->setEnabled(true);
- else backButton->setEnabled(false);
-
- if (historyPosition >= 0 && historyPosition < history.size()-1) forwardButton->setEnabled(true);
- else forwardButton->setEnabled(false);
+ Instruction ins(gb->disassemble_opcode(pos));
+ str << "<tr bgcolor=" << (isBP? "#ff0000" : (pos == gb->regs.PC ? "#ffc0c0" : (hilightBG ? "#d0d0d0" : "#ffffff"))) << ">" <<
+ "<td>" << tags->value(pos).toStdString() << "</td>" <<
+ "<td> <a href=\"togglebp:" << std::dec << pos << "\">"<< (isBP? "#" : " ") <<"</a> </font></td>" <<
+ "<td><a href=\"newtag:" << std::dec << pos << "\">0x" << std::hex << std::setw(4) << std::setfill('0') <<
+ pos << "</a></td><td>";
+ for (int i=0; i<ins.length; i++)
+ str << std::setw(2) << int(gb->memory.read(pos+i)) << " ";
+
+ str << "</td><td>";
+
+ str << insToHtml(ins) << "</td></tr>";
+ pos += ins.length;
+
+ hilightBG = !hilightBG;
+ }
+
+ str << "</table></body></html>";
+
+ browser->setHtml(QString(str.str().c_str()));
+ currentAddress=addr;
+
+ // If there are "forward" history elements
+ // - check if we are going forwards or backwards
+ // - else, delete forward history and insert the new address
+ if (historyPosition < history.size()-1 && history[historyPosition+1] == addr)
+ historyPosition++;
+ else if (historyPosition > 0 && history[historyPosition-1] == addr)
+ historyPosition--;
+ else
+ {
+ while (history.size() > historyPosition+1)
+ history.pop_back();
+ history.push_back(addr);
+ historyPosition++;
+ }
+
+ // enable/disable navigation buttons
+ if (historyPosition >= 1) backButton->setEnabled(true);
+ else backButton->setEnabled(false);
+
+ if (historyPosition >= 0 && historyPosition < history.size()-1) forwardButton->setEnabled(true);
+ else forwardButton->setEnabled(false);
}
void QtBoiDisassemblyWindow::gotoPC()
{
- gotoAddress(gb->regs.PC);
+ gotoAddress(gb->regs.PC);
}
void QtBoiDisassemblyWindow::refresh()
{
- gotoAddress(currentAddress);
+ gotoAddress(currentAddress);
}
void QtBoiDisassemblyWindow::historyBack()
{
- if (historyPosition >= 1)
- gotoAddress(history[historyPosition-1]);
+ if (historyPosition >= 1)
+ gotoAddress(history[historyPosition-1]);
}
void QtBoiDisassemblyWindow::historyForward()
{
- if (historyPosition < history.size()-1)
- gotoAddress(history[historyPosition+1]);
+ if (historyPosition < history.size()-1)
+ gotoAddress(history[historyPosition+1]);
}
#include "QtBoiStatusWindow.h"
QtBoiStatusWindow::QtBoiStatusWindow(QWidget *parent, GameBoy *gb)
- :gb(gb)
+:gb(gb)
{
- setFocusPolicy(Qt::NoFocus);
- setMinimumSize(200,200);
- setMaximumWidth(320);
+ setFocusPolicy(Qt::NoFocus);
+ setMinimumSize(200,200);
+ setMaximumWidth(320);
}
QtBoiStatusWindow::~QtBoiStatusWindow()
void QtBoiStatusWindow::update()
{
- std::ostringstream str;
-
- str << "<html><head><title>Status</title></head><body>";
-
- str << "<table cellpadding=0 cellspacing=0><tr><td>";
- // 8-bit regs table
- str << "<table cellpadding=0 cellspacing=0>";
- str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">8-bit</th></tr>";
- str << "<tr><td>A = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.A) << "</td></tr>";
- str << "<tr><td>B = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.B) << "</td></tr>";
- str << "<tr><td>C = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.C) << "</td></tr>";
- str << "<tr><td>D = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.D) << "</td></tr>";
- str << "<tr><td>E = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.E) << "</td></tr>";
- str << "<tr><td>H = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.H) << "</td></tr>";
- str << "<tr><td>L = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.L) << "</td></tr>";
- str << "</table>";
- str << "</td><td width=20></td><td>";
- // 16-bit regs table
- str << "<table cellpadding=0 cellspacing=0>";
- str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">16-bit</th></tr>";
- str << "<tr><td>BC = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.BC) << "</td></tr>";
- str << "<tr><td>DE = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.DE) << "</td></tr>";
- str << "<tr><td>HL = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.HL) << "</td></tr>";
- str << "<tr></tr>";
- str << "<tr><td>SP = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.SP) << "</td></tr>";
- str << "<tr></tr>";
- str << "<tr><td>PC = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.PC) << "</td></tr>";
- str << "</table>";
- str << "</td><td width=20></td><td>";
- // Flags & state table (TODO: Interpret IE and IF registers)
- str << "<table cellpadding=0 cellspacing=0>";
- str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">Flags</th></tr>";
- str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::ZERO_FLAG)? "#FF0000" : "#FFFFFF") << ">Z</td></tr>";
- str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::ADD_SUB_FLAG)? "#FF0000" : "#FFFFFF") << ">N</td></tr>";
- str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::HALF_CARRY_FLAG)? "#FF0000" : "#FFFFFF") << ">H</td></tr>";
- str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::CARRY_FLAG)? "#FF0000" : "#FFFFFF") << ">C</td></tr>";
- str << "<tr><td>IME = " << int(gb->IME) << "</td></tr>";
- int IE = int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH));
- str << "<tr><td>IE =";
- if (IE & GameBoy::IRQ_VBLANK) str << " VBL";
- if (IE & GameBoy::IRQ_LCD_STAT) str << " LCD";
- if (IE & GameBoy::IRQ_TIMER) str << " TIM";
- if (IE & GameBoy::IRQ_SERIAL) str << " SER";
- if (IE & GameBoy::IRQ_JOYPAD) str << " JOYP";
- str << "</td></tr>";
- int IF = int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH));
- str << "<tr><td>IF =";
- if (IF & GameBoy::IRQ_VBLANK) str << " VBL";
- if (IF & GameBoy::IRQ_LCD_STAT) str << " LCD";
- if (IF & GameBoy::IRQ_TIMER) str << " TIM";
- if (IF & GameBoy::IRQ_SERIAL) str << " SER";
- if (IF & GameBoy::IRQ_JOYPAD) str << " JOYP";
- str << "</td></tr>";
- str << "</table>";
- str << "</td></tr>";
- str << "</table></body></html>";
+ std::ostringstream str;
- setHtml(QString(str.str().c_str()));
+ str << "<html><head><title>Status</title></head><body>";
+
+ str << "<table cellpadding=0 cellspacing=0><tr><td>";
+ // 8-bit regs table
+ str << "<table cellpadding=0 cellspacing=0>";
+ str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">8-bit</th></tr>";
+ str << "<tr><td>A = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.A) << "</td></tr>";
+ str << "<tr><td>B = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.B) << "</td></tr>";
+ str << "<tr><td>C = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.C) << "</td></tr>";
+ str << "<tr><td>D = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.D) << "</td></tr>";
+ str << "<tr><td>E = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.E) << "</td></tr>";
+ str << "<tr><td>H = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.H) << "</td></tr>";
+ str << "<tr><td>L = </td><td>0x" << std::hex << std::setw(2) << std::setfill('0') << int(gb->regs.L) << "</td></tr>";
+ str << "</table>";
+ str << "</td><td width=20></td><td>";
+ // 16-bit regs table
+ str << "<table cellpadding=0 cellspacing=0>";
+ str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">16-bit</th></tr>";
+ str << "<tr><td>BC = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.BC) << "</td></tr>";
+ str << "<tr><td>DE = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.DE) << "</td></tr>";
+ str << "<tr><td>HL = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.HL) << "</td></tr>";
+ str << "<tr></tr>";
+ str << "<tr><td>SP = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.SP) << "</td></tr>";
+ str << "<tr></tr>";
+ str << "<tr><td>PC = </td><td>0x" << std::hex << std::setw(4) << std::setfill('0') << int(gb->regs.PC) << "</td></tr>";
+ str << "</table>";
+ str << "</td><td width=20></td><td>";
+ // Flags & state table (TODO: Interpret IE and IF registers)
+ str << "<table cellpadding=0 cellspacing=0>";
+ str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">Flags</th></tr>";
+ str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::ZERO_FLAG)? "#FF0000" : "#FFFFFF") << ">Z</td></tr>";
+ str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::ADD_SUB_FLAG)? "#FF0000" : "#FFFFFF") << ">N</td></tr>";
+ str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::HALF_CARRY_FLAG)? "#FF0000" : "#FFFFFF") << ">H</td></tr>";
+ str << "<tr><td bgcolor=" << (gb->check_flag(GameBoy::CARRY_FLAG)? "#FF0000" : "#FFFFFF") << ">C</td></tr>";
+ str << "<tr><td>IME = " << int(gb->IME) << "</td></tr>";
+ int IE = int(gb->memory.read(0xFFFF, GBMemory::DONT_WATCH));
+ str << "<tr><td>IE =";
+ if (IE & GameBoy::IRQ_VBLANK) str << " VBL";
+ if (IE & GameBoy::IRQ_LCD_STAT) str << " LCD";
+ if (IE & GameBoy::IRQ_TIMER) str << " TIM";
+ if (IE & GameBoy::IRQ_SERIAL) str << " SER";
+ if (IE & GameBoy::IRQ_JOYPAD) str << " JOYP";
+ str << "</td></tr>";
+ int IF = int(gb->memory.read(0xFF0F, GBMemory::DONT_WATCH));
+ str << "<tr><td>IF =";
+ if (IF & GameBoy::IRQ_VBLANK) str << " VBL";
+ if (IF & GameBoy::IRQ_LCD_STAT) str << " LCD";
+ if (IF & GameBoy::IRQ_TIMER) str << " TIM";
+ if (IF & GameBoy::IRQ_SERIAL) str << " SER";
+ if (IF & GameBoy::IRQ_JOYPAD) str << " JOYP";
+ str << "</td></tr>";
+ str << "</table>";
+ str << "</td></tr>";
+ str << "</table><hr>";
+
+ str << "<table>";
+ str << "<tr bgcolor=#c0ffc0><th colspan=\"2\">Breakpoints</th></tr>";
+ GameBoy::BreakpointMap bpmap = gb->get_breakpoints();
+ for (GameBoy::BreakpointMap::iterator i = bpmap.begin(); i != bpmap.end(); i++){
+ str << "<tr><td> " << i->first << " </td>";
+ str << "<td>0x" << std::hex << i->second.addr << (i->second.enabled? "":"(disabled)") << "</td></tr>";
+ }
+
+ str <<"</table></body></html>";
+
+ setHtml(QString(str.str().c_str()));
}