From f3fe475d44730b7ca825c0386dba3d4fe79bb284 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Fri, 9 Jun 2017 10:23:51 +0100 Subject: [PATCH] Implement enough changes to build LR35902 --- LR35902/inc/Bus.h | 106 ++++++++++++++++++ LR35902/inc/LR35902.h | 36 +++--- LR35902/inc/StatusFlags.h | 83 ++++++++++++++ LR35902/src/Bus.cpp | 32 ++++++ LR35902/src/Disassembler.cpp | 16 +-- LR35902/src/LR35902.cpp | 82 +++++++------- LR35902/src/LR35902.vcxproj | 166 ++++++++++++++++++++++++++++ LR35902/src/LR35902.vcxproj.filters | 57 ++++++++++ LR35902/src/stdafx.cpp | 1 + LR35902/src/stdafx.h | 37 +++++++ inc/Memory.h | 15 ++- 11 files changed, 567 insertions(+), 64 deletions(-) create mode 100644 LR35902/inc/Bus.h create mode 100644 LR35902/inc/StatusFlags.h create mode 100644 LR35902/src/Bus.cpp create mode 100644 LR35902/src/LR35902.vcxproj create mode 100644 LR35902/src/LR35902.vcxproj.filters create mode 100644 LR35902/src/stdafx.cpp create mode 100644 LR35902/src/stdafx.h diff --git a/LR35902/inc/Bus.h b/LR35902/inc/Bus.h new file mode 100644 index 0000000..8eba042 --- /dev/null +++ b/LR35902/inc/Bus.h @@ -0,0 +1,106 @@ +#pragma once + +#include "Memory.h" + +class Bus : public EightBit::Memory { +public: + + 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; +}; diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index f7e7490..6cd919b 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -3,8 +3,9 @@ #include #include "Processor.h" +#include "Bus.h" -class LR35902 : public Processor { +class LR35902 : public EightBit::Processor { public: enum StatusBits { ZF = Bit7, @@ -15,7 +16,7 @@ public: LR35902(Bus& memory); - Signal ExecutingInstruction; + EightBit::Signal ExecutingInstruction; void stop() { m_stopped = true; } void start() { m_stopped = false; } @@ -33,7 +34,7 @@ public: // Mutable access to processor!! - register16_t& AF() { + EightBit::register16_t& AF() { m_accumulatorFlag.low &= 0xf0; return m_accumulatorFlag; } @@ -41,21 +42,21 @@ public: uint8_t& A() { return AF().high; } uint8_t& F() { return AF().low; } - register16_t& BC() { + EightBit::register16_t& BC() { return m_registers[BC_IDX]; } uint8_t& B() { return BC().high; } uint8_t& C() { return BC().low; } - register16_t& DE() { + EightBit::register16_t& DE() { return m_registers[DE_IDX]; } uint8_t& D() { return DE().high; } uint8_t& E() { return DE().low; } - register16_t& HL() { + EightBit::register16_t& HL() { return m_registers[HL_IDX]; } @@ -68,8 +69,8 @@ public: private: enum { BC_IDX, DE_IDX, HL_IDX }; - std::array m_registers; - register16_t m_accumulatorFlag; + std::array m_registers; + EightBit::register16_t m_accumulatorFlag; bool m_ime; @@ -80,6 +81,12 @@ private: 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()); } @@ -110,28 +117,29 @@ private: case 5: return L(); case 6: - return m_memory.reference(HL().word); + m_memory.ADDRESS() = HL(); + return m_memory.reference(); case 7: return A(); } throw std::logic_error("Unhandled registry mechanism"); } - uint16_t& RP(int rp) { + EightBit::register16_t& RP(int rp) { switch (rp) { case 3: return sp; default: - return m_registers[rp].word; + return m_registers[rp]; } } - uint16_t& RP2(int rp) { + EightBit::register16_t& RP2(int rp) { switch (rp) { case 3: - return AF().word; + return AF(); default: - return m_registers[rp].word; + return m_registers[rp]; } } diff --git a/LR35902/inc/StatusFlags.h b/LR35902/inc/StatusFlags.h new file mode 100644 index 0000000..8821511 --- /dev/null +++ b/LR35902/inc/StatusFlags.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +struct StatusFlags { + + bool SF; + bool ZF; + bool YF; + bool HF; + bool XF; + bool PF; + bool NF; + bool CF; + + enum StatusBits { + Sign = 0x80, // SF + Zero = 0x40, // ZF + YFlag = 0x20, // YF + HalfCarry = 0x10, // HC + XFlag= 0x8, // XF + Parity = 0x4, // PF + Overflow = 0x4, // PF + Subtract = 0x2, // NF + Carry = 0x1, // CF + }; + + StatusFlags(uint8_t value = 0) { + SF = (value & StatusBits::Sign) != 0; + ZF = (value & StatusBits::Zero) != 0; + YF = (value & StatusBits::YFlag) != 0; + HF = (value & StatusBits::HalfCarry) != 0; + XF = (value & StatusBits::XFlag) != 0; + PF = (value & StatusBits::Parity) != 0; // parity/overflow + NF = (value & StatusBits::Subtract) != 0; + CF = (value & StatusBits::Carry) != 0; + } + + operator uint8_t() const { + + uint8_t flags = 0; + + if (SF) + flags |= StatusBits::Sign; + + if (ZF) + flags |= StatusBits::Zero; + + if (YF) + flags |= StatusBits::YFlag; + + if (HF) + flags |= StatusBits::HalfCarry; + + if (XF) + flags |= StatusBits::XFlag; + + if (PF) + flags |= StatusBits::Parity; + + if (NF) + flags |= StatusBits::Subtract; + + if (CF) + flags |= StatusBits::Carry; + + return flags; + } + + operator std::string() const { + std::string returned; + returned += SF ? "S" : "-"; + returned += ZF ? "Z" : "-"; + returned += YF ? "Y" : "-"; + returned += HF ? "H" : "-"; + returned += XF ? "X" : "-"; + returned += PF ? "P" : "-"; + returned += NF ? "N" : "-"; + returned += CF ? "C" : "-"; + return returned; + } +}; diff --git a/LR35902/src/Bus.cpp b/LR35902/src/Bus.cpp new file mode 100644 index 0000000..18960c1 --- /dev/null +++ b/LR35902/src/Bus.cpp @@ -0,0 +1,32 @@ +#include "stdafx.h" +#include "Bus.h" + +Bus::Bus() +: Memory(0xffff) { +} + +void Bus::reset() { + REG(NR52) = 0xf1; + REG(LCDC) = 0x91; +} + +void 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() { + auto effective = effectiveAddress(ADDRESS().word); + if (isBootRom(effective)) + return placeDATA(m_boot[effective]); + return Memory::reference(); +} + +uint8_t Bus::peek(uint16_t address) const { + auto effective = effectiveAddress(address); + if (isBootRom(effective)) + return m_boot[effective]; + return m_bus[effective]; +} \ No newline at end of file diff --git a/LR35902/src/Disassembler.cpp b/LR35902/src/Disassembler.cpp index 85c96f4..9a96dca 100644 --- a/LR35902/src/Disassembler.cpp +++ b/LR35902/src/Disassembler.cpp @@ -34,9 +34,9 @@ std::string Disassembler::state(LR35902& cpu) { std::ostringstream output; output - << "PC=" << hex(pc) + << "PC=" << hex(pc.word) << " " - << "SP=" << hex(sp) + << "SP=" << hex(sp.word) << " " << "A=" << hex(a) << " " << "F=" << flags(f) << " " << "B=" << hex(b) << " " << "C=" << hex(c) << " " << "D=" << hex(d) << " " << "E=" << hex(e) @@ -142,7 +142,7 @@ std::string Disassembler::alu(int which) { std::string Disassembler::disassemble(LR35902& cpu) { m_prefixCB = false; std::ostringstream output; - disassemble(output, cpu, cpu.getProgramCounter()); + disassemble(output, cpu, cpu.getProgramCounter().word); return output.str(); } @@ -162,7 +162,7 @@ void Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_ auto q = (y & 1); auto immediate = memory.peek(pc + 1); - auto absolute = cpu.getWord(pc + 1); + auto absolute = memory.peekWord(pc + 1); auto displacement = (int8_t)immediate; auto relative = pc + displacement + 2; auto indexedImmediate = memory.peek(pc + 1); @@ -517,10 +517,10 @@ std::string Disassembler::flags(uint8_t value) { << flag(value, LR35902::NF, "N") << flag(value, LR35902::HC, "H") << flag(value, LR35902::CF, "C") - << flag(value, Processor::Bit3, "+") - << flag(value, Processor::Bit2, "+") - << flag(value, Processor::Bit1, "+") - << flag(value, Processor::Bit0, "+"); + << flag(value, EightBit::Processor::Bit3, "+") + << flag(value, EightBit::Processor::Bit2, "+") + << flag(value, EightBit::Processor::Bit1, "+") + << flag(value, EightBit::Processor::Bit0, "+"); return output.str(); } diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index b02bc0a..0674cf3 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -12,7 +12,7 @@ LR35902::LR35902(Bus& memory) void LR35902::reset() { Processor::reset(); - setStackPointer(0xfffe); + sp.word = 0xfffe; di(); } @@ -60,13 +60,13 @@ void LR35902::postDecrement(uint8_t value) { void LR35902::restart(uint8_t address) { pushWord(pc); - pc = address; + pc.word = address; } void LR35902::jrConditional(int conditional) { auto offset = (int8_t)fetchByte(); if (conditional) { - pc += offset; + pc.word += offset; cycles++; } } @@ -121,22 +121,25 @@ void LR35902::jumpConditionalFlag(int flag) { cycles--; // Giving 8 cycles break; case 5: // GB: LD (nn),A - m_memory.set(fetchWord(), A()); + m_memory.ADDRESS() = fetchWord(); + m_memory.reference() = A(); cycles++; // Giving 16 cycles break; case 6: // GB: LD A,(FF00 + C) - A() = m_memory.get(0xff00 + C()); + m_memory.ADDRESS().word = 0xff00 + C(); + A() = m_memory.reference(); cycles--; // 8 cycles break; case 7: // GB: LD A,(nn) - A() = m_memory.get(fetchWord()); + m_memory.ADDRESS() = fetchWord(); + A() = m_memory.reference(); cycles++; // Giving 16 cycles break; } } void LR35902::ret() { - pc = popWord(); + popWord(pc); } void LR35902::reti() { @@ -172,10 +175,10 @@ void LR35902::returnConditionalFlag(int flag) { case 5: { // GB: ADD SP,dd auto before = sp; auto value = fetchByte(); - sp += (int8_t)value; + sp.word += (int8_t)value; clearFlag(ZF | NF); - setFlag(CF, sp & Bit16); - adjustHalfCarryAdd(Memory::highByte(before), value, Memory::highByte(sp)); + setFlag(CF, sp.word & Bit16); + adjustHalfCarryAdd(before.high, value, sp.high); } cycles += 2; // 16 cycles break; @@ -186,11 +189,10 @@ void LR35902::returnConditionalFlag(int flag) { case 7: { // GB: LD HL,SP + dd auto before = sp; auto value = fetchByte(); - uint16_t result = before + (int8_t)value; - HL().word = result; + HL().word = before.word + (int8_t)value; clearFlag(ZF | NF); - setFlag(CF, result & Bit16); - adjustHalfCarryAdd(Memory::highByte(before), value, Memory::highByte(result)); + setFlag(CF, HL().word & Bit16); + adjustHalfCarryAdd(before.high, value, HL().high); } cycles++; // 12 cycles break; @@ -198,16 +200,14 @@ void LR35902::returnConditionalFlag(int flag) { } void LR35902::call(uint16_t address) { - pushWord(pc + 2); - pc = address; + pushWord(pc); + pc.word = address; } void LR35902::callConditional(uint16_t address, int condition) { if (condition) { call(address); cycles += 3; - } else { - pc += 2; } } @@ -238,14 +238,14 @@ uint16_t LR35902::sbc(uint16_t value) { auto hl = RP(HL_IDX); - auto high = Memory::highByte(hl); - auto highValue = Memory::highByte(value); + auto high = hl.high; + auto highValue = EightBit::Memory::highByte(value); auto applyCarry = F() & CF; - uint32_t result = (int)hl - (int)value; + uint32_t result = (int)hl.word - (int)value; if (applyCarry) --result; - auto highResult = Memory::highByte(result); + auto highResult = EightBit::Memory::highByte(result); adjustZero(result); adjustHalfCarrySub(high, highValue, highResult); @@ -260,14 +260,14 @@ uint16_t LR35902::adc(uint16_t value) { auto hl = RP(HL_IDX); - auto high = Memory::highByte(hl); - auto highValue = Memory::highByte(value); + auto high = hl.high; + auto highValue = EightBit::Memory::highByte(value); auto applyCarry = F() & CF; - uint32_t result = (int)hl + (int)value; + uint32_t result = (int)hl.word + (int)value; if (applyCarry) ++result; - auto highResult = Memory::highByte(result); + auto highResult = EightBit::Memory::highByte(result); adjustZero(result); adjustHalfCarryAdd(high, highValue, highResult); @@ -282,12 +282,12 @@ uint16_t LR35902::add(uint16_t value) { auto hl = RP(HL_IDX); - auto high = Memory::highByte(hl); - auto highValue = Memory::highByte(value); + auto high = hl.high; + auto highValue = EightBit::Memory::highByte(value); - uint32_t result = (int)hl + (int)value; + uint32_t result = (int)hl.word + (int)value; - auto highResult = Memory::highByte(result); + auto highResult = EightBit::Memory::highByte(result); clearFlag(NF); setFlag(CF, result & Bit16); @@ -304,7 +304,7 @@ void LR35902::sub(uint8_t& operand, uint8_t value, bool carry) { if (carry && (F() & CF)) --result; - operand = Memory::lowByte(result); + operand = EightBit::Memory::lowByte(result); adjustZero(operand); adjustHalfCarrySub(before, value, result); @@ -328,7 +328,7 @@ void LR35902::add(uint8_t& operand, uint8_t value, bool carry) { if (carry && (F() & CF)) ++result; - operand = Memory::lowByte(result); + operand = EightBit::Memory::lowByte(result); adjustZero(operand); adjustHalfCarryAdd(before, value, result); @@ -625,7 +625,7 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { cycles++; break; case 1: // GB: LD (nn),SP - m_memory.setWord(fetchWord(), sp); + m_memory.setWord(fetchWord().word, sp); cycles += 5; break; case 2: // GB: STOP @@ -649,7 +649,7 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { cycles += 3; break; case 1: // ADD HL,rp - RP(HL_IDX) = add(RP(p)); + RP(HL_IDX).word = add(RP(p).word); cycles += 2; break; } @@ -701,10 +701,10 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { case 3: // 16-bit INC/DEC switch (q) { case 0: // INC rp - ++RP(p); + ++RP(p).word; break; case 1: // DEC rp - --RP(p); + --RP(p).word; break; } cycles += 2; @@ -806,7 +806,7 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { case 1: // POP & various ops switch (q) { case 0: // POP rp2[p] - RP2(p) = popWord(); + popWord(RP2(p)); cycles += 3; break; case 1: @@ -820,11 +820,11 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { cycles += 4; break; case 2: // JP HL - pc = HL().word; + pc = HL(); cycles += 1; break; case 3: // LD SP,HL - sp = HL().word; + sp = HL(); cycles += 2; break; } @@ -855,7 +855,7 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { } break; case 4: // Conditional call: CALL cc[y], nn - callConditionalFlag(getWord(pc), y); + callConditionalFlag(fetchWord().word, y); cycles += 3; break; case 5: // PUSH & various ops @@ -867,7 +867,7 @@ void LR35902::executeOther(int x, int y, int z, int p, int q) { case 1: switch (p) { case 0: // CALL nn - callConditional(getWord(pc), true); + callConditional(fetchWord().word, true); cycles += 3; break; } diff --git a/LR35902/src/LR35902.vcxproj b/LR35902/src/LR35902.vcxproj new file mode 100644 index 0000000..aa9fd0b --- /dev/null +++ b/LR35902/src/LR35902.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {7730ECF5-8206-4ECB-BA6B-6B5CFE50CFB2} + Win32Proj + LR35902 + 8.1 + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\inc;..\..\inc;C:\local\boost_1_64_0;C:\local\SDL2-2.0.5\include;$(IncludePath) + + + ..\inc;..\..\inc;C:\local\boost_1_64_0;C:\local\SDL2-2.0.5\include;$(IncludePath) + + + ..\inc;..\..\inc;C:\local\boost_1_64_0;C:\local\SDL2-2.0.5\include;$(IncludePath) + + + ..\inc;..\..\inc;C:\local\boost_1_64_0;C:\local\SDL2-2.0.5\include;$(IncludePath) + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + + + + + Use + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/LR35902/src/LR35902.vcxproj.filters b/LR35902/src/LR35902.vcxproj.filters new file mode 100644 index 0000000..5400e33 --- /dev/null +++ b/LR35902/src/LR35902.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/LR35902/src/stdafx.cpp b/LR35902/src/stdafx.cpp new file mode 100644 index 0000000..1577c4e --- /dev/null +++ b/LR35902/src/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" \ No newline at end of file diff --git a/LR35902/src/stdafx.h b/LR35902/src/stdafx.h new file mode 100644 index 0000000..15b7810 --- /dev/null +++ b/LR35902/src/stdafx.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define HOST_LITTLE_ENDIAN +#endif + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +#define HOST_BIG_ENDIAN +#endif + +#ifdef _MSC_VER +#pragma comment(lib, "SDL2.lib") +#pragma comment(lib, "SDL2main.lib") +#endif diff --git a/inc/Memory.h b/inc/Memory.h index 840b5da..124d9a1 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -28,6 +28,15 @@ namespace EightBit { class Memory { public: + + static uint8_t highByte(uint16_t value) { + return value >> 8; + } + + static uint8_t lowByte(uint16_t value) { + return value & 0xff; + } + Memory(uint16_t addressMask); virtual register16_t& ADDRESS() { return m_address; } @@ -62,10 +71,14 @@ namespace EightBit { virtual void setWord(uint16_t address, register16_t value); virtual uint8_t& reference() { - uint16_t effective = ADDRESS().word & m_addressMask; + auto effective = effectiveAddress(ADDRESS().word); return m_locked[effective] ? placeDATA(m_bus[effective]) : referenceDATA(m_bus[effective]); } + virtual uint16_t effectiveAddress(uint16_t address) const { + return address & m_addressMask; + } + void clear(); void loadRom(const std::string& path, uint16_t offset); void loadRam(const std::string& path, uint16_t offset);