Overhaul Cpu, interrupts, cycling, addressing, instructions, etc

This commit is contained in:
scawful
2024-04-22 16:59:04 -04:00
parent 1a4563f9e7
commit fd64835d22
4 changed files with 469 additions and 392 deletions

View File

@@ -6,10 +6,33 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include "app/emu/cpu/internal/opcodes.h"
namespace yaze { namespace yaze {
namespace app { namespace app {
namespace emu { namespace emu {
void Cpu::Reset(bool hard) {
if (hard) {
A = 0;
X = 0;
Y = 0;
PC = 0;
PB = 0;
D = 0;
DB = 0;
E = 0;
status = 0;
irq_wanted_ = false;
}
reset_wanted_ = true;
stopped_ = false;
waiting_ = false;
nmi_wanted_ = false;
int_wanted_ = false;
}
void Cpu::Update(UpdateMode mode, int stepCount) { void Cpu::Update(UpdateMode mode, int stepCount) {
int cycles = (mode == UpdateMode::Run) ? clock.GetCycleCount() : stepCount; int cycles = (mode == UpdateMode::Run) ? clock.GetCycleCount() : stepCount;
@@ -22,17 +45,80 @@ void Cpu::Update(UpdateMode mode, int stepCount) {
// Fetch and execute an instruction // Fetch and execute an instruction
ExecuteInstruction(ReadByte((PB << 16) + PC)); ExecuteInstruction(ReadByte((PB << 16) + PC));
// Handle any interrupts, if necessary
HandleInterrupts();
if (mode == UpdateMode::Step) { if (mode == UpdateMode::Step) {
break; break;
} }
} }
} }
void Cpu::RunOpcode() {
if (reset_wanted_) {
reset_wanted_ = false;
// reset: brk/interrupt without writes
auto sp = SP();
ReadByte((PB << 16) | PC);
callbacks_.idle(false);
ReadByte(0x100 | (sp-- & 0xff));
ReadByte(0x100 | (sp-- & 0xff));
ReadByte(0x100 | (sp-- & 0xff));
sp = (sp & 0xff) | 0x100;
SetSP(sp);
SetInterruptFlag(true);
SetInterruptFlag(true);
SetDecimalFlag(false);
SetFlags(status); // updates x and m flags, clears
// upper half of x and y if needed
PB = 0;
PC = ReadWord(0xfffc);
return;
}
if (stopped_) {
callbacks_.idle(true);
return;
}
if (waiting_) {
if (irq_wanted_ || nmi_wanted_) {
waiting_ = false;
callbacks_.idle(false);
CheckInt();
callbacks_.idle(false);
return;
} else {
callbacks_.idle(true);
return;
}
}
// not stopped or waiting, execute a opcode or go to interrupt
if (int_wanted_) {
ReadByte((PB << 16) | PC);
DoInterrupt();
} else {
// uint8_t opcode = ReadOpcode();
ExecuteInstruction(ReadByte((PB << 16) | PC));
}
}
void Cpu::DoInterrupt() {
callbacks_.idle(false);
PushByte(status);
PushWord(PC);
PushByte(status);
SetInterruptFlag(true);
SetDecimalFlag(false);
PB = 0;
int_wanted_ = false;
if (nmi_wanted_) {
nmi_wanted_ = false;
PC = ReadWord(0xffea);
} else { // irq
PC = ReadWord(0xffee);
}
}
void Cpu::ExecuteInstruction(uint8_t opcode) { void Cpu::ExecuteInstruction(uint8_t opcode) {
uint8_t cycles = 0;
uint8_t instruction_length = 0; uint8_t instruction_length = 0;
uint32_t operand = 0; uint32_t operand = 0;
bool immediate = false; bool immediate = false;
@@ -41,49 +127,30 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
switch (opcode) { switch (opcode) {
case 0x61: // ADC DP Indexed Indirect, X case 0x61: // ADC DP Indexed Indirect, X
{ {
cycles = 6;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByte(DirectPageIndexedIndirectX()); operand = ReadByte(DirectPageIndexedIndirectX());
ADC(operand); ADC(operand);
break; break;
} }
case 0x63: // ADC Stack Relative case 0x63: // ADC Stack Relative
{ {
cycles = 4;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByte(StackRelative()); operand = ReadByte(StackRelative());
ADC(operand); ADC(operand);
break; break;
} }
case 0x65: // ADC Direct Page case 0x65: // ADC Direct Page
{ {
cycles = 3;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByte(DirectPage()); operand = ReadByte(DirectPage());
ADC(operand); ADC(operand);
break; break;
} }
case 0x67: // ADC DP Indirect Long case 0x67: // ADC DP Indirect Long
{ {
cycles = 6;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadWord(DirectPageIndirectLong()); operand = ReadWord(DirectPageIndirectLong());
ADC(operand); ADC(operand);
break; break;
} }
case 0x69: // ADC Immediate case 0x69: // ADC Immediate
{ {
cycles = 2;
if (!m()) cycles++;
if (GetAccumulatorSize()) {
instruction_length = 2;
} else {
instruction_length = 3;
}
operand = Immediate(); operand = Immediate();
immediate = true; immediate = true;
ADC(operand); ADC(operand);
@@ -91,90 +158,60 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
} }
case 0x6D: // ADC Absolute case 0x6D: // ADC Absolute
{ {
cycles = 4;
if (!m()) cycles++;
instruction_length = 3;
operand = ReadWord(Absolute()); operand = ReadWord(Absolute());
ADC(operand); ADC(operand);
break; break;
} }
case 0x6F: // ADC Absolute Long case 0x6F: // ADC Absolute Long
{ {
cycles = 5;
if (!m()) cycles++;
instruction_length = 4;
operand = ReadWord(AbsoluteLong()); operand = ReadWord(AbsoluteLong());
ADC(operand); ADC(operand);
break; break;
} }
case 0x71: // ADC DP Indirect Indexed, Y case 0x71: // ADC DP Indirect Indexed, Y
{ {
cycles = 5;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByteOrWord(DirectPageIndirectIndexedY()); operand = ReadByteOrWord(DirectPageIndirectIndexedY());
ADC(operand); ADC(operand);
break; break;
} }
case 0x72: // ADC DP Indirect case 0x72: // ADC DP Indirect
{ {
cycles = 5;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByte(DirectPageIndirect()); operand = ReadByte(DirectPageIndirect());
ADC(operand); ADC(operand);
break; break;
} }
case 0x73: // ADC SR Indirect Indexed, Y case 0x73: // ADC SR Indirect Indexed, Y
{ {
cycles = 7;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByte(StackRelativeIndirectIndexedY()); operand = ReadByte(StackRelativeIndirectIndexedY());
ADC(operand); ADC(operand);
break; break;
} }
case 0x75: // ADC DP Indexed, X case 0x75: // ADC DP Indexed, X
{ {
cycles = 4;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByteOrWord(DirectPageIndexedX()); operand = ReadByteOrWord(DirectPageIndexedX());
ADC(operand); ADC(operand);
break; break;
} }
case 0x77: // ADC DP Indirect Long Indexed, Y case 0x77: // ADC DP Indirect Long Indexed, Y
{ {
cycles = 6;
if (!m()) cycles++;
instruction_length = 2;
operand = ReadByteOrWord(DirectPageIndirectLongIndexedY()); operand = ReadByteOrWord(DirectPageIndirectLongIndexedY());
ADC(operand); ADC(operand);
break; break;
} }
case 0x79: // ADC Absolute Indexed, Y case 0x79: // ADC Absolute Indexed, Y
{ {
cycles = 4;
if (!m()) cycles++;
instruction_length = 3;
operand = ReadWord(AbsoluteIndexedY()); operand = ReadWord(AbsoluteIndexedY());
ADC(operand); ADC(operand);
break; break;
} }
case 0x7D: // ADC Absolute Indexed, X case 0x7D: // ADC Absolute Indexed, X
{ {
cycles = 4;
if (!m()) cycles++;
instruction_length = 3;
operand = ReadWord(AbsoluteIndexedX()); operand = ReadWord(AbsoluteIndexedX());
ADC(operand); ADC(operand);
break; break;
} }
case 0x7F: // ADC Absolute Long Indexed, X case 0x7F: // ADC Absolute Long Indexed, X
{ {
cycles = 5;
if (!m()) cycles++;
instruction_length = 4;
operand = ReadByteOrWord(AbsoluteLongIndexedX()); operand = ReadByteOrWord(AbsoluteLongIndexedX());
ADC(operand); ADC(operand);
break; break;
@@ -390,29 +427,6 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
case 0x00: // BRK Break case 0x00: // BRK Break
{ {
BRK(); BRK();
std::cout << "BRK" << std::endl;
// Print all the registers
std::cout << "A: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)A << std::endl;
std::cout << "X: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)X << std::endl;
std::cout << "Y: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)Y << std::endl;
std::cout << "S: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)SP() << std::endl;
std::cout << "PC: " << std::hex << std::setw(4) << std::setfill('0')
<< (int)PC << std::endl;
std::cout << "PB: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)PB << std::endl;
std::cout << "D: " << std::hex << std::setw(4) << std::setfill('0')
<< (int)D << std::endl;
std::cout << "DB: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)DB << std::endl;
std::cout << "E: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)E << std::endl;
// status registers
std::cout << "C: " << std::hex << std::setw(2) << std::setfill('0')
<< (int)status << std::endl;
break; break;
} }
@@ -1470,7 +1484,9 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
break; break;
} }
LogInstructions(PC, opcode, operand, immediate, accumulator_mode); if (log_instructions_) {
LogInstructions(PC, opcode, operand, immediate, accumulator_mode);
}
instruction_length = GetInstructionLength(opcode); instruction_length = GetInstructionLength(opcode);
UpdatePC(instruction_length); UpdatePC(instruction_length);
} }
@@ -1927,71 +1943,6 @@ uint8_t Cpu::GetInstructionLength(uint8_t opcode) {
} }
} }
// TODO: Implement 65816 interrupts.
void Cpu::HandleInterrupts() {
if (GetInterruptFlag()) {
return;
}
/**
if (GetIRQFlag()) {
if (GetEmulationFlag()) {
PushWord(PC);
PushByte(status);
SetInterruptFlag(true);
SetDecimalFlag(false);
SetIRQFlag(false);
SetEmulationFlag(true);
try {
PC = memory.ReadWord(0xFFFE);
} catch (const std::exception& e) {
std::cout << "IRQ: " << e.what() << std::endl;
}
} else {
PushWord(PC);
PushByte(status);
SetInterruptFlag(true);
SetDecimalFlag(false);
SetIRQFlag(false);
SetEmulationFlag(false);
try {
PC = memory.ReadWord(0xFFFE);
} catch (const std::exception& e) {
std::cout << "IRQ: " << e.what() << std::endl;
}
}
}
if (GetNMIFlag()) {
if (GetEmulationFlag()) {
PushWord(PC);
PushByte(status);
SetInterruptFlag(true);
SetDecimalFlag(false);
SetNMIFlag(false);
SetEmulationFlag(true);
try {
PC = memory.ReadWord(0xFFFA);
} catch (const std::exception& e) {
std::cout << "NMI: " << e.what() << std::endl;
}
} else {
PushWord(PC);
PushByte(status);
SetInterruptFlag(true);
SetDecimalFlag(false);
SetNMIFlag(false);
SetEmulationFlag(false);
try {
PC = memory.ReadWord(0xFFFA);
} catch (const std::exception& e) {
std::cout << "NMI: " << e.what() << std::endl;
}
}
}
*/
}
} // namespace emu } // namespace emu
} // namespace app } // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -38,44 +38,30 @@ class InstructionEntry {
const int kCpuClockSpeed = 21477272; // 21.477272 MHz const int kCpuClockSpeed = 21477272; // 21.477272 MHz
class Cpu : public memory::Memory, class Cpu : public Loggable, public core::ExperimentFlags {
public Loggable,
public core::ExperimentFlags {
public: public:
explicit Cpu(Memory& mem, Clock& vclock) : memory(mem), clock(vclock) {} explicit Cpu(memory::Memory& mem, Clock& vclock,
memory::CpuCallbacks& callbacks)
: memory(mem), clock(vclock), callbacks_(callbacks) {}
enum class UpdateMode { Run, Step, Pause }; enum class UpdateMode { Run, Step, Pause };
void Init(bool verbose = false) { clock.SetFrequency(kCpuClockSpeed); } void Init(bool verbose = false) { clock.SetFrequency(kCpuClockSpeed); }
void Reset(bool hard = false);
void Update(UpdateMode mode = UpdateMode::Run, int stepCount = 1); void Update(UpdateMode mode = UpdateMode::Run, int stepCount = 1);
void RunOpcode();
void ExecuteInstruction(uint8_t opcode); void ExecuteInstruction(uint8_t opcode);
void LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand, void LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
bool immediate, bool accumulator_mode); bool immediate, bool accumulator_mode);
void UpdatePC(uint8_t instruction_length) { PC += instruction_length; } void UpdatePC(uint8_t instruction_length) { PC += instruction_length; }
uint8_t GetInstructionLength(uint8_t opcode);
uint16_t SP() const override { return memory.SP(); }
void SetSP(uint16_t value) override { memory.SetSP(value); }
void set_next_pc(uint16_t value) { next_pc_ = value; }
void UpdateClock(int delta_time) { clock.UpdateClock(delta_time); } void UpdateClock(int delta_time) { clock.UpdateClock(delta_time); }
bool IsBreakpoint(uint32_t address) { void SetIrq(bool state) { irq_wanted_ = state; }
return std::find(breakpoints_.begin(), breakpoints_.end(), address) != void Nmi() { nmi_wanted_ = true; }
breakpoints_.end();
} uint8_t GetInstructionLength(uint8_t opcode);
void SetBreakpoint(uint32_t address) { breakpoints_.push_back(address); }
void ClearBreakpoint(uint32_t address) {
breakpoints_.erase(
std::remove(breakpoints_.begin(), breakpoints_.end(), address),
breakpoints_.end());
}
void ClearBreakpoints() {
breakpoints_.clear();
breakpoints_.shrink_to_fit();
}
auto GetBreakpoints() { return breakpoints_; }
std::vector<uint32_t> breakpoints_; std::vector<uint32_t> breakpoints_;
std::vector<InstructionEntry> instruction_log_; std::vector<InstructionEntry> instruction_log_;
@@ -90,7 +76,7 @@ class Cpu : public memory::Memory,
// 0xFFF8,F9 - ABORT 0xFFE8,E9 - ABORT // 0xFFF8,F9 - ABORT 0xFFE8,E9 - ABORT
// 0xFFE6,E7 - BRK // 0xFFE6,E7 - BRK
// 0xFFF4,F5 - COP 0xFFE4,E5 - COP // 0xFFF4,F5 - COP 0xFFE4,E5 - COP
void HandleInterrupts(); void DoInterrupt();
// ====================================================== // ======================================================
// Registers // Registers
@@ -117,18 +103,21 @@ class Cpu : public memory::Memory,
// E 6502 emulation mode // E 6502 emulation mode
// B #$10 00010000 Break (emulation mode only) // B #$10 00010000 Break (emulation mode only)
void SetFlags(uint8_t val) {
status = val;
if (E) {
status |= 0x10;
}
if (status & 0x20) {
X &= 0xff;
Y &= 0xff;
}
}
// Setting flags in the status register // Setting flags in the status register
bool m() { return GetAccumulatorSize() ? 1 : 0; } bool m() { return GetAccumulatorSize() ? 1 : 0; }
int GetAccumulatorSize() const { return status & 0x20; } int GetAccumulatorSize() const { return status & 0x20; }
int GetIndexSize() const { return status & 0x10; } int GetIndexSize() const { return status & 0x10; }
void set_16_bit_mode() {
SetAccumulatorSize(true);
SetIndexSize(true);
}
void set_8_bit_mode() {
SetAccumulatorSize(false);
SetIndexSize(false);
}
void SetAccumulatorSize(bool set) { SetFlag(0x20, set); } void SetAccumulatorSize(bool set) { SetFlag(0x20, set); }
void SetIndexSize(bool set) { SetFlag(0x10, set); } void SetIndexSize(bool set) { SetFlag(0x10, set); }
@@ -152,9 +141,120 @@ class Cpu : public memory::Memory,
enum class AccessType { Control, Data }; enum class AccessType { Control, Data };
// Memory access routines
uint8_t ReadByte(uint32_t address) const {
return callbacks_.read_byte(address);
}
uint16_t ReadWord(uint32_t address) const {
uint8_t value = ReadByte(address);
uint8_t value2 = ReadByte(address + 1);
return value | (value2 << 8);
}
uint32_t ReadWordLong(uint32_t address) const {
uint8_t value = ReadByte(address);
uint8_t value2 = ReadByte(address + 1);
uint8_t value3 = ReadByte(address + 2);
return value | (value2 << 8) | (value3 << 16);
}
void WriteByte(uint32_t address, uint8_t value) {
callbacks_.write_byte(address, value);
}
void WriteWord(uint32_t address, uint16_t value) {
WriteByte(address, value & 0xFF);
WriteByte(address + 1, value >> 8);
}
void WriteLong(uint32_t address, uint32_t value) {
WriteByte(address, value & 0xFF);
WriteByte(address + 1, (value >> 8) & 0xFF);
WriteByte(address + 2, value >> 16);
}
uint8_t FetchByte() {
uint32_t address = (PB << 16) | PC + 1;
uint8_t byte = ReadByte(address);
return byte;
}
uint16_t FetchWord() {
uint32_t address = (PB << 16) | PC + 1;
uint16_t value = ReadWord(address);
return value;
}
uint32_t FetchLong() {
uint32_t value = ReadWordLong((PB << 16) | PC + 1);
return value;
}
int8_t FetchSignedByte() { return static_cast<int8_t>(FetchByte()); }
int16_t FetchSignedWord() {
auto offset = static_cast<int16_t>(FetchWord());
return offset;
}
uint8_t FetchByteDirectPage(uint8_t operand) {
uint16_t distance = D * 0x100;
// Calculate the effective address in the Direct Page
uint16_t effectiveAddress = operand + distance;
// Fetch the byte from memory
uint8_t fetchedByte = ReadByte(effectiveAddress);
next_pc_ = PC + 1;
return fetchedByte;
}
uint16_t ReadByteOrWord(uint32_t address) {
if (GetAccumulatorSize()) {
// 8-bit mode
return ReadByte(address) & 0xFF;
} else {
// 16-bit mode
return ReadWord(address);
}
}
void PushByte(uint8_t value) {
WriteByte(SP(), value);
SetSP(SP() - 1);
if (E) SetSP((SP() & 0xff) | 0x100);
}
void PushWord(uint16_t value, bool int_check = false) {
PushByte(value >> 8);
if (int_check) CheckInt();
PushByte(value & 0xFF);
}
void PushLong(uint32_t value) { // Push 24-bit value
PushByte(value >> 16);
PushWord(value & 0xFFFF);
}
uint8_t PopByte() {
SetSP(SP() + 1);
if (E) SetSP((SP() & 0xff) | 0x100);
return ReadByte(SP());
}
uint16_t PopWord(bool int_check = false) {
uint8_t low = PopByte();
if (int_check) CheckInt();
return low | (PopByte() << 8);
}
uint32_t PopLong() { // Pop 24-bit value
uint32_t low = PopWord();
uint32_t high = PopByte();
return (high << 16) | low;
}
// ========================================================================== // ==========================================================================
// Addressing Modes // Addressing Modes
void AdrImp();
// Effective Address: // Effective Address:
// Bank: Data Bank Register if locating data // Bank: Data Bank Register if locating data
// Program Bank Register if transferring control // Program Bank Register if transferring control
@@ -321,88 +421,6 @@ class Cpu : public memory::Memory,
// LDA (sr, S), Y // LDA (sr, S), Y
uint32_t StackRelativeIndirectIndexedY(); uint32_t StackRelativeIndirectIndexedY();
// Memory access routines
uint8_t ReadByte(uint32_t address) const override {
return memory.ReadByte(address);
}
uint16_t ReadWord(uint32_t address) const override {
return memory.ReadWord(address);
}
uint32_t ReadWordLong(uint32_t address) const override {
return memory.ReadWordLong(address);
}
std::vector<uint8_t> ReadByteVector(uint32_t address,
uint16_t size) const override {
return memory.ReadByteVector(address, size);
}
void WriteByte(uint32_t address, uint8_t value) override {
memory.WriteByte(address, value);
}
void WriteWord(uint32_t address, uint16_t value) override {
memory.WriteWord(address, value);
}
void WriteLong(uint32_t address, uint32_t value) override {
memory.WriteLong(address, value);
}
uint8_t FetchByte() {
uint32_t address = (PB << 16) | PC + 1;
uint8_t byte = memory.ReadByte(address);
return byte;
}
uint16_t FetchWord() {
uint32_t address = (PB << 16) | PC + 1;
uint16_t value = memory.ReadWord(address);
return value;
}
uint32_t FetchLong() {
uint32_t value = memory.ReadWordLong((PB << 16) | PC + 1);
return value;
}
int8_t FetchSignedByte() { return static_cast<int8_t>(FetchByte()); }
int16_t FetchSignedWord() {
auto offset = static_cast<int16_t>(FetchWord());
return offset;
}
uint8_t FetchByteDirectPage(uint8_t operand) {
uint16_t distance = D * 0x100;
// Calculate the effective address in the Direct Page
uint16_t effectiveAddress = operand + distance;
// Fetch the byte from memory
uint8_t fetchedByte = memory.ReadByte(effectiveAddress);
next_pc_ = PC + 1;
return fetchedByte;
}
uint16_t ReadByteOrWord(uint32_t address) {
if (GetAccumulatorSize()) {
// 8-bit mode
return memory.ReadByte(address) & 0xFF;
} else {
// 16-bit mode
return memory.ReadWord(address);
}
}
void PushByte(uint8_t value) override { memory.PushByte(value); }
void PushWord(uint16_t value) override { memory.PushWord(value); }
uint8_t PopByte() override { return memory.PopByte(); }
uint16_t PopWord() override { return memory.PopWord(); }
void PushLong(uint32_t value) override { memory.PushLong(value); }
uint32_t PopLong() override { return memory.PopLong(); }
// ====================================================== // ======================================================
// Instructions // Instructions
@@ -684,6 +702,33 @@ class Cpu : public memory::Memory,
// XCE: Exchange carry and emulation bits // XCE: Exchange carry and emulation bits
void XCE(); void XCE();
// ==========================================================================
uint16_t SP() const { return memory.SP(); }
void SetSP(uint16_t value) { memory.SetSP(value); }
void set_next_pc(uint16_t value) { next_pc_ = value; }
bool IsBreakpoint(uint32_t address) {
return std::find(breakpoints_.begin(), breakpoints_.end(), address) !=
breakpoints_.end();
}
void SetBreakpoint(uint32_t address) { breakpoints_.push_back(address); }
void ClearBreakpoint(uint32_t address) {
breakpoints_.erase(
std::remove(breakpoints_.begin(), breakpoints_.end(), address),
breakpoints_.end());
}
void ClearBreakpoints() {
breakpoints_.clear();
breakpoints_.shrink_to_fit();
}
auto GetBreakpoints() { return breakpoints_; }
void CheckInt() {
int_wanted_ = nmi_wanted_ || (irq_wanted_ && !GetInterruptFlag());
}
auto mutable_log_instructions() -> bool* { return &log_instructions_; }
private: private:
void compare(uint16_t register_value, uint16_t memory_value) { void compare(uint16_t register_value, uint16_t memory_value) {
uint16_t result; uint16_t result;
@@ -711,14 +756,22 @@ class Cpu : public memory::Memory,
} }
bool GetFlag(uint8_t mask) const { return (status & mask) != 0; } bool GetFlag(uint8_t mask) const { return (status & mask) != 0; }
void ClearMemory() override { memory.ClearMemory(); }
uint8_t operator[](int i) const override { return 0; } bool log_instructions_ = false;
uint8_t at(int i) const override { return 0; }
bool waiting_ = false;
bool stopped_ = false;
bool irq_wanted_ = false;
bool nmi_wanted_ = false;
bool reset_wanted_ = false;
bool int_wanted_ = false;
uint16_t last_call_frame_; uint16_t last_call_frame_;
uint16_t next_pc_; uint16_t next_pc_;
Memory& memory; memory::CpuCallbacks callbacks_;
memory::Memory& memory;
Clock& clock; Clock& clock;
}; };

