Compare commits

..

5 commits

Author SHA1 Message Date
Robert 6504148654 add logger module 2023-01-30 17:14:20 +01:00
Robert f495a88081 add prototype for mapper 01 2023-01-30 15:46:43 +01:00
Robert 57e0eb2fbe remove ini files 2023-01-29 20:02:20 +01:00
Robert e9264127c5 add framerate limiter 2023-01-29 17:42:46 +01:00
Robert 9ce2fa6124 supply rom as cmd line argument 2023-01-28 03:41:04 +01:00
14 changed files with 170 additions and 15 deletions

1
.gitignore vendored
View file

@ -4,6 +4,7 @@
out/
build/
*.json
*.ini
*.nes
!roms/nestest.nes

View file

@ -5,6 +5,9 @@ cmake_minimum_required (VERSION 3.8)
project ("NES Emulator")
set(CMAKE_CXX_STANDARD_REQUIRED 17)
set(CMAKE_CXX_STANDARD 17)
find_package(glfw3)
if(NOT glfw3_FOUND)
add_subdirectory("vendor/glfw")

View file

@ -14,14 +14,14 @@
#include "Debugger.hpp"
#include "gfx/Window.hpp"
void Application::Launch()
void Application::Launch(const char* rom)
{
glfwInit();
Application* app = nullptr;
try
{
app = new Application;
app = new Application(rom);
}
catch (const std::runtime_error& err)
{
@ -43,7 +43,7 @@ void Application::Launch()
glfwTerminate();
}
Application::Application() :
Application::Application(const char* rom) :
bus(nullptr), window(nullptr)
{
LOG_CORE_INFO("Creating window");
@ -93,7 +93,7 @@ Application::Application() :
throw err;
}
bus = new Bus(screen);
bus = new Bus(rom, screen);
debugger = new Debugger(bus);
}
@ -140,5 +140,13 @@ bool Application::Update()
debugger->Render();
window->End();
std::chrono::microseconds frametime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - lastFrameTime);
lastFrameTime = std::chrono::steady_clock::now();
if (frametime < std::chrono::microseconds(1000000 / 60)) {
std::this_thread::sleep_for(std::chrono::microseconds(1000000 / 60) - frametime);
}
return !window->ShouldClose();
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <chrono>
class Bus;
class Window;
class Debugger;
@ -14,10 +16,10 @@ public:
/**
* @brief Create and launch a new application.
*/
static void Launch();
static void Launch(const char* rom);
private:
Application();
Application(const char* rom);
~Application();
/**
@ -33,4 +35,6 @@ private:
Bus* bus;
Screen* screen;
Debugger* debugger;
std::chrono::steady_clock::time_point lastFrameTime;
};

View file

@ -5,7 +5,7 @@
#include "controllers/StandardController.hpp"
Bus::Bus(Screen* screen) :
Bus::Bus(const char* rom, Screen* screen) :
cpu(this), ppu(this, screen), apu(this), cartridge(this)
{
LOG_CORE_INFO("Allocating RAM");
@ -16,7 +16,7 @@ Bus::Bus(Screen* screen) :
palettes = std::vector<Byte>(0x20, 0);
LOG_CORE_INFO("Inserting cartridge");
cartridge.Load("roms/mario.nes");
cartridge.Load(rom);
LOG_CORE_INFO("Powering up CPU");
cpu.Powerup();

View file

@ -25,7 +25,7 @@ class Bus
friend class Palettes;
public:
Bus(Screen* screen);
Bus(const char* rom, Screen* screen);
/**
* @brief Reboot the NES.

View file

@ -7,13 +7,26 @@ add_executable(nesemu
"mappers/Mapper000.cpp"
"Log.cpp"
"PPU.cpp"
"APU.cpp"
"gfx/Window.cpp"
"gfx/Input.cpp"
"gfx/Screen.cpp"
"debugger/CPUWatcher.cpp"
"debugger/Debugger.cpp"
"debugger/PPUWatcher.cpp"
"debugger/Disassembler.cpp"
"debugger/MemoryViewer.cpp"
"debugger/NametableViewer.cpp" "ControllerPort.cpp" "controllers/StandardController.cpp" "gfx/Input.cpp" "debugger/ControllerPortViewer.cpp" "gfx/Screen.cpp" "debugger/Palettes.cpp" "APU.cpp" "debugger/PatternTableViewer.cpp" "mappers/Mapper003.cpp" "mappers/Mapper001.cpp" "debugger/OAMViewer.cpp")
"debugger/NametableViewer.cpp"
"debugger/ControllerPortViewer.cpp"
"debugger/PatternTableViewer.cpp"
"debugger/OAMViewer.cpp"
"debugger/Palettes.cpp"
"debugger/Logger.cpp"
"ControllerPort.cpp"
"controllers/StandardController.cpp"
"mappers/Mapper003.cpp"
"mappers/Mapper001.cpp"
)
target_include_directories(nesemu PRIVATE
mappers

View file

@ -14,6 +14,7 @@
#include "PatternTableViewer.hpp"
#include "ControllerPortViewer.hpp"
#include "Palettes.hpp"
#include "Logger.hpp"
Debugger::Debugger(Bus* bus) :
bus(bus)
@ -32,6 +33,9 @@ Debugger::Debugger(Bus* bus) :
windows.push_back(new PatternTableViewer(this, bus->cartridge.GetMapper()));
windows.push_back(new ControllerPortViewer(this, &bus->controllerPort));
windows.push_back(new Palettes(this, bus));
Logger::Init(this);
windows.push_back(Logger::GetInstance());
}
Debugger::~Debugger()
@ -42,6 +46,7 @@ Debugger::~Debugger()
bool Debugger::Frame()
{
Logger::GetInstance()->Log("Debugger", "Frame!\n");
try
{
while (!bus->ppu.IsFrameDone())
@ -61,7 +66,7 @@ bool Debugger::Frame()
return true;
}
return false;
return true;
}
bool Debugger::Update()
@ -161,6 +166,10 @@ void Debugger::Render()
ImGui::InputScalar("Reset Vector", ImGuiDataType_U16, &resetVector, (const void*)0, (const void*)0, "%04X", ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::Separator();
ImGui::Text("FPS: %f", ImGui::GetIO().Framerate);
for (DebugWindow* window : windows)
{
if (window->isOpen) window->OnRender();

80
src/debugger/Logger.cpp Normal file
View file

@ -0,0 +1,80 @@
#include "Logger.hpp"
#include <imgui/imgui.h>
Logger::Logger(Debugger* debugger) :
DebugWindow("Log", debugger), autoScroll(true)
{
buffer.clear();
offsets.clear();
offsets.push_back(0);
}
void Logger::Init(Debugger* debugger)
{
if (Logger::instance != nullptr) {
return;
}
Logger::instance = new Logger(debugger);
}
void Logger::Log(const char* module, const char* fmt, ...)
{
int old_size = buffer.size();
va_list args;
va_start(args, fmt);
buffer.appendf("[%s] ", module);
buffer.appendfv(fmt, args);
va_end(args);
for (int new_size = buffer.size(); old_size < new_size; old_size++) {
if (buffer[old_size] == '\n') {
offsets.push_back(old_size + 1);
}
}
}
void Logger::OnRender()
{
ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(title.c_str(), &isOpen)) {
ImGui::End();
return;
}
if (ImGui::BeginPopup("Options")) {
ImGui::Checkbox("Auto scroll", &autoScroll);
ImGui::EndPopup();
}
if (ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
const char* buf = buffer.begin();
const char* buf_end = buffer.end();
ImGuiListClipper clipper;
clipper.Begin((int)offsets.size());
while (clipper.Step())
{
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
{
const char* line_start = buf + offsets[line_no];
const char* line_end = (line_no + 1 < offsets.size()) ? (buf + offsets[line_no + 1] - 1) : buf_end;
ImGui::TextUnformatted(line_start, line_end);
}
}
clipper.End();
ImGui::PopStyleVar();
if (autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
ImGui::SetScrollHereY(1.0f);
}
ImGui::EndChild();
ImGui::End();
}

29
src/debugger/Logger.hpp Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include <vector>
#include <imgui/imgui.h>
#include "DebugWindow.hpp"
class Logger final:
public DebugWindow
{
public:
static void Init(Debugger* debugger);
static Logger* GetInstance() {
return instance;
}
void Log(const char* module, const char* fmt, ...);
virtual void OnRender() override;
private:
Logger(Debugger* debugger);
private:
inline static Logger* instance = nullptr;
ImGuiTextBuffer buffer;
std::vector<int> offsets;
bool autoScroll;
};

View file

@ -11,6 +11,7 @@ Window::Window(uint16_t width, uint16_t height, const std::string& title) :
handle(nullptr)
{
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
handle = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
if (handle == nullptr)
{
@ -20,6 +21,7 @@ Window::Window(uint16_t width, uint16_t height, const std::string& title) :
}
glfwMakeContextCurrent(handle);
glfwSwapInterval(0);
Input::SetWindow(this);
}

View file

@ -1,10 +1,16 @@
#include "Application.hpp"
#include "Log.hpp"
int main()
int main(int argc, char** argv)
{
Log::Init();
Application::Launch();
if (argc != 2) {
LOG_CORE_FATAL("Usage: {0} <rom>", argv[0]);
return -1;
}
Application::Launch(argv[1]);
return 0;
}

View file

@ -36,7 +36,7 @@ Byte Mapper001::ReadCPU(Word addr)
break;
}
return PRG_ROM[addr & (0x4000 * selectedBank - 1)];
return PRG_ROM[(addr & (0x4000 * selectedBank - 1)) & 0x7FFF];
}
return 0x00;

2
vendor/imgui vendored

@ -1 +1 @@
Subproject commit 8639a2f9f8d6d53f4c7a221579de5871051153d9
Subproject commit 88dfd85e9296fc03ac858f66cc6507ba443294ef