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

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