From 93bac4254797c86c255ad5206243da065513a4ef Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Fri, 9 Jun 2017 11:42:32 +0100 Subject: [PATCH] Bring LR35902 a little more in line with the Z80 implementation. Signed-off-by: Adrian.Conlon --- LR35902/inc/Bus.h | 202 ++++++++-------- LR35902/inc/Disassembler.h | 81 ++++--- LR35902/inc/LR35902.h | 446 ++++++++++++++++++----------------- LR35902/inc/Profiler.h | 30 +-- LR35902/src/Bus.cpp | 10 +- LR35902/src/Disassembler.cpp | 36 +-- LR35902/src/LR35902.cpp | 171 ++++++++------ LR35902/src/Profiler.cpp | 10 +- 8 files changed, 511 insertions(+), 475 deletions(-) diff --git a/LR35902/inc/Bus.h b/LR35902/inc/Bus.h index 8eba042..de98757 100644 --- a/LR35902/inc/Bus.h +++ b/LR35902/inc/Bus.h @@ -2,105 +2,107 @@ #include "Memory.h" -class Bus : public EightBit::Memory { -public: +namespace EightBit { + class Bus : public Memory { + public: - enum { - TotalLineCount = 154 + enum { + TotalLineCount = 154 + }; + + enum { + VideoRam = 0x8000 + }; + + enum { + + BASE = 0xFF00, + + // Port/Mode Registers + P1 = 0x0, + SB = 0x1, + SC = 0x2, + DIV = 0x4, + TIMA = 0x5, + TMA = 0x6, + TAC = 0x7, + + // Interrupt Flags + IF = 0xF, + IE = 0xFF, + + // LCD Display Registers + LCDC = 0x40, + STAT = 0x41, + SCY = 0x42, + SCX = 0x43, + LY = 0x44, + LYC = 0x45, + DMA = 0x46, + BGP = 0x47, + OBP0 = 0x48, + OBP1 = 0x49, + WY = 0x4A, + WX = 0x4B, + + // Sound Registers + NR10 = 0x10, + NR11 = 0x11, + NR12 = 0x12, + NR13 = 0x13, + NR14 = 0x14, + NR21 = 0x16, + NR22 = 0x17, + NR23 = 0x18, + NR24 = 0x19, + NR30 = 0x1A, + NR31 = 0x1B, + NR32 = 0x1C, + NR33 = 0x1D, + NR34 = 0x1E, + NR41 = 0x20, + NR42 = 0x21, + NR43 = 0x22, + NR44 = 0x23, + NR50 = 0x24, + NR51 = 0x25, + NR52 = 0x26, + + WPRAM_START = 0x30, + WPRAM_END = 0x3F, + + // Boot rom control + BOOT_DISABLE = 0x50, + }; + + Bus(); + + void reset(); + + uint8_t& REG(int offset) { + ADDRESS().word = BASE + offset; + return Memory::reference(); + } + + void incrementLY() { + REG(LY) = (REG(LY) + 1) % TotalLineCount; + } + + void resetLY() { + REG(LY) = 0; + } + + void loadBootRom(const std::string& path); + + bool isBootRom(uint16_t address) const { + return (address < m_boot.size()) && (peek(BASE + BOOT_DISABLE) == 0); + } + + virtual uint8_t peek(uint16_t address) const; + + virtual uint8_t& reference(); + + private: + std::array m_boot; }; - - enum { - VideoRam = 0x8000 - }; - - enum { - - BASE = 0xFF00, - - // Port/Mode Registers - P1 = 0x0, - SB = 0x1, - SC = 0x2, - DIV = 0x4, - TIMA = 0x5, - TMA = 0x6, - TAC = 0x7, - - // Interrupt Flags - IF = 0xF, - IE = 0xFF, - - // LCD Display Registers - LCDC = 0x40, - STAT = 0x41, - SCY = 0x42, - SCX = 0x43, - LY = 0x44, - LYC = 0x45, - DMA = 0x46, - BGP = 0x47, - OBP0 = 0x48, - OBP1 = 0x49, - WY = 0x4A, - WX = 0x4B, - - // Sound Registers - NR10 = 0x10, - NR11 = 0x11, - NR12 = 0x12, - NR13 = 0x13, - NR14 = 0x14, - NR21 = 0x16, - NR22 = 0x17, - NR23 = 0x18, - NR24 = 0x19, - NR30 = 0x1A, - NR31 = 0x1B, - NR32 = 0x1C, - NR33 = 0x1D, - NR34 = 0x1E, - NR41 = 0x20, - NR42 = 0x21, - NR43 = 0x22, - NR44 = 0x23, - NR50 = 0x24, - NR51 = 0x25, - NR52 = 0x26, - - WPRAM_START = 0x30, - WPRAM_END = 0x3F, - - // Boot rom control - BOOT_DISABLE = 0x50, - }; - - Bus(); - - void reset(); - - uint8_t& REG(int offset) { - ADDRESS().word = BASE + offset; - return Memory::reference(); - } - - void incrementLY() { - REG(LY) = (REG(LY) + 1) % TotalLineCount; - } - - void resetLY() { - REG(LY) = 0; - } - - void loadBootRom(const std::string& path); - - bool isBootRom(uint16_t address) const { - return (address < m_boot.size()) && (peek(BASE + BOOT_DISABLE) == 0); - } - - virtual uint8_t peek(uint16_t address) const; - - virtual uint8_t& reference(); - -private: - std::array m_boot; -}; +} \ No newline at end of file diff --git a/LR35902/inc/Disassembler.h b/LR35902/inc/Disassembler.h index c6c3101..eea6604 100644 --- a/LR35902/inc/Disassembler.h +++ b/LR35902/inc/Disassembler.h @@ -3,51 +3,54 @@ #include #include -class LR35902; +namespace EightBit { -class Disassembler { -public: - Disassembler(); + class LR35902; - static std::string state(LR35902& cpu); - std::string disassemble(LR35902& cpu); + class Disassembler { + public: + Disassembler(); - static std::string flag(uint8_t value, int flag, const std::string& represents); - static std::string flags(uint8_t value); - static std::string hex(uint8_t value); - static std::string hex(uint16_t value); - static std::string binary(uint8_t value); - static std::string decimal(uint8_t value); + static std::string state(LR35902& cpu); + std::string disassemble(LR35902& cpu); - static std::string invalid(uint8_t value); + static std::string flag(uint8_t value, int flag, const std::string& represents); + static std::string flags(uint8_t value); + static std::string hex(uint8_t value); + static std::string hex(uint16_t value); + static std::string binary(uint8_t value); + static std::string decimal(uint8_t value); -private: - mutable boost::format m_formatter; - bool m_prefixCB; + static std::string invalid(uint8_t value); - void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc); + private: + mutable boost::format m_formatter; + bool m_prefixCB; - void disassembleCB( - std::ostringstream& output, - LR35902& cpu, - uint16_t pc, - std::string& specification, - int& dumpCount, - int x, int y, int z, - int p, int q); + void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc); - void disassembleOther( - std::ostringstream& output, - LR35902& cpu, - uint16_t pc, - std::string& specification, - int& dumpCount, - int x, int y, int z, - int p, int q); + void disassembleCB( + std::ostringstream& output, + LR35902& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q); - std::string RP(int rp) const; - std::string RP2(int rp) const; - std::string R(int r) const; - static std::string cc(int flag); - static std::string alu(int which); -}; + void disassembleOther( + std::ostringstream& output, + LR35902& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q); + + std::string RP(int rp) const; + std::string RP2(int rp) const; + std::string R(int r) const; + static std::string cc(int flag); + static std::string alu(int which); + }; +} \ No newline at end of file diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 6cd919b..e6ccf72 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -5,226 +5,228 @@ #include "Processor.h" #include "Bus.h" -class LR35902 : public EightBit::Processor { -public: - enum StatusBits { - ZF = Bit7, - NF = Bit6, - HC = Bit5, - CF = Bit4, +namespace EightBit { + class LR35902 : public Processor { + public: + enum StatusBits { + ZF = Bit7, + NF = Bit6, + HC = Bit5, + CF = Bit4, + }; + + LR35902(Bus& memory); + + Signal ExecutingInstruction; + + void stop() { m_stopped = true; } + void start() { m_stopped = false; } + bool stopped() const { return m_stopped; } + + bool& IME() { return m_ime; } + + void di(); + void ei(); + + int interrupt(uint8_t value); + + int execute(uint8_t opcode); + int step(); + + // Mutable access to processor!! + + register16_t& AF() { + m_accumulatorFlag.low &= 0xf0; + return m_accumulatorFlag; + } + + uint8_t& A() { return AF().high; } + uint8_t& F() { return AF().low; } + + register16_t& BC() { + return m_registers[BC_IDX]; + } + + uint8_t& B() { return BC().high; } + uint8_t& C() { return BC().low; } + + register16_t& DE() { + return m_registers[DE_IDX]; + } + + uint8_t& D() { return DE().high; } + uint8_t& E() { return DE().low; } + + register16_t& HL() { + return m_registers[HL_IDX]; + } + + uint8_t& H() { return HL().high; } + uint8_t& L() { return HL().low; } + + virtual void reset(); + virtual void initialise(); + + private: + enum { BC_IDX, DE_IDX, HL_IDX }; + + std::array m_registers; + register16_t m_accumulatorFlag; + + bool m_ime; + + bool m_prefixCB; + + bool m_stopped; + + std::array m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } }; + std::array m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } }; + + register16_t fetchWord() { + register16_t returned; + Processor::fetchWord(returned); + return returned; + } + + int fetchExecute() { + return execute(fetchByte()); + } + + void clearFlag(int flag) { F() &= ~flag; } + void setFlag(int flag) { F() |= flag; } + + void setFlag(int flag, int condition) { setFlag(flag, condition != 0); } + void setFlag(int flag, uint32_t condition) { setFlag(flag, condition != 0); } + void setFlag(int flag, bool condition) { condition ? setFlag(flag) : clearFlag(flag); } + + void clearFlag(int flag, int condition) { clearFlag(flag, condition != 0); } + void clearFlag(int flag, uint32_t condition) { clearFlag(flag, condition != 0); } + void clearFlag(int flag, bool condition) { condition ? clearFlag(flag) : setFlag(flag); } + + uint8_t& R(int r) { + 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: + m_memory.ADDRESS() = HL(); + return m_memory.reference(); + case 7: + return A(); + } + throw std::logic_error("Unhandled registry mechanism"); + } + + register16_t& RP(int rp) { + switch (rp) { + case 3: + return sp; + default: + return m_registers[rp]; + } + } + + register16_t& RP2(int rp) { + switch (rp) { + case 3: + return AF(); + default: + return m_registers[rp]; + } + } + + int buildHalfCarryIndex(uint8_t before, uint8_t value, int calculation) { + return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3); + } + + void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) { + auto index = buildHalfCarryIndex(before, value, calculation); + setFlag(HC, m_halfCarryTableAdd[index & 0x7]); + } + + void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) { + auto index = buildHalfCarryIndex(before, value, calculation); + setFlag(HC, m_halfCarryTableSub[index & 0x7]); + } + + void executeCB(int x, int y, int z, int p, int q); + void executeOther(int x, int y, int z, int p, int q); + + void adjustZero(uint8_t value); + + void postIncrement(uint8_t value); + void postDecrement(uint8_t value); + + void restart(uint8_t address); + + void jrConditional(int conditional); + void jrConditionalFlag(int flag); + + void ret(); + void reti(); + + void returnConditional(int condition); + void returnConditionalFlag(int flag); + + void jumpConditional(int condition); + void jumpConditionalFlag(int flag); + + void call(uint16_t address); + void callConditional(uint16_t address, int condition); + void callConditionalFlag(uint16_t address, int flag); + + uint16_t sbc(uint16_t value); + uint16_t adc(uint16_t value); + + uint16_t add(uint16_t value); + + void sub(uint8_t& operand, uint8_t value, bool carry); + void sub(uint8_t& operand, uint8_t value); + void sbc(uint8_t& operand, uint8_t value); + + void add(uint8_t& operand, uint8_t value, bool carry); + void add(uint8_t& operand, uint8_t value); + void adc(uint8_t& operand, uint8_t value); + + void andr(uint8_t& operand, uint8_t value); + + void anda(uint8_t value); + void xora(uint8_t value); + void ora(uint8_t value); + void compare(uint8_t value); + + void rlca(); + void rrca(); + void rla(); + void rra(); + + void rlc(uint8_t& operand); + void rrc(uint8_t& operand); + void rl(uint8_t& operand); + void rr(uint8_t& operand); + void sla(uint8_t& operand); + void sra(uint8_t& operand); + void srl(uint8_t& operand); + + void bit(int n, uint8_t& operand); + void res(int n, uint8_t& operand); + void set(int nit, uint8_t& operand); + + void daa(); + + void scf(); + void ccf(); + void cpl(); + + void swap(uint8_t& operand); }; - - LR35902(Bus& memory); - - EightBit::Signal ExecutingInstruction; - - void stop() { m_stopped = true; } - void start() { m_stopped = false; } - bool stopped() const { return m_stopped; } - - bool& IME() { return m_ime; } - - void di(); - void ei(); - - int interrupt(uint8_t value); - - int execute(uint8_t opcode); - int step(); - - // Mutable access to processor!! - - EightBit::register16_t& AF() { - m_accumulatorFlag.low &= 0xf0; - return m_accumulatorFlag; - } - - uint8_t& A() { return AF().high; } - uint8_t& F() { return AF().low; } - - EightBit::register16_t& BC() { - return m_registers[BC_IDX]; - } - - uint8_t& B() { return BC().high; } - uint8_t& C() { return BC().low; } - - EightBit::register16_t& DE() { - return m_registers[DE_IDX]; - } - - uint8_t& D() { return DE().high; } - uint8_t& E() { return DE().low; } - - EightBit::register16_t& HL() { - return m_registers[HL_IDX]; - } - - uint8_t& H() { return HL().high; } - uint8_t& L() { return HL().low; } - - virtual void reset(); - virtual void initialise(); - -private: - enum { BC_IDX, DE_IDX, HL_IDX }; - - std::array m_registers; - EightBit::register16_t m_accumulatorFlag; - - bool m_ime; - - bool m_prefixCB; - - bool m_stopped; - - std::array m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } }; - std::array m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } }; - - EightBit::register16_t fetchWord() { - EightBit::register16_t returned; - Processor::fetchWord(returned); - return returned; - } - - int fetchExecute() { - return execute(fetchByte()); - } - - void clearFlag(int flag) { F() &= ~flag; } - void setFlag(int flag) { F() |= flag; } - - void setFlag(int flag, int condition) { setFlag(flag, condition != 0); } - void setFlag(int flag, uint32_t condition) { setFlag(flag, condition != 0); } - void setFlag(int flag, bool condition) { condition ? setFlag(flag) : clearFlag(flag); } - - void clearFlag(int flag, int condition) { clearFlag(flag, condition != 0); } - void clearFlag(int flag, uint32_t condition) { clearFlag(flag, condition != 0); } - void clearFlag(int flag, bool condition) { condition ? clearFlag(flag) : setFlag(flag); } - - uint8_t& R(int r) { - 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: - m_memory.ADDRESS() = HL(); - return m_memory.reference(); - case 7: - return A(); - } - throw std::logic_error("Unhandled registry mechanism"); - } - - EightBit::register16_t& RP(int rp) { - switch (rp) { - case 3: - return sp; - default: - return m_registers[rp]; - } - } - - EightBit::register16_t& RP2(int rp) { - switch (rp) { - case 3: - return AF(); - default: - return m_registers[rp]; - } - } - - int buildHalfCarryIndex(uint8_t before, uint8_t value, int calculation) { - return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3); - } - - void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) { - auto index = buildHalfCarryIndex(before, value, calculation); - setFlag(HC, m_halfCarryTableAdd[index & 0x7]); - } - - void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) { - auto index = buildHalfCarryIndex(before, value, calculation); - setFlag(HC, m_halfCarryTableSub[index & 0x7]); - } - - void executeCB(int x, int y, int z, int p, int q); - void executeOther(int x, int y, int z, int p, int q); - - void adjustZero(uint8_t value); - - void postIncrement(uint8_t value); - void postDecrement(uint8_t value); - - void restart(uint8_t address); - - void jrConditional(int conditional); - void jrConditionalFlag(int flag); - - void ret(); - void reti(); - - void returnConditional(int condition); - void returnConditionalFlag(int flag); - - void jumpConditional(int condition); - void jumpConditionalFlag(int flag); - - void call(uint16_t address); - void callConditional(uint16_t address, int condition); - void callConditionalFlag(uint16_t address, int flag); - - uint16_t sbc(uint16_t value); - uint16_t adc(uint16_t value); - - uint16_t add(uint16_t value); - - void sub(uint8_t& operand, uint8_t value, bool carry); - void sub(uint8_t& operand, uint8_t value); - void sbc(uint8_t& operand, uint8_t value); - - void add(uint8_t& operand, uint8_t value, bool carry); - void add(uint8_t& operand, uint8_t value); - void adc(uint8_t& operand, uint8_t value); - - void andr(uint8_t& operand, uint8_t value); - - void anda(uint8_t value); - void xora(uint8_t value); - void ora(uint8_t value); - void compare(uint8_t value); - - void rlca(); - void rrca(); - void rla(); - void rra(); - - void rlc(uint8_t& operand); - void rrc(uint8_t& operand); - void rl(uint8_t& operand); - void rr(uint8_t& operand); - void sla(uint8_t& operand); - void sra(uint8_t& operand); - void srl(uint8_t& operand); - - void bit(int n, uint8_t& operand); - void res(int n, uint8_t& operand); - void set(int nit, uint8_t& operand); - - void daa(); - - void scf(); - void ccf(); - void cpl(); - - void swap(uint8_t& operand); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/LR35902/inc/Profiler.h b/LR35902/inc/Profiler.h index 3f49a9b..f5b9843 100644 --- a/LR35902/inc/Profiler.h +++ b/LR35902/inc/Profiler.h @@ -5,24 +5,26 @@ #include "Disassembler.h" -class LR35902; +namespace EightBit { -class Profiler { -public: - Profiler(LR35902& cpu); + class LR35902; - void add(uint16_t address, uint8_t instruction); + class Profiler { + public: + Profiler(LR35902& cpu); - void dump() const; + void add(uint16_t address, uint8_t instruction); -private: - std::array m_instructions; - std::array m_addresses; - LR35902& m_cpu; + void dump() const; - Disassembler m_disassembler; + private: + std::array m_instructions; + std::array m_addresses; + LR35902& m_cpu; - void dumpInstructionProfiles() const; - void dumpAddressProfiles() const; -}; + Disassembler m_disassembler; + void dumpInstructionProfiles() const; + void dumpAddressProfiles() const; + }; +} \ No newline at end of file diff --git a/LR35902/src/Bus.cpp b/LR35902/src/Bus.cpp index 18960c1..b695e05 100644 --- a/LR35902/src/Bus.cpp +++ b/LR35902/src/Bus.cpp @@ -1,30 +1,30 @@ #include "stdafx.h" #include "Bus.h" -Bus::Bus() +EightBit::Bus::Bus() : Memory(0xffff) { } -void Bus::reset() { +void EightBit::Bus::reset() { REG(NR52) = 0xf1; REG(LCDC) = 0x91; } -void Bus::loadBootRom(const std::string& path) { +void EightBit::Bus::loadBootRom(const std::string& path) { auto size = loadMemory(path, 0); if (size != 0x100) throw std::runtime_error("Incorrectly sized boot ROM"); std::copy_n(m_bus.cbegin(), size, m_boot.begin()); } -uint8_t& Bus::reference() { +uint8_t& EightBit::Bus::reference() { auto effective = effectiveAddress(ADDRESS().word); if (isBootRom(effective)) return placeDATA(m_boot[effective]); return Memory::reference(); } -uint8_t Bus::peek(uint16_t address) const { +uint8_t EightBit::Bus::peek(uint16_t address) const { auto effective = effectiveAddress(address); if (isBootRom(effective)) return m_boot[effective]; diff --git a/LR35902/src/Disassembler.cpp b/LR35902/src/Disassembler.cpp index 9a96dca..5dbc6a2 100644 --- a/LR35902/src/Disassembler.cpp +++ b/LR35902/src/Disassembler.cpp @@ -9,12 +9,12 @@ #include "LR35902.h" #include "StatusFlags.h" -Disassembler::Disassembler() { +EightBit::Disassembler::Disassembler() { // Disable exceptions where too many format arguments are available m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); } -std::string Disassembler::state(LR35902& cpu) { +std::string EightBit::Disassembler::state(EightBit::LR35902& cpu) { auto pc = cpu.getProgramCounter(); auto sp = cpu.getStackPointer(); @@ -45,7 +45,7 @@ std::string Disassembler::state(LR35902& cpu) { return output.str(); } -std::string Disassembler::RP(int rp) const { +std::string EightBit::Disassembler::RP(int rp) const { switch (rp) { case 0: return "BC"; @@ -59,7 +59,7 @@ std::string Disassembler::RP(int rp) const { throw std::logic_error("Unhandled register pair"); } -std::string Disassembler::RP2(int rp) const { +std::string EightBit::Disassembler::RP2(int rp) const { switch (rp) { case 0: return "BC"; @@ -73,7 +73,7 @@ std::string Disassembler::RP2(int rp) const { throw std::logic_error("Unhandled register pair"); } -std::string Disassembler::R(int r) const { +std::string EightBit::Disassembler::R(int r) const { switch (r) { case 0: return "B"; @@ -95,7 +95,7 @@ std::string Disassembler::R(int r) const { throw std::logic_error("Unhandled register"); } -std::string Disassembler::cc(int flag) { +std::string EightBit::Disassembler::cc(int flag) { switch (flag) { case 0: return "NZ"; @@ -117,7 +117,7 @@ std::string Disassembler::cc(int flag) { throw std::logic_error("Unhandled condition"); } -std::string Disassembler::alu(int which) { +std::string EightBit::Disassembler::alu(int which) { switch (which) { case 0: // ADD A,n return "ADD"; @@ -139,14 +139,14 @@ std::string Disassembler::alu(int which) { throw std::logic_error("Unhandled alu operation"); } -std::string Disassembler::disassemble(LR35902& cpu) { +std::string EightBit::Disassembler::disassemble(LR35902& cpu) { m_prefixCB = false; std::ostringstream output; disassemble(output, cpu, cpu.getProgramCounter().word); return output.str(); } -void Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) { +void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) { auto& memory = cpu.getMemory(); auto opcode = memory.peek(pc); @@ -190,7 +190,7 @@ void Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_ output << m_formatter % (int)immediate % (int)absolute % relative % (int)displacement % indexedImmediate; } -void Disassembler::disassembleCB( +void EightBit::Disassembler::disassembleCB( std::ostringstream& output, LR35902& cpu, uint16_t pc, @@ -240,7 +240,7 @@ void Disassembler::disassembleCB( } } -void Disassembler::disassembleOther( +void EightBit::Disassembler::disassembleOther( std::ostringstream& output, LR35902& cpu, uint16_t pc, @@ -504,13 +504,13 @@ void Disassembler::disassembleOther( } } -std::string Disassembler::flag(uint8_t value, int flag, const std::string& represents) { +std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) { std::ostringstream output; output << (value & flag ? represents : "-"); return output.str(); } -std::string Disassembler::flags(uint8_t value) { +std::string EightBit::Disassembler::flags(uint8_t value) { std::ostringstream output; output << flag(value, LR35902::ZF, "Z") @@ -524,31 +524,31 @@ std::string Disassembler::flags(uint8_t value) { return output.str(); } -std::string Disassembler::hex(uint8_t value) { +std::string EightBit::Disassembler::hex(uint8_t value) { std::ostringstream output; output << std::hex << std::setw(2) << std::setfill('0') << (int)value; return output.str(); } -std::string Disassembler::hex(uint16_t value) { +std::string EightBit::Disassembler::hex(uint16_t value) { std::ostringstream output; output << std::hex << std::setw(4) << std::setfill('0') << (int)value; return output.str(); } -std::string Disassembler::binary(uint8_t value) { +std::string EightBit::Disassembler::binary(uint8_t value) { std::ostringstream output; output << std::bitset<8>(value); return output.str(); } -std::string Disassembler::decimal(uint8_t value) { +std::string EightBit::Disassembler::decimal(uint8_t value) { std::ostringstream output; output << (int)value; return output.str(); } -std::string Disassembler::invalid(uint8_t value) { +std::string EightBit::Disassembler::invalid(uint8_t value) { std::ostringstream output; output << "Invalid instruction: " << hex(value) << "(" << binary(value) << ")"; return output.str(); diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index 0674cf3..ca7f098 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -4,19 +4,19 @@ // based on http://www.z80.info/decoding.htm // Half carry flag help from https://github.com/oubiwann/z80 -LR35902::LR35902(Bus& memory) +EightBit::LR35902::LR35902(Bus& memory) : Processor(memory), m_ime(false), m_prefixCB(false) { } -void LR35902::reset() { +void EightBit::LR35902::reset() { Processor::reset(); sp.word = 0xfffe; di(); } -void LR35902::initialise() { +void EightBit::LR35902::initialise() { Processor::initialise(); @@ -28,42 +28,54 @@ void LR35902::initialise() { m_prefixCB = false; } -void LR35902::di() { +#pragma region Interrupt routines + +void EightBit::LR35902::di() { IME() = false; } -void LR35902::ei() { +void EightBit::LR35902::ei() { IME() = true; } -int LR35902::interrupt(uint8_t value) { +int EightBit::LR35902::interrupt(uint8_t value) { + cycles = 0; di(); restart(value); return 4; } -void LR35902::adjustZero(uint8_t value) { +#pragma endregion Interrupt routines + +#pragma region Flag manipulation helpers + +void EightBit::LR35902::adjustZero(uint8_t value) { clearFlag(ZF, value); } -void LR35902::postIncrement(uint8_t value) { +void EightBit::LR35902::postIncrement(uint8_t value) { adjustZero(value); clearFlag(NF); clearFlag(HC, lowNibble(value)); } -void LR35902::postDecrement(uint8_t value) { +void EightBit::LR35902::postDecrement(uint8_t value) { adjustZero(value); setFlag(NF); clearFlag(HC, lowNibble(value + 1)); } -void LR35902::restart(uint8_t address) { +#pragma endregion Flag manipulation helpers + +#pragma region PC manipulation: call/ret/jp/jr + +void EightBit::LR35902::restart(uint8_t address) { pushWord(pc); - pc.word = address; + pc.low = address; + pc.high = 0; } -void LR35902::jrConditional(int conditional) { +void EightBit::LR35902::jrConditional(int conditional) { auto offset = (int8_t)fetchByte(); if (conditional) { pc.word += offset; @@ -71,7 +83,7 @@ void LR35902::jrConditional(int conditional) { } } -void LR35902::jrConditionalFlag(int flag) { +void EightBit::LR35902::jrConditionalFlag(int flag) { switch (flag) { case 0: // NZ jrConditional(!(F() & ZF)); @@ -94,7 +106,7 @@ void LR35902::jrConditionalFlag(int flag) { } } -void LR35902::jumpConditional(int conditional) { +void EightBit::LR35902::jumpConditional(int conditional) { auto address = fetchWord(); if (conditional) { pc = address; @@ -102,7 +114,7 @@ void LR35902::jumpConditional(int conditional) { } } -void LR35902::jumpConditionalFlag(int flag) { +void EightBit::LR35902::jumpConditionalFlag(int flag) { switch (flag) { case 0: // NZ jumpConditional(!(F() & ZF)); @@ -138,23 +150,23 @@ void LR35902::jumpConditionalFlag(int flag) { } } -void LR35902::ret() { +void EightBit::LR35902::ret() { popWord(pc); } -void LR35902::reti() { +void EightBit::LR35902::reti() { ret(); ei(); } -void LR35902::returnConditional(int condition) { +void EightBit::LR35902::returnConditional(int condition) { if (condition) { ret(); cycles += 3; } } -void LR35902::returnConditionalFlag(int flag) { +void EightBit::LR35902::returnConditionalFlag(int flag) { switch (flag) { case 0: // NZ returnConditional(!(F() & ZF)); @@ -199,19 +211,19 @@ void LR35902::returnConditionalFlag(int flag) { } } -void LR35902::call(uint16_t address) { +void EightBit::LR35902::call(uint16_t address) { pushWord(pc); pc.word = address; } -void LR35902::callConditional(uint16_t address, int condition) { +void EightBit::LR35902::callConditional(uint16_t address, int condition) { if (condition) { call(address); cycles += 3; } } -void LR35902::callConditionalFlag(uint16_t address, int flag) { +void EightBit::LR35902::callConditionalFlag(uint16_t address, int flag) { switch (flag) { case 0: // NZ callConditional(address, !(F() & ZF)); @@ -234,18 +246,22 @@ void LR35902::callConditionalFlag(uint16_t address, int flag) { } } -uint16_t LR35902::sbc(uint16_t value) { +#pragma endregion PC manipulation: call/ret/jp/jr + +#pragma region 16-bit arithmetic + +uint16_t EightBit::LR35902::sbc(uint16_t value) { auto hl = RP(HL_IDX); auto high = hl.high; - auto highValue = EightBit::Memory::highByte(value); + auto highValue = Memory::highByte(value); auto applyCarry = F() & CF; uint32_t result = (int)hl.word - (int)value; if (applyCarry) --result; - auto highResult = EightBit::Memory::highByte(result); + auto highResult = Memory::highByte(result); adjustZero(result); adjustHalfCarrySub(high, highValue, highResult); @@ -256,18 +272,18 @@ uint16_t LR35902::sbc(uint16_t value) { return result; } -uint16_t LR35902::adc(uint16_t value) { +uint16_t EightBit::LR35902::adc(uint16_t value) { auto hl = RP(HL_IDX); auto high = hl.high; - auto highValue = EightBit::Memory::highByte(value); + auto highValue = Memory::highByte(value); auto applyCarry = F() & CF; uint32_t result = (int)hl.word + (int)value; if (applyCarry) ++result; - auto highResult = EightBit::Memory::highByte(result); + auto highResult = Memory::highByte(result); adjustZero(result); adjustHalfCarryAdd(high, highValue, highResult); @@ -278,16 +294,16 @@ uint16_t LR35902::adc(uint16_t value) { return result; } -uint16_t LR35902::add(uint16_t value) { +uint16_t EightBit::LR35902::add(uint16_t value) { auto hl = RP(HL_IDX); auto high = hl.high; - auto highValue = EightBit::Memory::highByte(value); + auto highValue = Memory::highByte(value); uint32_t result = (int)hl.word + (int)value; - auto highResult = EightBit::Memory::highByte(result); + auto highResult = Memory::highByte(result); clearFlag(NF); setFlag(CF, result & Bit16); @@ -296,7 +312,11 @@ uint16_t LR35902::add(uint16_t value) { return result; } -void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) { +#pragma endregion 16-bit arithmetic + +#pragma region ALU + +void EightBit::LR35902::sub(uint8_t& operand, uint8_t value, bool carry) { auto before = operand; @@ -304,7 +324,7 @@ void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) { if (carry && (F() & CF)) --result; - operand = EightBit::Memory::lowByte(result); + operand = Memory::lowByte(result); adjustZero(operand); adjustHalfCarrySub(before, value, result); @@ -312,15 +332,15 @@ void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) { setFlag(CF, result & Bit8); } -void LR35902::sbc(uint8_t& operand, uint8_t value) { +void EightBit::LR35902::sbc(uint8_t& operand, uint8_t value) { sub(operand, value, true); } -void LR35902::sub(uint8_t& operand, uint8_t value) { +void EightBit::LR35902::sub(uint8_t& operand, uint8_t value) { sub(operand, value, false); } -void LR35902::add(uint8_t& operand, uint8_t value, bool carry) { +void EightBit::LR35902::add(uint8_t& operand, uint8_t value, bool carry) { auto before = operand; @@ -328,7 +348,7 @@ void LR35902::add(uint8_t& operand, uint8_t value, bool carry) { if (carry && (F() & CF)) ++result; - operand = EightBit::Memory::lowByte(result); + operand = Memory::lowByte(result); adjustZero(operand); adjustHalfCarryAdd(before, value, result); @@ -336,47 +356,49 @@ void LR35902::add(uint8_t& operand, uint8_t value, bool carry) { setFlag(CF, result & Bit8); } -void LR35902::adc(uint8_t& operand, uint8_t value) { +void EightBit::LR35902::adc(uint8_t& operand, uint8_t value) { add(operand, value, true); } -void LR35902::add(uint8_t& operand, uint8_t value) { +void EightBit::LR35902::add(uint8_t& operand, uint8_t value) { add(operand, value, false); } // -void LR35902::andr(uint8_t& operand, uint8_t value) { +void EightBit::LR35902::andr(uint8_t& operand, uint8_t value) { setFlag(HC); clearFlag(CF | NF); operand &= value; adjustZero(operand); } -void LR35902::anda(uint8_t value) { +void EightBit::LR35902::anda(uint8_t value) { andr(A(), value); } -void LR35902::xora(uint8_t value) { +void EightBit::LR35902::xora(uint8_t value) { clearFlag(HC | CF | NF); A() ^= value; adjustZero(A()); } -void LR35902::ora(uint8_t value) { +void EightBit::LR35902::ora(uint8_t value) { clearFlag(HC | CF | NF); A() |= value; adjustZero(A()); } -void LR35902::compare(uint8_t value) { +void EightBit::LR35902::compare(uint8_t value) { auto check = A(); sub(check, value); } -// +#pragma endregion ALU -void LR35902::rlc(uint8_t& operand) { +#pragma region Shift and rotate + +void EightBit::LR35902::rlc(uint8_t& operand) { auto carry = operand & Bit7; operand <<= 1; setFlag(CF, carry); @@ -385,7 +407,7 @@ void LR35902::rlc(uint8_t& operand) { adjustZero(operand); } -void LR35902::rrc(uint8_t& operand) { +void EightBit::LR35902::rrc(uint8_t& operand) { auto carry = operand & Bit0; operand >>= 1; carry ? operand |= Bit7 : operand &= ~Bit7; @@ -394,7 +416,7 @@ void LR35902::rrc(uint8_t& operand) { adjustZero(operand); } -void LR35902::rl(uint8_t& operand) { +void EightBit::LR35902::rl(uint8_t& operand) { auto oldCarry = F() & CF; auto newCarry = operand & Bit7; operand <<= 1; @@ -404,7 +426,7 @@ void LR35902::rl(uint8_t& operand) { adjustZero(operand); } -void LR35902::rr(uint8_t& operand) { +void EightBit::LR35902::rr(uint8_t& operand) { auto oldCarry = F() & CF; auto newCarry = operand & Bit0; operand >>= 1; @@ -416,7 +438,7 @@ void LR35902::rr(uint8_t& operand) { // -void LR35902::sla(uint8_t& operand) { +void EightBit::LR35902::sla(uint8_t& operand) { auto newCarry = operand & Bit7; operand <<= 1; setFlag(CF, newCarry); @@ -424,7 +446,7 @@ void LR35902::sla(uint8_t& operand) { adjustZero(operand); } -void LR35902::sra(uint8_t& operand) { +void EightBit::LR35902::sra(uint8_t& operand) { auto new7 = operand & Bit7; auto newCarry = operand & Bit0; operand >>= 1; @@ -434,7 +456,7 @@ void LR35902::sra(uint8_t& operand) { adjustZero(operand); } -void LR35902::srl(uint8_t& operand) { +void EightBit::LR35902::srl(uint8_t& operand) { auto newCarry = operand & Bit0; operand >>= 1; operand &= ~Bit7; // clear bit 7 @@ -445,44 +467,48 @@ void LR35902::srl(uint8_t& operand) { // -void LR35902::rlca() { +void EightBit::LR35902::rlca() { rlc(A()); } -void LR35902::rrca() { +void EightBit::LR35902::rrca() { rrc(A()); } -void LR35902::rla() { +void EightBit::LR35902::rla() { rl(A()); } -void LR35902::rra() { +void EightBit::LR35902::rra() { rr(A()); } -// +#pragma endregion Shift and rotate -void LR35902::bit(int n, uint8_t& operand) { +#pragma region BIT/SET/RES + +void EightBit::LR35902::bit(int n, uint8_t& operand) { auto carry = F() & CF; uint8_t discarded = operand; andr(discarded, 1 << n); setFlag(CF, carry); } -void LR35902::res(int n, uint8_t& operand) { +void EightBit::LR35902::res(int n, uint8_t& operand) { auto bit = 1 << n; operand &= ~bit; } -void LR35902::set(int n, uint8_t& operand) { +void EightBit::LR35902::set(int n, uint8_t& operand) { auto bit = 1 << n; operand |= bit; } -// +#pragma endregion BIT/SET/RES -void LR35902::daa() { +#pragma region Miscellaneous instructions + +void EightBit::LR35902::daa() { uint8_t a = A(); @@ -508,23 +534,23 @@ void LR35902::daa() { A() = a; } -void LR35902::cpl() { +void EightBit::LR35902::cpl() { A() = ~A(); setFlag(HC | NF); } -void LR35902::scf() { +void EightBit::LR35902::scf() { setFlag(CF); clearFlag(HC | NF); } -void LR35902::ccf() { +void EightBit::LR35902::ccf() { auto carry = F() & CF; clearFlag(CF, carry); clearFlag(NF | HC); } -void LR35902::swap(uint8_t& operand) { +void EightBit::LR35902::swap(uint8_t& operand) { auto low = lowNibble(operand); auto high = highNibble(operand); operand = promoteNibble(low) | demoteNibble(high); @@ -532,13 +558,16 @@ void LR35902::swap(uint8_t& operand) { clearFlag(NF | HC | CF); } -int LR35902::step() { +#pragma endregion Miscellaneous instructions + +int EightBit::LR35902::step() { ExecutingInstruction.fire(*this); m_prefixCB = false; + cycles = 0; return fetchExecute(); } -int LR35902::execute(uint8_t opcode) { +int EightBit::LR35902::execute(uint8_t opcode) { auto x = (opcode & 0b11000000) >> 6; auto y = (opcode & 0b111000) >> 3; @@ -547,8 +576,6 @@ int LR35902::execute(uint8_t opcode) { auto p = (y & 0b110) >> 1; auto q = (y & 1); - cycles = 0; - if (m_prefixCB) executeCB(x, y, z, p, q); else @@ -560,7 +587,7 @@ int LR35902::execute(uint8_t opcode) { return cycles * 4; } -void LR35902::executeCB(int x, int y, int z, int p, int q) { +void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) { switch (x) { case 0: // rot[y] r[z] switch (y) { @@ -615,7 +642,7 @@ void LR35902::executeCB(int x, int y, int z, int p, int q) { } } -void LR35902::executeOther(int x, int y, int z, int p, int q) { +void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) { switch (x) { case 0: switch (z) { diff --git a/LR35902/src/Profiler.cpp b/LR35902/src/Profiler.cpp index 10c7cd8..8eb4383 100644 --- a/LR35902/src/Profiler.cpp +++ b/LR35902/src/Profiler.cpp @@ -2,13 +2,13 @@ #include "Profiler.h" #include "LR35902.h" -Profiler::Profiler(LR35902& cpu) +EightBit::Profiler::Profiler(LR35902& cpu) : m_cpu(cpu) { std::fill(m_instructions.begin(), m_instructions.end(), 0); std::fill(m_addresses.begin(), m_addresses.end(), 0); } -void Profiler::add(uint16_t address, uint8_t instruction) { +void EightBit::Profiler::add(uint16_t address, uint8_t instruction) { m_instructions[instruction]++; @@ -19,12 +19,12 @@ void Profiler::add(uint16_t address, uint8_t instruction) { m_addresses[address]++; } -void Profiler::dump() const { +void EightBit::Profiler::dump() const { dumpInstructionProfiles(); dumpAddressProfiles(); } -void Profiler::dumpInstructionProfiles() const { +void EightBit::Profiler::dumpInstructionProfiles() const { std::cout << "** instructions" << std::endl; for (int i = 0; i < 0x100; ++i) { auto count = m_instructions[i]; @@ -33,7 +33,7 @@ void Profiler::dumpInstructionProfiles() const { } } -void Profiler::dumpAddressProfiles() const { +void EightBit::Profiler::dumpAddressProfiles() const { std::cout << "** addresses" << std::endl; for (int i = 0; i < 0x10000; ++i) { auto count = m_addresses[i];