Adding SDL window with static noise, generated by PPU

This commit is contained in:
Selim Mustafaev 2023-08-24 23:07:27 +03:00
parent 7a954c705e
commit db3b744ab2
7 changed files with 90 additions and 35 deletions

View File

@ -1,28 +1,28 @@
#include "src/Nes.h" #include "src/Nes.h"
#include <iostream> #include "src/Window.h"
#include <sstream>
#include <functional>
#include <chrono>
#include <thread>
int main() { int main() {
using namespace std::placeholders;
nes::Nes device; nes::Nes device;
nes::SdlWindow window(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT);
// std::stringstream ss; device.setNewFrameCallback(std::bind(&nes::SdlWindow::drawFrame, &window, _1));
// ss << "A2 0A 8E 00 00 A2 03 8E 01 00 AC 00 00 A9 00 18 6D 01 00 88 D0 FA 8D 02 00 EA EA EA"; device.insertCartridge("/home/selim/Downloads/nestest.nes");
// uint16_t nOffset = 0x8000;
// while (!ss.eof())
// {
// std::string b;
// ss >> b;
// device.write(nOffset++, (uint8_t)std::stoul(b, nullptr, 16));
// }
//
// // Set Reset Vector
// device.write(0xFFFC, 0x00);
// device.write(0xFFFD, 0x80);
//
// device.reset();
device.runRom("/home/selim/Downloads/nestest.nes", 0xC000); uint64_t cycles = 0;
while (cycles < 1000000000) {
device.tick();
cycles++;
//int64_t us = static_cast<int64_t>(1000000000.0/(60*nes::Ppu::SCREEN_WIDTH*nes::Ppu::SCREEN_HEIGHT));
//std::this_thread::sleep_for(std::chrono::nanoseconds(1));
}
return 0; return 0;
} }

View File

