2017-06-04 20:38:34 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Disassembler.h"
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <bitset>
|
|
|
|
|
|
|
|
#include "Memory.h"
|
|
|
|
#include "LR35902.h"
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
EightBit::GameBoy::Disassembler::Disassembler() {
|
2017-06-04 20:38:34 +00:00
|
|
|
// Disable exceptions where too many format arguments are available
|
|
|
|
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::state(LR35902& cpu) {
|
2017-06-04 20:38:34 +00:00
|
|
|
|
2017-06-19 12:53:00 +00:00
|
|
|
auto pc = cpu.PC();
|
|
|
|
auto sp = cpu.SP();
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
|
|
auto a = cpu.A();
|
|
|
|
auto f = cpu.F();
|
|
|
|
|
|
|
|
auto b = cpu.B();
|
|
|
|
auto c = cpu.C();
|
|
|
|
|
|
|
|
auto d = cpu.D();
|
|
|
|
auto e = cpu.E();
|
|
|
|
|
|
|
|
auto h = cpu.H();
|
|
|
|
auto l = cpu.L();
|
|
|
|
|
|
|
|
std::ostringstream output;
|
|
|
|
|
|
|
|
output
|
2017-06-09 09:23:51 +00:00
|
|
|
<< "PC=" << hex(pc.word)
|
2017-06-04 20:38:34 +00:00
|
|
|
<< " "
|
2017-06-09 09:23:51 +00:00
|
|
|
<< "SP=" << hex(sp.word)
|
2017-06-04 20:38:34 +00:00
|
|
|
<< " " << "A=" << hex(a) << " " << "F=" << flags(f)
|
|
|
|
<< " " << "B=" << hex(b) << " " << "C=" << hex(c)
|
|
|
|
<< " " << "D=" << hex(d) << " " << "E=" << hex(e)
|
|
|
|
<< " " << "H=" << hex(h) << " " << "L=" << hex(l);
|
|
|
|
|
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::RP(int rp) const {
|
2017-06-04 20:38:34 +00:00
|
|
|
switch (rp) {
|
|
|
|
case 0:
|
|
|
|
return "BC";
|
|
|
|
case 1:
|
|
|
|
return "DE";
|
|
|
|
case 2:
|
|
|
|
return "HL";
|
|
|
|
case 3:
|
|
|
|
return "SP";
|
|
|
|
}
|
|
|
|
throw std::logic_error("Unhandled register pair");
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::RP2(int rp) const {
|
2017-06-04 20:38:34 +00:00
|
|
|
switch (rp) {
|
|
|
|
case 0:
|
|
|
|
return "BC";
|
|
|
|
case 1:
|
|
|
|
return "DE";
|
|
|
|
case 2:
|
|
|
|
return "HL";
|
|
|
|
case 3:
|
|
|
|
return "AF";
|
|
|
|
}
|
|
|
|
throw std::logic_error("Unhandled register pair");
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::R(int r) const {
|
2017-06-04 20:38:34 +00:00
|
|
|
switch (r) {
|
|
|
|
case 0:
|
|
|
|
return "B";
|
|
|
|
case 1:
|
|
|
|
return "C";
|
|
|
|
case 2:
|
|
|
|
return "D";
|
|
|
|
case 3:
|
|
|
|
return "E";
|
|
|
|
case 4:
|
|
|
|
return "H";
|
|
|
|
case 5:
|
|
|
|
return "L";
|
|
|
|
case 6:
|
|
|
|
return "(HL)";
|
|
|
|
case 7:
|
|
|
|
return "A";
|
|
|
|
}
|
|
|
|
throw std::logic_error("Unhandled register");
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::cc(int flag) {
|
2017-06-04 20:38:34 +00:00
|
|
|
switch (flag) {
|
|
|
|
case 0:
|
|
|
|
return "NZ";
|
|
|
|
case 1:
|
|
|
|
return "Z";
|
|
|
|
case 2:
|
|
|
|
return "NC";
|
|
|
|
case 3:
|
|
|
|
return "C";
|
|
|
|
case 4:
|
|
|
|
return "PO";
|
|
|
|
case 5:
|
|
|
|
return "PE";
|
|
|
|
case 6:
|
|
|
|
return "P";
|
|
|
|
case 7:
|
|
|
|
return "M";
|
|
|
|
}
|
|
|
|
throw std::logic_error("Unhandled condition");
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::alu(int which) {
|
2017-06-04 20:38:34 +00:00
|
|
|
switch (which) {
|
|
|
|
case 0: // ADD A,n
|
|
|
|
return "ADD";
|
|
|
|
case 1: // ADC
|
|
|
|
return "ADC";
|
|
|
|
case 2: // SUB n
|
|
|
|
return "SUB";
|
|
|
|
case 3: // SBC A,n
|
|
|
|
return "SBC";
|
|
|
|
case 4: // AND n
|
|
|
|
return "AND";
|
|
|
|
case 5: // XOR n
|
|
|
|
return "XOR";
|
|
|
|
case 6: // OR n
|
|
|
|
return "OR";
|
|
|
|
case 7: // CP n
|
|
|
|
return "CP";
|
|
|
|
}
|
|
|
|
throw std::logic_error("Unhandled alu operation");
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::disassemble(LR35902& cpu) {
|
2017-06-04 20:38:34 +00:00
|
|
|
m_prefixCB = false;
|
|
|
|
std::ostringstream output;
|
2017-06-19 12:53:00 +00:00
|
|
|
disassemble(output, cpu, cpu.PC().word);
|
2017-06-04 20:38:34 +00:00
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) {
|
2017-06-04 20:38:34 +00:00
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
auto& bus = cpu.BUS();
|
|
|
|
auto opcode = bus.peek(pc);
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
|
|
// hex opcode
|
|
|
|
output << hex(opcode);
|
|
|
|
|
|
|
|
auto x = (opcode & 0b11000000) >> 6;
|
|
|
|
auto y = (opcode & 0b111000) >> 3;
|
|
|
|
auto z = (opcode & 0b111);
|
|
|
|
|
|
|
|
auto p = (y & 0b110) >> 1;
|
|
|
|
auto q = (y & 1);
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
auto immediate = bus.peek(pc + 1);
|
|
|
|
auto absolute = bus.peekWord(pc + 1);
|
2017-06-04 20:38:34 +00:00
|
|
|
auto displacement = (int8_t)immediate;
|
|
|
|
auto relative = pc + displacement + 2;
|
2017-09-07 00:15:28 +00:00
|
|
|
auto indexedImmediate = bus.peek(pc + 1);
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
|
|
auto dumpCount = 0;
|
2017-08-31 16:18:38 +00:00
|
|
|
auto ioRegister = IoRegister::Unused;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
|
|
std::string specification = "";
|
|
|
|
|
|
|
|
if (m_prefixCB)
|
|
|
|
disassembleCB(
|
|
|
|
output, cpu, pc,
|
|
|
|
specification, dumpCount,
|
|
|
|
x, y, z, p, q);
|
|
|
|
else
|
|
|
|
disassembleOther(
|
|
|
|
output, cpu, pc,
|
2017-08-31 16:18:38 +00:00
|
|
|
specification, dumpCount, ioRegister,
|
2017-06-04 20:38:34 +00:00
|
|
|
x, y, z, p, q);
|
|
|
|
|
|
|
|
for (int i = 0; i < dumpCount; ++i)
|
2017-09-07 00:15:28 +00:00
|
|
|
output << hex(bus.peek(pc + i + 1));
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
|
|
output << '\t';
|
|
|
|
m_formatter.parse(specification);
|
|
|
|
output << m_formatter % (int)immediate % (int)absolute % relative % (int)displacement % indexedImmediate;
|
2017-08-31 16:18:38 +00:00
|
|
|
|
|
|
|
switch (ioRegister) {
|
|
|
|
case Abbreviated:
|
|
|
|
output << "; register " << io(immediate);
|
|
|
|
break;
|
|
|
|
case Absolute:
|
|
|
|
output << "; register (Absolute)";
|
|
|
|
break;
|
|
|
|
case Register:
|
|
|
|
output << "; register C:" << io(cpu.C());
|
|
|
|
break;
|
|
|
|
case Unused:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
__assume(0);
|
|
|
|
}
|
2017-06-04 20:38:34 +00:00
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
void EightBit::GameBoy::Disassembler::disassembleCB(
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream& output,
|
|
|
|
LR35902& cpu,
|
|
|
|
uint16_t pc,
|
|
|
|
std::string& specification,
|
|
|
|
int& dumpCount,
|
|
|
|
int x, int y, int z,
|
|
|
|
int p, int q) {
|
|
|
|
|
|
|
|
switch (x) {
|
|
|
|
case 0: // rot[y] r[z]
|
|
|
|
switch (y) {
|
|
|
|
case 0:
|
|
|
|
specification = "RLC " + R(z);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
specification = "RRC " + R(z);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
specification = "RL " + R(z);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
specification = "RR " + R(z);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
specification = "SLA " + R(z);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
specification = "SRA " + R(z);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
specification = "SWAP " + R(z);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
specification = "SRL " + R(z);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // BIT y, r[z]
|
|
|
|
specification = "BIT " + decimal(y) + "," + R(z);
|
|
|
|
break;
|
|
|
|
case 2: // RES y, r[z]
|
|
|
|
specification = "RES " + decimal(y) + "," + R(z);
|
|
|
|
break;
|
|
|
|
case 3: // SET y, r[z]
|
|
|
|
specification = "SET " + decimal(y) + "," + R(z);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
void EightBit::GameBoy::Disassembler::disassembleOther(
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream& output,
|
|
|
|
LR35902& cpu,
|
|
|
|
uint16_t pc,
|
|
|
|
std::string& specification,
|
|
|
|
int& dumpCount,
|
2017-08-31 16:18:38 +00:00
|
|
|
IoRegister& ioRegister,
|
2017-06-04 20:38:34 +00:00
|
|
|
int x, int y, int z,
|
|
|
|
int p, int q) {
|
|
|
|
|
|
|
|
switch (x) {
|
|
|
|
case 0:
|
|
|
|
switch (z) {
|
|
|
|
case 0: // Relative jumps and assorted ops
|
|
|
|
switch (y) {
|
|
|
|
case 0: // NOP
|
|
|
|
specification = "NOP";
|
|
|
|
break;
|
|
|
|
case 1: // GB: LD (nn),SP
|
|
|
|
specification = "LD (%2$04XH),SP";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
case 2: // GB: STOP
|
|
|
|
specification = "STOP";
|
|
|
|
break;
|
|
|
|
case 3: // JR d
|
|
|
|
specification = "JR %3$04XH";
|
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
default: // JR cc,d
|
|
|
|
specification = "JR " + cc(y - 4) + ",%3$04XH";
|
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // 16-bit load immediate/add
|
|
|
|
switch (q) {
|
|
|
|
case 0: // LD rp,nn
|
|
|
|
specification = "LD " + RP(p) + ",%2$04XH";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
case 1: // ADD HL,rp
|
|
|
|
specification = "ADD HL," + RP(p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: // Indirect loading
|
|
|
|
switch (q) {
|
|
|
|
case 0:
|
|
|
|
switch (p) {
|
|
|
|
case 0: // LD (BC),A
|
|
|
|
specification = "LD (BC),A";
|
|
|
|
break;
|
|
|
|
case 1: // LD (DE),A
|
|
|
|
specification = "LD (DE),A";
|
|
|
|
break;
|
|
|
|
case 2: // GB: LDI (HL),A
|
|
|
|
specification = "LDI (HL),A";
|
|
|
|
break;
|
|
|
|
case 3: // GB: LDD (HL),A
|
|
|
|
specification = "LDD (HL),A";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
switch (p) {
|
|
|
|
case 0: // LD A,(BC)
|
|
|
|
specification = "LD A,(BC)";
|
|
|
|
break;
|
|
|
|
case 1: // LD A,(DE)
|
|
|
|
specification = "LD A,(DE)";
|
|
|
|
break;
|
|
|
|
case 2: // GB: LDI A,(HL)
|
|
|
|
specification = "LDI A,(HL)";
|
|
|
|
break;
|
|
|
|
case 3: // GB: LDD A,(HL)
|
|
|
|
specification = "LDD A,(HL)";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: // 16-bit INC/DEC
|
|
|
|
switch (q) {
|
|
|
|
case 0: // INC rp
|
|
|
|
specification = "INC " + RP(p);
|
|
|
|
break;
|
|
|
|
case 1: // DEC rp
|
|
|
|
specification = "DEC " + RP(p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4: // 8-bit INC
|
|
|
|
specification = "INC " + R(y);
|
|
|
|
break;
|
|
|
|
case 5: // 8-bit DEC
|
|
|
|
specification = "DEC " + R(y);
|
|
|
|
break;
|
|
|
|
case 6: // 8-bit load immediate
|
|
|
|
specification = "LD " + R(y) + ",%1$02XH";
|
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
case 7: // Assorted operations on accumulator/flags
|
|
|
|
switch (y) {
|
|
|
|
case 0:
|
|
|
|
specification = "RLCA";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
specification = "RRCA";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
specification = "RLA";
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
specification = "RRA";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
specification = "DAA";
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
specification = "CPL";
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
specification = "SCF";
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
specification = "CCF";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // 8-bit loading
|
|
|
|
if (z == 6 && y == 6) { // Exception (replaces LD (HL), (HL))
|
|
|
|
specification = "HALT";
|
|
|
|
} else {
|
|
|
|
specification = "LD " + R(y) + "," + R(z);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: // Operate on accumulator and register/memory location
|
|
|
|
specification = alu(y) + " A," + R(z);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
switch (z) {
|
|
|
|
case 0: // Conditional return
|
|
|
|
switch (y) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
specification = "RET " + cc(y);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
specification = "LD (FF00H+%1$02XH),A";
|
2017-08-31 16:18:38 +00:00
|
|
|
ioRegister = IoRegister::Abbreviated;
|
2017-06-04 20:38:34 +00:00
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
specification = "ADD SP,%3$04XH";
|
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
specification = "LD A,(FF00H+%1$02XH)";
|
2017-08-31 16:18:38 +00:00
|
|
|
ioRegister = IoRegister::Abbreviated;
|
2017-06-04 20:38:34 +00:00
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
case 7:
|
2017-07-22 13:07:26 +00:00
|
|
|
specification = "LD HL,SP%4$+i";
|
2017-06-04 20:38:34 +00:00
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // POP & various ops
|
|
|
|
switch (q) {
|
|
|
|
case 0: // POP rp2[p]
|
|
|
|
specification = "POP " + RP2(p);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
switch (p) {
|
|
|
|
case 0: // RET
|
|
|
|
specification = "RET";
|
|
|
|
break;
|
|
|
|
case 1: // GB: RETI
|
|
|
|
specification = "RETI";
|
|
|
|
break;
|
|
|
|
case 2: // JP (HL)
|
|
|
|
specification = "JP (HL)";
|
|
|
|
break;
|
|
|
|
case 3: // LD SP,HL
|
2017-08-14 21:57:46 +00:00
|
|
|
specification = "LD SP,HL";
|
2017-06-04 20:38:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: // Conditional jump
|
|
|
|
switch (y) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
specification = "JP " + cc(y) + ",%2$04XH";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
specification = "LD (FF00H+C),A";
|
2017-08-31 16:18:38 +00:00
|
|
|
ioRegister = IoRegister::Register;
|
2017-06-04 20:38:34 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
specification = "LD (%2$04XH),A";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
specification = "LD A,(FF00H+C)";
|
2017-08-31 16:18:38 +00:00
|
|
|
ioRegister = IoRegister::Register;
|
2017-06-04 20:38:34 +00:00
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
specification = "LD A,(%2$04XH)";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: // Assorted operations
|
|
|
|
switch (y) {
|
|
|
|
case 0: // JP nn
|
|
|
|
specification = "JP %2$04XH";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
case 1: // CB prefix
|
|
|
|
m_prefixCB = true;
|
|
|
|
disassemble(output, cpu, pc + 1);
|
|
|
|
break;
|
|
|
|
case 6: // DI
|
|
|
|
specification = "DI";
|
|
|
|
break;
|
|
|
|
case 7: // EI
|
|
|
|
specification = "EI";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4: // Conditional call: CALL cc[y], nn
|
|
|
|
specification = "CALL " + cc(y) + ",%2$04XH";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
case 5: // PUSH & various ops
|
|
|
|
switch (q) {
|
|
|
|
case 0: // PUSH rp2[p]
|
|
|
|
specification = "PUSH " + RP2(p);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
switch (p) {
|
|
|
|
case 0: // CALL nn
|
|
|
|
specification = "CALL %2$04XH";
|
|
|
|
dumpCount += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6: // Operate on accumulator and immediate operand: alu[y] n
|
|
|
|
specification = alu(y) + " A,%1$02XH";
|
|
|
|
dumpCount++;
|
|
|
|
break;
|
|
|
|
case 7: // Restart: RST y * 8
|
|
|
|
specification = "RST " + hex((uint8_t)(y * 8)) + "H";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::flag(uint8_t value, int flag, const std::string& represents) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output << (value & flag ? represents : "-");
|
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::flags(uint8_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output
|
|
|
|
<< flag(value, LR35902::ZF, "Z")
|
|
|
|
<< flag(value, LR35902::NF, "N")
|
|
|
|
<< flag(value, LR35902::HC, "H")
|
|
|
|
<< flag(value, LR35902::CF, "C")
|
2017-06-09 09:23:51 +00:00
|
|
|
<< flag(value, EightBit::Processor::Bit3, "+")
|
|
|
|
<< flag(value, EightBit::Processor::Bit2, "+")
|
|
|
|
<< flag(value, EightBit::Processor::Bit1, "+")
|
|
|
|
<< flag(value, EightBit::Processor::Bit0, "+");
|
2017-06-04 20:38:34 +00:00
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::hex(uint8_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output << std::hex << std::setw(2) << std::setfill('0') << (int)value;
|
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::hex(uint16_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output << std::hex << std::setw(4) << std::setfill('0') << (int)value;
|
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::binary(uint8_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output << std::bitset<8>(value);
|
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::decimal(uint8_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output << (int)value;
|
|
|
|
return output.str();
|
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::invalid(uint8_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
std::ostringstream output;
|
|
|
|
output << "Invalid instruction: " << hex(value) << "(" << binary(value) << ")";
|
|
|
|
return output.str();
|
2017-08-31 16:18:38 +00:00
|
|
|
}
|
|
|
|
|
2017-09-07 00:15:28 +00:00
|
|
|
std::string EightBit::GameBoy::Disassembler::io(uint8_t value) {
|
2017-08-31 16:18:38 +00:00
|
|
|
switch (value) {
|
|
|
|
|
|
|
|
// Port/Mode Registers
|
|
|
|
case Bus::P1:
|
|
|
|
return "P1";
|
|
|
|
case Bus::SB:
|
|
|
|
return "SB";
|
|
|
|
case Bus::SC:
|
|
|
|
return "SC";
|
|
|
|
case Bus::DIV:
|
|
|
|
return "DIV";
|
|
|
|
case Bus::TIMA:
|
|
|
|
return "TIMA";
|
|
|
|
case Bus::TMA:
|
|
|
|
return "TMA";
|
|
|
|
case Bus::TAC:
|
|
|
|
return "TAC";
|
|
|
|
|
|
|
|
// Interrupt Flags
|
|
|
|
case Bus::IF:
|
|
|
|
return "IF";
|
|
|
|
case Bus::IE:
|
|
|
|
return "IE";
|
|
|
|
|
|
|
|
// LCD Display Registers
|
|
|
|
case Bus::LCDC:
|
|
|
|
return "LCDC";
|
|
|
|
case Bus::STAT:
|
|
|
|
return "STAT";
|
|
|
|
case Bus::SCY:
|
|
|
|
return "SCY";
|
|
|
|
case Bus::SCX:
|
|
|
|
return "SCX";
|
|
|
|
case Bus::LY:
|
|
|
|
return "LY";
|
|
|
|
case Bus::LYC:
|
|
|
|
return "LYC";
|
|
|
|
case Bus::DMA:
|
|
|
|
return "DMA";
|
|
|
|
case Bus::BGP:
|
|
|
|
return "BGP";
|
|
|
|
case Bus::OBP0:
|
|
|
|
return "OBP0";
|
|
|
|
case Bus::OBP1:
|
|
|
|
return "OBP1";
|
|
|
|
case Bus::WY:
|
|
|
|
return "WY";
|
|
|
|
case Bus::WX:
|
|
|
|
return "WX";
|
|
|
|
|
|
|
|
// Sound Registers
|
|
|
|
case Bus::NR10:
|
|
|
|
return "NR10";
|
|
|
|
case Bus::NR11:
|
|
|
|
return "NR11";
|
|
|
|
case Bus::NR12:
|
|
|
|
return "NR12";
|
|
|
|
case Bus::NR13:
|
|
|
|
return "NR13";
|
|
|
|
case Bus::NR14:
|
|
|
|
return "NR14";
|
|
|
|
case Bus::NR21:
|
|
|
|
return "NR21";
|
|
|
|
case Bus::NR22:
|
|
|
|
return "NR22";
|
|
|
|
case Bus::NR23:
|
|
|
|
return "NR23";
|
|
|
|
case Bus::NR24:
|
|
|
|
return "NR24";
|
|
|
|
case Bus::NR30:
|
|
|
|
return "NR30";
|
|
|
|
case Bus::NR31:
|
|
|
|
return "NR31";
|
|
|
|
case Bus::NR32:
|
|
|
|
return "NR32";
|
|
|
|
case Bus::NR33:
|
|
|
|
return "NR33";
|
|
|
|
case Bus::NR34:
|
|
|
|
return "NR34";
|
|
|
|
case Bus::NR41:
|
|
|
|
return "NR41";
|
|
|
|
case Bus::NR42:
|
|
|
|
return "NR42";
|
|
|
|
case Bus::NR43:
|
|
|
|
return "NR43";
|
|
|
|
case Bus::NR44:
|
|
|
|
return "NR44";
|
|
|
|
case Bus::NR50:
|
|
|
|
return "NR50";
|
|
|
|
case Bus::NR51:
|
|
|
|
return "NR51";
|
|
|
|
case Bus::NR52:
|
|
|
|
return "NR52";
|
|
|
|
|
|
|
|
case Bus::WPRAM_START:
|
|
|
|
return "WPRAM_START";
|
|
|
|
case Bus::WPRAM_END:
|
|
|
|
return "WPRAM_END";
|
|
|
|
|
|
|
|
// Boot rom control
|
|
|
|
case Bus::BOOT_DISABLE:
|
|
|
|
return "BOOT_DISABLE";
|
|
|
|
|
|
|
|
default:
|
|
|
|
return hex(value);
|
|
|
|
}
|
|
|
|
}
|