implemented background tile fetching

This commit is contained in:
Lauchmelder 2022-03-02 14:59:42 +01:00
parent f4e6198a99
commit e7b78f281f
No known key found for this signature in database
GPG key ID: C2403C69D78F011D
9 changed files with 474 additions and 131 deletions

View file

@ -16,9 +16,13 @@ Debugger::Debugger(Bus* bus) :
bus(bus)
{
windows.push_back(new CPUWatcher(this, &bus->cpu));
windows.push_back(new PPUWatcher(this, &bus->ppu));
ppuWatcher = new PPUWatcher(this, &bus->ppu);
windows.push_back(ppuWatcher);
disassembler = new Disassembler(this, &bus->cpu);
windows.push_back(disassembler);
windows.push_back(new MemoryViewer(this, bus));
windows.push_back(new NametableViewer(this, bus));
windows.push_back(new ControllerPortViewer(this, &bus->controllerPort));
@ -37,7 +41,7 @@ bool Debugger::Frame()
while (!bus->ppu.IsFrameDone())
{
bus->Tick();
if (disassembler->BreakpointHit())
if (disassembler->BreakpointHit() || ppuWatcher->BreakpointHit())
{
running = false;
break;
@ -92,13 +96,18 @@ void Debugger::Render()
if (running)
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.7f, 0.7f, 0.7f, 0.7f });
if (ImGui::Button("PPU Tick"))
bus->PPUTick();
ImGui::SameLine();
if (ImGui::Button("Single Step"))
bus->Instruction();
ImGui::SameLine();
if (ImGui::Button("Single Frame"))
bus->Frame();
Frame();
if (running)
ImGui::PopStyleColor();

View file

@ -5,6 +5,7 @@
class Bus;
class Disassembler;
class PPUWatcher;
class Debugger
{
@ -27,4 +28,5 @@ private:
std::vector<DebugWindow*> windows;
Disassembler* disassembler;
PPUWatcher* ppuWatcher;
};

View file

@ -98,7 +98,7 @@ void NametableViewer::DisplayNametable(uint8_t index)
for (Word hi = 0x0; hi <= 0x3F; hi++)
{
Byte hiOffset = hi << 4;
Word hiOffset = hi << 4;
ImGui::TableNextColumn();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f));

View file

