Adding controller.
Adding logging. Fixing lots of bugs.
This commit is contained in:
parent
40c7ff5882
commit
796828fa01
@ -22,7 +22,7 @@ add_executable(nes
|
||||
src/Window.cpp
|
||||
src/Window.h
|
||||
src/Shifter.cpp
|
||||
src/Shifter.h)
|
||||
src/Shifter.h src/Logger.cpp src/Logger.h src/Controller.cpp src/Controller.h src/SdlKeyboardController.cpp src/SdlKeyboardController.h)
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
|
||||
6
main.cpp
6
main.cpp
@ -1,5 +1,6 @@
|
||||
#include "src/Nes.h"
|
||||
#include "src/Window.h"
|
||||
#include "src/SdlKeyboardController.h"
|
||||
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
@ -14,9 +15,10 @@ int main() {
|
||||
window.setSize(nes::Ppu::SCREEN_WIDTH * 4, nes::Ppu::SCREEN_HEIGHT * 4);
|
||||
|
||||
device.setNewFrameCallback(std::bind(&nes::SdlWindow::drawFrame, &window, _1));
|
||||
//device.insertCartridge("/home/selim/Downloads/nestest.nes");
|
||||
device.connect(std::make_shared<SdlKeyboardController>());
|
||||
device.insertCartridge("/home/selim/Downloads/smb.nes");
|
||||
//device.insertCartridge("/Users/selim/Documents/nestest.nes");
|
||||
device.insertCartridge("C:\\Users\\selim\\Documents\\nestest.nes");
|
||||
//device.insertCartridge("C:\\Users\\selim\\Documents\\nestest.nes");
|
||||
|
||||
SDL_Event e;
|
||||
uint64_t cycles = 0;
|
||||
|
||||
21
src/Bus.cpp
21
src/Bus.cpp
@ -23,6 +23,9 @@ namespace nes {
|
||||
else if(address >= 0x8000) {
|
||||
return _cartridge->readPrg(address);
|
||||
}
|
||||
else if(address == 0x4016) {
|
||||
return _controller1->read();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -37,6 +40,9 @@ namespace nes {
|
||||
else if(address >= 0x8000) {
|
||||
std::cout << "Cartridge write at address: " << address << std::endl;
|
||||
}
|
||||
else if(address == 0x4016) {
|
||||
_controller1->poll();
|
||||
}
|
||||
}
|
||||
|
||||
void Bus::connect(std::shared_ptr<Cartridge> cartridge) {
|
||||
@ -46,4 +52,19 @@ namespace nes {
|
||||
void Bus::connect(std::shared_ptr<Ppu> ppu) {
|
||||
_ppu = std::move(ppu);
|
||||
}
|
||||
|
||||
void Bus::connect(std::shared_ptr<Controller> controller) {
|
||||
_controller1 = std::move(controller);
|
||||
}
|
||||
|
||||
// For debug
|
||||
// Calc "hash" - just sum of the bytes of first page
|
||||
// Can be useful for detecting change in ram
|
||||
uint32_t Bus::zpHash() const {
|
||||
uint32_t sum = 0;
|
||||
for(size_t i = 0; i < 2048; ++i) {
|
||||
sum += _ram[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "Cartridge.h"
|
||||
#include "Ppu.h"
|
||||
#include "Controller.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@ -20,11 +21,14 @@ namespace nes {
|
||||
void write(uint16_t address, uint8_t value);
|
||||
void connect(std::shared_ptr<Cartridge> cartridge);
|
||||
void connect(std::shared_ptr<Ppu> ppu);
|
||||
void connect(std::shared_ptr<Controller> controller);
|
||||
[[nodiscard]] uint32_t zpHash() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> _ram;
|
||||
std::shared_ptr<Cartridge> _cartridge;
|
||||
std::shared_ptr<Ppu> _ppu;
|
||||
std::shared_ptr<Controller> _controller1;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
18
src/Controller.cpp
Normal file
18
src/Controller.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by selim on 9/17/23.
|
||||
//
|
||||
|
||||
#include "Controller.h"
|
||||
|
||||
namespace nes {
|
||||
|
||||
Controller::Controller(): _data{} {
|
||||
|
||||
}
|
||||
|
||||
uint8_t Controller::read() {
|
||||
uint8_t result = (_data & 0x80) > 0;
|
||||
_data <<= 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
36
src/Controller.h
Normal file
36
src/Controller.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Created by selim on 9/17/23.
|
||||
//
|
||||
|
||||
#ifndef NES_CONTROLLER_H
|
||||
#define NES_CONTROLLER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace nes {
|
||||
|
||||
class Controller {
|
||||
public:
|
||||
enum Key: uint8_t {
|
||||
A = 7,
|
||||
B = 6,
|
||||
Select = 5,
|
||||
Start = 4,
|
||||
Up = 3,
|
||||
Down = 2,
|
||||
Left = 1,
|
||||
Right = 0
|
||||
};
|
||||
|
||||
public:
|
||||
Controller();
|
||||
uint8_t read();
|
||||
virtual void poll() = 0;
|
||||
|
||||
protected:
|
||||
uint8_t _data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //NES_CONTROLLER_H
|
||||
37
src/Cpu.cpp
37
src/Cpu.cpp
@ -75,7 +75,7 @@ namespace nes {
|
||||
_instructions[0xD0] = {"BNE", &Cpu::BNE, &Cpu::REL, 2, false};
|
||||
_instructions[0x81] = {"STA", &Cpu::STA, &Cpu::IZX, 6, false};
|
||||
_instructions[0x8D] = {"STA", &Cpu::STA, &Cpu::ABS, 4, false};
|
||||
_instructions[0x91] = {"STA", &Cpu::STA, &Cpu::IZY, 5, true};
|
||||
_instructions[0x91] = {"STA", &Cpu::STA, &Cpu::IZY, 6, false};
|
||||
_instructions[0x95] = {"STA", &Cpu::STA, &Cpu::ZPX, 4, false};
|
||||
_instructions[0x99] = {"STA", &Cpu::STA, &Cpu::ABY, 5, false};
|
||||
_instructions[0x9D] = {"STA", &Cpu::STA, &Cpu::ABX, 5, false};
|
||||
@ -174,34 +174,36 @@ namespace nes {
|
||||
uint16_t hi = _bus->read(0xFFFD);
|
||||
|
||||
PC = (hi << 8) | lo;
|
||||
|
||||
_ticks = 8;
|
||||
}
|
||||
|
||||
void Cpu::tick() {
|
||||
bool Cpu::tick() {
|
||||
bool executed = false;
|
||||
|
||||
if(_ticks == 0) {
|
||||
uint8_t opcode = _bus->read(PC++);
|
||||
auto instruction = _instructions[opcode];
|
||||
_currentOpcode = opcode;
|
||||
|
||||
if(instruction.getAddress == nullptr) {
|
||||
std::cout << "Unknown instruction: " << (int)opcode << std::endl;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto args = (this->*instruction.getAddress)();
|
||||
(this->*instruction.process)(args);
|
||||
|
||||
// auto str = std::format("{} ({:02X}), PC: {:X}, SP: {:X}, A: {:02X}, X: {:02X}, Y: {:02X}, [N:{}, V:{}, B{}, D{}, I{}, Z:{}, C:{}]", instruction.name, opcode, PC, SP, A, X, Y,
|
||||
// (int)getFlag(Negative), (int)getFlag(Overflow), (int)getFlag(Break), (int)getFlag(DecimalMode), (int)getFlag(InterruptDisable), (int)getFlag(Zero), (int)getFlag(Carry));
|
||||
// std::cout << str << std::endl;
|
||||
|
||||
//std::cout << instruction.name << std::hex << ", OpCode: " << (int)opcode << ", PC: " << (int)PC << ", SP: " << (int)SP << ", A: " << (int)A << ", X: " << (int)X << ", Y: " << (int)Y << std::endl;
|
||||
|
||||
_ticks = instruction.cycles;
|
||||
_ticks += instruction.cycles;
|
||||
if(instruction.variableCycles) {
|
||||
_ticks += args.cycles;
|
||||
}
|
||||
|
||||
executed = true;
|
||||
}
|
||||
|
||||
_ticks--;
|
||||
return executed;
|
||||
}
|
||||
|
||||
void Cpu::nmi() {
|
||||
@ -220,6 +222,21 @@ namespace nes {
|
||||
_ticks = 8;
|
||||
}
|
||||
|
||||
std::string Cpu::state() const {
|
||||
return std::format("{} ({:02X}), PC: {:X}, SP: {:X}, A: {:02X}, X: {:02X}, Y: {:02X}, [N:{}, V:{}, B{}, D{}, I{}, Z:{}, C:{}], H: {:08X}",
|
||||
_instructions[_currentOpcode].name,
|
||||
_currentOpcode,
|
||||
PC, SP, A, X, Y,
|
||||
(int)getFlag(Negative),
|
||||
(int)getFlag(Overflow),
|
||||
(int)getFlag(Break),
|
||||
(int)getFlag(DecimalMode),
|
||||
(int)getFlag(InterruptDisable),
|
||||
(int)getFlag(Zero),
|
||||
(int)getFlag(Carry),
|
||||
_bus->zpHash());
|
||||
}
|
||||
|
||||
void Cpu::setFlag(CpuFlags flag, bool value) {
|
||||
if(value) {
|
||||
flags |= flag;
|
||||
|
||||
@ -42,12 +42,13 @@ namespace nes {
|
||||
public:
|
||||
Cpu();
|
||||
void reset();
|
||||
void tick();
|
||||
bool tick();
|
||||
void setFlag(CpuFlags flag, bool value);
|
||||
bool getFlag(CpuFlags flag) const;
|
||||
void setStartAddress(uint16_t address);
|
||||
Bus* bus() const;
|
||||
void nmi();
|
||||
std::string state() const;
|
||||
|
||||
private:
|
||||
size_t _ticks;
|
||||
@ -64,6 +65,10 @@ namespace nes {
|
||||
uint8_t SP; // Stack Pointer
|
||||
uint8_t flags;
|
||||
|
||||
private:
|
||||
// Debug info
|
||||
uint8_t _currentOpcode;
|
||||
|
||||
private:
|
||||
void branch(InstructionArgs args);
|
||||
|
||||
|
||||
35
src/Logger.cpp
Normal file
35
src/Logger.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by selim on 9/16/23.
|
||||
//
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <format>
|
||||
|
||||
namespace nes {
|
||||
|
||||
Logger::Logger(size_t size): _size{size}, _offset{0} {
|
||||
_data = std::make_unique<uint8_t[]>(size);
|
||||
}
|
||||
|
||||
void Logger::addLine(uint64_t cycle, std::string_view line) {
|
||||
if((_offset + line.size() + 10) >= _size) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cycleString = std::format("[{:06d}] ", cycle);
|
||||
std::memcpy(_data.get() + _offset, cycleString.data(), cycleString.size());
|
||||
_offset += cycleString.size();
|
||||
|
||||
std::memcpy(_data.get() + _offset, line.data(), line.size());
|
||||
_offset += line.size();
|
||||
_data[_offset++] = '\n';
|
||||
}
|
||||
|
||||
void Logger::dump(const fs::path &path) {
|
||||
std::ofstream file(path, std::ios::binary);
|
||||
file.write(reinterpret_cast<char*>(_data.get()), static_cast<std::streamsize>(_offset));
|
||||
}
|
||||
}
|
||||
30
src/Logger.h
Normal file
30
src/Logger.h
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by selim on 9/16/23.
|
||||
//
|
||||
|
||||
#ifndef NES_LOGGER_H
|
||||
#define NES_LOGGER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
|
||||
namespace nes {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
explicit Logger(size_t size);
|
||||
void addLine(uint64_t cycle, std::string_view line);
|
||||
void dump(const fs::path& path);
|
||||
|
||||
private:
|
||||
size_t _size;
|
||||
size_t _offset;
|
||||
std::unique_ptr<uint8_t[]> _data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //NES_LOGGER_H
|
||||
20
src/Nes.cpp
20
src/Nes.cpp
@ -10,7 +10,7 @@
|
||||
|
||||
namespace nes {
|
||||
|
||||
Nes::Nes(): _cycles{} {
|
||||
Nes::Nes(): _cycles{}, _logger(100*1024*1024) {
|
||||
_cpu = std::make_unique<Cpu>();
|
||||
_ppu = std::make_shared<Ppu>();
|
||||
}
|
||||
@ -23,6 +23,10 @@ namespace nes {
|
||||
reset(address);
|
||||
}
|
||||
|
||||
void Nes::connect(std::shared_ptr<Controller> controller) {
|
||||
_cpu->bus()->connect(std::move(controller));
|
||||
}
|
||||
|
||||
void Nes::reset(std::optional<uint16_t> address) {
|
||||
_cpu->reset();
|
||||
_ppu->reset();
|
||||
@ -36,15 +40,27 @@ namespace nes {
|
||||
}
|
||||
|
||||
void Nes::tick() {
|
||||
|
||||
bool needInterrupt = _ppu->tick();
|
||||
// _logger.addLine(_cycles, _ppu->state());
|
||||
|
||||
if(_cycles % 3 == 0) {
|
||||
_cpu->tick();
|
||||
bool instructionExecuted = _cpu->tick();
|
||||
// if(instructionExecuted) {
|
||||
// _logger.addLine(_cycles, _cpu->state());
|
||||
// }
|
||||
}
|
||||
|
||||
if(needInterrupt) {
|
||||
_cpu->nmi();
|
||||
// _logger.addLine(_cycles, "NMI");
|
||||
// _logger.addLine(_cycles, _cpu->state());
|
||||
}
|
||||
|
||||
// if(_cycles == 500000) {
|
||||
// _logger.dump("/home/selim/Documents/log.txt");
|
||||
// }
|
||||
|
||||
_cycles++;
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "Cpu.h"
|
||||
#include "Cartridge.h"
|
||||
#include "Ppu.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
@ -20,6 +21,7 @@ namespace nes {
|
||||
public:
|
||||
Nes();
|
||||
void insertCartridge(const fs::path& path, std::optional<uint16_t> address = std::nullopt);
|
||||
void connect(std::shared_ptr<Controller> controller);
|
||||
void reset(std::optional<uint16_t> address = std::nullopt);
|
||||
void setNewFrameCallback(std::function<void(const Pixel*)> onNewFrame);
|
||||
void tick();
|
||||
@ -29,6 +31,7 @@ namespace nes {
|
||||
std::unique_ptr<Cpu> _cpu;
|
||||
std::shared_ptr<Ppu> _ppu;
|
||||
std::shared_ptr<Cartridge> _cartridge;
|
||||
Logger _logger;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
71
src/Ppu.cpp
71
src/Ppu.cpp
@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "Ppu.h"
|
||||
#include <format>
|
||||
|
||||
namespace nes {
|
||||
|
||||
@ -80,8 +81,13 @@ namespace nes {
|
||||
|
||||
bool Ppu::tick() {
|
||||
|
||||
_needEmitNmi = false;
|
||||
|
||||
if(_scanline == 241 && _column == 1) {
|
||||
_status.verticalBlank = 1;
|
||||
if(_control.enableNmi) {
|
||||
_needEmitNmi = true;
|
||||
}
|
||||
}
|
||||
|
||||
// All visible scanlines
|
||||
@ -97,8 +103,10 @@ namespace nes {
|
||||
|
||||
// Preloading some data ahead of time
|
||||
if ((_column >= 2 && _column < 258) || (_column >= 321 && _column < 338)) {
|
||||
_bgPatternShifter.shift();
|
||||
_bgAttribShifter.shift();
|
||||
if(_mask.renderBackground) {
|
||||
_bgPatternShifter.shift();
|
||||
_bgAttribShifter.shift();
|
||||
}
|
||||
prepareNextBgTile(_column);
|
||||
}
|
||||
|
||||
@ -125,21 +133,15 @@ namespace nes {
|
||||
uint8_t colorIndex = 0;
|
||||
uint8_t palette = 0;
|
||||
|
||||
if(_column < SCREEN_WIDTH && _scanline < SCREEN_HEIGHT && _scanline >= 0) {
|
||||
if(_mask.renderBackground) {
|
||||
colorIndex = _bgPatternShifter.getValue(_fineX);
|
||||
palette = _bgAttribShifter.getValue(_fineX);
|
||||
Pixel pixel = getColor(palette, colorIndex);
|
||||
|
||||
if(_mask.renderBackground) {
|
||||
colorIndex = _bgPatternShifter.getValue(_fineX);
|
||||
palette = _bgAttribShifter.getValue(_fineX);
|
||||
Pixel pixel = getColor(palette, colorIndex);
|
||||
|
||||
// For debugging
|
||||
if (colorIndex != 0) {
|
||||
pixel = Pixel(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
else {
|
||||
pixel = Pixel();
|
||||
}
|
||||
_curPalette = palette;
|
||||
_curColorIndex = colorIndex;
|
||||
|
||||
if(_column < SCREEN_WIDTH && _scanline < SCREEN_HEIGHT && _scanline >= 0) {
|
||||
setPixel(_scanline, _column, pixel);
|
||||
}
|
||||
}
|
||||
@ -155,7 +157,7 @@ namespace nes {
|
||||
}
|
||||
}
|
||||
|
||||
return _status.verticalBlank && _control.enableNmi;
|
||||
return _needEmitNmi;
|
||||
}
|
||||
|
||||
uint8_t Ppu::read(uint16_t address) {
|
||||
@ -204,7 +206,7 @@ namespace nes {
|
||||
_tRamAddress.value = (_tRamAddress.value & 0xFF00) | value;
|
||||
_vRamAddress.value = _tRamAddress.value;
|
||||
} else {
|
||||
_tRamAddress.value = ((value & 0x3F) << 8) | (_tRamAddress.value & 0x00FF);
|
||||
_tRamAddress.value = (((value & 0x3F) << 8) | (_tRamAddress.value & 0x00FF));
|
||||
}
|
||||
_addressWriteInProgress = !_addressWriteInProgress;
|
||||
break;
|
||||
@ -273,9 +275,6 @@ namespace nes {
|
||||
else if(address >= 0x2000 && address < 0x3F00) {
|
||||
address &= 0x0FFF;
|
||||
_nameTable[address & 0x03FF] = value;
|
||||
if (value == 32) {
|
||||
int x = 0;
|
||||
}
|
||||
}
|
||||
else if(address >= 0x3F00 && address < 0x4000) {
|
||||
address &= 0x1F;
|
||||
@ -325,7 +324,7 @@ namespace nes {
|
||||
uint16_t address = (_control.patternBackground << 12)
|
||||
| ((uint16_t)_nextBgTile.id << 4)
|
||||
| (_vRamAddress.fineY + 8);
|
||||
_nextBgTile.lsb = internalRead(address);
|
||||
_nextBgTile.msb = internalRead(address);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
@ -367,17 +366,43 @@ namespace nes {
|
||||
}
|
||||
|
||||
void Ppu::updateScrollX() {
|
||||
if(_mask.renderBackground && !_mask.renderSprites) {
|
||||
if(_mask.renderBackground || _mask.renderSprites) {
|
||||
_vRamAddress.nameTableX = _tRamAddress.nameTableX;
|
||||
_vRamAddress.coarseX = _tRamAddress.coarseX;
|
||||
}
|
||||
}
|
||||
|
||||
void Ppu::updateScrollY() {
|
||||
if(_mask.renderBackground && !_mask.renderSprites) {
|
||||
if(_mask.renderBackground || _mask.renderSprites) {
|
||||
_vRamAddress.nameTableY =_tRamAddress.nameTableY;
|
||||
_vRamAddress.coarseY = _tRamAddress.coarseY;
|
||||
_vRamAddress.fineY = _tRamAddress.fineY;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Ppu::state() const {
|
||||
|
||||
auto palettes = (uint32_t*)_paletteTable.get();
|
||||
|
||||
return std::format("X:{:03d}, Y:{:03d}, V:{:d}, vR: [CX:{:02X}, CY:{:02X}, NX:{:d}, NY:{:d}, FY:{:d}], tR: [CX:{:02X}, CY:{:02X}, NX:{:d}, NY:{:d}, FY:{:d}], FX:{:d}, AL:{:d}, PI:{:02X}, CI:{:02X}, ASL:{:04X}, ASH:{:04X}",
|
||||
_column,
|
||||
_scanline,
|
||||
_status.verticalBlank,
|
||||
_vRamAddress.coarseX,
|
||||
_vRamAddress.coarseY,
|
||||
_vRamAddress.nameTableX,
|
||||
_vRamAddress.nameTableY,
|
||||
_vRamAddress.fineY,
|
||||
_tRamAddress.coarseX,
|
||||
_tRamAddress.coarseY,
|
||||
_tRamAddress.nameTableX,
|
||||
_tRamAddress.nameTableY,
|
||||
_tRamAddress.fineY,
|
||||
_fineX,
|
||||
_addressWriteInProgress,
|
||||
_curPalette,
|
||||
_curColorIndex,
|
||||
_bgAttribShifter._lo,
|
||||
_bgAttribShifter._hi);
|
||||
}
|
||||
}
|
||||
18
src/Ppu.h
18
src/Ppu.h
@ -80,12 +80,12 @@ namespace nes {
|
||||
|
||||
union LoopyRegister {
|
||||
struct {
|
||||
uint8_t coarseX : 5;
|
||||
uint8_t coarseY : 5;
|
||||
uint8_t nameTableX : 1;
|
||||
uint8_t nameTableY : 1;
|
||||
uint8_t fineY : 3;
|
||||
uint8_t unused : 1;
|
||||
uint16_t coarseX : 5;
|
||||
uint16_t coarseY : 5;
|
||||
uint16_t nameTableX : 1;
|
||||
uint16_t nameTableY : 1;
|
||||
uint16_t fineY : 3;
|
||||
uint16_t unused : 1;
|
||||
};
|
||||
uint16_t value;
|
||||
};
|
||||
@ -105,6 +105,7 @@ namespace nes {
|
||||
void setPixel(uint16_t row, uint16_t column, Pixel pixel);
|
||||
void connect(std::shared_ptr<Cartridge> cartridge);
|
||||
void reset();
|
||||
std::string state() const;
|
||||
|
||||
public:
|
||||
std::function<void(const Pixel*)> onNewFrame;
|
||||
@ -134,6 +135,7 @@ namespace nes {
|
||||
TileInfo _nextBgTile;
|
||||
Shifter _bgPatternShifter;
|
||||
Shifter _bgAttribShifter;
|
||||
bool _needEmitNmi;
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> _nameTable;
|
||||
@ -143,6 +145,10 @@ namespace nes {
|
||||
private:
|
||||
std::unique_ptr<Pixel[]> _frameBuffer;
|
||||
std::shared_ptr<Cartridge> _cartridge;
|
||||
|
||||
private: // For debug
|
||||
uint8_t _curPalette;
|
||||
uint8_t _curColorIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
19
src/SdlKeyboardController.cpp
Normal file
19
src/SdlKeyboardController.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by selim on 9/17/23.
|
||||
//
|
||||
|
||||
#include "SdlKeyboardController.h"
|
||||
#include <SDL.h>
|
||||
|
||||
void SdlKeyboardController::poll() {
|
||||
auto state = SDL_GetKeyboardState(nullptr);
|
||||
_data = 0;
|
||||
_data |= state[SDL_SCANCODE_Z] << Key::A;
|
||||
_data |= state[SDL_SCANCODE_X] << Key::B;
|
||||
_data |= state[SDL_SCANCODE_TAB] << Key::Select;
|
||||
_data |= state[SDL_SCANCODE_RETURN] << Key::Start;
|
||||
_data |= state[SDL_SCANCODE_UP] << Key::Up;
|
||||
_data |= state[SDL_SCANCODE_DOWN] << Key::Down;
|
||||
_data |= state[SDL_SCANCODE_LEFT] << Key::Left;
|
||||
_data |= state[SDL_SCANCODE_RIGHT] << Key::Right;
|
||||
}
|
||||
16
src/SdlKeyboardController.h
Normal file
16
src/SdlKeyboardController.h
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by selim on 9/17/23.
|
||||
//
|
||||
|
||||
#ifndef NES_SDLKEYBOARDCONTROLLER_H
|
||||
#define NES_SDLKEYBOARDCONTROLLER_H
|
||||
|
||||
#include "Controller.h"
|
||||
|
||||
class SdlKeyboardController: public nes::Controller {
|
||||
public:
|
||||
void poll() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //NES_SDLKEYBOARDCONTROLLER_H
|
||||
@ -16,7 +16,7 @@ namespace nes {
|
||||
void shift();
|
||||
uint16_t getValue(uint8_t offset);
|
||||
|
||||
private:
|
||||
public:
|
||||
uint16_t _lo;
|
||||
uint16_t _hi;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user