From 129286f1a76b0ed233689b0753a7eef3da9ef0d6 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Thu, 7 Sep 2017 01:15:28 +0100 Subject: [PATCH] Ensure LR35902 fuse tests run successfully to completion. Signed-off-by: Adrian.Conlon --- LR35902/fusetest_LR35902/FuseRegisterState.h | 2 +- LR35902/fusetest_LR35902/FuseTestRunner.cpp | 26 +- LR35902/fusetest_LR35902/FuseTestRunner.h | 20 +- LR35902/inc/AbstractColourPalette.h | 40 +- LR35902/inc/Bus.h | 233 ----------- LR35902/inc/CharacterDefinition.h | 40 +- LR35902/inc/Disassembler.h | 105 ++--- LR35902/inc/Display.h | 48 +-- LR35902/inc/GameBoyBus.h | 266 ++++++++++++ LR35902/inc/LR35902.h | 408 ++++++++++--------- LR35902/inc/Profiler.h | 30 +- LR35902/src/Disassembler.cpp | 50 +-- LR35902/src/Display.cpp | 8 +- LR35902/src/{Bus.cpp => GameBoyBus.cpp} | 62 ++- LR35902/src/LR35902.cpp | 90 ++-- LR35902/src/LR35902.vcxproj | 4 +- LR35902/src/LR35902.vcxproj.filters | 10 +- LR35902/src/Profiler.cpp | 10 +- 18 files changed, 748 insertions(+), 704 deletions(-) delete mode 100644 LR35902/inc/Bus.h create mode 100644 LR35902/inc/GameBoyBus.h rename LR35902/src/{Bus.cpp => GameBoyBus.cpp} (69%) diff --git a/LR35902/fusetest_LR35902/FuseRegisterState.h b/LR35902/fusetest_LR35902/FuseRegisterState.h index e6da15a..cb1a72e 100644 --- a/LR35902/fusetest_LR35902/FuseRegisterState.h +++ b/LR35902/fusetest_LR35902/FuseRegisterState.h @@ -4,7 +4,7 @@ #include #include -#include "Memory.h" +#include namespace Fuse { class RegisterState { diff --git a/LR35902/fusetest_LR35902/FuseTestRunner.cpp b/LR35902/fusetest_LR35902/FuseTestRunner.cpp index 11cf5f2..858ad7a 100644 --- a/LR35902/fusetest_LR35902/FuseTestRunner.cpp +++ b/LR35902/fusetest_LR35902/FuseTestRunner.cpp @@ -5,18 +5,18 @@ Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected) : m_test(test), m_expected(expected), - m_cpu(m_bus), + m_ram(0x10000), + m_cpu(*this), m_failed(false), m_unimplemented(false) { - m_bus.clear(); m_cpu.initialise(); } // void Fuse::TestRunner::initialise() { - m_bus.disableBootRom(); - m_bus.disableGameRom(); + disableBootRom(); + disableGameRom(); initialiseRegisters(); initialiseMemory(); m_cpu.powerOn(); @@ -41,7 +41,7 @@ void Fuse::TestRunner::initialiseMemory() { auto address = memoryDatum.address; auto bytes = memoryDatum.bytes; for (int i = 0; i < bytes.size(); ++i) - m_bus.poke(address + i, bytes[i]); + poke(address + i, bytes[i]); } } @@ -55,9 +55,9 @@ void Fuse::TestRunner::check() { void Fuse::TestRunner::dumpDifference(const std::string& description, uint8_t actual, uint8_t expected) const { std::cerr << "**** " << description << ", Expected: " - << EightBit::Disassembler::hex(expected) + << EightBit::GameBoy::Disassembler::hex(expected) << ", Got: " - << EightBit::Disassembler::hex(actual) + << EightBit::GameBoy::Disassembler::hex(actual) << std::endl; } @@ -111,9 +111,9 @@ void Fuse::TestRunner::checkregisters() { if (expectedF != gotF) { std::cerr << "**** F, Expected: " - << EightBit::Disassembler::flags(expectedF) + << EightBit::GameBoy::Disassembler::flags(expectedF) << ", Got: " - << EightBit::Disassembler::flags(gotF) + << EightBit::GameBoy::Disassembler::flags(gotF) << std::endl; } } @@ -159,7 +159,7 @@ void Fuse::TestRunner::checkMemory() { for (int i = 0; i < bytes.size(); ++i) { auto expected = bytes[i]; uint16_t address = memoryDatum.address + i; - auto actual = m_cpu.getMemory().peek(address); + auto actual = m_cpu.BUS().peek(address); if (expected != actual) { m_failed = true; if (first) { @@ -168,9 +168,9 @@ void Fuse::TestRunner::checkMemory() { } std::cerr << "**** Difference: " - << "Address: " << EightBit::Disassembler::hex(address) - << " Expected: " << EightBit::Disassembler::hex(expected) - << " Actual: " << EightBit::Disassembler::hex(actual) + << "Address: " << EightBit::GameBoy::Disassembler::hex(address) + << " Expected: " << EightBit::GameBoy::Disassembler::hex(expected) + << " Actual: " << EightBit::GameBoy::Disassembler::hex(actual) << std::endl; } } diff --git a/LR35902/fusetest_LR35902/FuseTestRunner.h b/LR35902/fusetest_LR35902/FuseTestRunner.h index a330ebc..ab21be3 100644 --- a/LR35902/fusetest_LR35902/FuseTestRunner.h +++ b/LR35902/fusetest_LR35902/FuseTestRunner.h @@ -1,13 +1,17 @@ #pragma once +#include +#include + #include "FuseTest.h" #include "FuseExpectedTestResult.h" -#include "Bus.h" -#include "LR35902.h" +#include +#include +#include namespace Fuse { - class TestRunner { + class TestRunner : public EightBit::GameBoy::Bus { private: const Test& m_test; const ExpectedTestResult& m_expected; @@ -15,8 +19,8 @@ namespace Fuse { bool m_failed; bool m_unimplemented; - EightBit::Bus m_bus; - EightBit::LR35902 m_cpu; + EightBit::Ram m_ram; + EightBit::GameBoy::LR35902 m_cpu; void initialise(); void initialiseRegisters(); @@ -32,6 +36,12 @@ namespace Fuse { const std::string& lowDescription, EightBit::register16_t actual, EightBit::register16_t expected) const; + protected: + virtual uint8_t& reference(uint16_t address, bool& rom) { + rom = false; + return m_ram.reference(address); + } + public: TestRunner(const Test& test, const ExpectedTestResult& expected); diff --git a/LR35902/inc/AbstractColourPalette.h b/LR35902/inc/AbstractColourPalette.h index d47ce32..f102331 100644 --- a/LR35902/inc/AbstractColourPalette.h +++ b/LR35902/inc/AbstractColourPalette.h @@ -4,24 +4,26 @@ #include namespace EightBit { - class AbstractColourPalette { - public: - enum { - Off, - Light, - Medium, - Dark + namespace GameBoy { + class AbstractColourPalette { + public: + enum { + Off, + Light, + Medium, + Dark + }; + + AbstractColourPalette::AbstractColourPalette() + : m_colours(4) { + } + + uint32_t getColour(size_t index) const { + return m_colours[index]; + } + + protected: + std::vector m_colours; }; - - AbstractColourPalette::AbstractColourPalette() - : m_colours(4) { - } - - uint32_t getColour(size_t index) const { - return m_colours[index]; - } - - protected: - std::vector m_colours; - }; + } } \ No newline at end of file diff --git a/LR35902/inc/Bus.h b/LR35902/inc/Bus.h deleted file mode 100644 index 64fce5d..0000000 --- a/LR35902/inc/Bus.h +++ /dev/null @@ -1,233 +0,0 @@ -#pragma once - -#include -#include - -namespace EightBit { - class Bus : public Memory { - public: - - enum CartridgeType { - ROM = 0, - ROM_MBC1 = 1, - ROM_MBC1_RAM = 2, - ROM_MBC1_RAM_BATTERY = 3, - }; - - enum { - TotalLineCount = 154, - RomPageSize = 0x4000 - }; - - 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, - }; - - // IF and IE flags - enum Interrupts { - VerticalBlank = Processor::Bit0, // VBLANK - DisplayControlStatus = Processor::Bit1, // LCDC Status - TimerOverflow = Processor::Bit2, // Timer Overflow - SerialTransfer = Processor::Bit3, // Serial Transfer - Keypad = Processor::Bit3 // Hi-Lo of P10-P13 - }; - - enum LcdcControl { - DisplayBackground = Processor::Bit0, - ObjectEnable = Processor::Bit1, - ObjectBlockCompositionSelection = Processor::Bit2, - BackgroundCodeAreaSelection = Processor::Bit3, - BackgroundCharacterDataSelection = Processor::Bit4, - WindowEnable = Processor::Bit5, - WindowCodeAreaSelection = Processor::Bit6, - LcdEnable = Processor::Bit7 - }; - - enum LcdStatusMode { - CpuAccessAllowed = 0b00, - VerticalBlankingPeriod = 0b01, - SearchingOamRam = 0b10, - TransferringDataToLcd = 0b11 - }; - - Bus(); - - void reset(); - - virtual void clear() override; - - void triggerInterrupt(int cause) { - pokeRegister(IF, peekRegister(IF) | cause); - } - - void writeRegister(int offset, uint8_t content) { - Memory::write(BASE + offset, content); - } - - void pokeRegister(int offset, uint8_t content) { - poke(BASE + offset, content); - } - - uint8_t readRegister(int offset) { - return Memory::read(BASE + offset); - } - - uint8_t peekRegister(int offset) { - return peek(BASE + offset); - } - - void checkTimers(int cycles); - - int timerClockTicks() { - switch (timerClock()) { - case 0b00: - return 1024; // 4.096 Khz - case 0b01: - return 16; // 262.144 Khz - case 0b10: - return 64; // 65.536 Khz - case 0b11: - return 256; // 16.384 Khz - default: - __assume(0); - } - throw std::domain_error("Invalid timer clock specification"); - } - - int timerClock() { - return peekRegister(TAC) & Processor::Mask2; - } - - bool timerEnabled() { - return !timerDisabled(); - } - - bool timerDisabled() { - return (peekRegister(TAC) & Processor::Bit2) == 0; - } - - void incrementDIV(int cycles) { - m_divCounter.word += cycles; - pokeRegister(DIV, m_divCounter.high); - } - - void incrementTIMA() { - uint16_t updated = peekRegister(TIMA) + 1; - if (updated & Processor::Bit8) { - triggerInterrupt(TimerOverflow); - updated = peekRegister(TMA); - } - pokeRegister(TIMA, updated & Processor::Mask8); - } - - void incrementLY() { - pokeRegister(LY, (peekRegister(LY) + 1) % TotalLineCount); - } - - void resetLY() { - pokeRegister(LY, 0); - } - - void disableBootRom() { m_disableBootRom = true; } - void enableBootRom() { m_disableBootRom = false; } - - void disableGameRom() { m_disableGameRom = true; } - void enableGameRom() { m_disableGameRom = false; } - - bool bootRomDisabled() const { return m_disableBootRom; } - bool bootRomEnabled() const { return !bootRomDisabled(); } - - bool gameRomDisabled() const { return m_disableGameRom; } - bool gameRomEnabled() const { return !gameRomDisabled(); } - - void loadBootRom(const std::string& path); - void loadGameRom(const std::string& path); - - private: - std::vector m_bootRom; - std::vector m_gameRom; - - bool m_disableBootRom; - bool m_disableGameRom; - - bool m_rom; - bool m_banked; - bool m_ram; - bool m_battery; - - bool m_higherRomBank; - bool m_ramBankSwitching; - - int m_romBank; - int m_ramBank; - - register16_t m_divCounter; - int m_timerCounter; - int m_timerRate; - - void Bus_WrittenByte(const AddressEventArgs& e); - - void checkTimer(int cycles); - - void validateCartridgeType(); - - virtual uint8_t& reference(uint16_t address, bool& rom); - }; -} \ No newline at end of file diff --git a/LR35902/inc/CharacterDefinition.h b/LR35902/inc/CharacterDefinition.h index 7cf77ae..7a2632c 100644 --- a/LR35902/inc/CharacterDefinition.h +++ b/LR35902/inc/CharacterDefinition.h @@ -6,36 +6,38 @@ #include "Bus.h" namespace EightBit { - class CharacterDefinition { - public: - CharacterDefinition() {} + namespace GameBoy { + class CharacterDefinition { + public: + CharacterDefinition() {} - CharacterDefinition(Bus& bus, uint16_t address) { + CharacterDefinition(Bus& bus, uint16_t address) { - for (auto row = 0; row < 8; ++row) { + for (auto row = 0; row < 8; ++row) { - auto planeAddress = address + row * 2; + auto planeAddress = address + row * 2; - auto planeLow = bus.peek(planeAddress); - auto planeHigh = bus.peek(planeAddress + 1); + auto planeLow = bus.peek(planeAddress); + auto planeHigh = bus.peek(planeAddress + 1); - for (int bit = 0; bit < 8; ++bit) { + for (int bit = 0; bit < 8; ++bit) { - auto mask = 1 << bit; + auto mask = 1 << bit; - auto bitLow = planeLow & mask ? 1 : 0; - auto bitHigh = planeHigh & mask ? 0b10 : 0; + auto bitLow = planeLow & mask ? 1 : 0; + auto bitHigh = planeHigh & mask ? 0b10 : 0; - auto colour = bitHigh | bitLow; + auto colour = bitHigh | bitLow; - m_definition[row * 8 + (7 - bit)] = colour; + m_definition[row * 8 + (7 - bit)] = colour; + } } } - } - const std::array& get() const { return m_definition; } + const std::array& get() const { return m_definition; } - private: - std::array m_definition; - }; + private: + std::array m_definition; + }; + } } \ No newline at end of file diff --git a/LR35902/inc/Disassembler.h b/LR35902/inc/Disassembler.h index a369cc2..3c6dfca 100644 --- a/LR35902/inc/Disassembler.h +++ b/LR35902/inc/Disassembler.h @@ -5,61 +5,64 @@ namespace EightBit { - class LR35902; + namespace GameBoy { - 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 io(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); + static std::string io(uint8_t value); - private: - enum IoRegister { - Abbreviated, // FF00 + dd - Absolute, // FFdd - Register, // C - Unused, // Unused! + static std::string invalid(uint8_t value); + + private: + enum IoRegister { + Abbreviated, // FF00 + dd + Absolute, // FFdd + Register, // C + Unused, // Unused! + }; + + mutable boost::format m_formatter; + bool m_prefixCB; + + void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc); + + 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 disassembleOther( + std::ostringstream& output, + LR35902& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + IoRegister& ioRegister, + 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); }; - - mutable boost::format m_formatter; - bool m_prefixCB; - - void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc); - - 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 disassembleOther( - std::ostringstream& output, - LR35902& cpu, - uint16_t pc, - std::string& specification, - int& dumpCount, - IoRegister& ioRegister, - 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/Display.h b/LR35902/inc/Display.h index dc93ba3..920e1f8 100644 --- a/LR35902/inc/Display.h +++ b/LR35902/inc/Display.h @@ -3,31 +3,33 @@ #include #include -#include "Bus.h" +#include "GameBoyBus.h" #include "AbstractColourPalette.h" namespace EightBit { - class Display { - public: - enum { - BufferWidth = 256, - BufferHeight = 256, - BufferCharacterWidth = BufferWidth / 8, - BufferCharacterHeight = BufferHeight / 8, - RasterWidth = 160, - RasterHeight = 144, + namespace GameBoy { + class Display { + public: + enum { + BufferWidth = 256, + BufferHeight = 256, + BufferCharacterWidth = BufferWidth / 8, + BufferCharacterHeight = BufferHeight / 8, + RasterWidth = 160, + RasterHeight = 144, + }; + + Display(const AbstractColourPalette* colours, Bus& bus); + + const std::vector& pixels() const; + + void initialise(); + void render(); + + private: + std::vector m_pixels; + Bus& m_bus; + const AbstractColourPalette* m_colours; }; - - Display(const AbstractColourPalette* colours, Bus& bus); - - const std::vector& pixels() const; - - void initialise(); - void render(); - - private: - std::vector m_pixels; - Bus& m_bus; - const AbstractColourPalette* m_colours; - }; + } } \ No newline at end of file diff --git a/LR35902/inc/GameBoyBus.h b/LR35902/inc/GameBoyBus.h new file mode 100644 index 0000000..79148ea --- /dev/null +++ b/LR35902/inc/GameBoyBus.h @@ -0,0 +1,266 @@ +#pragma once + +#include +#include +#include +#include + +namespace EightBit { + namespace GameBoy { + class Bus : public EightBit::Bus { + public: + + enum CartridgeType { + ROM = 0, + ROM_MBC1 = 1, + ROM_MBC1_RAM = 2, + ROM_MBC1_RAM_BATTERY = 3, + }; + + enum { + TotalLineCount = 154, + RomPageSize = 0x4000 + }; + + 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, + }; + + // IF and IE flags + enum Interrupts { + VerticalBlank = Processor::Bit0, // VBLANK + DisplayControlStatus = Processor::Bit1, // LCDC Status + TimerOverflow = Processor::Bit2, // Timer Overflow + SerialTransfer = Processor::Bit3, // Serial Transfer + Keypad = Processor::Bit3 // Hi-Lo of P10-P13 + }; + + enum LcdcControl { + DisplayBackground = Processor::Bit0, + ObjectEnable = Processor::Bit1, + ObjectBlockCompositionSelection = Processor::Bit2, + BackgroundCodeAreaSelection = Processor::Bit3, + BackgroundCharacterDataSelection = Processor::Bit4, + WindowEnable = Processor::Bit5, + WindowCodeAreaSelection = Processor::Bit6, + LcdEnable = Processor::Bit7 + }; + + enum LcdStatusMode { + CpuAccessAllowed = 0b00, + VerticalBlankingPeriod = 0b01, + SearchingOamRam = 0b10, + TransferringDataToLcd = 0b11 + }; + + Bus(); + + void reset(); + + void triggerInterrupt(int cause) { + pokeRegister(IF, peekRegister(IF) | cause); + } + + void writeRegister(int offset, uint8_t content) { + write(BASE + offset, content); + } + + void pokeRegister(int offset, uint8_t content) { + poke(BASE + offset, content); + } + + uint8_t readRegister(int offset) { + return read(BASE + offset); + } + + uint8_t peekRegister(int offset) { + return peek(BASE + offset); + } + + void checkTimers(int cycles); + + int timerClockTicks() { + switch (timerClock()) { + case 0b00: + return 1024; // 4.096 Khz + case 0b01: + return 16; // 262.144 Khz + case 0b10: + return 64; // 65.536 Khz + case 0b11: + return 256; // 16.384 Khz + default: + __assume(0); + } + throw std::domain_error("Invalid timer clock specification"); + } + + int timerClock() { + return peekRegister(TAC) & Processor::Mask2; + } + + bool timerEnabled() { + return !timerDisabled(); + } + + bool timerDisabled() { + return (peekRegister(TAC) & Processor::Bit2) == 0; + } + + void incrementDIV(int cycles) { + m_divCounter.word += cycles; + pokeRegister(DIV, m_divCounter.high); + } + + void incrementTIMA() { + uint16_t updated = peekRegister(TIMA) + 1; + if (updated & Processor::Bit8) { + triggerInterrupt(TimerOverflow); + updated = peekRegister(TMA); + } + pokeRegister(TIMA, updated & Processor::Mask8); + } + + void incrementLY() { + pokeRegister(LY, (peekRegister(LY) + 1) % TotalLineCount); + } + + void resetLY() { + pokeRegister(LY, 0); + } + + void disableBootRom() { m_disableBootRom = true; } + void enableBootRom() { m_disableBootRom = false; } + + void disableGameRom() { m_disableGameRom = true; } + void enableGameRom() { m_disableGameRom = false; } + + bool bootRomDisabled() const { return m_disableBootRom; } + bool bootRomEnabled() const { return !bootRomDisabled(); } + + bool gameRomDisabled() const { return m_disableGameRom; } + bool gameRomEnabled() const { return !gameRomDisabled(); } + + void loadBootRom(const std::string& path); + void loadGameRom(const std::string& path); + + protected: + virtual uint8_t& reference(uint16_t address, bool& rom) { + + rom = true; + if ((address < 0x100) && bootRomEnabled()) + return m_bootRom.reference(address); + if ((address < 0x4000) && gameRomEnabled()) + return m_gameRomBanks[0].reference(address); + if ((address < 0x8000) && gameRomEnabled()) + return m_gameRomBanks[m_romBank].reference(address - 0x4000); + + rom = false; + if (address < 0xa000) + return m_videoRam.reference(address - 0x8000); + if (address < 0xc000) + return m_ramBanks[m_ramBank].reference(address - 0xa000); + if (address < 0xe000) + return m_lowInternalRam.reference(address - 0xc000); + if (address < 0xfe00) + return m_lowInternalRam.reference(address - 0xe000); // Low internal RAM mirror + if (address < 0xff00) + return m_oamRam.reference(address - 0xfe00); + if (address < 0xff80) + return m_ioPorts.reference(address - 0xff00); + return m_highInternalRam.reference(address - 0xff80); + } + + private: + Rom m_bootRom; // 0x0000 - 0x00ff + std::vector m_gameRomBanks; // 0x0000 - 0x3fff, 0x4000 - 0x7fff (switchable) + Ram m_videoRam; // 0x8000 - 0x9fff + std::vector m_ramBanks; // 0xa000 - 0xbfff (switchable) + Ram m_lowInternalRam; // 0xc000 - 0xdfff (mirrored at 0xe000) + Ram m_oamRam; // 0xfe00 - 0xfe9f + Ram m_ioPorts; // 0xff00 - 0xff7f + Ram m_highInternalRam; // 0xff80 - 0xffff + + bool m_disableBootRom; + bool m_disableGameRom; + + bool m_rom; + bool m_banked; + bool m_ram; + bool m_battery; + + bool m_higherRomBank; + bool m_ramBankSwitching; + + int m_romBank; + int m_ramBank; + + register16_t m_divCounter; + int m_timerCounter; + int m_timerRate; + + void Bus_WrittenByte(const AddressEventArgs& e); + + void checkTimer(int cycles); + + void validateCartridgeType(); + }; + } +} \ No newline at end of file diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 96c5bc0..dc1b251 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -5,211 +5,213 @@ #include #include -#include "Bus.h" +#include "GameBoyBus.h" #include "Display.h" namespace EightBit { - class LR35902 : public IntelProcessor { - public: - enum StatusBits { - ZF = Bit7, - NF = Bit6, - HC = Bit5, - CF = Bit4, + namespace GameBoy { + class LR35902 : public IntelProcessor { + public: + enum StatusBits { + ZF = Bit7, + NF = Bit6, + HC = Bit5, + CF = Bit4, + }; + + LR35902(Bus& memory); + + Signal ExecutingInstruction; + + virtual register16_t& AF() override { + af.low &= 0xf0; + return af; + } + + virtual register16_t& BC() override { return bc; } + virtual register16_t& DE() override { return de; } + virtual register16_t& HL() override { return hl; } + + virtual void reset() override; + + static int framesPerSecond() { return 60; } + static int cyclesPerFrame() { return cyclesPerSecond() / framesPerSecond(); } + + int runRasterLines(); + int runRasterLine(); + int runVerticalBlankLines(); + + int singleStep(); + + protected: + int runRasterLines(int limit); + virtual int execute(uint8_t opcode); + int step(); + + private: + Bus& m_bus; + + register16_t af; + register16_t bc; + register16_t de; + register16_t hl; + + bool m_ime; + bool m_stopped; + + bool m_prefixCB; + + static int cyclesPerSecond() { return 4 * 1024 * 1024; } + static int cyclesPerLine() { return cyclesPerFrame() / Bus::TotalLineCount; } + + bool& IME() { return m_ime; } + + uint8_t R(int r, uint8_t& a) { + 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 getByte(HL()); + case 7: + return a; + } + throw std::logic_error("Unhandled registry mechanism"); + } + + void R(int r, uint8_t& a, uint8_t value) { + switch (r) { + case 0: + B() = value; + break; + case 1: + C() = value; + break; + case 2: + D() = value; + break; + case 3: + E() = value; + break; + case 4: + H() = value; + break; + case 5: + L() = value; + break; + case 6: + setByte(HL(), value); + break; + case 7: + a = value; + break; + } + } + + register16_t& RP(int rp) { + __assume(rp < 4); + __assume(rp >= 0); + switch (rp) { + case 0b00: + return BC(); + case 0b01: + return DE(); + case 0b10: + return HL(); + case 0b11: + return SP(); + default: + __assume(0); + } + } + + register16_t& RP2(int rp) { + __assume(rp < 4); + __assume(rp >= 0); + switch (rp) { + case 0b00: + return BC(); + case 0b01: + return DE(); + case 0b10: + return HL(); + case 0b11: + return AF(); + default: + __assume(0); + } + } + + static void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) { + setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation)); + } + + static void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) { + setFlag(f, HC, calculateHalfCarrySub(before, value, calculation)); + } + + static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); + + int interrupt(uint8_t value); + + void executeCB(int x, int y, int z, int p, int q); + void executeOther(int x, int y, int z, int p, int q); + + static void increment(uint8_t& f, uint8_t& operand); + static void decrement(uint8_t& f, uint8_t& operand); + + void stop() { m_stopped = true; } + void start() { m_stopped = false; } + bool stopped() const { return m_stopped; } + + void di(); + void ei(); + + void reti(); + + bool jrConditionalFlag(uint8_t& f, int flag); + bool returnConditionalFlag(uint8_t& f, int flag); + bool jumpConditionalFlag(uint8_t& f, int flag); + bool callConditionalFlag(uint8_t& f, int flag); + + void add(uint8_t& f, register16_t& operand, register16_t value); + + static void add(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); + static void adc(uint8_t& f, uint8_t& operand, uint8_t value); + static void sbc(uint8_t& f, uint8_t& operand, uint8_t value); + static void andr(uint8_t& f, uint8_t& operand, uint8_t value); + static void xorr(uint8_t& f, uint8_t& operand, uint8_t value); + static void orr(uint8_t& f, uint8_t& operand, uint8_t value); + static void compare(uint8_t& f, uint8_t check, uint8_t value); + + static uint8_t rlc(uint8_t& f, uint8_t operand); + static uint8_t rrc(uint8_t& f, uint8_t operand); + static uint8_t rl(uint8_t& f, uint8_t operand); + static uint8_t rr(uint8_t& f, uint8_t operand); + static uint8_t sla(uint8_t& f, uint8_t operand); + static uint8_t sra(uint8_t& f, uint8_t operand); + static uint8_t srl(uint8_t& f, uint8_t operand); + + static uint8_t bit(uint8_t& f, int n, uint8_t operand); + static uint8_t res(int n, uint8_t operand); + static uint8_t set(int n, uint8_t operand); + + static void daa(uint8_t& a, uint8_t& f); + + static void scf(uint8_t& a, uint8_t& f); + static void ccf(uint8_t& a, uint8_t& f); + static void cpl(uint8_t& a, uint8_t& f); + + static uint8_t swap(uint8_t& f, uint8_t operand); }; - - LR35902(Bus& memory); - - Signal ExecutingInstruction; - - virtual register16_t& AF() override { - af.low &= 0xf0; - return af; - } - - virtual register16_t& BC() override { return bc; } - virtual register16_t& DE() override { return de; } - virtual register16_t& HL() override { return hl; } - - virtual void reset() override; - - static int framesPerSecond() { return 60; } - static int cyclesPerFrame() { return cyclesPerSecond() / framesPerSecond(); } - - int runRasterLines(); - int runRasterLine(); - int runVerticalBlankLines(); - - int singleStep(); - - protected: - int runRasterLines(int limit); - virtual int execute(uint8_t opcode); - int step(); - - private: - Bus& m_bus; - - register16_t af; - register16_t bc; - register16_t de; - register16_t hl; - - bool m_ime; - bool m_stopped; - - bool m_prefixCB; - - static int cyclesPerSecond() { return 4 * 1024 * 1024; } - static int cyclesPerLine() { return cyclesPerFrame() / Bus::TotalLineCount; } - - bool& IME() { return m_ime; } - - uint8_t R(int r, uint8_t& a) { - 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 getByte(HL()); - case 7: - return a; - } - throw std::logic_error("Unhandled registry mechanism"); - } - - void R(int r, uint8_t& a, uint8_t value) { - switch (r) { - case 0: - B() = value; - break; - case 1: - C() = value; - break; - case 2: - D() = value; - break; - case 3: - E() = value; - break; - case 4: - H() = value; - break; - case 5: - L() = value; - break; - case 6: - setByte(HL(), value); - break; - case 7: - a = value; - break; - } - } - - register16_t& RP(int rp) { - __assume(rp < 4); - __assume(rp >= 0); - switch (rp) { - case 0b00: - return BC(); - case 0b01: - return DE(); - case 0b10: - return HL(); - case 0b11: - return SP(); - default: - __assume(0); - } - } - - register16_t& RP2(int rp) { - __assume(rp < 4); - __assume(rp >= 0); - switch (rp) { - case 0b00: - return BC(); - case 0b01: - return DE(); - case 0b10: - return HL(); - case 0b11: - return AF(); - default: - __assume(0); - } - } - - static void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) { - setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation)); - } - - static void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) { - setFlag(f, HC, calculateHalfCarrySub(before, value, calculation)); - } - - static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); - - int interrupt(uint8_t value); - - void executeCB(int x, int y, int z, int p, int q); - void executeOther(int x, int y, int z, int p, int q); - - static void increment(uint8_t& f, uint8_t& operand); - static void decrement(uint8_t& f, uint8_t& operand); - - void stop() { m_stopped = true; } - void start() { m_stopped = false; } - bool stopped() const { return m_stopped; } - - void di(); - void ei(); - - void reti(); - - bool jrConditionalFlag(uint8_t& f, int flag); - bool returnConditionalFlag(uint8_t& f, int flag); - bool jumpConditionalFlag(uint8_t& f, int flag); - bool callConditionalFlag(uint8_t& f, int flag); - - void add(uint8_t& f, register16_t& operand, register16_t value); - - static void add(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); - static void adc(uint8_t& f, uint8_t& operand, uint8_t value); - static void sbc(uint8_t& f, uint8_t& operand, uint8_t value); - static void andr(uint8_t& f, uint8_t& operand, uint8_t value); - static void xorr(uint8_t& f, uint8_t& operand, uint8_t value); - static void orr(uint8_t& f, uint8_t& operand, uint8_t value); - static void compare(uint8_t& f, uint8_t check, uint8_t value); - - static uint8_t rlc(uint8_t& f, uint8_t operand); - static uint8_t rrc(uint8_t& f, uint8_t operand); - static uint8_t rl(uint8_t& f, uint8_t operand); - static uint8_t rr(uint8_t& f, uint8_t operand); - static uint8_t sla(uint8_t& f, uint8_t operand); - static uint8_t sra(uint8_t& f, uint8_t operand); - static uint8_t srl(uint8_t& f, uint8_t operand); - - static uint8_t bit(uint8_t& f, int n, uint8_t operand); - static uint8_t res(int n, uint8_t operand); - static uint8_t set(int n, uint8_t operand); - - static void daa(uint8_t& a, uint8_t& f); - - static void scf(uint8_t& a, uint8_t& f); - static void ccf(uint8_t& a, uint8_t& f); - static void cpl(uint8_t& a, uint8_t& f); - - static uint8_t swap(uint8_t& f, uint8_t operand); - }; + } } \ No newline at end of file diff --git a/LR35902/inc/Profiler.h b/LR35902/inc/Profiler.h index f5b9843..f8e147c 100644 --- a/LR35902/inc/Profiler.h +++ b/LR35902/inc/Profiler.h @@ -6,25 +6,27 @@ #include "Disassembler.h" namespace EightBit { + namespace GameBoy { - class LR35902; + class LR35902; - class Profiler { - public: - Profiler(LR35902& cpu); + class Profiler { + public: + Profiler(LR35902& cpu); - void add(uint16_t address, uint8_t instruction); + void add(uint16_t address, uint8_t instruction); - void dump() const; + void dump() const; - private: - std::array m_instructions; - std::array m_addresses; - LR35902& m_cpu; + private: + std::array m_instructions; + std::array m_addresses; + LR35902& m_cpu; - Disassembler m_disassembler; + Disassembler m_disassembler; - void dumpInstructionProfiles() const; - void dumpAddressProfiles() const; - }; + void dumpInstructionProfiles() const; + void dumpAddressProfiles() const; + }; + } } \ No newline at end of file diff --git a/LR35902/src/Disassembler.cpp b/LR35902/src/Disassembler.cpp index c1f28d4..da8297e 100644 --- a/LR35902/src/Disassembler.cpp +++ b/LR35902/src/Disassembler.cpp @@ -8,12 +8,12 @@ #include "Memory.h" #include "LR35902.h" -EightBit::Disassembler::Disassembler() { +EightBit::GameBoy::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 EightBit::Disassembler::state(EightBit::LR35902& cpu) { +std::string EightBit::GameBoy::Disassembler::state(LR35902& cpu) { auto pc = cpu.PC(); auto sp = cpu.SP(); @@ -44,7 +44,7 @@ std::string EightBit::Disassembler::state(EightBit::LR35902& cpu) { return output.str(); } -std::string EightBit::Disassembler::RP(int rp) const { +std::string EightBit::GameBoy::Disassembler::RP(int rp) const { switch (rp) { case 0: return "BC"; @@ -58,7 +58,7 @@ std::string EightBit::Disassembler::RP(int rp) const { throw std::logic_error("Unhandled register pair"); } -std::string EightBit::Disassembler::RP2(int rp) const { +std::string EightBit::GameBoy::Disassembler::RP2(int rp) const { switch (rp) { case 0: return "BC"; @@ -72,7 +72,7 @@ std::string EightBit::Disassembler::RP2(int rp) const { throw std::logic_error("Unhandled register pair"); } -std::string EightBit::Disassembler::R(int r) const { +std::string EightBit::GameBoy::Disassembler::R(int r) const { switch (r) { case 0: return "B"; @@ -94,7 +94,7 @@ std::string EightBit::Disassembler::R(int r) const { throw std::logic_error("Unhandled register"); } -std::string EightBit::Disassembler::cc(int flag) { +std::string EightBit::GameBoy::Disassembler::cc(int flag) { switch (flag) { case 0: return "NZ"; @@ -116,7 +116,7 @@ std::string EightBit::Disassembler::cc(int flag) { throw std::logic_error("Unhandled condition"); } -std::string EightBit::Disassembler::alu(int which) { +std::string EightBit::GameBoy::Disassembler::alu(int which) { switch (which) { case 0: // ADD A,n return "ADD"; @@ -138,17 +138,17 @@ std::string EightBit::Disassembler::alu(int which) { throw std::logic_error("Unhandled alu operation"); } -std::string EightBit::Disassembler::disassemble(LR35902& cpu) { +std::string EightBit::GameBoy::Disassembler::disassemble(LR35902& cpu) { m_prefixCB = false; std::ostringstream output; disassemble(output, cpu, cpu.PC().word); return output.str(); } -void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) { +void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) { - auto& memory = cpu.getMemory(); - auto opcode = memory.peek(pc); + auto& bus = cpu.BUS(); + auto opcode = bus.peek(pc); // hex opcode output << hex(opcode); @@ -160,11 +160,11 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cp auto p = (y & 0b110) >> 1; auto q = (y & 1); - auto immediate = memory.peek(pc + 1); - auto absolute = memory.peekWord(pc + 1); + auto immediate = bus.peek(pc + 1); + auto absolute = bus.peekWord(pc + 1); auto displacement = (int8_t)immediate; auto relative = pc + displacement + 2; - auto indexedImmediate = memory.peek(pc + 1); + auto indexedImmediate = bus.peek(pc + 1); auto dumpCount = 0; auto ioRegister = IoRegister::Unused; @@ -183,7 +183,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cp x, y, z, p, q); for (int i = 0; i < dumpCount; ++i) - output << hex(memory.peek(pc + i + 1)); + output << hex(bus.peek(pc + i + 1)); output << '\t'; m_formatter.parse(specification); @@ -206,7 +206,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cp } } -void EightBit::Disassembler::disassembleCB( +void EightBit::GameBoy::Disassembler::disassembleCB( std::ostringstream& output, LR35902& cpu, uint16_t pc, @@ -256,7 +256,7 @@ void EightBit::Disassembler::disassembleCB( } } -void EightBit::Disassembler::disassembleOther( +void EightBit::GameBoy::Disassembler::disassembleOther( std::ostringstream& output, LR35902& cpu, uint16_t pc, @@ -525,13 +525,13 @@ void EightBit::Disassembler::disassembleOther( } } -std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) { +std::string EightBit::GameBoy::Disassembler::flag(uint8_t value, int flag, const std::string& represents) { std::ostringstream output; output << (value & flag ? represents : "-"); return output.str(); } -std::string EightBit::Disassembler::flags(uint8_t value) { +std::string EightBit::GameBoy::Disassembler::flags(uint8_t value) { std::ostringstream output; output << flag(value, LR35902::ZF, "Z") @@ -545,37 +545,37 @@ std::string EightBit::Disassembler::flags(uint8_t value) { return output.str(); } -std::string EightBit::Disassembler::hex(uint8_t value) { +std::string EightBit::GameBoy::Disassembler::hex(uint8_t value) { std::ostringstream output; output << std::hex << std::setw(2) << std::setfill('0') << (int)value; return output.str(); } -std::string EightBit::Disassembler::hex(uint16_t value) { +std::string EightBit::GameBoy::Disassembler::hex(uint16_t value) { std::ostringstream output; output << std::hex << std::setw(4) << std::setfill('0') << (int)value; return output.str(); } -std::string EightBit::Disassembler::binary(uint8_t value) { +std::string EightBit::GameBoy::Disassembler::binary(uint8_t value) { std::ostringstream output; output << std::bitset<8>(value); return output.str(); } -std::string EightBit::Disassembler::decimal(uint8_t value) { +std::string EightBit::GameBoy::Disassembler::decimal(uint8_t value) { std::ostringstream output; output << (int)value; return output.str(); } -std::string EightBit::Disassembler::invalid(uint8_t value) { +std::string EightBit::GameBoy::Disassembler::invalid(uint8_t value) { std::ostringstream output; output << "Invalid instruction: " << hex(value) << "(" << binary(value) << ")"; return output.str(); } -std::string EightBit::Disassembler::io(uint8_t value) { +std::string EightBit::GameBoy::Disassembler::io(uint8_t value) { switch (value) { // Port/Mode Registers diff --git a/LR35902/src/Display.cpp b/LR35902/src/Display.cpp index 729c098..c50df7c 100644 --- a/LR35902/src/Display.cpp +++ b/LR35902/src/Display.cpp @@ -3,20 +3,20 @@ #include "Processor.h" #include "CharacterDefinition.h" -EightBit::Display::Display(const AbstractColourPalette* colours, Bus& bus) +EightBit::GameBoy::Display::Display(const AbstractColourPalette* colours, Bus& bus) : m_bus(bus), m_colours(colours) { } -const std::vector& EightBit::Display::pixels() const { +const std::vector& EightBit::GameBoy::Display::pixels() const { return m_pixels; } -void EightBit::Display::initialise() { +void EightBit::GameBoy::Display::initialise() { m_pixels.resize(RasterWidth * RasterHeight); } -void EightBit::Display::render() { +void EightBit::GameBoy::Display::render() { auto control = m_bus.peekRegister(Bus::LCDC); auto on = control & Bus::LcdEnable; diff --git a/LR35902/src/Bus.cpp b/LR35902/src/GameBoyBus.cpp similarity index 69% rename from LR35902/src/Bus.cpp rename to LR35902/src/GameBoyBus.cpp index 3741f6b..77d3f22 100644 --- a/LR35902/src/Bus.cpp +++ b/LR35902/src/GameBoyBus.cpp @@ -1,11 +1,11 @@ #include "stdafx.h" -#include "Bus.h" +#include "GameBoyBus.h" -EightBit::Bus::Bus() -: Memory(0xffff), - m_disableBootRom(false), +EightBit::GameBoy::Bus::Bus() +: m_disableBootRom(false), m_disableGameRom(false), m_rom(false), + m_banked(false), m_ram(false), m_battery(false), m_higherRomBank(true), @@ -14,47 +14,35 @@ EightBit::Bus::Bus() m_ramBank(0), m_timerCounter(0), m_timerRate(0) { - m_bootRom.resize(0x100); - m_gameRom.resize(0x10000); - WrittenByte.connect(std::bind(&Bus::Bus_WrittenByte, this, std::placeholders::_1)); + WrittenByte.connect(std::bind(&GameBoy::Bus::Bus_WrittenByte, this, std::placeholders::_1)); m_divCounter.word = 0xabcc; } -void EightBit::Bus::reset() { +void EightBit::GameBoy::Bus::reset() { pokeRegister(NR52, 0xf1); pokeRegister(LCDC, DisplayBackground | BackgroundCharacterDataSelection | LcdEnable); m_divCounter.word = 0xabcc; m_timerCounter = 0; } -void EightBit::Bus::clear() { - Memory::clear(); - std::fill(m_bootRom.begin(), m_bootRom.end(), 0); - std::fill(m_gameRom.begin(), m_gameRom.end(), 0); +void EightBit::GameBoy::Bus::loadBootRom(const std::string& path) { + m_bootRom.load(path); } -void EightBit::Bus::loadBootRom(const std::string& path) { - loadBinary(path, m_bootRom, 0, 0x100); -} - -void EightBit::Bus::loadGameRom(const std::string& path) { - loadBinary(path, m_gameRom); +void EightBit::GameBoy::Bus::loadGameRom(const std::string& path) { + const auto bankSize = 0x4000; + m_gameRomBanks.resize(1); + const auto size = m_gameRomBanks[0].load(path, bankSize); + auto banks = size / bankSize; + if (banks > 1) { + m_gameRomBanks.resize(banks); + for (int bank = 1; bank < banks; ++banks) + m_gameRomBanks[bank].load(path, bankSize, bankSize * bank); + } validateCartridgeType(); } -uint8_t& EightBit::Bus::reference(uint16_t address, bool& rom) { - rom = true; - if ((address < 0x100) && bootRomEnabled()) - return m_bootRom[address]; - if ((address < 0x4000) && gameRomEnabled()) - return m_gameRom[address]; - if ((address < 0x8000) && gameRomEnabled()) - return m_gameRom[(address - RomPageSize) + (m_romBank * RomPageSize)]; - rom = false; - return m_bus[address]; -} - -void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) { +void EightBit::GameBoy::Bus::Bus_WrittenByte(const AddressEventArgs& e) { const auto address = e.getAddress(); const auto value = e.getCell(); @@ -110,7 +98,7 @@ void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) { break; case BASE + DIV: // R/W - Memory::reference() = 0; + EightBit::Bus::reference() = 0; m_timerCounter = m_divCounter.word = 0; break; case BASE + TIMA: // R/W @@ -145,7 +133,7 @@ void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) { case BASE + DMA: break; case BASE + LY: // R/O - Memory::reference() = 0; + EightBit::Bus::reference() = 0; break; case BASE + BGP: case BASE + OBP0: @@ -165,12 +153,12 @@ void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) { } } -void EightBit::Bus::checkTimers(int cycles) { +void EightBit::GameBoy::Bus::checkTimers(int cycles) { incrementDIV(cycles); checkTimer(cycles); } -void EightBit::Bus::checkTimer(int cycles) { +void EightBit::GameBoy::Bus::checkTimer(int cycles) { if (timerEnabled()) { m_timerCounter -= cycles; if (m_timerCounter <= 0) { @@ -180,11 +168,11 @@ void EightBit::Bus::checkTimer(int cycles) { } } -void EightBit::Bus::validateCartridgeType() { +void EightBit::GameBoy::Bus::validateCartridgeType() { m_rom = m_banked = m_ram = m_battery = false; - switch (m_gameRom[0x147]) { + switch (m_gameRomBanks[0].peek(0x147)) { case ROM: m_rom = true; break; diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index c14b723..ae49498 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -5,7 +5,7 @@ #pragma region Reset and initialisation -EightBit::LR35902::LR35902(Bus& memory) +EightBit::GameBoy::LR35902::LR35902(Bus& memory) : IntelProcessor(memory), m_bus(memory), m_ime(false), @@ -13,7 +13,7 @@ EightBit::LR35902::LR35902(Bus& memory) m_prefixCB(false) { } -void EightBit::LR35902::reset() { +void EightBit::GameBoy::LR35902::reset() { IntelProcessor::reset(); di(); SP().word = Mask16 - 1; @@ -24,15 +24,15 @@ void EightBit::LR35902::reset() { #pragma region Interrupt routines -void EightBit::LR35902::di() { +void EightBit::GameBoy::LR35902::di() { IME() = false; } -void EightBit::LR35902::ei() { +void EightBit::GameBoy::LR35902::ei() { IME() = true; } -int EightBit::LR35902::interrupt(uint8_t value) { +int EightBit::GameBoy::LR35902::interrupt(uint8_t value) { di(); restart(value); return 4; @@ -42,13 +42,13 @@ int EightBit::LR35902::interrupt(uint8_t value) { #pragma region Flag manipulation helpers -void EightBit::LR35902::increment(uint8_t& f, uint8_t& operand) { +void EightBit::GameBoy::LR35902::increment(uint8_t& f, uint8_t& operand) { clearFlag(f, NF); adjustZero(f, ++operand); clearFlag(f, HC, lowNibble(operand)); } -void EightBit::LR35902::decrement(uint8_t& f, uint8_t& operand) { +void EightBit::GameBoy::LR35902::decrement(uint8_t& f, uint8_t& operand) { setFlag(f, NF); clearFlag(f, HC, lowNibble(operand)); adjustZero(f, --operand); @@ -58,7 +58,7 @@ void EightBit::LR35902::decrement(uint8_t& f, uint8_t& operand) { #pragma region PC manipulation: call/ret/jp/jr -bool EightBit::LR35902::jrConditionalFlag(uint8_t& f, int flag) { +bool EightBit::GameBoy::LR35902::jrConditionalFlag(uint8_t& f, int flag) { switch (flag) { case 0: // NZ return jrConditional(!(f & ZF)); @@ -74,7 +74,7 @@ bool EightBit::LR35902::jrConditionalFlag(uint8_t& f, int flag) { throw std::logic_error("Unhandled JR conditional"); } -bool EightBit::LR35902::jumpConditionalFlag(uint8_t& f, int flag) { +bool EightBit::GameBoy::LR35902::jumpConditionalFlag(uint8_t& f, int flag) { switch (flag) { case 0: // NZ return jumpConditional(!(f & ZF)); @@ -90,12 +90,12 @@ bool EightBit::LR35902::jumpConditionalFlag(uint8_t& f, int flag) { throw std::logic_error("Unhandled JP conditional"); } -void EightBit::LR35902::reti() { +void EightBit::GameBoy::LR35902::reti() { ret(); ei(); } -bool EightBit::LR35902::returnConditionalFlag(uint8_t& f, int flag) { +bool EightBit::GameBoy::LR35902::returnConditionalFlag(uint8_t& f, int flag) { switch (flag) { case 0: // NZ return returnConditional(!(f & ZF)); @@ -111,7 +111,7 @@ bool EightBit::LR35902::returnConditionalFlag(uint8_t& f, int flag) { throw std::logic_error("Unhandled RET conditional"); } -bool EightBit::LR35902::callConditionalFlag(uint8_t& f, int flag) { +bool EightBit::GameBoy::LR35902::callConditionalFlag(uint8_t& f, int flag) { switch (flag) { case 0: // NZ return callConditional(!(f & ZF)); @@ -131,7 +131,7 @@ bool EightBit::LR35902::callConditionalFlag(uint8_t& f, int flag) { #pragma region 16-bit arithmetic -void EightBit::LR35902::add(uint8_t& f, register16_t& operand, register16_t value) { +void EightBit::GameBoy::LR35902::add(uint8_t& f, register16_t& operand, register16_t value) { MEMPTR() = operand; @@ -148,7 +148,7 @@ void EightBit::LR35902::add(uint8_t& f, register16_t& operand, register16_t valu #pragma region ALU -void EightBit::LR35902::add(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { +void EightBit::GameBoy::LR35902::add(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { register16_t result; result.word = operand + value + carry; @@ -162,11 +162,11 @@ void EightBit::LR35902::add(uint8_t& f, uint8_t& operand, uint8_t value, int car adjustZero(f, operand); } -void EightBit::LR35902::adc(uint8_t& f, uint8_t& operand, uint8_t value) { +void EightBit::GameBoy::LR35902::adc(uint8_t& f, uint8_t& operand, uint8_t value) { add(f, operand, value, (f & CF) >> 4); } -void EightBit::LR35902::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { +void EightBit::GameBoy::LR35902::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { register16_t result; result.word = operand - value - carry; @@ -180,27 +180,27 @@ void EightBit::LR35902::subtract(uint8_t& f, uint8_t& operand, uint8_t value, in adjustZero(f, operand); } -void EightBit::LR35902::sbc(uint8_t& f, uint8_t& operand, uint8_t value) { +void EightBit::GameBoy::LR35902::sbc(uint8_t& f, uint8_t& operand, uint8_t value) { subtract(f, operand, value, (f & CF) >> 4); } -void EightBit::LR35902::andr(uint8_t& f, uint8_t& operand, uint8_t value) { +void EightBit::GameBoy::LR35902::andr(uint8_t& f, uint8_t& operand, uint8_t value) { setFlag(f, HC); clearFlag(f, CF | NF); adjustZero(f, operand &= value); } -void EightBit::LR35902::xorr(uint8_t& f, uint8_t& operand, uint8_t value) { +void EightBit::GameBoy::LR35902::xorr(uint8_t& f, uint8_t& operand, uint8_t value) { clearFlag(f, HC | CF | NF); adjustZero(f, operand ^= value); } -void EightBit::LR35902::orr(uint8_t& f, uint8_t& operand, uint8_t value) { +void EightBit::GameBoy::LR35902::orr(uint8_t& f, uint8_t& operand, uint8_t value) { clearFlag(f, HC | CF | NF); adjustZero(f, operand |= value); } -void EightBit::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) { +void EightBit::GameBoy::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) { subtract(f, check, value); } @@ -208,50 +208,50 @@ void EightBit::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) { #pragma region Shift and rotate -uint8_t EightBit::LR35902::rlc(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::rlc(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); setFlag(f, CF, operand & Bit7); return _rotl8(operand, 1); } -uint8_t EightBit::LR35902::rrc(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::rrc(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); setFlag(f, CF, operand & Bit0); return _rotr8(operand, 1); } -uint8_t EightBit::LR35902::rl(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::rl(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); const auto carry = f & CF; setFlag(f, CF, operand & Bit7); return (operand << 1) | (carry >> 4); // CF at Bit4 } -uint8_t EightBit::LR35902::rr(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::rr(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); const auto carry = f & CF; setFlag(f, CF, operand & Bit0); return (operand >> 1) | (carry << 3); // CF at Bit4 } -uint8_t EightBit::LR35902::sla(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::sla(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); setFlag(f, CF, operand & Bit7); return operand << 1; } -uint8_t EightBit::LR35902::sra(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::sra(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); setFlag(f, CF, operand & Bit0); return (operand >> 1) | (operand & Bit7); } -uint8_t EightBit::LR35902::swap(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::swap(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | CF); return promoteNibble(operand) | demoteNibble(operand); } -uint8_t EightBit::LR35902::srl(uint8_t& f, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::srl(uint8_t& f, uint8_t operand) { clearFlag(f, NF | HC | ZF); setFlag(f, CF, operand & Bit0); return (operand >> 1) & ~Bit7; @@ -261,7 +261,7 @@ uint8_t EightBit::LR35902::srl(uint8_t& f, uint8_t operand) { #pragma region BIT/SET/RES -uint8_t EightBit::LR35902::bit(uint8_t& f, int n, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::bit(uint8_t& f, int n, uint8_t operand) { auto carry = f & CF; uint8_t discarded = operand; andr(f, discarded, 1 << n); @@ -269,11 +269,11 @@ uint8_t EightBit::LR35902::bit(uint8_t& f, int n, uint8_t operand) { return operand; } -uint8_t EightBit::LR35902::res(int n, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::res(int n, uint8_t operand) { return operand & ~(1 << n); } -uint8_t EightBit::LR35902::set(int n, uint8_t operand) { +uint8_t EightBit::GameBoy::LR35902::set(int n, uint8_t operand) { return operand | (1 << n); } @@ -281,7 +281,7 @@ uint8_t EightBit::LR35902::set(int n, uint8_t operand) { #pragma region Miscellaneous instructions -void EightBit::LR35902::daa(uint8_t& a, uint8_t& f) { +void EightBit::GameBoy::LR35902::daa(uint8_t& a, uint8_t& f) { int updated = a; @@ -304,17 +304,17 @@ void EightBit::LR35902::daa(uint8_t& a, uint8_t& f) { adjustZero(f, a); } -void EightBit::LR35902::cpl(uint8_t& a, uint8_t& f) { +void EightBit::GameBoy::LR35902::cpl(uint8_t& a, uint8_t& f) { setFlag(f, HC | NF); a = ~a; } -void EightBit::LR35902::scf(uint8_t& a, uint8_t& f) { +void EightBit::GameBoy::LR35902::scf(uint8_t& a, uint8_t& f) { setFlag(f, CF); clearFlag(f, HC | NF); } -void EightBit::LR35902::ccf(uint8_t& a, uint8_t& f) { +void EightBit::GameBoy::LR35902::ccf(uint8_t& a, uint8_t& f) { clearFlag(f, NF | HC); clearFlag(f, CF, f & CF); } @@ -323,19 +323,19 @@ void EightBit::LR35902::ccf(uint8_t& a, uint8_t& f) { #pragma region Controlled instruction execution -int EightBit::LR35902::runRasterLines() { +int EightBit::GameBoy::LR35902::runRasterLines() { m_bus.resetLY(); return runRasterLines(Display::RasterHeight); } -int EightBit::LR35902::runRasterLines(int limit) { +int EightBit::GameBoy::LR35902::runRasterLines(int limit) { int count = 0; for (int line = 0; line < limit; ++line) count += runRasterLine(); return count; } -int EightBit::LR35902::runRasterLine() { +int EightBit::GameBoy::LR35902::runRasterLine() { const auto count = run(cyclesPerLine()); m_bus.incrementLY(); if ((m_bus.peekRegister(Bus::STAT) & Bit6) && (m_bus.peekRegister(Bus::LYC) == m_bus.peekRegister(Bus::LY))) @@ -343,12 +343,12 @@ int EightBit::LR35902::runRasterLine() { return count; } -int EightBit::LR35902::runVerticalBlankLines() { +int EightBit::GameBoy::LR35902::runVerticalBlankLines() { m_bus.triggerInterrupt(Bus::Interrupts::VerticalBlank); return runRasterLines(Bus::TotalLineCount - Display::RasterHeight); } -int EightBit::LR35902::singleStep() { +int EightBit::GameBoy::LR35902::singleStep() { int current = 0; @@ -385,7 +385,7 @@ int EightBit::LR35902::singleStep() { return current; } -int EightBit::LR35902::step() { +int EightBit::GameBoy::LR35902::step() { ExecutingInstruction.fire(*this); m_prefixCB = false; cycles = 0; @@ -396,7 +396,7 @@ int EightBit::LR35902::step() { #pragma region Instruction decode and execution -int EightBit::LR35902::execute(uint8_t opcode) { +int EightBit::GameBoy::LR35902::execute(uint8_t opcode) { const auto& decoded = getDecodedOpcode(opcode); @@ -418,7 +418,7 @@ int EightBit::LR35902::execute(uint8_t opcode) { return cycles * 4; } -void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) { +void EightBit::GameBoy::LR35902::executeCB(int x, int y, int z, int p, int q) { auto& a = A(); auto& f = F(); switch (x) { @@ -481,7 +481,7 @@ void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) { } } -void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) { +void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q) { auto& a = A(); auto& f = F(); switch (x) { diff --git a/LR35902/src/LR35902.vcxproj b/LR35902/src/LR35902.vcxproj index a793495..23edb69 100644 --- a/LR35902/src/LR35902.vcxproj +++ b/LR35902/src/LR35902.vcxproj @@ -140,7 +140,7 @@ - + @@ -149,7 +149,7 @@ - + diff --git a/LR35902/src/LR35902.vcxproj.filters b/LR35902/src/LR35902.vcxproj.filters index c1b68a5..7909042 100644 --- a/LR35902/src/LR35902.vcxproj.filters +++ b/LR35902/src/LR35902.vcxproj.filters @@ -23,9 +23,6 @@ Header Files - - Header Files - Header Files @@ -35,6 +32,9 @@ Header Files + + Header Files + @@ -49,10 +49,10 @@ Source Files - + Source Files - + Source Files diff --git a/LR35902/src/Profiler.cpp b/LR35902/src/Profiler.cpp index 8eb4383..e77975d 100644 --- a/LR35902/src/Profiler.cpp +++ b/LR35902/src/Profiler.cpp @@ -2,13 +2,13 @@ #include "Profiler.h" #include "LR35902.h" -EightBit::Profiler::Profiler(LR35902& cpu) +EightBit::GameBoy::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 EightBit::Profiler::add(uint16_t address, uint8_t instruction) { +void EightBit::GameBoy::Profiler::add(uint16_t address, uint8_t instruction) { m_instructions[instruction]++; @@ -19,12 +19,12 @@ void EightBit::Profiler::add(uint16_t address, uint8_t instruction) { m_addresses[address]++; } -void EightBit::Profiler::dump() const { +void EightBit::GameBoy::Profiler::dump() const { dumpInstructionProfiles(); dumpAddressProfiles(); } -void EightBit::Profiler::dumpInstructionProfiles() const { +void EightBit::GameBoy::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 EightBit::Profiler::dumpInstructionProfiles() const { } } -void EightBit::Profiler::dumpAddressProfiles() const { +void EightBit::GameBoy::Profiler::dumpAddressProfiles() const { std::cout << "** addresses" << std::endl; for (int i = 0; i < 0x10000; ++i) { auto count = m_addresses[i];