@ -1,11 +1,38 @@
#include "PPUWatcher.hpp"
#include <map>
#include <imgui/imgui.h>
#include "../PPU.hpp"
static const std::map<ScanlineType, std::string> scanlineTypeNames = {
{ScanlineType::PreRender, "Pre-render"},
{ScanlineType::Visible, "Visible"},
{ScanlineType::PostRender, "Post-render"},
{ScanlineType::VBlank, "VBlank"}
};
static const std::map<CycleType, std::string> cycleTypeNames = {
{CycleType::Idle, "Idle"},
{CycleType::Fetching, "Fetching BG Tiles"},
{CycleType::SpriteFetching, "Sprite Fetching"},
{CycleType::PreFetching, "Pre-Fetching"},
{CycleType::UnknownFetching, "Random Fetches"}
};
static const std::map<FetchingPhase, std::string> fetchingPhaseNames = {
{FetchingPhase::NametableByte, "Nametable"},
{FetchingPhase::AttributeTableByte, "Attribute Table"},
{FetchingPhase::PatternTableLo, "Pattern Table (lo)"},
{FetchingPhase::PatternTableHi, "Pattern Table (hi)"},
};
PPUWatcher::PPUWatcher(Debugger* debugger, PPU* ppu) :
DebugWindow("PPU Watch", debugger), ppu(ppu)
{
breakpoints.emplace_back(ScanlineType::PreRender, "Pre-Render");
breakpoints.emplace_back(ScanlineType::Visible, "Visible");
breakpoints.emplace_back(ScanlineType::PostRender, "Post-Render");
breakpoints.emplace_back(ScanlineType::VBlank, "VBlank");
}
void PPUWatcher::OnRender()
@ -18,135 +45,205 @@ void PPUWatcher::OnRender()
}
ImGui::Text("On Pixel (%d, %d)", ppu->x, ppu->y);
ImGui::Text("Scanline : %s", scanlineTypeNames.find(ppu->scanlineType)->second.c_str());
ImGui::Text("Cycle : %s", cycleTypeNames.find(ppu->cycleType)->second.c_str());
ImGui::Text("Fetching Phase: %s", fetchingPhaseNames.find(ppu->fetchPhase)->second.c_str());
ImGui::Separator();
if (ImGui::CollapsingHeader("PPUCTRL"))
if (ImGui::CollapsingHeader("Internal Registers"))
{
if (ImGui::BeginTable("ppuctrl", 2))
ImGui::Text("Current VRAM Address (v) : %02X ($%04X)", ppu->current.Raw, 0x2000 | (ppu->current.Raw & 0x0FFF));
if (ImGui::TreeNode("Breakdown (v)"))
{
ImGui::TableNextColumn();
ImGui::Text("Base Nametable Addr");
ImGui::TableNextColumn();
ImGui::Text("$%04X", 0x2000 + 0x400 * ppu->ppuctrl.Flag.BaseNametableAddr);
ImGui::Text("Coarse X : %02X", ppu->current.CoarseX);
ImGui::Text("Coarse Y : %02X", ppu->current.CoarseY);
ImGui::Text("Nametable: %02X", ppu->current.NametableSel);
ImGui::Text("Fine Y : %02X", ppu->current.FineY);
ImGui::TableNextColumn();
ImGui::Text("VRAM Addr Increment");
ImGui::TableNextColumn();
ImGui::Text("%d", ppu->ppuctrl.Flag.VRAMAddrIncrement ? 32 : 1);
ImGui::TreePop();
}
ImGui::TableNextColumn();
ImGui::Text("Sprite Pattern Table Addr");
ImGui::TableNextColumn();
ImGui::Text("$%04X", ppu->ppuctrl.Flag.SpritePatternTableAddr ? 0x1000 : 0x0000);
ImGui::Text("Temporary VRAM Address (t): %02X ($%04X)", ppu->temporary.Raw, 0x2000 | (ppu->current.Raw & 0x0FFF));
if (ImGui::TreeNode("Breakdown (t)"))
{
ImGui::Text("Coarse X : %02X", ppu->temporary.CoarseX);
ImGui::Text("Coarse Y : %02X", ppu->temporary.CoarseY);
ImGui::Text("Nametable: %02X", ppu->temporary.NametableSel);
ImGui::Text("Fine Y : %02X", ppu->temporary.FineY);
ImGui::TableNextColumn();
ImGui::Text("Backgr Pattern Table Addr");
ImGui::TableNextColumn();
ImGui::Text("$%04X", ppu->ppuctrl.Flag.BackgrPatternTableAddr ? 0x1000 : 0x0000);
ImGui::TreePop();
}
ImGui::TableNextColumn();
ImGui::Text("Master/Slave");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppuctrl.Flag.MasterSlaveSelect ? "Output to EXT" : "Read from EXT");
ImGui::Text("Fine X Scroll : %02X", ppu->fineX);
ImGui::Text("Write Toggle Bit : %02X", ppu->addressLatch);
}
ImGui::TableNextColumn();
ImGui::Text("VBlank NMI Generation");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppuctrl.Flag.VBlankNMI ? "On" : "Off");
if (ImGui::CollapsingHeader("Latches"))
{
ImGui::Text("Nametable Byte : %02X", ppu->nametableByte);
ImGui::Text("Attribute Byte : %02X", ppu->attributeTableByte);
ImGui::Text("Pattern Tile Lo: %02X", ppu->patternTableLo);
ImGui::Text("Pattern Tile Hi: %02X", ppu->patternTableHi);
}
if (ImGui::CollapsingHeader("Registers"))
{
if (ImGui::TreeNode("PPUCTRL"))
{
if (ImGui::BeginTable("ppuctrl", 2))
{
ImGui::TableNextColumn();
ImGui::Text("Base Nametable Addr");
ImGui::TableNextColumn();
ImGui::Text("$%04X", 0x2000 + 0x400 * ppu->ppuctrl.Flag.BaseNametableAddr);
ImGui::EndTable();
ImGui::TableNextColumn();
ImGui::Text("VRAM Addr Increment");
ImGui::TableNextColumn();
ImGui::Text("%d", ppu->ppuctrl.Flag.VRAMAddrIncrement ? 32 : 1);
ImGui::TableNextColumn();
ImGui::Text("Sprite Pattern Table Addr");
ImGui::TableNextColumn();
ImGui::Text("$%04X", ppu->ppuctrl.Flag.SpritePatternTableAddr ? 0x1000 : 0x0000);
ImGui::TableNextColumn();
ImGui::Text("Backgr Pattern Table Addr");
ImGui::TableNextColumn();
ImGui::Text("$%04X", ppu->ppuctrl.Flag.BackgrPatternTableAddr ? 0x1000 : 0x0000);
ImGui::TableNextColumn();
ImGui::Text("Master/Slave");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppuctrl.Flag.MasterSlaveSelect ? "Output to EXT" : "Read from EXT");
ImGui::TableNextColumn();
ImGui::Text("VBlank NMI Generation");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppuctrl.Flag.VBlankNMI ? "On" : "Off");
ImGui::EndTable();
ImGui::TreePop();
}
}
if (ImGui::TreeNode("PPUMASK"))
{
if (ImGui::BeginTable("ppumask", 2))
{
ImGui::TableNextColumn();
ImGui::Text("Greyscale");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.Greyscale ? "On" : "Off");
ImGui::TableNextColumn();
ImGui::Text("Left Col Background");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.BackgroundOnLeft ? "Show" : "Hide");
ImGui::TableNextColumn();
ImGui::Text("Left Col Sprites");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.SpriteOnLeft ? "Show" : "Hide");
ImGui::TableNextColumn();
ImGui::Text("Show Background");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.ShowBackground ? "On" : "Off");
ImGui::TableNextColumn();
ImGui::Text("Show Sprites");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.ShowSprites ? "On" : "Off");
ImGui::TableNextColumn();
ImGui::Text("Emphasized Colors");
ImGui::TableNextColumn();
ImGui::Text("%s%s%s", ppu->ppumask.Flag.EmphasizeRed ? "R" : "-", ppu->ppumask.Flag.EmphasizeGreen ? "G" : "-", ppu->ppumask.Flag.EmphasizeBlue ? "B" : "-");
ImGui::EndTable();
ImGui::TreePop();
}
}
if (ImGui::TreeNode("PPUSTATUS"))
{
if (ImGui::BeginTable("ppustatus", 2))
{
ImGui::TableNextColumn();
ImGui::Text("Lower 5 Bits");
ImGui::TableNextColumn();
ImGui::Text("%02X", ppu->ppustatus.Flag.Unused);
ImGui::TableNextColumn();
ImGui::Text("Sprite Overflow");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppustatus.Flag.SpriteOverflow ? "Yes" : "No");
ImGui::TableNextColumn();
ImGui::Text("Sprite 0 Hit");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppustatus.Flag.SpriteZeroHit ? "Yes" : "No");
ImGui::TableNextColumn();
ImGui::Text("VBlank Started");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppustatus.Flag.VBlankStarted ? "Yes" : "No");
ImGui::EndTable();
ImGui::TreePop();
}
}
if (ImGui::TreeNode("PPUSCROLL & PPUADDR"))
{
if (ImGui::BeginTable("ppuscrolladdr", 2))
{
ImGui::TableNextColumn();
ImGui::Text("Scroll X");
ImGui::TableNextColumn();
ImGui::Text("%d", ppu->ppuscroll.x);
ImGui::TableNextColumn();
ImGui::Text("Scroll Y");
ImGui::TableNextColumn();
ImGui::Text("%d", ppu->ppuscroll.x);
ImGui::TableNextColumn();
ImGui::Text("Address");
ImGui::TableNextColumn();
ImGui::Text("$%04X", ppu->ppuaddr.Raw);
ImGui::EndTable();
ImGui::TreePop();
}
}
}
if (ImGui::CollapsingHeader("PPUMASK"))
if (ImGui::CollapsingHeader("Breakpoints"))
{
if (ImGui::BeginTable("ppumask", 2))
ImGui::Text("Break at beginning of");
for (FrameStateBreakpoint& breakpoint : breakpoints)
{
ImGui::TableNextColumn();
ImGui::Text("Greyscale");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.Greyscale ? "On" : "Off");
ImGui::TableNextColumn();
ImGui::Text("Left Col Background");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.BackgroundOnLeft ? "Show" : "Hide");
ImGui::TableNextColumn();
ImGui::Text("Left Col Sprites");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.SpriteOnLeft ? "Show" : "Hide");
ImGui::TableNextColumn();
ImGui::Text("Show Background");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.ShowBackground ? "On" : "Off");
ImGui::TableNextColumn();
ImGui::Text("Show Sprites");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppumask.Flag.ShowSprites ? "On" : "Off");
ImGui::TableNextColumn();
ImGui::Text("Emphasized Colors");
ImGui::TableNextColumn();
ImGui::Text("%s%s%s", ppu->ppumask.Flag.EmphasizeRed ? "R" : "-", ppu->ppumask.Flag.EmphasizeGreen ? "G" : "-", ppu->ppumask.Flag.EmphasizeBlue ? "B" : "-");
ImGui::EndTable();
}
}
if (ImGui::CollapsingHeader("PPUSTATUS"))
{
if (ImGui::BeginTable("ppustatus", 2))
{
ImGui::TableNextColumn();
ImGui::Text("Lower 5 Bits");
ImGui::TableNextColumn();
ImGui::Text("%02X", ppu->ppustatus.Flag.Unused);
ImGui::TableNextColumn();
ImGui::Text("Sprite Overflow");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppustatus.Flag.SpriteOverflow ? "Yes" : "No");
ImGui::TableNextColumn();
ImGui::Text("Sprite 0 Hit");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppustatus.Flag.SpriteZeroHit ? "Yes" : "No");
ImGui::TableNextColumn();
ImGui::Text("VBlank Started");
ImGui::TableNextColumn();
ImGui::Text(ppu->ppustatus.Flag.VBlankStarted ? "Yes" : "No");
ImGui::EndTable();
}
}
if (ImGui::CollapsingHeader("PPUSCROLL & PPUADDR"))
{
if (ImGui::BeginTable("ppuscrolladdr", 2))
{
ImGui::TableNextColumn();
ImGui::Text("Scroll X");
ImGui::TableNextColumn();
ImGui::Text("%d", ppu->ppuscroll.x);
ImGui::TableNextColumn();
ImGui::Text("Scroll Y");
ImGui::TableNextColumn();
ImGui::Text("%d", ppu->ppuscroll.x);
ImGui::TableNextColumn();
ImGui::Text("Address");
ImGui::TableNextColumn();
ImGui::Text("$%04X", ppu->ppuaddr.Raw);
ImGui::EndTable();
ImGui::Checkbox(breakpoint.name.c_str(), &breakpoint.enabled);
}
}
ImGui::End();
}
bool PPUWatcher::BreakpointHit()
{
if (ppu->x > 2)
return false;
for (const FrameStateBreakpoint& breakpoint : breakpoints)
{
if (breakpoint.enabled && breakpoint.location == ppu->scanlineType)
return true;
}
return false;
}

View file

@ -1,8 +1,19 @@
#pragma once
#include <vector>
#include "DebugWindow.hpp"
#include "../PPU.hpp"
class PPU;
struct FrameStateBreakpoint
{
FrameStateBreakpoint(ScanlineType location, const std::string& name) :
location(location), name(name), enabled(false)
{ }
ScanlineType location;
std::string name;
bool enabled;
};
class PPUWatcher :
public DebugWindow
@ -11,7 +22,9 @@ public:
PPUWatcher(Debugger* debugger, PPU* ppu);
virtual void OnRender() override;
bool BreakpointHit();
private:
PPU* ppu;
std::vector<FrameStateBreakpoint> breakpoints;
};