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)
|
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) {
|
for (auto& memory_space : m_memory_spaces) {
|
||||||
auto& memory = memory_space.second;
|
auto& memory = memory_space.second;
|
||||||
if (address >= memory.start_address && address <= memory.end_address) {
|
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
|
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) {
|
for (const auto& memory_space : m_memory_spaces) {
|
||||||
const auto& memory = memory_space.second;
|
const auto& memory = memory_space.second;
|
||||||
if (address >= memory.start_address && address <= memory.end_address) {
|
if (address >= memory.start_address && address <= memory.end_address) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include <cstdint> // uint32_t
|
#include <cstdint> // uint32_t
|
||||||
#include <memory> // std::shared_ptr
|
#include <memory> // std::shared_ptr
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
+61
-6
@@ -18,10 +18,15 @@
|
|||||||
|
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "ppu.h"
|
#include "ppu.h"
|
||||||
|
#include "ruc/meta/assert.h"
|
||||||
|
|
||||||
PPU ::PPU(uint32_t frequency)
|
PPU ::PPU(uint32_t frequency)
|
||||||
: ProcessingUnit(frequency)
|
: ProcessingUnit(frequency)
|
||||||
{
|
{
|
||||||
|
m_shared_registers.emplace("LY", &m_lcd_y_coordinate);
|
||||||
|
|
||||||
|
// Setup screen
|
||||||
|
|
||||||
auto& scene = Inferno::Application::the().scene();
|
auto& scene = Inferno::Application::the().scene();
|
||||||
m_entity = scene.createEntity("Screen");
|
m_entity = scene.createEntity("Screen");
|
||||||
|
|
||||||
@@ -46,12 +51,54 @@ void PPU::update()
|
|||||||
|
|
||||||
// print("PPU update\n");
|
// print("PPU update\n");
|
||||||
|
|
||||||
// Increment LY (LCD Y Coordinate)
|
m_clocks_into_frame++;
|
||||||
uint32_t ly_register = Emu::the().readMemory(0xff44) + 1;
|
|
||||||
if (ly_register >= 154) {
|
switch (m_state) {
|
||||||
ly_register = 0;
|
case State::OAMSearch:
|
||||||
}
|
// OAM logic goes here..
|
||||||
Emu::the().writeMemory(0xff44, ly_register);
|
|
||||||
|
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()
|
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;
|
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(uint32_t frequency);
|
||||||
~PPU();
|
~PPU();
|
||||||
|
|
||||||
|
enum State : uint8_t {
|
||||||
|
OAMSearch,
|
||||||
|
PixelTransfer,
|
||||||
|
HBlank,
|
||||||
|
VBlank,
|
||||||
|
};
|
||||||
|
|
||||||
void update() override;
|
void update() override;
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
void drawTile(uint32_t screen_x, uint32_t screen_y, uint32_t tile_address, uint8_t bg_palette);
|
void drawTile(uint32_t screen_x, uint32_t screen_y, uint32_t tile_address, uint8_t bg_palette);
|
||||||
|
void resetFrame();
|
||||||
|
|
||||||
private:
|
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;
|
uint32_t m_entity;
|
||||||
std::array<uint8_t, SCREEN_WIDTH * FORMAT_SIZE * SCREEN_HEIGHT> m_screen;
|
std::array<uint8_t, SCREEN_WIDTH * FORMAT_SIZE * SCREEN_HEIGHT> m_screen;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user