Ensure LR35902 fuse tests run successfully to completion.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-09-07 01:15:28 +01:00
parent cae34d61d1
commit 129286f1a7
18 changed files with 748 additions and 704 deletions

View File

@ -4,7 +4,7 @@
#include <string>
#include <fstream>
#include "Memory.h"
#include <Register.h>
namespace Fuse {
class RegisterState {

View File

@ -5,18 +5,18 @@
Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected)
: m_test(test),
m_expected(expected),
m_cpu(m_bus),
m_ram(0x10000),
m_cpu(*this),
m_failed(false),
m_unimplemented(false) {
m_bus.clear();
m_cpu.initialise();
}
//
void Fuse::TestRunner::initialise() {
m_bus.disableBootRom();
m_bus.disableGameRom();
disableBootRom();
disableGameRom();
initialiseRegisters();
initialiseMemory();
m_cpu.powerOn();
@ -41,7 +41,7 @@ void Fuse::TestRunner::initialiseMemory() {
auto address = memoryDatum.address;
auto bytes = memoryDatum.bytes;
for (int i = 0; i < bytes.size(); ++i)
m_bus.poke(address + i, bytes[i]);
poke(address + i, bytes[i]);
}
}
@ -55,9 +55,9 @@ void Fuse::TestRunner::check() {
void Fuse::TestRunner::dumpDifference(const std::string& description, uint8_t actual, uint8_t expected) const {
std::cerr
<< "**** " << description << ", Expected: "
<< EightBit::Disassembler::hex(expected)
<< EightBit::GameBoy::Disassembler::hex(expected)
<< ", Got: "
<< EightBit::Disassembler::hex(actual)
<< EightBit::GameBoy::Disassembler::hex(actual)
<< std::endl;
}
@ -111,9 +111,9 @@ void Fuse::TestRunner::checkregisters() {
if (expectedF != gotF) {
std::cerr
<< "**** F, Expected: "
<< EightBit::Disassembler::flags(expectedF)
<< EightBit::GameBoy::Disassembler::flags(expectedF)
<< ", Got: "
<< EightBit::Disassembler::flags(gotF)
<< EightBit::GameBoy::Disassembler::flags(gotF)
<< std::endl;
}
}
@ -159,7 +159,7 @@ void Fuse::TestRunner::checkMemory() {
for (int i = 0; i < bytes.size(); ++i) {
auto expected = bytes[i];
uint16_t address = memoryDatum.address + i;
auto actual = m_cpu.getMemory().peek(address);
auto actual = m_cpu.BUS().peek(address);
if (expected != actual) {
m_failed = true;
if (first) {
@ -168,9 +168,9 @@ void Fuse::TestRunner::checkMemory() {
}
std::cerr
<< "**** Difference: "
<< "Address: " << EightBit::Disassembler::hex(address)
<< " Expected: " << EightBit::Disassembler::hex(expected)
<< " Actual: " << EightBit::Disassembler::hex(actual)
<< "Address: " << EightBit::GameBoy::Disassembler::hex(address)
<< " Expected: " << EightBit::GameBoy::Disassembler::hex(expected)
<< " Actual: " << EightBit::GameBoy::Disassembler::hex(actual)
<< std::endl;
}
}

View File

@ -1,13 +1,17 @@
#pragma once
#include <Bus.h>
#include <LR35902.h>
#include "FuseTest.h"
#include "FuseExpectedTestResult.h"
#include "Bus.h"
#include "LR35902.h"
#include <LR35902.h>
#include <GameBoyBus.h>
#include <Ram.h>
namespace Fuse {
class TestRunner {
class TestRunner : public EightBit::GameBoy::Bus {
private:
const Test& m_test;
const ExpectedTestResult& m_expected;
@ -15,8 +19,8 @@ namespace Fuse {
bool m_failed;
bool m_unimplemented;
EightBit::Bus m_bus;
EightBit::LR35902 m_cpu;
EightBit::Ram m_ram;
EightBit::GameBoy::LR35902 m_cpu;
void initialise();
void initialiseRegisters();
@ -32,6 +36,12 @@ namespace Fuse {
const std::string& lowDescription,
EightBit::register16_t actual, EightBit::register16_t expected) const;
protected:
virtual uint8_t& reference(uint16_t address, bool& rom) {
rom = false;
return m_ram.reference(address);
}
public:
TestRunner(const Test& test, const ExpectedTestResult& expected);

View File

@ -4,24 +4,26 @@
#include <cstdint>
namespace EightBit {
class AbstractColourPalette {
public:
enum {
Off,
Light,
Medium,
Dark
namespace GameBoy {
class AbstractColourPalette {
public:
enum {
Off,
Light,
Medium,
Dark
};
AbstractColourPalette::AbstractColourPalette()
: m_colours(4) {
}
uint32_t getColour(size_t index) const {
return m_colours[index];
}
protected:
std::vector<uint32_t> m_colours;
};
AbstractColourPalette::AbstractColourPalette()
: m_colours(4) {
}
uint32_t getColour(size_t index) const {
return m_colours[index];
}
protected:
std::vector<uint32_t> m_colours;
};
}
}

View File

@ -1,233 +0,0 @@
#pragma once
#include <Memory.h>
#include <Processor.h>
namespace EightBit {
class Bus : public Memory {
public:
enum CartridgeType {
ROM = 0,
ROM_MBC1 = 1,
ROM_MBC1_RAM = 2,
ROM_MBC1_RAM_BATTERY = 3,
};
enum {
TotalLineCount = 154,
RomPageSize = 0x4000
};
enum {
BASE = 0xFF00,
// Port/Mode Registers
P1 = 0x0,
SB = 0x1,
SC = 0x2,
DIV = 0x4,
TIMA = 0x5,
TMA = 0x6,
TAC = 0x7,
// Interrupt Flags
IF = 0xF,
IE = 0xFF,
// LCD Display Registers
LCDC = 0x40,
STAT = 0x41,
SCY = 0x42,
SCX = 0x43,
LY = 0x44,
LYC = 0x45,
DMA = 0x46,
BGP = 0x47,
OBP0 = 0x48,
OBP1 = 0x49,
WY = 0x4A,
WX = 0x4B,
// Sound Registers
NR10 = 0x10,
NR11 = 0x11,
NR12 = 0x12,
NR13 = 0x13,
NR14 = 0x14,
NR21 = 0x16,
NR22 = 0x17,
NR23 = 0x18,
NR24 = 0x19,
NR30 = 0x1A,
NR31 = 0x1B,
NR32 = 0x1C,
NR33 = 0x1D,
NR34 = 0x1E,
NR41 = 0x20,
NR42 = 0x21,
NR43 = 0x22,
NR44 = 0x23,
NR50 = 0x24,
NR51 = 0x25,
NR52 = 0x26,
WPRAM_START = 0x30,
WPRAM_END = 0x3F,
// Boot rom control
BOOT_DISABLE = 0x50,
};
// IF and IE flags
enum Interrupts {
VerticalBlank = Processor::Bit0, // VBLANK
DisplayControlStatus = Processor::Bit1, // LCDC Status
TimerOverflow = Processor::Bit2, // Timer Overflow
SerialTransfer = Processor::Bit3, // Serial Transfer
Keypad = Processor::Bit3 // Hi-Lo of P10-P13
};
enum LcdcControl {
DisplayBackground = Processor::Bit0,
ObjectEnable = Processor::Bit1,
ObjectBlockCompositionSelection = Processor::Bit2,
BackgroundCodeAreaSelection = Processor::Bit3,
BackgroundCharacterDataSelection = Processor::Bit4,
WindowEnable = Processor::Bit5,
WindowCodeAreaSelection = Processor::Bit6,
LcdEnable = Processor::Bit7
};
enum LcdStatusMode {
CpuAccessAllowed = 0b00,
VerticalBlankingPeriod = 0b01,
SearchingOamRam = 0b10,
TransferringDataToLcd = 0b11
};
Bus();
void reset();
virtual void clear() override;
void triggerInterrupt(int cause) {
pokeRegister(IF, peekRegister(IF) | cause);
}
void writeRegister(int offset, uint8_t content) {
Memory::write(BASE + offset, content);
}
void pokeRegister(int offset, uint8_t content) {
poke(BASE + offset, content);
}
uint8_t readRegister(int offset) {
return Memory::read(BASE + offset);
}
uint8_t peekRegister(int offset) {
return peek(BASE + offset);
}
void checkTimers(int cycles);
int timerClockTicks() {
switch (timerClock()) {
case 0b00:
return 1024; // 4.096 Khz
case 0b01:
return 16; // 262.144 Khz
case 0b10:
return 64; // 65.536 Khz
case 0b11:
return 256; // 16.384 Khz
default:
__assume(0);
}
throw std::domain_error("Invalid timer clock specification");
}
int timerClock() {
return peekRegister(TAC) & Processor::Mask2;
}
bool timerEnabled() {
return !timerDisabled();
}
bool timerDisabled() {
return (peekRegister(TAC) & Processor::Bit2) == 0;
}
void incrementDIV(int cycles) {
m_divCounter.word += cycles;
pokeRegister(DIV, m_divCounter.high);
}
void incrementTIMA() {
uint16_t updated = peekRegister(TIMA) + 1;
if (updated & Processor::Bit8) {
triggerInterrupt(TimerOverflow);
updated = peekRegister(TMA);
}
pokeRegister(TIMA, updated & Processor::Mask8);
}
void incrementLY() {
pokeRegister(LY, (peekRegister(LY) + 1) % TotalLineCount);
}
void resetLY() {
pokeRegister(LY, 0);
}
void disableBootRom() { m_disableBootRom = true; }
void enableBootRom() { m_disableBootRom = false; }
void disableGameRom() { m_disableGameRom = true; }
void enableGameRom() { m_disableGameRom = false; }
bool bootRomDisabled() const { return m_disableBootRom; }
bool bootRomEnabled() const { return !bootRomDisabled(); }
bool gameRomDisabled() const { return m_disableGameRom; }
bool gameRomEnabled() const { return !gameRomDisabled(); }
void loadBootRom(const std::string& path);
void loadGameRom(const std::string& path);
private:
std::vector<uint8_t> m_bootRom;
std::vector<uint8_t> m_gameRom;
bool m_disableBootRom;
bool m_disableGameRom;
bool m_rom;
bool m_banked;
bool m_ram;
bool m_battery;
bool m_higherRomBank;
bool m_ramBankSwitching;
int m_romBank;
int m_ramBank;
register16_t m_divCounter;
int m_timerCounter;
int m_timerRate;
void Bus_WrittenByte(const AddressEventArgs& e);
void checkTimer(int cycles);
void validateCartridgeType();
virtual uint8_t& reference(uint16_t address, bool& rom);
};
}

View File

@ -6,36 +6,38 @@
#include "Bus.h"
namespace EightBit {
class CharacterDefinition {
public:
CharacterDefinition() {}
namespace GameBoy {
class CharacterDefinition {
public:
CharacterDefinition() {}
CharacterDefinition(Bus& bus, uint16_t address) {
CharacterDefinition(Bus& bus, uint16_t address) {
for (auto row = 0; row < 8; ++row) {
for (auto row = 0; row < 8; ++row) {
auto planeAddress = address + row * 2;
auto planeAddress = address + row * 2;
auto planeLow = bus.peek(planeAddress);
auto planeHigh = bus.peek(planeAddress + 1);
auto planeLow = bus.peek(planeAddress);
auto planeHigh = bus.peek(planeAddress + 1);
for (int bit = 0; bit < 8; ++bit) {
for (int bit = 0; bit < 8; ++bit) {
auto mask = 1 << bit;
auto mask = 1 << bit;
auto bitLow = planeLow & mask ? 1 : 0;
auto bitHigh = planeHigh & mask ? 0b10 : 0;
auto bitLow = planeLow & mask ? 1 : 0;
auto bitHigh = planeHigh & mask ? 0b10 : 0;
auto colour = bitHigh | bitLow;
auto colour = bitHigh | bitLow;
m_definition[row * 8 + (7 - bit)] = colour;
m_definition[row * 8 + (7 - bit)] = colour;
}
}
}
}
const std::array<int, 8 * 8>& get() const { return m_definition; }
const std::array<int, 8 * 8>& get() const { return m_definition; }
private:
std::array<int, 8 * 8> m_definition;
};
private:
std::array<int, 8 * 8> m_definition;
};
}
}

View File

@ -5,61 +5,64 @@
namespace EightBit {
class LR35902;
namespace GameBoy {
class Disassembler {
public:
Disassembler();
class LR35902;
static std::string state(LR35902& cpu);
std::string disassemble(LR35902& cpu);
class Disassembler {
public:
Disassembler();
static std::string flag(uint8_t value, int flag, const std::string& represents);
static std::string flags(uint8_t value);
static std::string hex(uint8_t value);
static std::string hex(uint16_t value);
static std::string binary(uint8_t value);
static std::string decimal(uint8_t value);
static std::string io(uint8_t value);
static std::string state(LR35902& cpu);
std::string disassemble(LR35902& cpu);
static std::string invalid(uint8_t value);
static std::string flag(uint8_t value, int flag, const std::string& represents);
static std::string flags(uint8_t value);
static std::string hex(uint8_t value);
static std::string hex(uint16_t value);
static std::string binary(uint8_t value);
static std::string decimal(uint8_t value);
static std::string io(uint8_t value);
private:
enum IoRegister {
Abbreviated, // FF00 + dd
Absolute, // FFdd
Register, // C
Unused, // Unused!
static std::string invalid(uint8_t value);
private:
enum IoRegister {
Abbreviated, // FF00 + dd
Absolute, // FFdd
Register, // C
Unused, // Unused!
};
mutable boost::format m_formatter;
bool m_prefixCB;
void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc);
void disassembleCB(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
int x, int y, int z,
int p, int q);
void disassembleOther(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
IoRegister& ioRegister,
int x, int y, int z,
int p, int q);
std::string RP(int rp) const;
std::string RP2(int rp) const;
std::string R(int r) const;
static std::string cc(int flag);
static std::string alu(int which);
};
mutable boost::format m_formatter;
bool m_prefixCB;
void disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc);
void disassembleCB(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
int x, int y, int z,
int p, int q);
void disassembleOther(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
std::string& specification,
int& dumpCount,
IoRegister& ioRegister,
int x, int y, int z,
int p, int q);
std::string RP(int rp) const;
std::string RP2(int rp) const;
std::string R(int r) const;
static std::string cc(int flag);
static std::string alu(int which);
};
}
}

View File

@ -3,31 +3,33 @@
#include <vector>
#include <cstdint>
#include "Bus.h"
#include "GameBoyBus.h"
#include "AbstractColourPalette.h"
namespace EightBit {
class Display {
public:
enum {
BufferWidth = 256,
BufferHeight = 256,
BufferCharacterWidth = BufferWidth / 8,
BufferCharacterHeight = BufferHeight / 8,
RasterWidth = 160,
RasterHeight = 144,
namespace GameBoy {
class Display {
public:
enum {
BufferWidth = 256,
BufferHeight = 256,
BufferCharacterWidth = BufferWidth / 8,
BufferCharacterHeight = BufferHeight / 8,
RasterWidth = 160,
RasterHeight = 144,
};
Display(const AbstractColourPalette* colours, Bus& bus);
const std::vector<uint32_t>& pixels() const;
void initialise();
void render();
private:
std::vector<uint32_t> m_pixels;
Bus& m_bus;
const AbstractColourPalette* m_colours;
};
Display(const AbstractColourPalette* colours, Bus& bus);
const std::vector<uint32_t>& pixels() const;
void initialise();
void render();
private:
std::vector<uint32_t> m_pixels;
Bus& m_bus;
const AbstractColourPalette* m_colours;
};
}
}

266
LR35902/inc/GameBoyBus.h Normal file
View File

@ -0,0 +1,266 @@
#pragma once
#include <Rom.h>
#include <Ram.h>
#include <Bus.h>
#include <Processor.h>
namespace EightBit {
namespace GameBoy {
class Bus : public EightBit::Bus {
public:
enum CartridgeType {
ROM = 0,
ROM_MBC1 = 1,
ROM_MBC1_RAM = 2,
ROM_MBC1_RAM_BATTERY = 3,
};
enum {
TotalLineCount = 154,
RomPageSize = 0x4000
};
enum {
BASE = 0xFF00,
// Port/Mode Registers
P1 = 0x0,
SB = 0x1,
SC = 0x2,
DIV = 0x4,
TIMA = 0x5,
TMA = 0x6,
TAC = 0x7,
// Interrupt Flags
IF = 0xF,
IE = 0xFF,
// LCD Display Registers
LCDC = 0x40,
STAT = 0x41,
SCY = 0x42,
SCX = 0x43,
LY = 0x44,
LYC = 0x45,
DMA = 0x46,
BGP = 0x47,
OBP0 = 0x48,
OBP1 = 0x49,
WY = 0x4A,
WX = 0x4B,
// Sound Registers
NR10 = 0x10,
NR11 = 0x11,
NR12 = 0x12,
NR13 = 0x13,
NR14 = 0x14,
NR21 = 0x16,
NR22 = 0x17,
NR23 = 0x18,
NR24 = 0x19,
NR30 = 0x1A,
NR31 = 0x1B,
NR32 = 0x1C,
NR33 = 0x1D,
NR34 = 0x1E,
NR41 = 0x20,
NR42 = 0x21,
NR43 = 0x22,
NR44 = 0x23,
NR50 = 0x24,
NR51 = 0x25,
NR52 = 0x26,
WPRAM_START = 0x30,
WPRAM_END = 0x3F,
// Boot rom control
BOOT_DISABLE = 0x50,
};
// IF and IE flags
enum Interrupts {
VerticalBlank = Processor::Bit0, // VBLANK
DisplayControlStatus = Processor::Bit1, // LCDC Status
TimerOverflow = Processor::Bit2, // Timer Overflow
SerialTransfer = Processor::Bit3, // Serial Transfer
Keypad = Processor::Bit3 // Hi-Lo of P10-P13
};
enum LcdcControl {
DisplayBackground = Processor::Bit0,
ObjectEnable = Processor::Bit1,
ObjectBlockCompositionSelection = Processor::Bit2,
BackgroundCodeAreaSelection = Processor::Bit3,
BackgroundCharacterDataSelection = Processor::Bit4,
WindowEnable = Processor::Bit5,
WindowCodeAreaSelection = Processor::Bit6,
LcdEnable = Processor::Bit7
};
enum LcdStatusMode {
CpuAccessAllowed = 0b00,
VerticalBlankingPeriod = 0b01,
SearchingOamRam = 0b10,
TransferringDataToLcd = 0b11
};
Bus();
void reset();
void triggerInterrupt(int cause) {
pokeRegister(IF, peekRegister(IF) | cause);
}
void writeRegister(int offset, uint8_t content) {
write(BASE + offset, content);
}
void pokeRegister(int offset, uint8_t content) {
poke(BASE + offset, content);
}
uint8_t readRegister(int offset) {
return read(BASE + offset);
}
uint8_t peekRegister(int offset) {
return peek(BASE + offset);
}
void checkTimers(int cycles);
int timerClockTicks() {
switch (timerClock()) {
case 0b00:
return 1024; // 4.096 Khz
case 0b01:
return 16; // 262.144 Khz
case 0b10:
return 64; // 65.536 Khz
case 0b11:
return 256; // 16.384 Khz
default:
__assume(0);
}
throw std::domain_error("Invalid timer clock specification");
}
int timerClock() {
return peekRegister(TAC) & Processor::Mask2;
}
bool timerEnabled() {
return !timerDisabled();
}
bool timerDisabled() {
return (peekRegister(TAC) & Processor::Bit2) == 0;
}
void incrementDIV(int cycles) {
m_divCounter.word += cycles;
pokeRegister(DIV, m_divCounter.high);
}
void incrementTIMA() {
uint16_t updated = peekRegister(TIMA) + 1;
if (updated & Processor::Bit8) {
triggerInterrupt(TimerOverflow);
updated = peekRegister(TMA);
}
pokeRegister(TIMA, updated & Processor::Mask8);
}
void incrementLY() {
pokeRegister(LY, (peekRegister(LY) + 1) % TotalLineCount);
}
void resetLY() {
pokeRegister(LY, 0);
}
void disableBootRom() { m_disableBootRom = true; }
void enableBootRom() { m_disableBootRom = false; }
void disableGameRom() { m_disableGameRom = true; }
void enableGameRom() { m_disableGameRom = false; }
bool bootRomDisabled() const { return m_disableBootRom; }
bool bootRomEnabled() const { return !bootRomDisabled(); }
bool gameRomDisabled() const { return m_disableGameRom; }
bool gameRomEnabled() const { return !gameRomDisabled(); }
void loadBootRom(const std::string& path);
void loadGameRom(const std::string& path);
protected:
virtual uint8_t& reference(uint16_t address, bool& rom) {
rom = true;
if ((address < 0x100) && bootRomEnabled())
return m_bootRom.reference(address);
if ((address < 0x4000) && gameRomEnabled())
return m_gameRomBanks[0].reference(address);
if ((address < 0x8000) && gameRomEnabled())
return m_gameRomBanks[m_romBank].reference(address - 0x4000);
rom = false;
if (address < 0xa000)
return m_videoRam.reference(address - 0x8000);
if (address < 0xc000)
return m_ramBanks[m_ramBank].reference(address - 0xa000);
if (address < 0xe000)
return m_lowInternalRam.reference(address - 0xc000);
if (address < 0xfe00)
return m_lowInternalRam.reference(address - 0xe000); // Low internal RAM mirror
if (address < 0xff00)
return m_oamRam.reference(address - 0xfe00);
if (address < 0xff80)
return m_ioPorts.reference(address - 0xff00);
return m_highInternalRam.reference(address - 0xff80);
}
private:
Rom m_bootRom; // 0x0000 - 0x00ff
std::vector<Rom> m_gameRomBanks; // 0x0000 - 0x3fff, 0x4000 - 0x7fff (switchable)
Ram m_videoRam; // 0x8000 - 0x9fff
std::vector<Ram> m_ramBanks; // 0xa000 - 0xbfff (switchable)
Ram m_lowInternalRam; // 0xc000 - 0xdfff (mirrored at 0xe000)
Ram m_oamRam; // 0xfe00 - 0xfe9f
Ram m_ioPorts; // 0xff00 - 0xff7f
Ram m_highInternalRam; // 0xff80 - 0xffff
bool m_disableBootRom;
bool m_disableGameRom;
bool m_rom;
bool m_banked;
bool m_ram;
bool m_battery;
bool m_higherRomBank;
bool m_ramBankSwitching;
int m_romBank;
int m_ramBank;
register16_t m_divCounter;
int m_timerCounter;
int m_timerRate;
void Bus_WrittenByte(const AddressEventArgs& e);
void checkTimer(int cycles);
void validateCartridgeType();
};
}
}

View File

@ -5,211 +5,213 @@
#include <IntelProcessor.h>
#include <Signal.h>
#include "Bus.h"
#include "GameBoyBus.h"
#include "Display.h"
namespace EightBit {
class LR35902 : public IntelProcessor {
public:
enum StatusBits {
ZF = Bit7,
NF = Bit6,
HC = Bit5,
CF = Bit4,
namespace GameBoy {
class LR35902 : public IntelProcessor {
public:
enum StatusBits {
ZF = Bit7,
NF = Bit6,
HC = Bit5,
CF = Bit4,
};
LR35902(Bus& memory);
Signal<LR35902> ExecutingInstruction;
virtual register16_t& AF() override {
af.low &= 0xf0;
return af;
}
virtual register16_t& BC() override { return bc; }
virtual register16_t& DE() override { return de; }
virtual register16_t& HL() override { return hl; }
virtual void reset() override;
static int framesPerSecond() { return 60; }
static int cyclesPerFrame() { return cyclesPerSecond() / framesPerSecond(); }
int runRasterLines();
int runRasterLine();
int runVerticalBlankLines();
int singleStep();
protected:
int runRasterLines(int limit);
virtual int execute(uint8_t opcode);
int step();
private:
Bus& m_bus;
register16_t af;
register16_t bc;
register16_t de;
register16_t hl;
bool m_ime;
bool m_stopped;
bool m_prefixCB;
static int cyclesPerSecond() { return 4 * 1024 * 1024; }
static int cyclesPerLine() { return cyclesPerFrame() / Bus::TotalLineCount; }
bool& IME() { return m_ime; }
uint8_t R(int r, uint8_t& a) {
switch (r) {
case 0:
return B();
case 1:
return C();
case 2:
return D();
case 3:
return E();
case 4:
return H();
case 5:
return L();
case 6:
return getByte(HL());
case 7:
return a;
}
throw std::logic_error("Unhandled registry mechanism");
}
void R(int r, uint8_t& a, uint8_t value) {
switch (r) {
case 0:
B() = value;
break;
case 1:
C() = value;
break;
case 2:
D() = value;
break;
case 3:
E() = value;
break;
case 4:
H() = value;
break;
case 5:
L() = value;
break;
case 6:
setByte(HL(), value);
break;
case 7:
a = value;
break;
}
}
register16_t& RP(int rp) {
__assume(rp < 4);
__assume(rp >= 0);
switch (rp) {
case 0b00:
return BC();
case 0b01:
return DE();
case 0b10:
return HL();
case 0b11:
return SP();
default:
__assume(0);
}
}
register16_t& RP2(int rp) {
__assume(rp < 4);
__assume(rp >= 0);
switch (rp) {
case 0b00:
return BC();
case 0b01:
return DE();
case 0b10:
return HL();
case 0b11:
return AF();
default:
__assume(0);
}
}
static void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
}
static void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
setFlag(f, HC, calculateHalfCarrySub(before, value, calculation));
}
static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
int interrupt(uint8_t value);
void executeCB(int x, int y, int z, int p, int q);
void executeOther(int x, int y, int z, int p, int q);
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
void stop() { m_stopped = true; }
void start() { m_stopped = false; }
bool stopped() const { return m_stopped; }
void di();
void ei();
void reti();
bool jrConditionalFlag(uint8_t& f, int flag);
bool returnConditionalFlag(uint8_t& f, int flag);
bool jumpConditionalFlag(uint8_t& f, int flag);
bool callConditionalFlag(uint8_t& f, int flag);
void add(uint8_t& f, register16_t& operand, register16_t value);
static void add(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
static void adc(uint8_t& f, uint8_t& operand, uint8_t value);
static void sbc(uint8_t& f, uint8_t& operand, uint8_t value);
static void andr(uint8_t& f, uint8_t& operand, uint8_t value);
static void xorr(uint8_t& f, uint8_t& operand, uint8_t value);
static void orr(uint8_t& f, uint8_t& operand, uint8_t value);
static void compare(uint8_t& f, uint8_t check, uint8_t value);
static uint8_t rlc(uint8_t& f, uint8_t operand);
static uint8_t rrc(uint8_t& f, uint8_t operand);
static uint8_t rl(uint8_t& f, uint8_t operand);
static uint8_t rr(uint8_t& f, uint8_t operand);
static uint8_t sla(uint8_t& f, uint8_t operand);
static uint8_t sra(uint8_t& f, uint8_t operand);
static uint8_t srl(uint8_t& f, uint8_t operand);
static uint8_t bit(uint8_t& f, int n, uint8_t operand);
static uint8_t res(int n, uint8_t operand);
static uint8_t set(int n, uint8_t operand);
static void daa(uint8_t& a, uint8_t& f);
static void scf(uint8_t& a, uint8_t& f);
static void ccf(uint8_t& a, uint8_t& f);
static void cpl(uint8_t& a, uint8_t& f);
static uint8_t swap(uint8_t& f, uint8_t operand);
};
LR35902(Bus& memory);
Signal<LR35902> ExecutingInstruction;
virtual register16_t& AF() override {
af.low &= 0xf0;
return af;
}
virtual register16_t& BC() override { return bc; }
virtual register16_t& DE() override { return de; }
virtual register16_t& HL() override { return hl; }
virtual void reset() override;
static int framesPerSecond() { return 60; }
static int cyclesPerFrame() { return cyclesPerSecond() / framesPerSecond(); }
int runRasterLines();
int runRasterLine();
int runVerticalBlankLines();
int singleStep();
protected:
int runRasterLines(int limit);
virtual int execute(uint8_t opcode);
int step();
private:
Bus& m_bus;
register16_t af;
register16_t bc;
register16_t de;
register16_t hl;
bool m_ime;
bool m_stopped;
bool m_prefixCB;
static int cyclesPerSecond() { return 4 * 1024 * 1024; }
static int cyclesPerLine() { return cyclesPerFrame() / Bus::TotalLineCount; }
bool& IME() { return m_ime; }
uint8_t R(int r, uint8_t& a) {
switch (r) {
case 0:
return B();
case 1:
return C();
case 2:
return D();
case 3:
return E();
case 4:
return H();
case 5:
return L();
case 6:
return getByte(HL());
case 7:
return a;
}
throw std::logic_error("Unhandled registry mechanism");
}
void R(int r, uint8_t& a, uint8_t value) {
switch (r) {
case 0:
B() = value;
break;
case 1:
C() = value;
break;
case 2:
D() = value;
break;
case 3:
E() = value;
break;
case 4:
H() = value;
break;
case 5:
L() = value;
break;
case 6:
setByte(HL(), value);
break;
case 7:
a = value;
break;
}
}
register16_t& RP(int rp) {
__assume(rp < 4);
__assume(rp >= 0);
switch (rp) {
case 0b00:
return BC();
case 0b01:
return DE();
case 0b10:
return HL();
case 0b11:
return SP();
default:
__assume(0);
}
}
register16_t& RP2(int rp) {
__assume(rp < 4);
__assume(rp >= 0);
switch (rp) {
case 0b00:
return BC();
case 0b01:
return DE();
case 0b10:
return HL();
case 0b11:
return AF();
default:
__assume(0);
}
}
static void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
}
static void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
setFlag(f, HC, calculateHalfCarrySub(before, value, calculation));
}
static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
int interrupt(uint8_t value);
void executeCB(int x, int y, int z, int p, int q);
void executeOther(int x, int y, int z, int p, int q);
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
void stop() { m_stopped = true; }
void start() { m_stopped = false; }
bool stopped() const { return m_stopped; }
void di();
void ei();
void reti();
bool jrConditionalFlag(uint8_t& f, int flag);
bool returnConditionalFlag(uint8_t& f, int flag);
bool jumpConditionalFlag(uint8_t& f, int flag);
bool callConditionalFlag(uint8_t& f, int flag);
void add(uint8_t& f, register16_t& operand, register16_t value);
static void add(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
static void adc(uint8_t& f, uint8_t& operand, uint8_t value);
static void sbc(uint8_t& f, uint8_t& operand, uint8_t value);
static void andr(uint8_t& f, uint8_t& operand, uint8_t value);
static void xorr(uint8_t& f, uint8_t& operand, uint8_t value);
static void orr(uint8_t& f, uint8_t& operand, uint8_t value);
static void compare(uint8_t& f, uint8_t check, uint8_t value);
static uint8_t rlc(uint8_t& f, uint8_t operand);
static uint8_t rrc(uint8_t& f, uint8_t operand);
static uint8_t rl(uint8_t& f, uint8_t operand);
static uint8_t rr(uint8_t& f, uint8_t operand);
static uint8_t sla(uint8_t& f, uint8_t operand);
static uint8_t sra(uint8_t& f, uint8_t operand);
static uint8_t srl(uint8_t& f, uint8_t operand);
static uint8_t bit(uint8_t& f, int n, uint8_t operand);
static uint8_t res(int n, uint8_t operand);
static uint8_t set(int n, uint8_t operand);
static void daa(uint8_t& a, uint8_t& f);
static void scf(uint8_t& a, uint8_t& f);
static void ccf(uint8_t& a, uint8_t& f);
static void cpl(uint8_t& a, uint8_t& f);
static uint8_t swap(uint8_t& f, uint8_t operand);
};
}
}

View File

@ -6,25 +6,27 @@
#include "Disassembler.h"
namespace EightBit {
namespace GameBoy {
class LR35902;
class LR35902;
class Profiler {
public:
Profiler(LR35902& cpu);
class Profiler {
public:
Profiler(LR35902& cpu);
void add(uint16_t address, uint8_t instruction);
void add(uint16_t address, uint8_t instruction);
void dump() const;
void dump() const;
private:
std::array<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
LR35902& m_cpu;
private:
std::array<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
LR35902& m_cpu;
Disassembler m_disassembler;
Disassembler m_disassembler;
void dumpInstructionProfiles() const;
void dumpAddressProfiles() const;
};
void dumpInstructionProfiles() const;
void dumpAddressProfiles() const;
};
}
}

View File

@ -8,12 +8,12 @@
#include "Memory.h"
#include "LR35902.h"
EightBit::Disassembler::Disassembler() {
EightBit::GameBoy::Disassembler::Disassembler() {
// Disable exceptions where too many format arguments are available
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
std::string EightBit::Disassembler::state(EightBit::LR35902& cpu) {
std::string EightBit::GameBoy::Disassembler::state(LR35902& cpu) {
auto pc = cpu.PC();
auto sp = cpu.SP();
@ -44,7 +44,7 @@ std::string EightBit::Disassembler::state(EightBit::LR35902& cpu) {
return output.str();
}
std::string EightBit::Disassembler::RP(int rp) const {
std::string EightBit::GameBoy::Disassembler::RP(int rp) const {
switch (rp) {
case 0:
return "BC";
@ -58,7 +58,7 @@ std::string EightBit::Disassembler::RP(int rp) const {
throw std::logic_error("Unhandled register pair");
}
std::string EightBit::Disassembler::RP2(int rp) const {
std::string EightBit::GameBoy::Disassembler::RP2(int rp) const {
switch (rp) {
case 0:
return "BC";
@ -72,7 +72,7 @@ std::string EightBit::Disassembler::RP2(int rp) const {
throw std::logic_error("Unhandled register pair");
}
std::string EightBit::Disassembler::R(int r) const {
std::string EightBit::GameBoy::Disassembler::R(int r) const {
switch (r) {
case 0:
return "B";
@ -94,7 +94,7 @@ std::string EightBit::Disassembler::R(int r) const {
throw std::logic_error("Unhandled register");
}
std::string EightBit::Disassembler::cc(int flag) {
std::string EightBit::GameBoy::Disassembler::cc(int flag) {
switch (flag) {
case 0:
return "NZ";
@ -116,7 +116,7 @@ std::string EightBit::Disassembler::cc(int flag) {
throw std::logic_error("Unhandled condition");
}
std::string EightBit::Disassembler::alu(int which) {
std::string EightBit::GameBoy::Disassembler::alu(int which) {
switch (which) {
case 0: // ADD A,n
return "ADD";
@ -138,17 +138,17 @@ std::string EightBit::Disassembler::alu(int which) {
throw std::logic_error("Unhandled alu operation");
}
std::string EightBit::Disassembler::disassemble(LR35902& cpu) {
std::string EightBit::GameBoy::Disassembler::disassemble(LR35902& cpu) {
m_prefixCB = false;
std::ostringstream output;
disassemble(output, cpu, cpu.PC().word);
return output.str();
}
void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) {
void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR35902& cpu, uint16_t pc) {
auto& memory = cpu.getMemory();
auto opcode = memory.peek(pc);
auto& bus = cpu.BUS();
auto opcode = bus.peek(pc);
// hex opcode
output << hex(opcode);
@ -160,11 +160,11 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cp
auto p = (y & 0b110) >> 1;
auto q = (y & 1);
auto immediate = memory.peek(pc + 1);
auto absolute = memory.peekWord(pc + 1);
auto immediate = bus.peek(pc + 1);
auto absolute = bus.peekWord(pc + 1);
auto displacement = (int8_t)immediate;
auto relative = pc + displacement + 2;
auto indexedImmediate = memory.peek(pc + 1);
auto indexedImmediate = bus.peek(pc + 1);
auto dumpCount = 0;
auto ioRegister = IoRegister::Unused;
@ -183,7 +183,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cp
x, y, z, p, q);
for (int i = 0; i < dumpCount; ++i)
output << hex(memory.peek(pc + i + 1));
output << hex(bus.peek(pc + i + 1));
output << '\t';
m_formatter.parse(specification);
@ -206,7 +206,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, LR35902& cp
}
}
void EightBit::Disassembler::disassembleCB(
void EightBit::GameBoy::Disassembler::disassembleCB(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
@ -256,7 +256,7 @@ void EightBit::Disassembler::disassembleCB(
}
}
void EightBit::Disassembler::disassembleOther(
void EightBit::GameBoy::Disassembler::disassembleOther(
std::ostringstream& output,
LR35902& cpu,
uint16_t pc,
@ -525,13 +525,13 @@ void EightBit::Disassembler::disassembleOther(
}
}
std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) {
std::string EightBit::GameBoy::Disassembler::flag(uint8_t value, int flag, const std::string& represents) {
std::ostringstream output;
output << (value & flag ? represents : "-");
return output.str();
}
std::string EightBit::Disassembler::flags(uint8_t value) {
std::string EightBit::GameBoy::Disassembler::flags(uint8_t value) {
std::ostringstream output;
output
<< flag(value, LR35902::ZF, "Z")
@ -545,37 +545,37 @@ std::string EightBit::Disassembler::flags(uint8_t value) {
return output.str();
}
std::string EightBit::Disassembler::hex(uint8_t value) {
std::string EightBit::GameBoy::Disassembler::hex(uint8_t value) {
std::ostringstream output;
output << std::hex << std::setw(2) << std::setfill('0') << (int)value;
return output.str();
}
std::string EightBit::Disassembler::hex(uint16_t value) {
std::string EightBit::GameBoy::Disassembler::hex(uint16_t value) {
std::ostringstream output;
output << std::hex << std::setw(4) << std::setfill('0') << (int)value;
return output.str();
}
std::string EightBit::Disassembler::binary(uint8_t value) {
std::string EightBit::GameBoy::Disassembler::binary(uint8_t value) {
std::ostringstream output;
output << std::bitset<8>(value);
return output.str();
}
std::string EightBit::Disassembler::decimal(uint8_t value) {
std::string EightBit::GameBoy::Disassembler::decimal(uint8_t value) {
std::ostringstream output;
output << (int)value;
return output.str();
}
std::string EightBit::Disassembler::invalid(uint8_t value) {
std::string EightBit::GameBoy::Disassembler::invalid(uint8_t value) {
std::ostringstream output;
output << "Invalid instruction: " << hex(value) << "(" << binary(value) << ")";
return output.str();
}
std::string EightBit::Disassembler::io(uint8_t value) {
std::string EightBit::GameBoy::Disassembler::io(uint8_t value) {
switch (value) {
// Port/Mode Registers

View File

@ -3,20 +3,20 @@
#include "Processor.h"
#include "CharacterDefinition.h"
EightBit::Display::Display(const AbstractColourPalette* colours, Bus& bus)
EightBit::GameBoy::Display::Display(const AbstractColourPalette* colours, Bus& bus)
: m_bus(bus),
m_colours(colours) {
}
const std::vector<uint32_t>& EightBit::Display::pixels() const {
const std::vector<uint32_t>& EightBit::GameBoy::Display::pixels() const {
return m_pixels;
}
void EightBit::Display::initialise() {
void EightBit::GameBoy::Display::initialise() {
m_pixels.resize(RasterWidth * RasterHeight);
}
void EightBit::Display::render() {
void EightBit::GameBoy::Display::render() {
auto control = m_bus.peekRegister(Bus::LCDC);
auto on = control & Bus::LcdEnable;

View File

@ -1,11 +1,11 @@
#include "stdafx.h"
#include "Bus.h"
#include "GameBoyBus.h"
EightBit::Bus::Bus()
: Memory(0xffff),
m_disableBootRom(false),
EightBit::GameBoy::Bus::Bus()
: m_disableBootRom(false),
m_disableGameRom(false),
m_rom(false),
m_banked(false),
m_ram(false),
m_battery(false),
m_higherRomBank(true),
@ -14,47 +14,35 @@ EightBit::Bus::Bus()
m_ramBank(0),
m_timerCounter(0),
m_timerRate(0) {
m_bootRom.resize(0x100);
m_gameRom.resize(0x10000);
WrittenByte.connect(std::bind(&Bus::Bus_WrittenByte, this, std::placeholders::_1));
WrittenByte.connect(std::bind(&GameBoy::Bus::Bus_WrittenByte, this, std::placeholders::_1));
m_divCounter.word = 0xabcc;
}
void EightBit::Bus::reset() {
void EightBit::GameBoy::Bus::reset() {
pokeRegister(NR52, 0xf1);
pokeRegister(LCDC, DisplayBackground | BackgroundCharacterDataSelection | LcdEnable);
m_divCounter.word = 0xabcc;
m_timerCounter = 0;
}
void EightBit::Bus::clear() {
Memory::clear();
std::fill(m_bootRom.begin(), m_bootRom.end(), 0);
std::fill(m_gameRom.begin(), m_gameRom.end(), 0);
void EightBit::GameBoy::Bus::loadBootRom(const std::string& path) {
m_bootRom.load(path);
}
void EightBit::Bus::loadBootRom(const std::string& path) {
loadBinary(path, m_bootRom, 0, 0x100);
}
void EightBit::Bus::loadGameRom(const std::string& path) {
loadBinary(path, m_gameRom);
void EightBit::GameBoy::Bus::loadGameRom(const std::string& path) {
const auto bankSize = 0x4000;
m_gameRomBanks.resize(1);
const auto size = m_gameRomBanks[0].load(path, bankSize);
auto banks = size / bankSize;
if (banks > 1) {
m_gameRomBanks.resize(banks);
for (int bank = 1; bank < banks; ++banks)
m_gameRomBanks[bank].load(path, bankSize, bankSize * bank);
}
validateCartridgeType();
}
uint8_t& EightBit::Bus::reference(uint16_t address, bool& rom) {
rom = true;
if ((address < 0x100) && bootRomEnabled())
return m_bootRom[address];
if ((address < 0x4000) && gameRomEnabled())
return m_gameRom[address];
if ((address < 0x8000) && gameRomEnabled())
return m_gameRom[(address - RomPageSize) + (m_romBank * RomPageSize)];
rom = false;
return m_bus[address];
}
void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) {
void EightBit::GameBoy::Bus::Bus_WrittenByte(const AddressEventArgs& e) {
const auto address = e.getAddress();
const auto value = e.getCell();
@ -110,7 +98,7 @@ void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) {
break;
case BASE + DIV: // R/W
Memory::reference() = 0;
EightBit::Bus::reference() = 0;
m_timerCounter = m_divCounter.word = 0;
break;
case BASE + TIMA: // R/W
@ -145,7 +133,7 @@ void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) {
case BASE + DMA:
break;
case BASE + LY: // R/O
Memory::reference() = 0;
EightBit::Bus::reference() = 0;
break;
case BASE + BGP:
case BASE + OBP0:
@ -165,12 +153,12 @@ void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) {
}
}
void EightBit::Bus::checkTimers(int cycles) {
void EightBit::GameBoy::Bus::checkTimers(int cycles) {
incrementDIV(cycles);
checkTimer(cycles);
}
void EightBit::Bus::checkTimer(int cycles) {
void EightBit::GameBoy::Bus::checkTimer(int cycles) {
if (timerEnabled()) {
m_timerCounter -= cycles;
if (m_timerCounter <= 0) {
@ -180,11 +168,11 @@ void EightBit::Bus::checkTimer(int cycles) {
}
}
void EightBit::Bus::validateCartridgeType() {
void EightBit::GameBoy::Bus::validateCartridgeType() {
m_rom = m_banked = m_ram = m_battery = false;
switch (m_gameRom[0x147]) {
switch (m_gameRomBanks[0].peek(0x147)) {
case ROM:
m_rom = true;
break;

View File

@ -5,7 +5,7 @@
#pragma region Reset and initialisation
EightBit::LR35902::LR35902(Bus& memory)
EightBit::GameBoy::LR35902::LR35902(Bus& memory)
: IntelProcessor(memory),
m_bus(memory),
m_ime(false),
@ -13,7 +13,7 @@ EightBit::LR35902::LR35902(Bus& memory)
m_prefixCB(false) {
}
void EightBit::LR35902::reset() {
void EightBit::GameBoy::LR35902::reset() {
IntelProcessor::reset();
di();
SP().word = Mask16 - 1;
@ -24,15 +24,15 @@ void EightBit::LR35902::reset() {
#pragma region Interrupt routines
void EightBit::LR35902::di() {
void EightBit::GameBoy::LR35902::di() {
IME() = false;
}
void EightBit::LR35902::ei() {
void EightBit::GameBoy::LR35902::ei() {
IME() = true;
}
int EightBit::LR35902::interrupt(uint8_t value) {
int EightBit::GameBoy::LR35902::interrupt(uint8_t value) {
di();
restart(value);
return 4;
@ -42,13 +42,13 @@ int EightBit::LR35902::interrupt(uint8_t value) {
#pragma region Flag manipulation helpers
void EightBit::LR35902::increment(uint8_t& f, uint8_t& operand) {
void EightBit::GameBoy::LR35902::increment(uint8_t& f, uint8_t& operand) {
clearFlag(f, NF);
adjustZero<LR35902>(f, ++operand);
clearFlag(f, HC, lowNibble(operand));
}
void EightBit::LR35902::decrement(uint8_t& f, uint8_t& operand) {
void EightBit::GameBoy::LR35902::decrement(uint8_t& f, uint8_t& operand) {
setFlag(f, NF);
clearFlag(f, HC, lowNibble(operand));
adjustZero<LR35902>(f, --operand);
@ -58,7 +58,7 @@ void EightBit::LR35902::decrement(uint8_t& f, uint8_t& operand) {
#pragma region PC manipulation: call/ret/jp/jr
bool EightBit::LR35902::jrConditionalFlag(uint8_t& f, int flag) {
bool EightBit::GameBoy::LR35902::jrConditionalFlag(uint8_t& f, int flag) {
switch (flag) {
case 0: // NZ
return jrConditional(!(f & ZF));
@ -74,7 +74,7 @@ bool EightBit::LR35902::jrConditionalFlag(uint8_t& f, int flag) {
throw std::logic_error("Unhandled JR conditional");
}
bool EightBit::LR35902::jumpConditionalFlag(uint8_t& f, int flag) {
bool EightBit::GameBoy::LR35902::jumpConditionalFlag(uint8_t& f, int flag) {
switch (flag) {
case 0: // NZ
return jumpConditional(!(f & ZF));
@ -90,12 +90,12 @@ bool EightBit::LR35902::jumpConditionalFlag(uint8_t& f, int flag) {
throw std::logic_error("Unhandled JP conditional");
}
void EightBit::LR35902::reti() {
void EightBit::GameBoy::LR35902::reti() {
ret();
ei();
}
bool EightBit::LR35902::returnConditionalFlag(uint8_t& f, int flag) {
bool EightBit::GameBoy::LR35902::returnConditionalFlag(uint8_t& f, int flag) {
switch (flag) {
case 0: // NZ
return returnConditional(!(f & ZF));
@ -111,7 +111,7 @@ bool EightBit::LR35902::returnConditionalFlag(uint8_t& f, int flag) {
throw std::logic_error("Unhandled RET conditional");
}
bool EightBit::LR35902::callConditionalFlag(uint8_t& f, int flag) {
bool EightBit::GameBoy::LR35902::callConditionalFlag(uint8_t& f, int flag) {
switch (flag) {
case 0: // NZ
return callConditional(!(f & ZF));
@ -131,7 +131,7 @@ bool EightBit::LR35902::callConditionalFlag(uint8_t& f, int flag) {
#pragma region 16-bit arithmetic
void EightBit::LR35902::add(uint8_t& f, register16_t& operand, register16_t value) {
void EightBit::GameBoy::LR35902::add(uint8_t& f, register16_t& operand, register16_t value) {
MEMPTR() = operand;
@ -148,7 +148,7 @@ void EightBit::LR35902::add(uint8_t& f, register16_t& operand, register16_t valu
#pragma region ALU
void EightBit::LR35902::add(uint8_t& f, uint8_t& operand, uint8_t value, int carry) {
void EightBit::GameBoy::LR35902::add(uint8_t& f, uint8_t& operand, uint8_t value, int carry) {
register16_t result;
result.word = operand + value + carry;
@ -162,11 +162,11 @@ void EightBit::LR35902::add(uint8_t& f, uint8_t& operand, uint8_t value, int car
adjustZero<LR35902>(f, operand);
}
void EightBit::LR35902::adc(uint8_t& f, uint8_t& operand, uint8_t value) {
void EightBit::GameBoy::LR35902::adc(uint8_t& f, uint8_t& operand, uint8_t value) {
add(f, operand, value, (f & CF) >> 4);
}
void EightBit::LR35902::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) {
void EightBit::GameBoy::LR35902::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) {
register16_t result;
result.word = operand - value - carry;
@ -180,27 +180,27 @@ void EightBit::LR35902::subtract(uint8_t& f, uint8_t& operand, uint8_t value, in
adjustZero<LR35902>(f, operand);
}
void EightBit::LR35902::sbc(uint8_t& f, uint8_t& operand, uint8_t value) {
void EightBit::GameBoy::LR35902::sbc(uint8_t& f, uint8_t& operand, uint8_t value) {
subtract(f, operand, value, (f & CF) >> 4);
}
void EightBit::LR35902::andr(uint8_t& f, uint8_t& operand, uint8_t value) {
void EightBit::GameBoy::LR35902::andr(uint8_t& f, uint8_t& operand, uint8_t value) {
setFlag(f, HC);
clearFlag(f, CF | NF);
adjustZero<LR35902>(f, operand &= value);
}
void EightBit::LR35902::xorr(uint8_t& f, uint8_t& operand, uint8_t value) {
void EightBit::GameBoy::LR35902::xorr(uint8_t& f, uint8_t& operand, uint8_t value) {
clearFlag(f, HC | CF | NF);
adjustZero<LR35902>(f, operand ^= value);
}
void EightBit::LR35902::orr(uint8_t& f, uint8_t& operand, uint8_t value) {
void EightBit::GameBoy::LR35902::orr(uint8_t& f, uint8_t& operand, uint8_t value) {
clearFlag(f, HC | CF | NF);
adjustZero<LR35902>(f, operand |= value);
}
void EightBit::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) {
void EightBit::GameBoy::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) {
subtract(f, check, value);
}
@ -208,50 +208,50 @@ void EightBit::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) {
#pragma region Shift and rotate
uint8_t EightBit::LR35902::rlc(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::rlc(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
setFlag(f, CF, operand & Bit7);
return _rotl8(operand, 1);
}
uint8_t EightBit::LR35902::rrc(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::rrc(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
setFlag(f, CF, operand & Bit0);
return _rotr8(operand, 1);
}
uint8_t EightBit::LR35902::rl(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::rl(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
const auto carry = f & CF;
setFlag(f, CF, operand & Bit7);
return (operand << 1) | (carry >> 4); // CF at Bit4
}
uint8_t EightBit::LR35902::rr(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::rr(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
const auto carry = f & CF;
setFlag(f, CF, operand & Bit0);
return (operand >> 1) | (carry << 3); // CF at Bit4
}
uint8_t EightBit::LR35902::sla(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::sla(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
setFlag(f, CF, operand & Bit7);
return operand << 1;
}
uint8_t EightBit::LR35902::sra(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::sra(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
setFlag(f, CF, operand & Bit0);
return (operand >> 1) | (operand & Bit7);
}
uint8_t EightBit::LR35902::swap(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::swap(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | CF);
return promoteNibble(operand) | demoteNibble(operand);
}
uint8_t EightBit::LR35902::srl(uint8_t& f, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::srl(uint8_t& f, uint8_t operand) {
clearFlag(f, NF | HC | ZF);
setFlag(f, CF, operand & Bit0);
return (operand >> 1) & ~Bit7;
@ -261,7 +261,7 @@ uint8_t EightBit::LR35902::srl(uint8_t& f, uint8_t operand) {
#pragma region BIT/SET/RES
uint8_t EightBit::LR35902::bit(uint8_t& f, int n, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::bit(uint8_t& f, int n, uint8_t operand) {
auto carry = f & CF;
uint8_t discarded = operand;
andr(f, discarded, 1 << n);
@ -269,11 +269,11 @@ uint8_t EightBit::LR35902::bit(uint8_t& f, int n, uint8_t operand) {
return operand;
}
uint8_t EightBit::LR35902::res(int n, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::res(int n, uint8_t operand) {
return operand & ~(1 << n);
}
uint8_t EightBit::LR35902::set(int n, uint8_t operand) {
uint8_t EightBit::GameBoy::LR35902::set(int n, uint8_t operand) {
return operand | (1 << n);
}
@ -281,7 +281,7 @@ uint8_t EightBit::LR35902::set(int n, uint8_t operand) {
#pragma region Miscellaneous instructions
void EightBit::LR35902::daa(uint8_t& a, uint8_t& f) {
void EightBit::GameBoy::LR35902::daa(uint8_t& a, uint8_t& f) {
int updated = a;
@ -304,17 +304,17 @@ void EightBit::LR35902::daa(uint8_t& a, uint8_t& f) {
adjustZero<LR35902>(f, a);
}
void EightBit::LR35902::cpl(uint8_t& a, uint8_t& f) {
void EightBit::GameBoy::LR35902::cpl(uint8_t& a, uint8_t& f) {
setFlag(f, HC | NF);
a = ~a;
}
void EightBit::LR35902::scf(uint8_t& a, uint8_t& f) {
void EightBit::GameBoy::LR35902::scf(uint8_t& a, uint8_t& f) {
setFlag(f, CF);
clearFlag(f, HC | NF);
}
void EightBit::LR35902::ccf(uint8_t& a, uint8_t& f) {
void EightBit::GameBoy::LR35902::ccf(uint8_t& a, uint8_t& f) {
clearFlag(f, NF | HC);
clearFlag(f, CF, f & CF);
}
@ -323,19 +323,19 @@ void EightBit::LR35902::ccf(uint8_t& a, uint8_t& f) {
#pragma region Controlled instruction execution
int EightBit::LR35902::runRasterLines() {
int EightBit::GameBoy::LR35902::runRasterLines() {
m_bus.resetLY();
return runRasterLines(Display::RasterHeight);
}
int EightBit::LR35902::runRasterLines(int limit) {
int EightBit::GameBoy::LR35902::runRasterLines(int limit) {
int count = 0;
for (int line = 0; line < limit; ++line)
count += runRasterLine();
return count;
}
int EightBit::LR35902::runRasterLine() {
int EightBit::GameBoy::LR35902::runRasterLine() {
const auto count = run(cyclesPerLine());
m_bus.incrementLY();
if ((m_bus.peekRegister(Bus::STAT) & Bit6) && (m_bus.peekRegister(Bus::LYC) == m_bus.peekRegister(Bus::LY)))
@ -343,12 +343,12 @@ int EightBit::LR35902::runRasterLine() {
return count;
}
int EightBit::LR35902::runVerticalBlankLines() {
int EightBit::GameBoy::LR35902::runVerticalBlankLines() {
m_bus.triggerInterrupt(Bus::Interrupts::VerticalBlank);
return runRasterLines(Bus::TotalLineCount - Display::RasterHeight);
}
int EightBit::LR35902::singleStep() {
int EightBit::GameBoy::LR35902::singleStep() {
int current = 0;
@ -385,7 +385,7 @@ int EightBit::LR35902::singleStep() {
return current;
}
int EightBit::LR35902::step() {
int EightBit::GameBoy::LR35902::step() {
ExecutingInstruction.fire(*this);
m_prefixCB = false;
cycles = 0;
@ -396,7 +396,7 @@ int EightBit::LR35902::step() {
#pragma region Instruction decode and execution
int EightBit::LR35902::execute(uint8_t opcode) {
int EightBit::GameBoy::LR35902::execute(uint8_t opcode) {
const auto& decoded = getDecodedOpcode(opcode);
@ -418,7 +418,7 @@ int EightBit::LR35902::execute(uint8_t opcode) {
return cycles * 4;
}
void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) {
void EightBit::GameBoy::LR35902::executeCB(int x, int y, int z, int p, int q) {
auto& a = A();
auto& f = F();
switch (x) {
@ -481,7 +481,7 @@ void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) {
}
}
void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q) {
auto& a = A();
auto& f = F();
switch (x) {

View File

@ -140,7 +140,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\inc\AbstractColourPalette.h" />
<ClInclude Include="..\inc\Bus.h" />
<ClInclude Include="..\inc\GameBoyBus.h" />
<ClInclude Include="..\inc\CharacterDefinition.h" />
<ClInclude Include="..\inc\Disassembler.h" />
<ClInclude Include="..\inc\Display.h" />
@ -149,7 +149,7 @@
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Bus.cpp" />
<ClCompile Include="GameBoyBus.cpp" />
<ClCompile Include="Disassembler.cpp" />
<ClCompile Include="Display.cpp" />
<ClCompile Include="LR35902.cpp" />

View File

@ -23,9 +23,6 @@
<ClInclude Include="..\inc\Profiler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Bus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\CharacterDefinition.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -35,6 +32,9 @@
<ClInclude Include="..\inc\Display.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\GameBoyBus.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -49,10 +49,10 @@
<ClCompile Include="Profiler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Bus.cpp">
<ClCompile Include="Display.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Display.cpp">
<ClCompile Include="GameBoyBus.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>

View File

@ -2,13 +2,13 @@
#include "Profiler.h"
#include "LR35902.h"
EightBit::Profiler::Profiler(LR35902& cpu)
EightBit::GameBoy::Profiler::Profiler(LR35902& cpu)
: m_cpu(cpu) {
std::fill(m_instructions.begin(), m_instructions.end(), 0);
std::fill(m_addresses.begin(), m_addresses.end(), 0);
}
void EightBit::Profiler::add(uint16_t address, uint8_t instruction) {
void EightBit::GameBoy::Profiler::add(uint16_t address, uint8_t instruction) {
m_instructions[instruction]++;
@ -19,12 +19,12 @@ void EightBit::Profiler::add(uint16_t address, uint8_t instruction) {
m_addresses[address]++;
}
void EightBit::Profiler::dump() const {
void EightBit::GameBoy::Profiler::dump() const {
dumpInstructionProfiles();
dumpAddressProfiles();
}
void EightBit::Profiler::dumpInstructionProfiles() const {
void EightBit::GameBoy::Profiler::dumpInstructionProfiles() const {
std::cout << "** instructions" << std::endl;
for (int i = 0; i < 0x100; ++i) {
auto count = m_instructions[i];
@ -33,7 +33,7 @@ void EightBit::Profiler::dumpInstructionProfiles() const {
}
}
void EightBit::Profiler::dumpAddressProfiles() const {
void EightBit::GameBoy::Profiler::dumpAddressProfiles() const {
std::cout << "** addresses" << std::endl;
for (int i = 0; i < 0x10000; ++i) {
auto count = m_addresses[i];