Emulator: Add state machine to PPU
This commit is contained in:
+17
@@ -64,6 +64,16 @@ void Emu::removeMemorySpace(std::string_view name)
|
||||
|
||||
void Emu::writeMemory(uint32_t address, uint32_t value)
|
||||
{
|
||||
// Bail if the CPU tries to write to a read-only address
|
||||
switch (address) {
|
||||
case 0xff44:
|
||||
ruc::error("writing to read-only address: {:#06x}", address);
|
||||
VERIFY_NOT_REACHED();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto& memory_space : m_memory_spaces) {
|
||||
auto& memory = memory_space.second;
|
||||
if (address >= memory.start_address && address <= memory.end_address) {
|
||||
@@ -96,6 +106,13 @@ void Emu::writeMemory(uint32_t address, uint32_t value)
|
||||
|
||||
uint32_t Emu::readMemory(uint32_t address) const
|
||||
{
|
||||
switch (address) {
|
||||
case 0xff44:
|
||||
return *m_processing_units.at("PPU")->sharedRegister("LY");
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
for (const auto& memory_space : m_memory_spaces) {
|
||||
const auto& memory = memory_space.second;
|
||||
if (address >= memory.start_address && address <= memory.end_address) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <cstdint> // uint32_t
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
+61
-6
@@ -18,10 +18,15 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "ppu.h"
|
||||
#include "ruc/meta/assert.h"
|
||||
|
||||
PPU ::PPU(uint32_t frequency)
|
||||
: ProcessingUnit(frequency)
|
||||
{
|
||||
m_shared_registers.emplace("LY", &m_lcd_y_coordinate);
|
||||
|
||||
// Setup screen
|
||||
|
||||
auto& scene = Inferno::Application::the().scene();
|
||||
m_entity = scene.createEntity("Screen");
|
||||
|
||||
@@ -46,12 +51,54 @@ void PPU::update()
|
||||
|
||||
// print("PPU update\n");
|
||||
|
||||
// Increment LY (LCD Y Coordinate)
|
||||
uint32_t ly_register = Emu::the().readMemory(0xff44) + 1;
|
||||
if (ly_register >= 154) {
|
||||
ly_register = 0;
|
||||
}
|
||||
Emu::the().writeMemory(0xff44, ly_register);
|
||||
m_clocks_into_frame++;
|
||||
|
||||
switch (m_state) {
|
||||
case State::OAMSearch:
|
||||
// OAM logic goes here..
|
||||
|
||||
if (m_clocks_into_frame % 20 == 0) {
|
||||
m_state = State::PixelTransfer;
|
||||
}
|
||||
break;
|
||||
case State::PixelTransfer:
|
||||
// PixelTransfer logic goes here..
|
||||
m_lcd_x_coordinate++;
|
||||
|
||||
if (m_lcd_x_coordinate == 160) {
|
||||
m_lcd_x_coordinate = 0;
|
||||
m_state = State::HBlank;
|
||||
}
|
||||
break;
|
||||
case State::HBlank:
|
||||
// H-Blank logic goes here..
|
||||
|
||||
if (m_clocks_into_frame % (20 + 43 + 51) == 0) {
|
||||
if (m_lcd_y_coordinate == 144) {
|
||||
m_state = State::VBlank;
|
||||
}
|
||||
else {
|
||||
m_state = State::OAMSearch;
|
||||
}
|
||||
m_lcd_y_coordinate++;
|
||||
}
|
||||
break;
|
||||
case State::VBlank:
|
||||
// V-Blank logic goes here..
|
||||
|
||||
if (m_clocks_into_frame % (20 + 43 + 51) == 0) {
|
||||
if (m_lcd_y_coordinate == 154) {
|
||||
m_lcd_y_coordinate = 0;
|
||||
m_clocks_into_frame = 0;
|
||||
m_state = State::OAMSearch;
|
||||
}
|
||||
m_lcd_y_coordinate++;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
}
|
||||
|
||||
void PPU::render()
|
||||
@@ -141,3 +188,11 @@ void PPU::drawTile(uint32_t x, uint32_t y, uint32_t tile_address, uint8_t bg_pal
|
||||
screen_index += SCREEN_WIDTH * FORMAT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::resetFrame()
|
||||
{
|
||||
m_state = State::OAMSearch;
|
||||
m_clocks_into_frame = 0;
|
||||
m_lcd_x_coordinate = 0;
|
||||
m_lcd_y_coordinate = 0;
|
||||
}
|
||||
|
||||
@@ -38,12 +38,25 @@ public:
|
||||
PPU(uint32_t frequency);
|
||||
~PPU();
|
||||
|
||||
enum State : uint8_t {
|
||||
OAMSearch,
|
||||
PixelTransfer,
|
||||
HBlank,
|
||||
VBlank,
|
||||
};
|
||||
|
||||
void update() override;
|
||||
void render();
|
||||
|
||||
void drawTile(uint32_t screen_x, uint32_t screen_y, uint32_t tile_address, uint8_t bg_palette);
|
||||
void resetFrame();
|
||||
|
||||
private:
|
||||
State m_state { State::OAMSearch };
|
||||
uint32_t m_clocks_into_frame { 0 };
|
||||
uint32_t m_lcd_x_coordinate { 0 };
|
||||
uint32_t m_lcd_y_coordinate { 0 }; // Note: includes V-Blank
|
||||
|
||||
uint32_t m_entity;
|
||||
std::array<uint8_t, SCREEN_WIDTH * FORMAT_SIZE * SCREEN_HEIGHT> m_screen;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user