Add cpu idling and int checks to instructions, refactor branching

This commit is contained in:
scawful
2024-04-22 19:09:00 -04:00
parent 365811739a
commit f301976316
6 changed files with 338 additions and 141 deletions

View File

@@ -27,24 +27,6 @@ void Spc700::Reset(bool hard) {
reset_wanted_ = true; reset_wanted_ = true;
} }
void Spc700::BootIplRom() {
PC = 0xFFC0;
A = 0;
X = 0;
Y = 0;
int i = 0;
while (PC != 0xFFC0 + 0x3F) {
uint8_t opcode = read(PC);
ExecuteInstructions(opcode);
PC++;
i++;
if (i > 1000) {
break;
}
}
}
void Spc700::RunOpcode() { void Spc700::RunOpcode() {
if (reset_wanted_) { if (reset_wanted_) {
// based on 6502, brk without writes // based on 6502, brk without writes

View File

@@ -130,8 +130,6 @@ class Spc700 {
void Reset(bool hard = false); void Reset(bool hard = false);
void BootIplRom();
void RunOpcode(); void RunOpcode();
void ExecuteInstructions(uint8_t opcode); void ExecuteInstructions(uint8_t opcode);

View File

@@ -66,7 +66,7 @@ void Cpu::RunOpcode() {
SetSP(sp); SetSP(sp);
SetInterruptFlag(true); E = 1;
SetInterruptFlag(true); SetInterruptFlag(true);
SetDecimalFlag(false); SetDecimalFlag(false);
SetFlags(status); // updates x and m flags, clears SetFlags(status); // updates x and m flags, clears
@@ -346,21 +346,21 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
case 0x90: // BCC Branch if carry clear case 0x90: // BCC Branch if carry clear
{ {
operand = FetchByte(); operand = FetchByte();
BCC(operand); DoBranch(!GetCarryFlag());
break; break;
} }
case 0xB0: // BCS Branch if carry set case 0xB0: // BCS Branch if carry set
{ {
operand = FetchByte(); operand = FetchByte();
BCS(operand); DoBranch(GetCarryFlag());
break; break;
} }
case 0xF0: // BEQ Branch if equal (zero set) case 0xF0: // BEQ Branch if equal (zero set)
{ {
operand = FetchByte(); operand = FetchByte();
BEQ(operand); DoBranch(GetZeroFlag());
break; break;
} }
@@ -398,29 +398,27 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
case 0x30: // BMI Branch if minus (negative set) case 0x30: // BMI Branch if minus (negative set)
{ {
operand = FetchByte(); DoBranch(GetNegativeFlag());
BMI(operand);
break; break;
} }
case 0xD0: // BNE Branch if not equal (zero clear) case 0xD0: // BNE Branch if not equal (zero clear)
{ {
operand = FetchSignedByte(); DoBranch(!GetZeroFlag());
BNE(operand);
break; break;
} }
case 0x10: // BPL Branch if plus (negative clear) case 0x10: // BPL Branch if plus (negative clear)
{ {
operand = FetchSignedByte(); operand = FetchByte();
BPL(operand); DoBranch(!GetNegativeFlag());
break; break;
} }
case 0x80: // BRA Branch always case 0x80: // BRA Branch always
{ {
operand = FetchByte(); operand = FetchByte();
BRA(operand); DoBranch(true);
break; break;
} }
@@ -431,7 +429,7 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
} }
case 0x82: // BRL Branch always long case 0x82: // BRL Branch always long
{ // operand = FetchSignedWord(); {
operand = FetchWord(); operand = FetchWord();
BRL(operand); BRL(operand);
break; break;
@@ -440,14 +438,14 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
case 0x50: // BVC Branch if overflow clear case 0x50: // BVC Branch if overflow clear
{ {
operand = FetchByte(); operand = FetchByte();
BVC(operand); DoBranch(!GetOverflowFlag());
break; break;
} }
case 0x70: // BVS Branch if overflow set case 0x70: // BVS Branch if overflow set
{ {
operand = FetchByte(); operand = FetchByte();
BVS(operand); DoBranch(GetOverflowFlag());
break; break;
} }
@@ -796,7 +794,7 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
} }
case 0x5C: // JMP Absolute Long case 0x5C: // JMP Absolute Long
{ {
JML(AbsoluteLong()); JML(FetchWord());
break; break;
} }
case 0x6C: // JMP Absolute Indirect case 0x6C: // JMP Absolute Indirect
@@ -827,7 +825,7 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
case 0x22: // JSL Absolute Long case 0x22: // JSL Absolute Long
{ {
JSL(AbsoluteLong()); JSL(FetchWord());
break; break;
} }
@@ -1023,8 +1021,16 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
break; break;
} }
case 0x42:
WDM();
break;
case 0x44:
MVP();
break;
case 0x54: case 0x54:
// MVN(); MVN();
break; break;
case 0xEA: // NOP case 0xEA: // NOP
@@ -1604,14 +1610,12 @@ uint8_t Cpu::GetInstructionLength(uint8_t opcode) {
case 0x00: // BRK case 0x00: // BRK
case 0x02: // COP case 0x02: // COP
PC = next_pc_; PC = next_pc_;
PB = next_pb_;
return 0; return 0;
// TODO: Handle JMPs in logging.
case 0x20: // JSR Absolute case 0x20: // JSR Absolute
case 0x4C: // JMP Absolute case 0x4C: // JMP Absolute
case 0x6C: // JMP Absolute Indirect case 0x6C: // JMP Absolute Indirect
case 0x5C: // JMP Absolute Indexed Indirect
case 0x22: // JSL Absolute Long
case 0x7C: // JMP Absolute Indexed Indirect case 0x7C: // JMP Absolute Indexed Indirect
case 0xFC: // JSR Absolute Indexed Indirect case 0xFC: // JSR Absolute Indexed Indirect
case 0xDC: // JMP Absolute Indirect Long case 0xDC: // JMP Absolute Indirect Long
@@ -1620,6 +1624,12 @@ uint8_t Cpu::GetInstructionLength(uint8_t opcode) {
PC = next_pc_; PC = next_pc_;
return 0; return 0;
case 0x22: // JSL Absolute Long
case 0x5C: // JMP Absolute Indexed Indirect
PC = next_pc_;
PB = next_pb_;
return 0;
case 0x80: // BRA Relative case 0x80: // BRA Relative
PC += next_pc_; PC += next_pc_;
return 2; return 2;

View File

@@ -250,6 +250,16 @@ class Cpu : public Loggable, public core::ExperimentFlags {
return (high << 16) | low; return (high << 16) | low;
} }
void DoBranch(bool check) {
if (!check) CheckInt();
uint8_t value = FetchByte();
if (check) {
CheckInt();
callbacks_.idle(false); // taken branch: 1 extra cycle
next_pc_ += (int8_t)value;
}
}
// ========================================================================== // ==========================================================================
// Addressing Modes // Addressing Modes
@@ -519,13 +529,13 @@ class Cpu : public Loggable, public core::ExperimentFlags {
void JMP(uint16_t address); void JMP(uint16_t address);
// JML: Jump long // JML: Jump long
void JML(uint32_t address); void JML(uint16_t address);
// JSR: Jump to subroutine // JSR: Jump to subroutine
void JSR(uint16_t address); void JSR(uint16_t address);
// JSL: Jump to subroutine long // JSL: Jump to subroutine long
void JSL(uint32_t address); void JSL(uint16_t address);
// LDA: Load accumulator // LDA: Load accumulator
void LDA(uint16_t address, bool immediate = false, bool direct_page = false, void LDA(uint16_t address, bool immediate = false, bool direct_page = false,
@@ -541,10 +551,10 @@ class Cpu : public Loggable, public core::ExperimentFlags {
void LSR(uint16_t address, bool accumulator = false); void LSR(uint16_t address, bool accumulator = false);
// MVN: Block move next // MVN: Block move next
void MVN(uint16_t source, uint16_t dest, uint16_t length); void MVN();
// MVP: Block move previous // MVP: Block move previous
void MVP(uint16_t source, uint16_t dest, uint16_t length); void MVP();
// NOP: No operation // NOP: No operation
void NOP(); void NOP();
@@ -769,6 +779,7 @@ class Cpu : public Loggable, public core::ExperimentFlags {
uint16_t last_call_frame_; uint16_t last_call_frame_;
uint16_t next_pc_; uint16_t next_pc_;
uint8_t next_pb_;
memory::CpuCallbacks callbacks_; memory::CpuCallbacks callbacks_;
memory::Memory& memory; memory::Memory& memory;

View File

@@ -10,13 +10,12 @@ namespace emu {
/** /**
* 65816 Instruction Set * 65816 Instruction Set
*
* TODO: STP, WDM
*/ */
void Cpu::ADC(uint16_t operand) { void Cpu::ADC(uint16_t operand) {
bool C = GetCarryFlag(); bool C = GetCarryFlag();
if (GetAccumulatorSize()) { // 8-bit mode if (GetAccumulatorSize()) { // 8-bit mode
CheckInt();
uint16_t result = static_cast<uint16_t>(A & 0xFF) + uint16_t result = static_cast<uint16_t>(A & 0xFF) +
static_cast<uint16_t>(operand) + (C ? 1 : 0); static_cast<uint16_t>(operand) + (C ? 1 : 0);
SetCarryFlag(result > 0xFF); // Update the carry flag SetCarryFlag(result > 0xFF); // Update the carry flag
@@ -50,6 +49,7 @@ 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
CheckInt();
operand = isImmediate ? value : ReadByte(value); operand = isImmediate ? value : ReadByte(value);
A &= operand; A &= operand;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
@@ -71,13 +71,24 @@ void Cpu::ANDAbsoluteLong(uint32_t address) {
} }
void Cpu::ASL(uint16_t address) { void Cpu::ASL(uint16_t address) {
uint8_t value = ReadByte(address); if (GetAccumulatorSize()) { // 8-bit mode
SetCarryFlag(!(value & 0x80)); // Set carry flag if bit 7 is set uint8_t value = ReadByte(address);
value <<= 1; // Shift left callbacks_.idle(false);
value &= 0xFE; // Clear bit 0 SetCarryFlag(value & 0x80);
WriteByte(address, value); value <<= 1;
SetNegativeFlag(!value); CheckInt();
SetZeroFlag(value); WriteByte(address, value);
SetZeroFlag(value == 0);
SetNegativeFlag(value & 0x80);
} else { // 16-bit mode
uint16_t value = ReadWord(address);
callbacks_.idle(false);
SetCarryFlag(value & 0x8000);
value <<= 1;
WriteWord(address, value);
SetZeroFlag(value == 0);
SetNegativeFlag(value & 0x8000);
}
} }
void Cpu::BCC(int8_t offset) { void Cpu::BCC(int8_t offset) {
@@ -99,6 +110,7 @@ void Cpu::BEQ(int8_t offset) {
} }
void Cpu::BIT(uint16_t address) { void Cpu::BIT(uint16_t address) {
CheckInt();
uint8_t value = ReadByte(address); uint8_t value = ReadByte(address);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
SetOverflowFlag(value & 0x40); SetOverflowFlag(value & 0x40);
@@ -107,39 +119,43 @@ void Cpu::BIT(uint16_t address) {
void Cpu::BMI(int8_t offset) { void Cpu::BMI(int8_t offset) {
if (GetNegativeFlag()) { // If the negative flag is set if (GetNegativeFlag()) { // If the negative flag is set
next_pc_ = offset; next_pc_ = PC + offset;
} }
} }
void Cpu::BNE(int8_t offset) { void Cpu::BNE(int8_t offset) {
if (!GetZeroFlag()) { // If the zero flag is clear if (!GetZeroFlag()) { // If the zero flag is clear
// PC += offset; // PC += offset;
next_pc_ = offset; next_pc_ = PC + offset;
} }
} }
void Cpu::BPL(int8_t offset) { void Cpu::BPL(int8_t offset) {
if (!GetNegativeFlag()) { // If the negative flag is clear if (!GetNegativeFlag()) { // If the negative flag is clear
next_pc_ = offset; next_pc_ = PC + offset;
} }
} }
void Cpu::BRA(int8_t offset) { next_pc_ = offset; } void Cpu::BRA(int8_t offset) { next_pc_ = PC + offset; }
void Cpu::BRK() { void Cpu::BRK() {
// ReadOpcode(); // ReadOpcode();
next_pc_ += 2; // Increment the program counter by 2 next_pc_ = PC + 2; // Increment the program counter by 2
ReadByte(PC); // Read the next byte ReadByte(PC); // Read the next byte
PushByte(PB); PushByte(PB);
PushByte(PC); // ,false PushByte(PC); // ,false
PushByte(status); PushByte(status);
SetInterruptFlag(true); SetInterruptFlag(true);
SetDecimalFlag(false); SetDecimalFlag(false);
PB = 0; next_pb_ = 0;
PC = ReadWord(0xFFE6); // ,true next_pc_ = ReadWord(0xFFE6); // ,true
} }
void Cpu::BRL(int16_t offset) { next_pc_ = offset; } void Cpu::BRL(int16_t offset) {
next_pc_ = PC + offset;
CheckInt();
callbacks_.idle(false);
}
void Cpu::BVC(int8_t offset) { void Cpu::BVC(int8_t offset) {
if (!GetOverflowFlag()) { // If the overflow flag is clear if (!GetOverflowFlag()) { // If the overflow flag is clear
@@ -153,19 +169,32 @@ void Cpu::BVS(int8_t offset) {
} }
} }
void Cpu::CLC() { status &= ~0x01; } void Cpu::CLC() {
AdrImp();
status &= ~0x01;
}
void Cpu::CLD() { status &= ~0x08; } void Cpu::CLD() {
AdrImp();
status &= ~0x08;
}
void Cpu::CLI() { status &= ~0x04; } void Cpu::CLI() {
AdrImp();
status &= ~0x04;
}
void Cpu::CLV() { status &= ~0x40; } void Cpu::CLV() {
AdrImp();
status &= ~0x40;
}
// n Set if MSB of result is set; else cleared // n Set if MSB of result is set; else cleared
// z Set if result is zero; else cleared // z Set if result is zero; else cleared
// c Set if no borrow; else cleared // c Set if no borrow; else cleared
void Cpu::CMP(uint32_t value, bool isImmediate) { void Cpu::CMP(uint32_t value, bool isImmediate) {
if (GetAccumulatorSize()) { // 8-bit if (GetAccumulatorSize()) { // 8-bit
CheckInt();
uint8_t result; uint8_t result;
if (isImmediate) { if (isImmediate) {
result = A - (value & 0xFF); result = A - (value & 0xFF);
@@ -191,7 +220,7 @@ 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_ = PC + 2; // Increment the program counter by 2
PushWord(next_pc_); PushWord(next_pc_);
PushByte(status); PushByte(status);
SetInterruptFlag(true); SetInterruptFlag(true);
@@ -201,10 +230,13 @@ void Cpu::COP() {
next_pc_ = ReadWord(0xFFE4); next_pc_ = ReadWord(0xFFE4);
} }
SetDecimalFlag(false); SetDecimalFlag(false);
next_pb_ = 0;
next_pc_ = ReadWord(0xFFE4);
} }
void Cpu::CPX(uint32_t value, bool isImmediate) { void Cpu::CPX(uint32_t value, bool isImmediate) {
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
CheckInt();
uint8_t memory_value = isImmediate ? value : ReadByte(value); uint8_t memory_value = isImmediate ? value : ReadByte(value);
compare(X, memory_value); compare(X, memory_value);
} else { // 16-bit } else { // 16-bit
@@ -215,6 +247,7 @@ void Cpu::CPX(uint32_t value, bool isImmediate) {
void Cpu::CPY(uint32_t value, bool isImmediate) { void Cpu::CPY(uint32_t value, bool isImmediate) {
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
CheckInt();
uint8_t memory_value = isImmediate ? value : ReadByte(value); uint8_t memory_value = isImmediate ? value : ReadByte(value);
compare(Y, memory_value); compare(Y, memory_value);
} else { // 16-bit } else { // 16-bit
@@ -225,6 +258,7 @@ void Cpu::CPY(uint32_t value, bool isImmediate) {
void Cpu::DEC(uint32_t address, bool accumulator) { void Cpu::DEC(uint32_t address, bool accumulator) {
if (accumulator) { if (accumulator) {
AdrImp();
if (GetAccumulatorSize()) { // 8-bit if (GetAccumulatorSize()) { // 8-bit
A = (A - 1) & 0xFF; A = (A - 1) & 0xFF;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
@@ -240,12 +274,15 @@ void Cpu::DEC(uint32_t address, bool accumulator) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
uint8_t value = ReadByte(address); uint8_t value = ReadByte(address);
value--; value--;
callbacks_.idle(false);
CheckInt();
WriteByte(address, value); WriteByte(address, value);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
} else { } else {
uint16_t value = ReadWord(address); uint16_t value = ReadWord(address);
value--; value--;
callbacks_.idle(false);
WriteWord(address, value); WriteWord(address, value);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
SetNegativeFlag(value & 0x8000); SetNegativeFlag(value & 0x8000);
@@ -253,6 +290,7 @@ void Cpu::DEC(uint32_t address, bool accumulator) {
} }
void Cpu::DEX() { void Cpu::DEX() {
AdrImp();
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
X = static_cast<uint8_t>(X - 1); X = static_cast<uint8_t>(X - 1);
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
@@ -265,6 +303,7 @@ void Cpu::DEX() {
} }
void Cpu::DEY() { void Cpu::DEY() {
AdrImp();
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
Y = static_cast<uint8_t>(Y - 1); Y = static_cast<uint8_t>(Y - 1);
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
@@ -278,6 +317,7 @@ void Cpu::DEY() {
void Cpu::EOR(uint32_t address, bool isImmediate) { void Cpu::EOR(uint32_t address, bool isImmediate) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
CheckInt();
A ^= isImmediate ? address : ReadByte(address); A ^= isImmediate ? address : ReadByte(address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
@@ -290,6 +330,7 @@ void Cpu::EOR(uint32_t address, bool isImmediate) {
void Cpu::INC(uint32_t address, bool accumulator) { void Cpu::INC(uint32_t address, bool accumulator) {
if (accumulator) { if (accumulator) {
AdrImp();
if (GetAccumulatorSize()) { // 8-bit if (GetAccumulatorSize()) { // 8-bit
A = (A + 1) & 0xFF; A = (A + 1) & 0xFF;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
@@ -305,12 +346,15 @@ void Cpu::INC(uint32_t address, bool accumulator) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
uint8_t value = ReadByte(address); uint8_t value = ReadByte(address);
value++; value++;
callbacks_.idle(false);
CheckInt();
WriteByte(address, value); WriteByte(address, value);
SetNegativeFlag(value & 0x80); SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
} else { } else {
uint16_t value = ReadWord(address); uint16_t value = ReadWord(address);
value++; value++;
callbacks_.idle(false);
WriteWord(address, value); WriteWord(address, value);
SetNegativeFlag(value & 0x8000); SetNegativeFlag(value & 0x8000);
SetZeroFlag(value == 0); SetZeroFlag(value == 0);
@@ -318,6 +362,7 @@ void Cpu::INC(uint32_t address, bool accumulator) {
} }
void Cpu::INX() { void Cpu::INX() {
AdrImp();
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
X = static_cast<uint8_t>(X + 1); X = static_cast<uint8_t>(X + 1);
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
@@ -330,6 +375,7 @@ void Cpu::INX() {
} }
void Cpu::INY() { void Cpu::INY() {
AdrImp();
if (GetIndexSize()) { // 8-bit if (GetIndexSize()) { // 8-bit
Y = static_cast<uint8_t>(Y + 1); Y = static_cast<uint8_t>(Y + 1);
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
@@ -345,21 +391,26 @@ void Cpu::JMP(uint16_t address) {
next_pc_ = address; // Set program counter to the new address next_pc_ = address; // Set program counter to the new address
} }
void Cpu::JML(uint32_t address) { void Cpu::JML(uint16_t address) {
next_pc_ = static_cast<uint16_t>(address & 0xFFFF); CheckInt();
// Set the PBR to the upper 8 bits of the address next_pc_ = address;
PB = static_cast<uint8_t>((address >> 16) & 0xFF); uint8_t new_pb = ReadByte(PC + 2);
next_pb_ = new_pb;
} }
void Cpu::JSR(uint16_t address) { void Cpu::JSR(uint16_t address) {
callbacks_.idle(false);
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(uint16_t address) {
PushLong(PC); // Push the program counter onto the stack as a long PushByte(PB);
// value (24 bits) callbacks_.idle(false);
uint8_t new_pb = ReadByte(PC + 2);
PushWord(PC);
next_pc_ = address; // Set program counter to the new address next_pc_ = address; // Set program counter to the new address
next_pb_ = new_pb;
} }
void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page, void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page,
@@ -369,6 +420,7 @@ void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page,
bank = 0; bank = 0;
} }
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
CheckInt();
A = isImmediate ? address : ReadByte((bank << 16) | address); A = isImmediate ? address : ReadByte((bank << 16) | address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
@@ -381,6 +433,7 @@ void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page,
void Cpu::LDX(uint16_t address, bool isImmediate) { void Cpu::LDX(uint16_t address, bool isImmediate) {
if (GetIndexSize()) { if (GetIndexSize()) {
CheckInt();
X = isImmediate ? address : ReadByte(address); X = isImmediate ? address : ReadByte(address);
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
@@ -393,6 +446,7 @@ 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()) {
CheckInt();
Y = isImmediate ? address : ReadByte(address); Y = isImmediate ? address : ReadByte(address);
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80); SetNegativeFlag(Y & 0x80);
@@ -405,6 +459,7 @@ void Cpu::LDY(uint16_t address, bool isImmediate) {
void Cpu::LSR(uint16_t address, bool accumulator) { void Cpu::LSR(uint16_t address, bool accumulator) {
if (accumulator) { if (accumulator) {
AdrImp();
if (GetAccumulatorSize()) { // 8-bit if (GetAccumulatorSize()) { // 8-bit
SetCarryFlag(A & 0x01); SetCarryFlag(A & 0x01);
A >>= 1; A >>= 1;
@@ -418,46 +473,73 @@ void Cpu::LSR(uint16_t address, bool accumulator) {
} }
return; return;
} }
uint8_t value = ReadByte(address);
SetCarryFlag(value & 0x01);
value >>= 1;
WriteByte(address, value);
SetNegativeFlag(false);
SetZeroFlag(value == 0);
}
void Cpu::MVN(uint16_t source, uint16_t dest, uint16_t length) { if (GetAccumulatorSize()) {
for (uint16_t i = 0; i < length; i++) { uint8_t value = ReadByte(address);
WriteByte(dest, ReadByte(source)); callbacks_.idle(false);
source++; SetCarryFlag(value & 0x01);
dest++; value >>= 1;
CheckInt();
WriteByte(address, value);
SetNegativeFlag(false);
SetZeroFlag(value == 0);
} else {
uint16_t value = ReadWord(address);
SetCarryFlag(value & 0x0001);
value >>= 1;
WriteWord(address, value);
SetNegativeFlag(false);
SetZeroFlag(value == 0);
} }
} }
void Cpu::MVP(uint16_t source, uint16_t dest, uint16_t length) { void Cpu::MVN() {
for (uint16_t i = 0; i < length; i++) { uint8_t dest = ReadByte(PC + 1);
WriteByte(dest, ReadByte(source)); uint8_t src = ReadByte(PC + 2);
source--; next_pc_ = PC + 3;
dest--; DB = dest;
WriteByte((dest << 16) | Y, ReadByte((src << 16) | X));
A--;
X++;
Y++;
if (A != 0xFFFF) {
next_pc_ -= 3;
} }
if (GetIndexSize()) {
X &= 0xFF;
Y &= 0xFF;
}
callbacks_.idle(false);
CheckInt();
callbacks_.idle(false);
}
void Cpu::MVP() {
uint8_t dest = ReadByte(PC + 1);
uint8_t src = ReadByte(PC + 2);
next_pc_ = PC + 3;
DB = dest;
WriteByte((dest << 16) | Y, ReadByte((src << 16) | X));
A--;
X--;
Y--;
if (A != 0xFFFF) {
next_pc_ -= 3;
}
if (GetIndexSize()) {
X &= 0xFF;
Y &= 0xFF;
}
callbacks_.idle(false);
CheckInt();
callbacks_.idle(false);
} }
void Cpu::NOP() { AdrImp(); } void Cpu::NOP() { AdrImp(); }
// 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()) {
CheckInt();
A |= isImmediate ? address : ReadByte(address); A |= isImmediate ? address : ReadByte(address);
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
@@ -615,6 +697,7 @@ void Cpu::REP() {
void Cpu::ROL(uint32_t address, bool accumulator) { void Cpu::ROL(uint32_t address, bool accumulator) {
if (accumulator) { if (accumulator) {
AdrImp();
if (GetAccumulatorSize()) { // 8-bit if (GetAccumulatorSize()) { // 8-bit
uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; uint8_t carry = GetCarryFlag() ? 0x01 : 0x00;
SetCarryFlag(A & 0x80); SetCarryFlag(A & 0x80);
@@ -633,18 +716,33 @@ void Cpu::ROL(uint32_t address, bool accumulator) {
return; return;
} }
uint8_t value = ReadByte(address); if (GetAccumulatorSize()) {
uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; uint8_t value = ReadByte(address);
SetCarryFlag(value & 0x80); callbacks_.idle(false);
value <<= 1; uint8_t carry = GetCarryFlag() ? 0x01 : 0x00;
value |= carry; SetCarryFlag(value & 0x80);
WriteByte(address, value); value <<= 1;
SetNegativeFlag(value & 0x80); value |= carry;
SetZeroFlag(value == 0); CheckInt();
WriteByte(address, value);
SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0);
} else {
uint16_t value = ReadWord(address);
callbacks_.idle(false);
uint8_t carry = GetCarryFlag() ? 0x01 : 0x00;
SetCarryFlag(value & 0x8000);
value <<= 1;
value |= carry;
WriteWord(address, value);
SetNegativeFlag(value & 0x8000);
SetZeroFlag(value == 0);
}
} }
void Cpu::ROR(uint32_t address, bool accumulator) { void Cpu::ROR(uint32_t address, bool accumulator) {
if (accumulator) { if (accumulator) {
AdrImp();
if (GetAccumulatorSize()) { // 8-bit if (GetAccumulatorSize()) { // 8-bit
uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; uint8_t carry = GetCarryFlag() ? 0x80 : 0x00;
SetCarryFlag(A & 0x01); SetCarryFlag(A & 0x01);
@@ -663,27 +761,54 @@ void Cpu::ROR(uint32_t address, bool accumulator) {
return; return;
} }
uint8_t value = ReadByte(address); if (GetAccumulatorSize()) {
uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; uint8_t value = ReadByte(address);
SetCarryFlag(value & 0x01); callbacks_.idle(false);
value >>= 1; uint8_t carry = GetCarryFlag() ? 0x80 : 0x00;
value |= carry; SetCarryFlag(value & 0x01);
WriteByte(address, value); value >>= 1;
SetNegativeFlag(value & 0x80); value |= carry;
SetZeroFlag(value == 0); CheckInt();
WriteByte(address, value);
SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0);
} else {
uint16_t value = ReadWord(address);
callbacks_.idle(false);
uint8_t carry = GetCarryFlag() ? 0x8000 : 0x00;
SetCarryFlag(value & 0x0001);
value >>= 1;
value |= carry;
WriteWord(address, value);
SetNegativeFlag(value & 0x8000);
SetZeroFlag(value == 0);
}
} }
void Cpu::RTI() { void Cpu::RTI() {
callbacks_.idle(false);
callbacks_.idle(false);
status = PopByte(); status = PopByte();
PC = PopWord(); next_pc_ = PopWord();
CheckInt();
next_pb_ = PopByte();
} }
void Cpu::RTL() { void Cpu::RTL() {
callbacks_.idle(false);
callbacks_.idle(false);
next_pc_ = PopWord(); next_pc_ = PopWord();
PB = PopByte(); CheckInt();
next_pb_ = PopByte();
} }
void Cpu::RTS() { last_call_frame_ = PopWord(); } void Cpu::RTS() {
callbacks_.idle(false);
callbacks_.idle(false);
last_call_frame_ = PopWord();
CheckInt();
callbacks_.idle(false);
}
void Cpu::SBC(uint32_t value, bool isImmediate) { void Cpu::SBC(uint32_t value, bool isImmediate) {
uint16_t operand; uint16_t operand;
@@ -702,6 +827,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
CheckInt();
operand = isImmediate ? value : 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
@@ -718,11 +844,20 @@ void Cpu::SBC(uint32_t value, bool isImmediate) {
} }
} }
void Cpu::SEC() { status |= 0x01; } void Cpu::SEC() {
AdrImp();
status |= 0x01;
}
void Cpu::SED() { status |= 0x08; } void Cpu::SED() {
AdrImp();
status |= 0x08;
}
void Cpu::SEI() { status |= 0x04; } void Cpu::SEI() {
AdrImp();
status |= 0x04;
}
void Cpu::SEP() { void Cpu::SEP() {
auto byte = FetchByte(); auto byte = FetchByte();
@@ -733,6 +868,7 @@ void Cpu::SEP() {
void Cpu::STA(uint32_t address) { void Cpu::STA(uint32_t address) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
CheckInt();
WriteByte(address, static_cast<uint8_t>(A)); WriteByte(address, static_cast<uint8_t>(A));
} else { } else {
WriteWord(address, A); WriteWord(address, A);
@@ -747,6 +883,7 @@ void Cpu::STP() {
void Cpu::STX(uint16_t address) { void Cpu::STX(uint16_t address) {
if (GetIndexSize()) { if (GetIndexSize()) {
CheckInt();
WriteByte(address, static_cast<uint8_t>(X)); WriteByte(address, static_cast<uint8_t>(X));
} else { } else {
WriteWord(address, X); WriteWord(address, X);
@@ -755,6 +892,7 @@ void Cpu::STX(uint16_t address) {
void Cpu::STY(uint16_t address) { void Cpu::STY(uint16_t address) {
if (GetIndexSize()) { if (GetIndexSize()) {
CheckInt();
WriteByte(address, static_cast<uint8_t>(Y)); WriteByte(address, static_cast<uint8_t>(Y));
} else { } else {
WriteWord(address, Y); WriteWord(address, Y);
@@ -763,6 +901,7 @@ void Cpu::STY(uint16_t address) {
void Cpu::STZ(uint16_t address) { void Cpu::STZ(uint16_t address) {
if (GetAccumulatorSize()) { if (GetAccumulatorSize()) {
CheckInt();
WriteByte(address, 0x00); WriteByte(address, 0x00);
} else { } else {
WriteWord(address, 0x0000); WriteWord(address, 0x0000);
@@ -770,46 +909,82 @@ void Cpu::STZ(uint16_t address) {
} }
void Cpu::TAX() { void Cpu::TAX() {
X = A; AdrImp();
if (GetIndexSize()) {
X = A & 0xFF;
} else {
X = A;
}
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
} }
void Cpu::TAY() { void Cpu::TAY() {
Y = A; AdrImp();
if (GetIndexSize()) {
Y = A & 0xFF;
} else {
Y = A;
}
SetZeroFlag(Y == 0); SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80); SetNegativeFlag(Y & 0x80);
} }
void Cpu::TCD() { void Cpu::TCD() {
AdrImp();
D = A; D = A;
SetZeroFlag(D == 0); SetZeroFlag(D == 0);
SetNegativeFlag(D & 0x80); SetNegativeFlag(D & 0x80);
} }
void Cpu::TCS() { SetSP(A); } void Cpu::TCS() {
AdrImp();
SetSP(A);
}
void Cpu::TDC() { void Cpu::TDC() {
AdrImp();
A = D; A = D;
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} }
void Cpu::TRB(uint16_t address) { void Cpu::TRB(uint16_t address) {
uint8_t value = ReadByte(address); if (GetAccumulatorSize()) {
SetZeroFlag((A & value) == 0); uint8_t value = ReadByte(address);
value &= ~A; callbacks_.idle(false);
WriteByte(address, value); SetZeroFlag((A & value) == 0);
value &= ~A;
CheckInt();
WriteByte(address, value);
} else {
uint16_t value = ReadWord(address);
callbacks_.idle(false);
SetZeroFlag((A & value) == 0);
value &= ~A;
WriteWord(address, value);
}
} }
void Cpu::TSB(uint16_t address) { void Cpu::TSB(uint16_t address) {
uint8_t value = ReadByte(address); if (GetAccumulatorSize()) {
SetZeroFlag((A & value) == 0); uint8_t value = ReadByte(address);
value |= A; callbacks_.idle(false);
WriteByte(address, value); SetZeroFlag((A & value) == 0);
value |= A;
CheckInt();
WriteByte(address, value);
} else {
uint16_t value = ReadWord(address);
callbacks_.idle(false);
SetZeroFlag((A & value) == 0);
value |= A;
WriteWord(address, value);
}
} }
void Cpu::TSC() { void Cpu::TSC() {
AdrImp();
A = SP(); A = SP();
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
@@ -817,14 +992,22 @@ void Cpu::TSC() {
void Cpu::TSX() { void Cpu::TSX() {
AdrImp(); AdrImp();
X = SP(); if (GetIndexSize()) {
X = SP() & 0xFF;
} else {
X = SP();
}
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
} }
void Cpu::TXA() { void Cpu::TXA() {
AdrImp(); AdrImp();
A = X; if (GetAccumulatorSize()) {
A = X & 0xFF;
} else {
A = X;
}
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} }
@@ -836,14 +1019,22 @@ void Cpu::TXS() {
void Cpu::TXY() { void Cpu::TXY() {
AdrImp(); AdrImp();
Y = X; if (GetIndexSize()) {
Y = X & 0xFF;
} else {
Y = X;
}
SetZeroFlag(X == 0); SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80); SetNegativeFlag(X & 0x80);
} }
void Cpu::TYA() { void Cpu::TYA() {
AdrImp(); AdrImp();
A = Y; if (GetAccumulatorSize()) {
A = Y & 0xFF;
} else {
A = Y;
}
SetZeroFlag(A == 0); SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80); SetNegativeFlag(A & 0x80);
} }
@@ -865,6 +1056,11 @@ void Cpu::WAI() {
callbacks_.idle(false); callbacks_.idle(false);
} }
void Cpu::WDM() {
CheckInt();
ReadByte(PC);
}
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;

View File

@@ -25,7 +25,7 @@ void TransferByte(SNES* snes, MemoryImpl* memory, uint16_t aAdr, uint8_t aBank,
uint8_t Read(MemoryImpl* memory, uint16_t address); uint8_t Read(MemoryImpl* memory, uint16_t address);
void Write(MemoryImpl* memory, uint16_t address, uint8_t data); void Write(MemoryImpl* memory, uint16_t address, uint8_t data);
void StartDma(MemoryImpl* memory, uint8_t val, bool hdma); void StartDma(MemoryImpl* memory, uint8_t val, bool hdma);
void DoDma(MemoryImpl* memory, int cycles); void DoDma(SNES* snes, MemoryImpl* memory, int cycles);
} // namespace dma } // namespace dma
} // namespace memory } // namespace memory