From ea033d398459de2c3ad6e179db83e5e2aebcba70 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 29 Aug 2017 22:23:32 +0100 Subject: [PATCH] Move a fair amount of code from the GameBoy implementation into the EightBit library for the LR35902 Signed-off-by: Adrian.Conlon --- LR35902/inc/AbstractColourPalette.h | 27 +++++++++ LR35902/inc/CharacterDefinition.h | 41 ++++++++++++++ LR35902/inc/Display.h | 33 +++++++++++ LR35902/inc/LR35902.h | 40 ++++++++++++-- LR35902/src/Display.cpp | 86 +++++++++++++++++++++++++++++ LR35902/src/LR35902.vcxproj | 4 ++ LR35902/src/LR35902.vcxproj.filters | 12 ++++ 7 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 LR35902/inc/AbstractColourPalette.h create mode 100644 LR35902/inc/CharacterDefinition.h create mode 100644 LR35902/inc/Display.h create mode 100644 LR35902/src/Display.cpp diff --git a/LR35902/inc/AbstractColourPalette.h b/LR35902/inc/AbstractColourPalette.h new file mode 100644 index 0000000..d47ce32 --- /dev/null +++ b/LR35902/inc/AbstractColourPalette.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace EightBit { + 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; + }; +} \ No newline at end of file diff --git a/LR35902/inc/CharacterDefinition.h b/LR35902/inc/CharacterDefinition.h new file mode 100644 index 0000000..7cf77ae --- /dev/null +++ b/LR35902/inc/CharacterDefinition.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#include "Bus.h" + +namespace EightBit { + class CharacterDefinition { + public: + CharacterDefinition() {} + + CharacterDefinition(Bus& bus, uint16_t address) { + + for (auto row = 0; row < 8; ++row) { + + auto planeAddress = address + row * 2; + + auto planeLow = bus.peek(planeAddress); + auto planeHigh = bus.peek(planeAddress + 1); + + for (int bit = 0; bit < 8; ++bit) { + + auto mask = 1 << bit; + + auto bitLow = planeLow & mask ? 1 : 0; + auto bitHigh = planeHigh & mask ? 0b10 : 0; + + auto colour = bitHigh | bitLow; + + m_definition[row * 8 + (7 - bit)] = colour; + } + } + } + + const std::array& get() const { return m_definition; } + + private: + std::array m_definition; + }; +} \ No newline at end of file diff --git a/LR35902/inc/Display.h b/LR35902/inc/Display.h new file mode 100644 index 0000000..dc93ba3 --- /dev/null +++ b/LR35902/inc/Display.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "Bus.h" +#include "AbstractColourPalette.h" + +namespace EightBit { + 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; + }; +} \ No newline at end of file diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 2fcaeb5..0be15c8 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -5,6 +5,7 @@ #include "IntelProcessor.h" #include "Bus.h" #include "Signal.h" +#include "Display.h" namespace EightBit { class LR35902 : public IntelProcessor { @@ -29,10 +30,6 @@ namespace EightBit { void di(); void ei(); - int run(int limit); - virtual int execute(uint8_t opcode); - int step(); - virtual register16_t& AF() override { af.low &= 0xf0; return af; @@ -53,6 +50,30 @@ namespace EightBit { virtual void reset(); virtual void initialise(); + static int framesPerSecond() { return 60; } + static int cyclesPerFrame() { return cyclesPerSecond() / framesPerSecond(); } + + int runRasterLines() { + m_bus.resetLY(); + int cycles = 0; + for (int line = 0; line < Display::RasterHeight; ++line) + cycles += runRasterLine(); + return cycles; + } + + int runVerticalBlankLines() { + m_bus.triggerInterrupt(Bus::Interrupts::VerticalBlank); + int cycles = 0; + for (int line = 0; line < (Bus::TotalLineCount - Display::RasterHeight); ++line) + cycles += runRasterLine(); + return cycles; + } + + protected: + int run(int limit); + virtual int execute(uint8_t opcode); + int step(); + private: Bus& m_bus; @@ -67,6 +88,17 @@ namespace EightBit { bool m_stopped; + static int cyclesPerSecond() { return 4 * 1024 * 1024; } + static int cyclesPerLine() { return cyclesPerFrame() / Bus::TotalLineCount; } + + int runRasterLine() { + auto cycles = run(cyclesPerLine()); + m_bus.incrementLY(); + if ((m_bus.peekRegister(Bus::STAT) & Processor::Bit6) && (m_bus.peekRegister(Bus::LYC) == m_bus.peekRegister(Bus::LY))) + m_bus.triggerInterrupt(Bus::Interrupts::DisplayControlStatus); + return cycles; + } + uint8_t R(int r, uint8_t& a) { switch (r) { case 0: diff --git a/LR35902/src/Display.cpp b/LR35902/src/Display.cpp new file mode 100644 index 0000000..729c098 --- /dev/null +++ b/LR35902/src/Display.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "Display.h" +#include "Processor.h" +#include "CharacterDefinition.h" + +EightBit::Display::Display(const AbstractColourPalette* colours, Bus& bus) +: m_bus(bus), + m_colours(colours) { +} + +const std::vector& EightBit::Display::pixels() const { + return m_pixels; +} + +void EightBit::Display::initialise() { + m_pixels.resize(RasterWidth * RasterHeight); +} + +void EightBit::Display::render() { + + auto control = m_bus.peekRegister(Bus::LCDC); + auto on = control & Bus::LcdEnable; + if (on) { + + auto windowArea = (control & Bus::WindowCodeAreaSelection) ? 0x9c00 : 0x9800; + auto window = (control & Bus::WindowEnable) != 0; + auto bgCharacters = (control & Bus::BackgroundCharacterDataSelection) ? 0x8000 : 0x8800; + auto bgArea = (control & Bus::BackgroundCodeAreaSelection) ? 0x9c00 : 0x9800; + auto objBlockHeight = (control & Bus::ObjectBlockCompositionSelection) ? 16 : 8; + auto objEnable = (control & Bus::ObjectEnable) != 0; + auto bgDisplay = (control & Bus::DisplayBackground) != 0; + + auto scrollX = m_bus.peekRegister(Bus::SCX); + auto scrollY = m_bus.peekRegister(Bus::SCY); + + auto paletteRaw = m_bus.peekRegister(Bus::BGP); + std::array palette; + palette[0] = paletteRaw & 0b11; + palette[1] = (paletteRaw & 0b1100) >> 2; + palette[2] = (paletteRaw & 0b110000) >> 4; + palette[3] = (paletteRaw & 0b11000000) >> 6; + + auto wx = m_bus.peekRegister(Bus::WX); + auto wy = m_bus.peekRegister(Bus::WY); + + auto offsetX = window ? wx - 7 : 0; + auto offsetY = window ? wy : 0; + + std::map definitions; + + for (int row = 0; row < BufferCharacterHeight; ++row) { + for (int column = 0; column < BufferCharacterWidth; ++column) { + + auto address = bgArea + row * BufferCharacterWidth + column; + auto character = m_bus.peek(address); + + auto definitionPair = definitions.find(character); + + if (definitionPair == definitions.end()) { + definitions[character] = CharacterDefinition(m_bus, bgCharacters + 16 * character); + definitionPair = definitions.find(character); + } + + auto definition = definitionPair->second; + + for (int cy = 0; cy < 8; ++cy) { + for (int cx = 0; cx < 8; ++cx) { + + uint8_t x = column * 8 + cx + offsetX - scrollX; + if (x >= RasterWidth) + break; + + uint8_t y = row * 8 + cy + offsetY - scrollY; + if (y >= RasterHeight) + break; + + auto outputPixel = y * RasterWidth + x; + + auto colour = palette[definition.get()[cy * 8 + cx]]; + m_pixels[outputPixel] = m_colours->getColour(colour); + } + } + } + } + } +} diff --git a/LR35902/src/LR35902.vcxproj b/LR35902/src/LR35902.vcxproj index d97bb84..a793495 100644 --- a/LR35902/src/LR35902.vcxproj +++ b/LR35902/src/LR35902.vcxproj @@ -139,8 +139,11 @@ + + + @@ -148,6 +151,7 @@ + diff --git a/LR35902/src/LR35902.vcxproj.filters b/LR35902/src/LR35902.vcxproj.filters index bdd2b4b..c1b68a5 100644 --- a/LR35902/src/LR35902.vcxproj.filters +++ b/LR35902/src/LR35902.vcxproj.filters @@ -26,6 +26,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -43,5 +52,8 @@ Source Files + + Source Files + \ No newline at end of file