2022-02-28 15:04:25 +00:00
|
|
|
#include "Bus.hpp"
|
|
|
|
#include "Log.hpp"
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
2022-03-01 17:13:47 +00:00
|
|
|
#include "controllers/StandardController.hpp"
|
|
|
|
|
2022-03-03 01:33:08 +00:00
|
|
|
Bus::Bus(Screen* screen) :
|
2022-03-03 16:29:56 +00:00
|
|
|
cpu(this), ppu(this, screen), apu(this), cartridge(this)
|
2022-02-28 15:04:25 +00:00
|
|
|
{
|
|
|
|
LOG_CORE_INFO("Allocating RAM");
|
|
|
|
RAM = std::vector<Byte>(0x800);
|
|
|
|
|
|
|
|
LOG_CORE_INFO("Allocating VRAM");
|
2022-03-01 02:34:19 +00:00
|
|
|
VRAM = std::vector<Byte>(0x800);
|
2022-03-03 16:29:56 +00:00
|
|
|
palettes = std::vector<Byte>(0x20, 0);
|
2022-02-28 15:04:25 +00:00
|
|
|
|
|
|
|
LOG_CORE_INFO("Inserting cartridge");
|
2022-03-03 16:29:56 +00:00
|
|
|
cartridge.Load("roms/mario.nes");
|
2022-02-28 15:04:25 +00:00
|
|
|
|
|
|
|
LOG_CORE_INFO("Powering up CPU");
|
|
|
|
cpu.Powerup();
|
|
|
|
|
|
|
|
LOG_CORE_INFO("Powering up PPU");
|
|
|
|
ppu.Powerup();
|
2022-03-01 17:13:47 +00:00
|
|
|
|
2022-03-03 16:29:56 +00:00
|
|
|
LOG_CORE_INFO("Powering up APU");
|
|
|
|
apu.Powerup();
|
|
|
|
|
2022-03-01 17:13:47 +00:00
|
|
|
controllerPort.PlugInController<StandardController>(0);
|
2022-02-28 15:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Bus::Reboot()
|
|
|
|
{
|
|
|
|
cpu.Powerup();
|
|
|
|
ppu.Powerup();
|
2022-03-03 16:29:56 +00:00
|
|
|
apu.Powerup();
|
2022-02-28 15:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Bus::Reset()
|
|
|
|
{
|
|
|
|
cpu.Reset();
|
|
|
|
ppu.Reset();
|
2022-03-03 16:29:56 +00:00
|
|
|
apu.Reset();
|
2022-02-28 15:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t Bus::Tick()
|
|
|
|
{
|
2022-03-01 17:13:47 +00:00
|
|
|
controllerPort.Tick();
|
|
|
|
|
2022-02-28 15:04:25 +00:00
|
|
|
uint8_t result = cpu.Tick();
|
|
|
|
|
|
|
|
// 3 ppu ticks per cpu tick
|
|
|
|
ppu.Tick();
|
|
|
|
ppu.Tick();
|
|
|
|
ppu.Tick();
|
|
|
|
|
2022-03-03 16:29:56 +00:00
|
|
|
// APU is only ticked every 2 cycles, but that logic
|
|
|
|
// is handled inside the APU class
|
|
|
|
apu.Tick();
|
|
|
|
|
2022-02-28 15:04:25 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-03-02 13:59:42 +00:00
|
|
|
void Bus::PPUTick()
|
|
|
|
{
|
|
|
|
if (ppuClock == 0)
|
2022-03-03 16:29:56 +00:00
|
|
|
{
|
2022-03-02 13:59:42 +00:00
|
|
|
cpu.Tick();
|
2022-03-03 16:29:56 +00:00
|
|
|
apu.Tick();
|
|
|
|
}
|
2022-03-02 13:59:42 +00:00
|
|
|
|
|
|
|
ppu.Tick();
|
|
|
|
ppuClock = (ppuClock + 1) % 3;
|
|
|
|
}
|
|
|
|
|
2022-02-28 15:04:25 +00:00
|
|
|
bool Bus::Instruction()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
while (Tick());
|
|
|
|
}
|
|
|
|
catch (const std::runtime_error& err)
|
|
|
|
{
|
|
|
|
LOG_CORE_FATAL("Fatal Bus error: {0}", err.what());
|
|
|
|
cpu.Halt();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Bus::Frame()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
while (!ppu.IsFrameDone())
|
|
|
|
Tick();
|
|
|
|
}
|
|
|
|
catch (const std::runtime_error& err)
|
|
|
|
{
|
|
|
|
LOG_CORE_FATAL("Fatal Bus error: {0}", err.what());
|
|
|
|
cpu.Halt();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Byte Bus::ReadCPU(Word addr)
|
|
|
|
{
|
|
|
|
if (0x0000 <= addr && addr < 0x2000)
|
|
|
|
{
|
|
|
|
return RAM[addr & 0x7FF];
|
|
|
|
}
|
|
|
|
else if (0x2000 <= addr && addr < 0x4000)
|
|
|
|
{
|
|
|
|
return ppu.ReadRegister(addr & 0x7);
|
|
|
|
}
|
|
|
|
else if (0x8000 <= addr && addr <= 0xFFFF)
|
|
|
|
{
|
|
|
|
return cartridge.ReadCPU(addr);
|
|
|
|
}
|
2022-03-01 17:13:47 +00:00
|
|
|
else if (0x4000 <= addr && addr <= 0x4017)
|
|
|
|
{
|
|
|
|
switch (addr)
|
|
|
|
{
|
|
|
|
case 0x4016:
|
|
|
|
case 0x4017:
|
|
|
|
return controllerPort.Read(addr);
|
|
|
|
}
|
|
|
|
}
|
2022-02-28 15:33:39 +00:00
|
|
|
|
|
|
|
return 0x00;
|
2022-02-28 15:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Byte Bus::ReadPPU(Word addr)
|
|
|
|
{
|
|
|
|
addr &= 0x3FFF;
|
|
|
|
|
|
|
|
if (0x0000 <= addr && addr < 0x2000)
|
|
|
|
{
|
|
|
|
return cartridge.ReadPPU(addr);
|
|
|
|
}
|
2022-03-03 16:29:56 +00:00
|
|
|
else if(0x2000 <= addr && addr < 0x3F00)
|
2022-02-28 15:04:25 +00:00
|
|
|
{
|
2022-03-01 02:34:19 +00:00
|
|
|
if (cartridge.MapCIRAM(addr))
|
|
|
|
return cartridge.ReadVRAM(addr);
|
|
|
|
|
2022-02-28 15:04:25 +00:00
|
|
|
return VRAM[addr & 0xFFF];
|
|
|
|
}
|
2022-03-03 16:29:56 +00:00
|
|
|
else if (0x3F00 <= addr && addr < 0x4000)
|
|
|
|
{
|
|
|
|
if ((addr & 0x3) == 0x00)
|
|
|
|
addr &= 0xF;
|
|
|
|
|
|
|
|
return palettes[addr & 0x1F];
|
|
|
|
}
|
2022-02-28 15:04:25 +00:00
|
|
|
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bus::WriteCPU(Word addr, Byte val)
|
|
|
|
{
|
|
|
|
if (0x0000 <= addr && addr < 0x2000)
|
|
|
|
{
|
2022-03-04 13:16:41 +00:00
|
|
|
if (addr == 0x0348)
|
|
|
|
volatile int jdfkdf = 3;
|
2022-02-28 15:04:25 +00:00
|
|
|
RAM[addr & 0x7FF] = val;
|
|
|
|
}
|
|
|
|
else if (0x2000 <= addr && addr < 0x4000)
|
|
|
|
{
|
|
|
|
ppu.WriteRegister(addr & 0x7, val);
|
|
|
|
}
|
|
|
|
else if (0x8000 <= addr && addr <= 0xFFFF)
|
|
|
|
{
|
|
|
|
cartridge.WriteCPU(addr, val);
|
|
|
|
}
|
2022-03-01 17:13:47 +00:00
|
|
|
else if (0x4000 <= addr && addr <= 0x4017)
|
|
|
|
{
|
|
|
|
switch (addr)
|
|
|
|
{
|
|
|
|
case 0x4016:
|
|
|
|
controllerPort.Write(addr, val);
|
|
|
|
break;
|
2022-03-03 16:29:56 +00:00
|
|
|
|
|
|
|
case 0x4017:
|
|
|
|
apu.WriteRegister(addr, val);
|
|
|
|
break;
|
2022-03-01 17:13:47 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-28 15:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Bus::WritePPU(Word addr, Byte val)
|
|
|
|
{
|
|
|
|
addr &= 0x3FFF;
|
|
|
|
|
|
|
|
if (0x0000 <= addr && addr < 0x2000)
|
|
|
|
{
|
|
|
|
cartridge.WritePPU(addr, val);
|
|
|
|
}
|
2022-03-03 16:29:56 +00:00
|
|
|
else if (0x2000 <= addr && addr < 0x3F00)
|
2022-02-28 15:04:25 +00:00
|
|
|
{
|
2022-03-01 02:34:19 +00:00
|
|
|
if(cartridge.MapCIRAM(addr))
|
|
|
|
cartridge.WriteVRAM(addr, val);
|
|
|
|
|
2022-02-28 15:04:25 +00:00
|
|
|
VRAM[addr & 0xFFF] = val;
|
|
|
|
}
|
2022-03-03 16:29:56 +00:00
|
|
|
else if (0x3F00 <= addr && addr < 0x4000)
|
|
|
|
{
|
|
|
|
if ((addr & 0x3) == 0x00)
|
|
|
|
addr &= 0xF;
|
|
|
|
|
|
|
|
palettes[addr & 0x1F] = val;
|
|
|
|
}
|
2022-02-28 15:04:25 +00:00
|
|
|
}
|