190 lines
5.1 KiB
C++
190 lines
5.1 KiB
C++
#include <iostream>
|
|
#include <cstdint>
|
|
#include <array>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include "Bus.h"
|
|
#include "j6502.h"
|
|
|
|
#define OLC_PGE_APPLICATION
|
|
#include "olcPixelGameEngine.h"
|
|
|
|
|
|
|
|
class Emulator : public olc::PixelGameEngine
|
|
{
|
|
public:
|
|
Emulator() { sAppName = "olc6502 Demonstration"; }
|
|
|
|
Bus nes;
|
|
std::map<uint16_t, std::string> mapAsm;
|
|
|
|
std::string hex(uint32_t n, uint8_t d)
|
|
{
|
|
std::string s(d, '0');
|
|
for (int i = d - 1; i >= 0; i--, n >>= 4)
|
|
s[i] = "0123456789ABCDEF"[n & 0xF];
|
|
return s;
|
|
};
|
|
|
|
void DrawRam(int x, int y, uint16_t nAddr, int nRows, int nColumns)
|
|
{
|
|
int nRamX = x, nRamY = y;
|
|
for (int row = 0; row < nRows; row++)
|
|
{
|
|
std::string sOffset = "$" + hex(nAddr, 4) + ":";
|
|
for (int col = 0; col < nColumns; col++)
|
|
{
|
|
sOffset += " " + hex(nes.read(nAddr, true), 2);
|
|
nAddr += 1;
|
|
}
|
|
DrawString(nRamX, nRamY, sOffset);
|
|
nRamY += 10;
|
|
}
|
|
}
|
|
|
|
void DrawCpu(int x, int y)
|
|
{
|
|
std::string status = "STATUS: ";
|
|
DrawString(x , y , "STATUS:", olc::WHITE);
|
|
DrawString(x + 64, y, "N", nes.cpu.status & j6502::N ? olc::GREEN : olc::RED);
|
|
DrawString(x + 80, y , "V", nes.cpu.status & j6502::V ? olc::GREEN : olc::RED);
|
|
DrawString(x + 96, y , "-", nes.cpu.status & j6502::U ? olc::GREEN : olc::RED);
|
|
DrawString(x + 112, y , "B", nes.cpu.status & j6502::B ? olc::GREEN : olc::RED);
|
|
DrawString(x + 128, y , "D", nes.cpu.status & j6502::D ? olc::GREEN : olc::RED);
|
|
DrawString(x + 144, y , "I", nes.cpu.status & j6502::I ? olc::GREEN : olc::RED);
|
|
DrawString(x + 160, y , "Z", nes.cpu.status & j6502::Z ? olc::GREEN : olc::RED);
|
|
DrawString(x + 178, y , "C", nes.cpu.status & j6502::C ? olc::GREEN : olc::RED);
|
|
DrawString(x , y + 10, "PC: $" + hex(nes.cpu.pc, 4));
|
|
DrawString(x , y + 20, "A: $" + hex(nes.cpu.a, 2) + " [" + std::to_string(nes.cpu.a) + "]");
|
|
DrawString(x , y + 30, "X: $" + hex(nes.cpu.x, 2) + " [" + std::to_string(nes.cpu.x) + "]");
|
|
DrawString(x , y + 40, "Y: $" + hex(nes.cpu.y, 2) + " [" + std::to_string(nes.cpu.y) + "]");
|
|
DrawString(x , y + 50, "Stack P: $" + hex(nes.cpu.sp, 4));
|
|
}
|
|
|
|
void DrawCode(int x, int y, int nLines)
|
|
{
|
|
auto it_a = mapAsm.find(nes.cpu.pc);
|
|
int nLineY = (nLines >> 1) * 10 + y;
|
|
if (it_a != mapAsm.end())
|
|
{
|
|
DrawString(x, nLineY, (*it_a).second, olc::CYAN);
|
|
while (nLineY < (nLines * 10) + y)
|
|
{
|
|
nLineY += 10;
|
|
if (++it_a != mapAsm.end())
|
|
{
|
|
DrawString(x, nLineY, (*it_a).second);
|
|
}
|
|
}
|
|
}
|
|
|
|
it_a = mapAsm.find(nes.cpu.pc);
|
|
nLineY = (nLines >> 1) * 10 + y;
|
|
if (it_a != mapAsm.end())
|
|
{
|
|
while (nLineY > y)
|
|
{
|
|
nLineY -= 10;
|
|
if (--it_a != mapAsm.end())
|
|
{
|
|
DrawString(x, nLineY, (*it_a).second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool OnUserCreate() override
|
|
{
|
|
// Load Program (assembled at https://www.masswerk.at/6502/assembler.html)
|
|
/*
|
|
*=$8000
|
|
LDX #10
|
|
STX $0000
|
|
LDX #3
|
|
STX $0001
|
|
LDY $0000
|
|
LDA #0
|
|
CLC
|
|
loop
|
|
ADC $0001
|
|
DEY
|
|
BNE loop
|
|
STA $0002
|
|
NOP
|
|
NOP
|
|
NOP
|
|
*/
|
|
|
|
// Convert hex string into bytes for RAM
|
|
std::stringstream ss;
|
|
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";
|
|
uint16_t nOffset = 0x8000;
|
|
while (!ss.eof())
|
|
{
|
|
std::string b;
|
|
ss >> b;
|
|
nes.ram[nOffset++] = (uint8_t)std::stoul(b, nullptr, 16);
|
|
}
|
|
|
|
// Set Reset Vector
|
|
nes.ram[0xFFFC] = 0x00;
|
|
nes.ram[0xFFFD] = 0x80;
|
|
|
|
// Dont forget to set IRQ and NMI vectors if you want to play with those
|
|
|
|
// Extract dissassembly
|
|
mapAsm = nes.cpu.disassemble(0x0000, 0xFFFF);
|
|
|
|
// Reset
|
|
nes.cpu.reset();
|
|
return true;
|
|
}
|
|
|
|
bool OnUserUpdate(float fElapsedTime)
|
|
{
|
|
Clear(olc::DARK_BLUE);
|
|
|
|
|
|
if (GetKey(olc::Key::SPACE).bPressed)
|
|
{
|
|
do
|
|
{
|
|
nes.cpu.clock();
|
|
}
|
|
while (!nes.cpu.complete());
|
|
}
|
|
|
|
if (GetKey(olc::Key::R).bPressed)
|
|
nes.cpu.reset();
|
|
|
|
if (GetKey(olc::Key::I).bPressed)
|
|
nes.cpu.irq();
|
|
|
|
if (GetKey(olc::Key::N).bPressed)
|
|
nes.cpu.nmi();
|
|
|
|
// Draw Ram Page 0x00
|
|
DrawRam(2, 2, 0x0000, 16, 16);
|
|
DrawRam(2, 182, 0x8000, 16, 16);
|
|
DrawCpu(448, 2);
|
|
DrawCode(448, 72, 26);
|
|
|
|
|
|
DrawString(10, 370, "SPACE = Step Instruction R = RESET I = IRQ N = NMI");
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
Emulator demo;
|
|
demo.Construct(680, 480, 2, 2);
|
|
demo.Start();
|
|
return 0;
|
|
}
|