@ -17,7 +17,7 @@ namespace nes {
return _ram[address & 0x07FF]; return _ram[address & 0x07FF];
} }
else if(address >= 0x2000 && address < 0x4000) { else if(address >= 0x2000 && address < 0x4000) {
std::cout << "PPU read at address: " << address << std::endl; //std::cout << "PPU read at address: " << address << std::endl;
return _ppu->read(address & 0x0007); return _ppu->read(address & 0x0007);
} }
else if(address >= 0x8000) { else if(address >= 0x8000) {

View File

@ -6,15 +6,16 @@
#include "Cartridge.h" #include "Cartridge.h"
#include "Cpu.h" #include "Cpu.h"
#include <iostream> #include <utility>
namespace nes { namespace nes {
Nes::Nes() { Nes::Nes(): _cycles{} {
_cpu = std::make_unique<Cpu>(); _cpu = std::make_unique<Cpu>();
_ppu = std::make_shared<Ppu>();
} }
void Nes::runRom(const fs::path &path, std::optional<uint16_t> address) { void Nes::insertCartridge(const fs::path &path, std::optional<uint16_t> address) {
_cartridge = std::make_shared<Cartridge>(path); _cartridge = std::make_shared<Cartridge>(path);
_cpu->bus()->connect(_cartridge); _cpu->bus()->connect(_cartridge);
_cpu->bus()->connect(_ppu); _cpu->bus()->connect(_ppu);
@ -23,21 +24,21 @@ namespace nes {
void Nes::reset(std::optional<uint16_t> address) { void Nes::reset(std::optional<uint16_t> address) {
_cpu->reset(); _cpu->reset();
if(address) { if(address) {
_cpu->setStartAddress(address.value()); _cpu->setStartAddress(address.value());
} }
}
size_t ticks = 0; void Nes::setNewFrameCallback(std::function<void(const Pixel *)> onNewFrame) {
while (ticks <= 15000) { _ppu->onNewFrame = std::move(onNewFrame);
}
void Nes::tick() {
_ppu->tick(); _ppu->tick();
if(ticks % 3 == 0) { if(_cycles % 3 == 0) {
_cpu->tick(); _cpu->tick();
} }
ticks++; _cycles++;
}
std::cout << "The end" << std::endl;
} }
} }

View File

@ -19,10 +19,13 @@ namespace nes {
class Nes { class Nes {
public: public:
Nes(); Nes();
void runRom(const fs::path& path, std::optional<uint16_t> address = std::nullopt); void insertCartridge(const fs::path& path, std::optional<uint16_t> address = std::nullopt);
void reset(std::optional<uint16_t> address = std::nullopt); void reset(std::optional<uint16_t> address = std::nullopt);
void setNewFrameCallback(std::function<void(const Pixel*)> onNewFrame);
void tick();
private: private:
uint64_t _cycles;
std::unique_ptr<Cpu> _cpu; std::unique_ptr<Cpu> _cpu;
std::shared_ptr<Ppu> _ppu; std::shared_ptr<Ppu> _ppu;
std::shared_ptr<Cartridge> _cartridge; std::shared_ptr<Cartridge> _cartridge;

View File

@ -12,7 +12,12 @@ namespace nes {
void Ppu::tick() { void Ppu::tick() {
setPixel(_scanline, _column, {}); if(_column < SCREEN_WIDTH && _scanline < SCREEN_HEIGHT && _scanline >= 0) {
Pixel black = {0, 0, 0, 100};
Pixel white = {255, 255, 255, 100};
Pixel pixel = std::rand() % 2 == 0 ? black : white;
setPixel(_scanline, _column, pixel);
}
_column++; _column++;
if(_column >= 341) { if(_column >= 341) {

View File

@ -6,4 +6,26 @@
namespace nes { namespace nes {
SdlWindow::SdlWindow(uint16_t width, uint16_t height): _width(width), _height(height) {
int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
if(res < 0) throw std::runtime_error("Error initializing SDL");
Uint32 flags = SDL_WINDOW_ALLOW_HIGHDPI; //| SDL_WINDOW_VULKAN | SDL_WINDOW_METAL;
_wnd.reset(SDL_CreateWindow("NES", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags));
if(!_wnd) throw std::runtime_error("Error creating SDL window");
_renderer.reset(SDL_CreateRenderer(_wnd.get(), -1, 0));
if(!_renderer) throw std::runtime_error("Error creating SDL renderer");
_texture.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height));
if(!_texture) throw std::runtime_error("Error creating SDL texture");
}
void SdlWindow::drawFrame(const Pixel *buffer) {
int pitch = static_cast<int>(_width*sizeof(Pixel));
SDL_UpdateTexture(_texture.get(), nullptr, buffer, pitch);
SDL_RenderClear(_renderer.get());
SDL_RenderCopy(_renderer.get(), _texture.get(), nullptr, nullptr);
SDL_RenderPresent(_renderer.get());
}
} }

View File

@ -5,12 +5,36 @@
#ifndef NES_WINDOW_H #ifndef NES_WINDOW_H
#define NES_WINDOW_H #define NES_WINDOW_H
#include "Ppu.h"
#include <SDL.h> #include <SDL.h>
#include <memory>
namespace nes { namespace nes {
class Window { class SdlWindow {
public:
struct SdlDeleter {
void operator()(SDL_Window* ptr) { SDL_DestroyWindow(ptr); }
void operator()(SDL_Renderer* ptr) { SDL_DestroyRenderer(ptr); }
void operator()(SDL_Texture* ptr) { SDL_DestroyTexture(ptr); }
};
template<typename T> using SdlUniquePtr = std::unique_ptr<T, SdlDeleter>;
using SdlWindowPtr = SdlUniquePtr<SDL_Window>;
using SdlRendererPtr = SdlUniquePtr<SDL_Renderer>;
using SdlTexturePtr = SdlUniquePtr<SDL_Texture>;
public:
SdlWindow(uint16_t width, uint16_t height);
void drawFrame(const Pixel* buffer);
private:
uint16_t _width;
uint16_t _height;
SdlWindowPtr _wnd;
SdlRendererPtr _renderer;
SdlTexturePtr _texture;
}; };
} }