View File

@@ -12,30 +12,31 @@ uint32_t Cpu::Absolute(Cpu::AccessType access_type) {
} }
uint32_t Cpu::AbsoluteIndexedX() { uint32_t Cpu::AbsoluteIndexedX() {
uint16_t address = memory.ReadWord((PB << 16) | (PC + 1)); uint16_t address = ReadWord((PB << 16) | (PC + 1));
uint32_t effective_address = (DB << 16) | ((address + X) & 0xFFFF); uint32_t effective_address = (DB << 16) | ((address + X) & 0xFFFF);
return effective_address; return effective_address;
} }
uint32_t Cpu::AbsoluteIndexedY() { uint32_t Cpu::AbsoluteIndexedY() {
uint16_t address = memory.ReadWord((PB << 16) | (PC + 1)); uint16_t address = ReadWord((PB << 16) | (PC + 1));
uint32_t effective_address = (DB << 16) | address + Y; uint32_t effective_address = (DB << 16) | address + Y;
return effective_address; return effective_address;
} }
uint16_t Cpu::AbsoluteIndexedIndirect() { uint16_t Cpu::AbsoluteIndexedIndirect() {
uint16_t address = FetchWord() + X; uint16_t address = FetchWord() + X;
return memory.ReadWord((DB << 16) | address & 0xFFFF); callbacks_.idle(false);
return ReadWord((DB << 16) | address & 0xFFFF);
} }
uint16_t Cpu::AbsoluteIndirect() { uint16_t Cpu::AbsoluteIndirect() {
uint16_t address = FetchWord(); uint16_t address = FetchWord();
return memory.ReadWord((PB << 16) | address); return ReadWord((PB << 16) | address);
} }
uint32_t Cpu::AbsoluteIndirectLong() { uint32_t Cpu::AbsoluteIndirectLong() {
uint16_t address = FetchWord(); uint16_t address = FetchWord();
return memory.ReadWordLong((PB << 16) | address); return ReadWordLong((PB << 16) | address);
} }
uint32_t Cpu::AbsoluteLong() { return FetchLong(); } uint32_t Cpu::AbsoluteLong() { return FetchLong(); }
@@ -44,7 +45,7 @@ uint32_t Cpu::AbsoluteLongIndexedX() { return FetchLong() + X; }
void Cpu::BlockMove(uint16_t source, uint16_t dest, uint16_t length) { void Cpu::BlockMove(uint16_t source, uint16_t dest, uint16_t length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
memory.WriteByte(dest + i, memory.ReadByte(source + i)); WriteByte(dest + i, ReadByte(source + i));
} }
} }
@@ -66,44 +67,47 @@ uint16_t Cpu::DirectPageIndexedY() {
uint16_t Cpu::DirectPageIndexedIndirectX() { uint16_t Cpu::DirectPageIndexedIndirectX() {
uint8_t operand = FetchByte(); uint8_t operand = FetchByte();
if (D & 0xFF) {
callbacks_.idle(false); // dpr not 0: 1 extra cycle
}
callbacks_.idle(false);
uint16_t indirect_address = D + operand + X; uint16_t indirect_address = D + operand + X;
uint16_t effective_address = memory.ReadWord(indirect_address & 0xFFFF); uint16_t effective_address = ReadWord(indirect_address & 0xFFFF);
return effective_address; return effective_address;
} }
uint16_t Cpu::DirectPageIndirect() { uint16_t Cpu::DirectPageIndirect() {
uint8_t dp = FetchByte(); uint8_t dp = FetchByte();
uint16_t effective_address = D + dp; uint16_t effective_address = D + dp;
return memory.ReadWord(effective_address); return ReadWord(effective_address);
} }
uint32_t Cpu::DirectPageIndirectLong() { uint32_t Cpu::DirectPageIndirectLong() {
uint8_t dp = FetchByte(); uint8_t dp = FetchByte();
uint16_t effective_address = D + dp; uint16_t effective_address = D + dp;
return memory.ReadWordLong((0x00 << 0x10) | effective_address); return ReadWordLong((0x00 << 0x10) | effective_address);
} }
uint16_t Cpu::DirectPageIndirectIndexedY() { uint16_t Cpu::DirectPageIndirectIndexedY() {
uint8_t operand = FetchByte(); uint8_t operand = FetchByte();
uint16_t indirect_address = D + operand; uint16_t indirect_address = D + operand;
return memory.ReadWord(indirect_address) + Y; return ReadWord(indirect_address) + Y;
} }
uint32_t Cpu::DirectPageIndirectLongIndexedY() { uint32_t Cpu::DirectPageIndirectLongIndexedY() {
uint8_t operand = FetchByte(); uint8_t operand = FetchByte();
uint16_t indirect_address = D + operand; uint16_t indirect_address = D + operand;
uint16_t y_by_mode = GetAccumulatorSize() ? Y : Y & 0xFF; uint16_t y_by_mode = GetAccumulatorSize() ? Y : Y & 0xFF;
uint32_t effective_address = uint32_t effective_address = ReadWordLong(indirect_address) + y_by_mode;
memory.ReadWordLong(indirect_address) + y_by_mode;
return effective_address; return effective_address;
} }
uint16_t Cpu::Immediate(bool index_size) { uint16_t Cpu::Immediate(bool index_size) {
bool bit_mode = index_size ? GetIndexSize() : GetAccumulatorSize(); bool bit_mode = index_size ? GetIndexSize() : GetAccumulatorSize();
if (bit_mode) { if (bit_mode) {
return memory.ReadByte((PB << 16) | PC + 1); return ReadByte((PB << 16) | PC + 1);
} else { } else {
return memory.ReadWord((PB << 16) | PC + 1); return ReadWord((PB << 16) | PC + 1);
} }
} }
@@ -115,7 +119,7 @@ uint16_t Cpu::StackRelative() {
uint32_t Cpu::StackRelativeIndirectIndexedY() { uint32_t Cpu::StackRelativeIndirectIndexedY() {
uint8_t sr = FetchByte(); uint8_t sr = FetchByte();
return (DB << 0x10) | (memory.ReadWord(SP() + sr) + Y); return (DB << 0x10) | (ReadWord(SP() + sr) + Y);
} }
} // namespace emu } // namespace emu

View File

@@ -50,12 +50,12 @@ void Cpu::ADC(uint16_t operand) {
void Cpu::AND(uint32_t value, bool isImmediate) { void Cpu::AND(uint32_t value, bool isImmediate) {
uint16_t operand; uint16_t operand;
if (GetAccumulatorSize()) { // 8-bit mode if (GetAccumulatorSize()) { // 8-bit mode
operand = isImmediate ? value : memory.ReadByte(value); operand = isImmediate ? value : ReadByte(value);
A &= operand; A &= operand;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} else { // 16-bit mode } else { // 16-bit mode
operand = isImmediate ? value : memory.ReadWord(value); operand = isImmediate ? value : ReadWord(value);
A &= operand; A &= operand;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000); SetNegativeFlag(A & 0x8000);
@@ -64,18 +64,18 @@ void Cpu::AND(uint32_t value, bool isImmediate) {
// New function for absolute long addressing mode // New function for absolute long addressing mode
void Cpu::ANDAbsoluteLong(uint32_t address) { void Cpu::ANDAbsoluteLong(uint32_t address) {
uint32_t operand32 = memory.ReadWordLong(address); uint32_t operand32 = ReadWordLong(address);
A &= operand32; A &= operand32;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000); SetNegativeFlag(A & 0x8000);
} }
void Cpu::ASL(uint16_t address) { void Cpu::ASL(uint16_t address) {
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
SetCarryFlag(!(value & 0x80)); // Set carry flag if bit 7 is set SetCarryFlag(!(value & 0x80)); // Set carry flag if bit 7 is set
value <<= 1; // Shift left value <<= 1; // Shift left
value &= 0xFE; // Clear bit 0 value &= 0xFE; // Clear bit 0
memory.WriteByte(address, value); WriteByte(address, value);
SetNegativeFlag(!value); SetNegativeFlag(!value);
SetZeroFlag(value); SetZeroFlag(value);
} }
@@ -99,7 +99,7 @@ void Cpu::BEQ(int8_t offset) {
} }
void Cpu::BIT(uint16_t address) { void Cpu::BIT(uint16_t address) {
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
SetOverflowFlag(value & 0x40); SetOverflowFlag(value & 0x40);
SetZeroFlag((A & value) == 0); SetZeroFlag((A & value) == 0);
@@ -127,15 +127,16 @@ void Cpu::BPL(int8_t offset) {
void Cpu::BRA(int8_t offset) { next_pc_ = offset; } void Cpu::BRA(int8_t offset) { next_pc_ = offset; }
void Cpu::BRK() { void Cpu::BRK() {
next_pc_ = PC + 2; // Increment the program counter by 2 // ReadOpcode();
memory.PushWord(next_pc_); next_pc_ += 2; // Increment the program counter by 2
memory.PushByte(status); ReadByte(PC); // Read the next byte
PushByte(PB);
PushByte(PC); // ,false
PushByte(status);
SetInterruptFlag(true); SetInterruptFlag(true);
try { SetDecimalFlag(false);
next_pc_ = memory.ReadWord(0xFFFE); PB = 0;
} catch (const std::exception& e) { PC = ReadWord(0xFFE6); // ,true
std::cout << "BRK: " << e.what() << std::endl;
}
} }
void Cpu::BRL(int16_t offset) { next_pc_ = offset; } void Cpu::BRL(int16_t offset) { next_pc_ = offset; }
@@ -169,7 +170,7 @@ void Cpu::CMP(uint32_t value, bool isImmediate) {
if (isImmediate) { if (isImmediate) {
result = A - (value & 0xFF); result = A - (value & 0xFF);
} else { } else {
uint8_t memory_value = memory.ReadByte(value); uint8_t memory_value = ReadByte(value);
result = A - memory_value; result = A - memory_value;
} }
SetZeroFlag(result == 0); SetZeroFlag(result == 0);
@@ -180,7 +181,7 @@ void Cpu::CMP(uint32_t value, bool isImmediate) {
if (isImmediate) { if (isImmediate) {
result = A - (value & 0xFFFF); result = A - (value & 0xFFFF);
} else { } else {
uint16_t memory_value = memory.ReadWord(value); uint16_t memory_value = ReadWord(value);
result = A - memory_value; result = A - memory_value;
} }
SetZeroFlag(result == 0); SetZeroFlag(result == 0);
@@ -191,33 +192,33 @@ void Cpu::CMP(uint32_t value, bool isImmediate) {
void Cpu::COP() { void Cpu::COP() {
next_pc_ += 2; // Increment the program counter by 2 next_pc_ += 2; // Increment the program counter by 2
memory.PushWord(next_pc_); PushWord(next_pc_);
memory.PushByte(status); PushByte(status);
SetInterruptFlag(true); SetInterruptFlag(true);
if (E) { if (E) {
next_pc_ = memory.ReadWord(0xFFF4); next_pc_ = ReadWord(0xFFF4);
} else { } else {
next_pc_ = memory.ReadWord(0xFFE4); next_pc_ = ReadWord(0xFFE4);
} }
SetDecimalFlag(false); SetDecimalFlag(false);
} }
void Cpu::CPX(uint32_t value, bool isImmediate) { void Cpu::CPX(uint32_t value, bool isImmediate) {
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
uint8_t memory_value = isImmediate ? value : memory.ReadByte(value); uint8_t memory_value = isImmediate ? value : ReadByte(value);
compare(X, memory_value); compare(X, memory_value);
} else { // 16-bit } else { // 16-bit
uint16_t memory_value = isImmediate ? value : memory.ReadWord(value); uint16_t memory_value = isImmediate ? value : ReadWord(value);
compare(X, memory_value); compare(X, memory_value);
} }
} }
void Cpu::CPY(uint32_t value, bool isImmediate) { void Cpu::CPY(uint32_t value, bool isImmediate) {
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
uint8_t memory_value = isImmediate ? value : memory.ReadByte(value); uint8_t memory_value = isImmediate ? value : ReadByte(value);
compare(Y, memory_value); compare(Y, memory_value);
} else { // 16-bit } else { // 16-bit
uint16_t memory_value = isImmediate ? value : memory.ReadWord(value); uint16_t memory_value = isImmediate ? value : ReadWord(value);
compare(Y, memory_value); compare(Y, memory_value);
} }
} }
@@ -237,15 +238,15 @@ void Cpu::DEC(uint32_t address, bool accumulator) {
} }
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
value--; value--;
memory.WriteByte(address, value); WriteByte(address, value);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
} else { } else {
uint16_t value = memory.ReadWord(address); uint16_t value = ReadWord(address);
value--; value--;
memory.WriteWord(address, value); WriteWord(address, value);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
SetNegativeFlag(value & 0x8000); SetNegativeFlag(value & 0x8000);
} }
@@ -277,11 +278,11 @@ void Cpu::DEY() {
void Cpu::EOR(uint32_t address, bool isImmediate) { void Cpu::EOR(uint32_t address, bool isImmediate) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
A ^= isImmediate ? address : memory.ReadByte(address); A ^= isImmediate ? address : ReadByte(address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} else { } else {
A ^= isImmediate ? address : memory.ReadWord(address); A ^= isImmediate ? address : ReadWord(address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000); SetNegativeFlag(A & 0x8000);
} }
@@ -302,15 +303,15 @@ void Cpu::INC(uint32_t address, bool accumulator) {
} }
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
value++; value++;
memory.WriteByte(address, value); WriteByte(address, value);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
} else { } else {
uint16_t value = memory.ReadWord(address); uint16_t value = ReadWord(address);
value++; value++;
memory.WriteWord(address, value); WriteWord(address, value);
SetNegativeFlag(value & 0x8000); SetNegativeFlag(value & 0x8000);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
} }
@@ -351,27 +352,28 @@ void Cpu::JML(uint32_t address) {
} }
void Cpu::JSR(uint16_t address) { void Cpu::JSR(uint16_t address) {
memory.PushWord(PC); // Push the program counter onto the stack PushWord(PC); // Push the program counter onto the stack
next_pc_ = address; // Set program counter to the new address next_pc_ = address; // Set program counter to the new address
} }
void Cpu::JSL(uint32_t address) { void Cpu::JSL(uint32_t address) {
memory.PushLong(PC); // Push the program counter onto the stack as a long PushLong(PC); // Push the program counter onto the stack as a long
// value (24 bits) // value (24 bits)
next_pc_ = address; // Set program counter to the new address next_pc_ = address; // Set program counter to the new address
} }
void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page, bool data_bank) { void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page,
bool data_bank) {
uint8_t bank = PB; uint8_t bank = PB;
if (direct_page) { if (direct_page) {
bank = 0; bank = 0;
} }
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
A = isImmediate ? address : memory.ReadByte((bank << 16) | address); A = isImmediate ? address : ReadByte((bank << 16) | address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} else { } else {
A = isImmediate ? address : memory.ReadWord((bank << 16) | address); A = isImmediate ? address : ReadWord((bank << 16) | address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000); SetNegativeFlag(A & 0x8000);
} }
@@ -379,11 +381,11 @@ void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page, bool data_ba
void Cpu::LDX(uint16_t address, bool isImmediate) { void Cpu::LDX(uint16_t address, bool isImmediate) {
if (GetIndexSize()) { if (GetIndexSize()) {
X = isImmediate ? address : memory.ReadByte(address); X = isImmediate ? address : ReadByte(address);
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
} else { } else {
X = isImmediate ? address : memory.ReadWord(address); X = isImmediate ? address : ReadWord(address);
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x8000); SetNegativeFlag(X & 0x8000);
} }
@@ -391,11 +393,11 @@ void Cpu::LDX(uint16_t address, bool isImmediate) {
void Cpu::LDY(uint16_t address, bool isImmediate) { void Cpu::LDY(uint16_t address, bool isImmediate) {
if (GetIndexSize()) { if (GetIndexSize()) {
Y = isImmediate ? address : memory.ReadByte(address); Y = isImmediate ? address : ReadByte(address);
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80); SetNegativeFlag(Y & 0x80);
} else { } else {
Y = isImmediate ? address : memory.ReadWord(address); Y = isImmediate ? address : ReadWord(address);
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x8000); SetNegativeFlag(Y & 0x8000);
} }
@@ -416,17 +418,17 @@ void Cpu::LSR(uint16_t address, bool accumulator) {
} }
return; return;
} }
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
SetCarryFlag(value & 0x01); SetCarryFlag(value & 0x01);
value >>= 1; value >>= 1;
memory.WriteByte(address, value); WriteByte(address, value);
SetNegativeFlag(false); SetNegativeFlag(false);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
} }
void Cpu::MVN(uint16_t source, uint16_t dest, uint16_t length) { void Cpu::MVN(uint16_t source, uint16_t dest, uint16_t length) {
for (uint16_t i = 0; i < length; i++) { for (uint16_t i = 0; i < length; i++) {
memory.WriteByte(dest, memory.ReadByte(source)); WriteByte(dest, ReadByte(source));
source++; source++;
dest++; dest++;
} }
@@ -434,23 +436,33 @@ void Cpu::MVN(uint16_t source, uint16_t dest, uint16_t length) {
void Cpu::MVP(uint16_t source, uint16_t dest, uint16_t length) { void Cpu::MVP(uint16_t source, uint16_t dest, uint16_t length) {
for (uint16_t i = 0; i < length; i++) { for (uint16_t i = 0; i < length; i++) {
memory.WriteByte(dest, memory.ReadByte(source)); WriteByte(dest, ReadByte(source));
source--; source--;
dest--; dest--;
} }
} }
void Cpu::NOP() { void Cpu::NOP() { AdrImp(); }
// Do nothing
} // void cpu_ora(uint32_t low, uint32_t high) {
// if (cpu->mf) {
// CheckInt();
// uint8_t value = cpu_read(cpu, low);
// cpu->a = (cpu->a & 0xff00) | ((cpu->a | value) & 0xff);
// } else {
// uint16_t value = cpu_readWord(cpu, low, high, true);
// cpu->a |= value;
// }
// cpu_setZN(cpu, cpu->a, cpu->mf);
// }
void Cpu::ORA(uint16_t address, bool isImmediate) { void Cpu::ORA(uint16_t address, bool isImmediate) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
A |= isImmediate ? address : memory.ReadByte(address); A |= isImmediate ? address : ReadByte(address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} else { } else {
A |= isImmediate ? address : memory.ReadWord(address); A |= isImmediate ? address : ReadWord(address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000); SetNegativeFlag(A & 0x8000);
} }
@@ -458,84 +470,122 @@ void Cpu::ORA(uint16_t address, bool isImmediate) {
void Cpu::PEA() { void Cpu::PEA() {
uint16_t address = FetchWord(); uint16_t address = FetchWord();
memory.PushWord(address); PushWord(address);
} }
void Cpu::PEI() { void Cpu::PEI() {
uint16_t address = FetchWord(); uint16_t address = FetchWord();
memory.PushWord(memory.ReadWord(address)); PushWord(ReadWord(address));
} }
void Cpu::PER() { void Cpu::PER() {
uint16_t address = FetchWord(); uint16_t address = FetchWord();
memory.PushWord(PC + address); callbacks_.idle(false);
PushWord(PC + address);
} }
void Cpu::PHA() { void Cpu::PHA() {
callbacks_.idle(false);
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
memory.PushByte(static_cast<uint8_t>(A)); CheckInt();
PushByte(static_cast<uint8_t>(A));
} else { } else {
memory.PushWord(A); PushWord(A);
} }
} }
void Cpu::PHB() { memory.PushByte(DB); } void Cpu::PHB() {
callbacks_.idle(false);
CheckInt();
PushByte(DB);
}
void Cpu::PHD() { memory.PushWord(D); } void Cpu::PHD() {
callbacks_.idle(false);
PushWord(D);
}
void Cpu::PHK() { memory.PushByte(PB); } void Cpu::PHK() {
callbacks_.idle(false);
CheckInt();
PushByte(PB);
}
void Cpu::PHP() { memory.PushByte(status); } void Cpu::PHP() {
callbacks_.idle(false);
CheckInt();
PushByte(status);
}
void Cpu::PHX() { void Cpu::PHX() {
callbacks_.idle(false);
if (GetIndexSize()) { if (GetIndexSize()) {
memory.PushByte(static_cast<uint8_t>(X)); CheckInt();
PushByte(static_cast<uint8_t>(X));
} else { } else {
memory.PushWord(X); PushWord(X);
} }
} }
void Cpu::PHY() { void Cpu::PHY() {
callbacks_.idle(false);
if (GetIndexSize()) { if (GetIndexSize()) {
memory.PushByte(static_cast<uint8_t>(Y)); CheckInt();
PushByte(static_cast<uint8_t>(Y));
} else { } else {
memory.PushWord(Y); PushWord(Y);
} }
} }
void Cpu::PLA() { void Cpu::PLA() {
callbacks_.idle(false);
callbacks_.idle(false);
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
A = memory.PopByte(); CheckInt();
A = PopByte();
SetNegativeFlag((A & 0x80) != 0); SetNegativeFlag((A & 0x80) != 0);
} else { } else {
A = memory.PopWord(); A = PopWord();
SetNegativeFlag((A & 0x8000) != 0); SetNegativeFlag((A & 0x8000) != 0);
} }
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
} }
void Cpu::PLB() { void Cpu::PLB() {
DB = memory.PopByte(); callbacks_.idle(false);
callbacks_.idle(false);
CheckInt();
DB = PopByte();
SetNegativeFlag((DB & 0x80) != 0); SetNegativeFlag((DB & 0x80) != 0);
SetZeroFlag(DB == 0); SetZeroFlag(DB == 0);
} }
// Pull Direct Page Register from Stack // Pull Direct Page Register from Stack
void Cpu::PLD() { void Cpu::PLD() {
D = memory.PopWord(); callbacks_.idle(false);
callbacks_.idle(false);
D = PopWord();
SetNegativeFlag((D & 0x8000) != 0); SetNegativeFlag((D & 0x8000) != 0);
SetZeroFlag(D == 0); SetZeroFlag(D == 0);
} }
// Pull Processor Status Register from Stack // Pull Processor Status Register from Stack
void Cpu::PLP() { status = memory.PopByte(); } void Cpu::PLP() {
callbacks_.idle(false);
callbacks_.idle(false);
CheckInt();
status = PopByte();
}
void Cpu::PLX() { void Cpu::PLX() {
callbacks_.idle(false);
callbacks_.idle(false);
if (GetIndexSize()) { if (GetIndexSize()) {
X = memory.PopByte(); CheckInt();
X = PopByte();
SetNegativeFlag((A & 0x80) != 0); SetNegativeFlag((A & 0x80) != 0);
} else { } else {
X = memory.PopWord(); X = PopWord();
SetNegativeFlag((A & 0x8000) != 0); SetNegativeFlag((A & 0x8000) != 0);
} }
@@ -543,11 +593,14 @@ void Cpu::PLX() {
} }
void Cpu::PLY() { void Cpu::PLY() {
callbacks_.idle(false);
callbacks_.idle(false);
if (GetIndexSize()) { if (GetIndexSize()) {
Y = memory.PopByte(); CheckInt();
Y = PopByte();
SetNegativeFlag((A & 0x80) != 0); SetNegativeFlag((A & 0x80) != 0);
} else { } else {
Y = memory.PopWord(); Y = PopWord();
SetNegativeFlag((A & 0x8000) != 0); SetNegativeFlag((A & 0x8000) != 0);
} }
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
@@ -555,7 +608,9 @@ void Cpu::PLY() {
void Cpu::REP() { void Cpu::REP() {
auto byte = FetchByte(); auto byte = FetchByte();
CheckInt();
status &= ~byte; status &= ~byte;
callbacks_.idle(false);
} }
void Cpu::ROL(uint32_t address, bool accumulator) { void Cpu::ROL(uint32_t address, bool accumulator) {
@@ -578,12 +633,12 @@ void Cpu::ROL(uint32_t address, bool accumulator) {
return; return;
} }
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; uint8_t carry = GetCarryFlag() ? 0x01 : 0x00;
SetCarryFlag(value & 0x80); SetCarryFlag(value & 0x80);
value <<= 1; value <<= 1;
value |= carry; value |= carry;
memory.WriteByte(address, value); WriteByte(address, value);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
} }
@@ -608,34 +663,32 @@ void Cpu::ROR(uint32_t address, bool accumulator) {
return; return;
} }
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; uint8_t carry = GetCarryFlag() ? 0x80 : 0x00;
SetCarryFlag(value & 0x01); SetCarryFlag(value & 0x01);
value >>= 1; value >>= 1;
value |= carry; value |= carry;
memory.WriteByte(address, value); WriteByte(address, value);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
} }
void Cpu::RTI() { void Cpu::RTI() {
status = memory.PopByte(); status = PopByte();
PC = memory.PopWord(); PC = PopWord();
} }
void Cpu::RTL() { void Cpu::RTL() {
next_pc_ = memory.PopWord(); next_pc_ = PopWord();
PB = memory.PopByte(); PB = PopByte();
} }
void Cpu::RTS() { void Cpu::RTS() { last_call_frame_ = PopWord(); }
last_call_frame_ = memory.PopWord();
}
void Cpu::SBC(uint32_t value, bool isImmediate) { void Cpu::SBC(uint32_t value, bool isImmediate) {
uint16_t operand; uint16_t operand;
if (!GetAccumulatorSize()) { // 16-bit mode if (!GetAccumulatorSize()) { // 16-bit mode
operand = isImmediate ? value : memory.ReadWord(value); operand = isImmediate ? value : ReadWord(value);
uint16_t result = A - operand - (GetCarryFlag() ? 0 : 1); uint16_t result = A - operand - (GetCarryFlag() ? 0 : 1);
SetCarryFlag(!(result > 0xFFFF)); // Update the carry flag SetCarryFlag(!(result > 0xFFFF)); // Update the carry flag
@@ -649,7 +702,7 @@ void Cpu::SBC(uint32_t value, bool isImmediate) {
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000); SetNegativeFlag(A & 0x8000);
} else { // 8-bit mode } else { // 8-bit mode
operand = isImmediate ? value : memory.ReadByte(value); operand = isImmediate ? value : ReadByte(value);
uint8_t result = A - operand - (GetCarryFlag() ? 0 : 1); uint8_t result = A - operand - (GetCarryFlag() ? 0 : 1);
SetCarryFlag(!(result > 0xFF)); // Update the carry flag SetCarryFlag(!(result > 0xFF)); // Update the carry flag
@@ -673,45 +726,46 @@ void Cpu::SEI() { status |= 0x04; }
void Cpu::SEP() { void Cpu::SEP() {
auto byte = FetchByte(); auto byte = FetchByte();
CheckInt();
status |= byte; status |= byte;
callbacks_.idle(false);
} }
void Cpu::STA(uint32_t address) { void Cpu::STA(uint32_t address) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
memory.WriteByte(address, static_cast<uint8_t>(A)); WriteByte(address, static_cast<uint8_t>(A));
} else { } else {
memory.WriteWord(address, A); WriteWord(address, A);
} }
} }
// TODO: Make this work with the Clock class of the CPU
void Cpu::STP() { void Cpu::STP() {
// During the next phase 2 clock cycle, stop the processors oscillator input stopped_ = true;
// The processor is effectively shut down until a reset occurs (RES` pin). callbacks_.idle(false);
callbacks_.idle(false);
} }
void Cpu::STX(uint16_t address) { void Cpu::STX(uint16_t address) {
if (GetIndexSize()) { if (GetIndexSize()) {
memory.WriteByte(address, static_cast<uint8_t>(X)); WriteByte(address, static_cast<uint8_t>(X));
} else { } else {
memory.WriteWord(address, X); WriteWord(address, X);
} }
} }
void Cpu::STY(uint16_t address) { void Cpu::STY(uint16_t address) {
if (GetIndexSize()) { if (GetIndexSize()) {
memory.WriteByte(address, static_cast<uint8_t>(Y)); WriteByte(address, static_cast<uint8_t>(Y));
} else { } else {
memory.WriteWord(address, Y); WriteWord(address, Y);
} }
} }
void Cpu::STZ(uint16_t address) { void Cpu::STZ(uint16_t address) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
memory.WriteByte(address, 0x00); WriteByte(address, 0x00);
} else { } else {
memory.WriteWord(address, 0x0000); WriteWord(address, 0x0000);
} }
} }
@@ -733,7 +787,7 @@ void Cpu::TCD() {
SetNegativeFlag(D & 0x80); SetNegativeFlag(D & 0x80);
} }
void Cpu::TCS() { memory.SetSP(A); } void Cpu::TCS() { SetSP(A); }
void Cpu::TDC() { void Cpu::TDC() {
A = D; A = D;
@@ -742,17 +796,17 @@ void Cpu::TDC() {
} }
void Cpu::TRB(uint16_t address) { void Cpu::TRB(uint16_t address) {
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
SetZeroFlag((A & value) == 0); SetZeroFlag((A & value) == 0);
value &= ~A; value &= ~A;
memory.WriteByte(address, value); WriteByte(address, value);
} }
void Cpu::TSB(uint16_t address) { void Cpu::TSB(uint16_t address) {
uint8_t value = memory.ReadByte(address); uint8_t value = ReadByte(address);
SetZeroFlag((A & value) == 0); SetZeroFlag((A & value) == 0);
value |= A; value |= A;
memory.WriteByte(address, value); WriteByte(address, value);
} }
void Cpu::TSC() { void Cpu::TSC() {
@@ -762,53 +816,68 @@ void Cpu::TSC() {
} }
void Cpu::TSX() { void Cpu::TSX() {
AdrImp();
X = SP(); X = SP();
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
} }
void Cpu::TXA() { void Cpu::TXA() {
AdrImp();
A = X; A = X;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} }
void Cpu::TXS() { memory.SetSP(X); } void Cpu::TXS() {
AdrImp();
SetSP(X);
}
void Cpu::TXY() { void Cpu::TXY() {
AdrImp();
Y = X; Y = X;
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
} }
void Cpu::TYA() { void Cpu::TYA() {
AdrImp();
A = Y; A = Y;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} }
void Cpu::TYX() { void Cpu::TYX() {
X = Y; AdrImp();
if (GetIndexSize()) {
X = Y & 0xFF;
} else {
X = Y;
}
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80); SetNegativeFlag(Y & 0x80);
} }
// TODO: Make this communicate with the SNES class
void Cpu::WAI() { void Cpu::WAI() {
// Pull the RDY pin low waiting_ = true;
// Power consumption is reduced(?) callbacks_.idle(false);
// RDY remains low until an external hardware interupt callbacks_.idle(false);
// (NMI, IRQ, ABORT, or RESET) is received from the SNES class
} }
void Cpu::XBA() { void Cpu::XBA() {
uint8_t lowByte = A & 0xFF; uint8_t lowByte = A & 0xFF;
uint8_t highByte = (A >> 8) & 0xFF; uint8_t highByte = (A >> 8) & 0xFF;
A = (lowByte << 8) | highByte; A = (lowByte << 8) | highByte;
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
callbacks_.idle(false);
CheckInt();
callbacks_.idle(false);
} }
void Cpu::XCE() { void Cpu::XCE() {
AdrImp();
uint8_t carry = status & 0x01; uint8_t carry = status & 0x01;
status &= ~0x01; status &= ~0x01;
status |= E; status |= E;