Files
MesenCE/Core/PCE/PceCpu.Instructions.cpp
SourMesen e391fd8f9a Code: Add auto-formatting rules for C++ (clang-format) and enforce in CI via "clang-format" and "dotnet format" (#78)
* Code: Add auto-formatting rules for C++ projects (clang-format) and enforce code style via "clang-format" and "dotnet format"

* fix ui format warnings
2026-04-30 06:03:55 -07:00

1015 lines
14 KiB
C++

#include "pch.h"
#include "PceCpu.h"
#include "PCE/PceMemoryManager.h"
void PceCpu::WriteMemoryModeValue(uint8_t value)
{
ClearFlags(PceCpuFlags::Zero | PceCpuFlags::Negative);
SetZeroNegativeFlags(value);
MemoryWrite(PceCpu::ZeroPage + X(), value);
}
void PceCpu::AND()
{
if(_memoryFlag) {
uint8_t op1 = GetOperandValue();
uint8_t op2 = MemoryRead(PceCpu::ZeroPage + X());
Idle();
WriteMemoryModeValue(op1 & op2);
} else {
SetA(A() & GetOperandValue());
}
}
void PceCpu::EOR()
{
if(_memoryFlag) {
uint8_t op1 = GetOperandValue();
uint8_t op2 = MemoryRead(PceCpu::ZeroPage + X());
Idle();
WriteMemoryModeValue(op1 ^ op2);
} else {
SetA(A() ^ GetOperandValue());
}
}
void PceCpu::ORA()
{
if(_memoryFlag) {
uint8_t op1 = GetOperandValue();
uint8_t op2 = MemoryRead(PceCpu::ZeroPage + X());
Idle();
WriteMemoryModeValue(op1 | op2);
} else {
SetA(A() | GetOperandValue());
}
}
void PceCpu::ADD(uint8_t value)
{
uint8_t source;
if(_memoryFlag) {
source = MemoryRead(PceCpu::ZeroPage + X());
Idle();
} else {
source = A();
}
uint16_t result;
if(CheckFlag(PceCpuFlags::Decimal)) {
if(_memoryFlag) {
Idle();
} else {
DummyRead();
}
result = (uint16_t)(source & 0x0F) + (uint16_t)(value & 0x0F) + (_state.PS & PceCpuFlags::Carry);
if(result > 0x09) {
result += 0x06;
}
result = (uint16_t)(source & 0xF0) + (uint16_t)(value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
if(result > 0x9F) {
result += 0x60;
}
} else {
result = (uint16_t)source + (uint16_t)value + (CheckFlag(PceCpuFlags::Carry) ? PceCpuFlags::Carry : 0x00);
if(~(source ^ value) & (source ^ result) & 0x80) {
SetFlags(PceCpuFlags::Overflow);
} else {
ClearFlags(PceCpuFlags::Overflow);
}
}
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
SetZeroNegativeFlags((uint8_t)result);
if(result > 0xFF) {
SetFlags(PceCpuFlags::Carry);
}
if(_memoryFlag) {
WriteMemoryModeValue((uint8_t)result);
} else {
SetA((uint8_t)result);
}
}
void PceCpu::SUB(uint8_t value)
{
int32_t result;
if(CheckFlag(PceCpuFlags::Decimal)) {
if(_memoryFlag) {
Idle();
} else {
DummyRead();
}
result = (A() & 0x0F) + (value & 0x0F) + (_state.PS & PceCpuFlags::Carry);
if(result <= 0x0F) {
result -= 0x06;
}
result = (A() & 0xF0) + (value & 0xF0) + (result > 0x0F ? 0x10 : 0) + (result & 0x0F);
if(result <= 0xFF) {
result -= 0x60;
}
} else {
result = (uint16_t)A() + (uint16_t)value + (_state.PS & PceCpuFlags::Carry);
if(~(A() ^ value) & (A() ^ result) & 0x80) {
SetFlags(PceCpuFlags::Overflow);
} else {
ClearFlags(PceCpuFlags::Overflow);
}
}
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
SetZeroNegativeFlags((uint8_t)result);
if(result > 0xFF) {
SetFlags(PceCpuFlags::Carry);
}
SetA((uint8_t)result);
}
void PceCpu::ADC()
{
ADD(GetOperandValue());
}
void PceCpu::SBC()
{
SUB(~GetOperandValue());
}
void PceCpu::CMP(uint8_t reg, uint8_t value)
{
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
auto result = reg - value;
if(reg >= value) {
SetFlags(PceCpuFlags::Carry);
}
if(reg == value) {
SetFlags(PceCpuFlags::Zero);
}
if((result & 0x80) == 0x80) {
SetFlags(PceCpuFlags::Negative);
}
}
void PceCpu::CPA()
{
CMP(A(), GetOperandValue());
}
void PceCpu::CPX()
{
CMP(X(), GetOperandValue());
}
void PceCpu::CPY()
{
CMP(Y(), GetOperandValue());
}
void PceCpu::INC()
{
uint16_t addr = GetOperand();
ClearFlags(PceCpuFlags::Negative | PceCpuFlags::Zero);
uint8_t value = MemoryRead(addr);
Idle();
value++;
SetZeroNegativeFlags(value);
MemoryWrite(addr, value);
}
void PceCpu::DEC()
{
uint16_t addr = GetOperand();
ClearFlags(PceCpuFlags::Negative | PceCpuFlags::Zero);
uint8_t value = MemoryRead(addr);
Idle();
value--;
SetZeroNegativeFlags(value);
MemoryWrite(addr, value);
}
uint8_t PceCpu::ASL(uint8_t value)
{
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
if(value & 0x80) {
SetFlags(PceCpuFlags::Carry);
}
uint8_t result = value << 1;
SetZeroNegativeFlags(result);
return result;
}
uint8_t PceCpu::LSR(uint8_t value)
{
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
if(value & 0x01) {
SetFlags(PceCpuFlags::Carry);
}
uint8_t result = value >> 1;
SetZeroNegativeFlags(result);
return result;
}
uint8_t PceCpu::ROL(uint8_t value)
{
bool carryFlag = CheckFlag(PceCpuFlags::Carry);
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
if(value & 0x80) {
SetFlags(PceCpuFlags::Carry);
}
uint8_t result = (value << 1 | (carryFlag ? 0x01 : 0x00));
SetZeroNegativeFlags(result);
return result;
}
uint8_t PceCpu::ROR(uint8_t value)
{
bool carryFlag = CheckFlag(PceCpuFlags::Carry);
ClearFlags(PceCpuFlags::Carry | PceCpuFlags::Negative | PceCpuFlags::Zero);
if(value & 0x01) {
SetFlags(PceCpuFlags::Carry);
}
uint8_t result = (value >> 1 | (carryFlag ? 0x80 : 0x00));
SetZeroNegativeFlags(result);
return result;
}
void PceCpu::ASLAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
Idle();
MemoryWrite(addr, ASL(value));
}
void PceCpu::LSRAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
Idle();
MemoryWrite(addr, LSR(value));
}
void PceCpu::ROLAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
Idle();
MemoryWrite(addr, ROL(value));
}
void PceCpu::RORAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
Idle();
MemoryWrite(addr, ROR(value));
}
void PceCpu::BranchRelative(bool branch)
{
int8_t offset = (int8_t)GetOperand();
if(branch) {
DummyRead();
Idle();
SetPC(PC() + offset);
}
}
void PceCpu::BIT()
{
uint8_t value = GetOperandValue();
ClearFlags(PceCpuFlags::Zero | PceCpuFlags::Overflow | PceCpuFlags::Negative);
if((A() & value) == 0) {
SetFlags(PceCpuFlags::Zero);
}
if(value & 0x40) {
SetFlags(PceCpuFlags::Overflow);
}
if(value & 0x80) {
SetFlags(PceCpuFlags::Negative);
}
}
void PceCpu::TSB()
{
uint8_t value = MemoryRead(_operand);
ClearFlags(PceCpuFlags::Zero | PceCpuFlags::Overflow | PceCpuFlags::Negative);
if(value & 0x40) {
SetFlags(PceCpuFlags::Overflow);
}
if(value & 0x80) {
SetFlags(PceCpuFlags::Negative);
}
value |= A();
if(value == 0) {
SetFlags(PceCpuFlags::Zero);
}
Idle();
MemoryWrite(_operand, value);
}
void PceCpu::TRB()
{
uint8_t value = MemoryRead(_operand);
ClearFlags(PceCpuFlags::Zero | PceCpuFlags::Overflow | PceCpuFlags::Negative);
if(value & 0x40) {
SetFlags(PceCpuFlags::Overflow);
}
if(value & 0x80) {
SetFlags(PceCpuFlags::Negative);
}
value &= ~A();
if(value == 0) {
SetFlags(PceCpuFlags::Zero);
}
Idle();
MemoryWrite(_operand, value);
}
void PceCpu::TST()
{
Idle();
uint8_t value = MemoryRead(_operand2);
Idle();
ClearFlags(PceCpuFlags::Zero | PceCpuFlags::Overflow | PceCpuFlags::Negative);
if(value & 0x40) {
SetFlags(PceCpuFlags::Overflow);
}
if(value & 0x80) {
SetFlags(PceCpuFlags::Negative);
}
value &= _operand;
if(value == 0) {
SetFlags(PceCpuFlags::Zero);
}
}
void PceCpu::CSL()
{
#ifndef DUMMYCPU
_memoryManager->SetSpeed(true);
#endif
//CSH/CSL take 3 cycles, last idle cycle is after the speed change takes effect
Idle();
}
void PceCpu::CSH()
{
#ifndef DUMMYCPU
_memoryManager->SetSpeed(false);
#endif
//CSH/CSL take 3 cycles, last idle cycle is after the speed change takes effect
Idle();
}
//OP Codes
void PceCpu::LDA()
{
SetA(GetOperandValue());
}
void PceCpu::LDX()
{
SetX(GetOperandValue());
}
void PceCpu::LDY()
{
SetY(GetOperandValue());
}
void PceCpu::STA()
{
MemoryWrite(GetOperand(), A());
}
void PceCpu::STX()
{
MemoryWrite(GetOperand(), X());
}
void PceCpu::STY()
{
MemoryWrite(GetOperand(), Y());
}
void PceCpu::STZ()
{
MemoryWrite(GetOperand(), 0);
}
void PceCpu::TAX()
{
SetX(A());
}
void PceCpu::TAY()
{
SetY(A());
}
void PceCpu::TSX()
{
SetX(SP());
}
void PceCpu::TXA()
{
SetA(X());
}
void PceCpu::TXS()
{
SetSP(X());
}
void PceCpu::TYA()
{
SetA(Y());
}
void PceCpu::PHA()
{
Push(A());
}
void PceCpu::PHX()
{
Push(X());
}
void PceCpu::PHY()
{
Push(Y());
}
void PceCpu::PHP()
{
uint8_t flags = PS() | PceCpuFlags::Break;
Push((uint8_t)flags);
}
void PceCpu::PLA()
{
Idle();
SetA(Pop());
}
void PceCpu::PLP()
{
Idle();
SetPS(Pop());
}
void PceCpu::PLX()
{
Idle();
SetX(Pop());
}
void PceCpu::PLY()
{
Idle();
SetY(Pop());
}
void PceCpu::INC_Acc()
{
SetA(A() + 1);
}
void PceCpu::INX()
{
SetX(X() + 1);
}
void PceCpu::INY()
{
SetY(Y() + 1);
}
void PceCpu::DEC_Acc()
{
SetA(A() - 1);
}
void PceCpu::DEX()
{
SetX(X() - 1);
}
void PceCpu::DEY()
{
SetY(Y() - 1);
}
void PceCpu::ASL_Acc()
{
SetA(ASL(A()));
}
void PceCpu::ASL_Memory()
{
ASLAddr();
}
void PceCpu::LSR_Acc()
{
SetA(LSR(A()));
}
void PceCpu::LSR_Memory()
{
LSRAddr();
}
void PceCpu::ROL_Acc()
{
SetA(ROL(A()));
}
void PceCpu::ROL_Memory()
{
ROLAddr();
}
void PceCpu::ROR_Acc()
{
SetA(ROR(A()));
}
void PceCpu::ROR_Memory()
{
RORAddr();
}
void PceCpu::JMP_Abs()
{
SetPC(GetOperand());
}
void PceCpu::JMP_Ind()
{
//Unlike the 6502 CPU, this CPU works normally when crossing a page during indirect jumps
Idle();
SetPC(MemoryReadWord(_operand));
Idle();
}
void PceCpu::JMP_AbsX()
{
SetPC(MemoryReadWord(_operand));
Idle();
}
void PceCpu::JSR()
{
uint8_t lo = ReadByte();
Idle();
Push(PC());
uint16_t addr = (ReadByte() << 8) | lo;
Idle();
SetPC(addr);
}
void PceCpu::RTS()
{
Idle();
uint16_t addr = PopWord();
Idle();
Idle();
SetPC(addr + 1);
}
void PceCpu::BCC()
{
BranchRelative(!CheckFlag(PceCpuFlags::Carry));
}
void PceCpu::BCS()
{
BranchRelative(CheckFlag(PceCpuFlags::Carry));
}
void PceCpu::BEQ()
{
BranchRelative(CheckFlag(PceCpuFlags::Zero));
}
void PceCpu::BMI()
{
BranchRelative(CheckFlag(PceCpuFlags::Negative));
}
void PceCpu::BNE()
{
BranchRelative(!CheckFlag(PceCpuFlags::Zero));
}
void PceCpu::BPL()
{
BranchRelative(!CheckFlag(PceCpuFlags::Negative));
}
void PceCpu::BVC()
{
BranchRelative(!CheckFlag(PceCpuFlags::Overflow));
}
void PceCpu::BVS()
{
BranchRelative(CheckFlag(PceCpuFlags::Overflow));
}
void PceCpu::CLC()
{
ClearFlags(PceCpuFlags::Carry);
}
void PceCpu::CLD()
{
ClearFlags(PceCpuFlags::Decimal);
}
void PceCpu::CLI()
{
ClearFlags(PceCpuFlags::Interrupt);
}
void PceCpu::CLV()
{
ClearFlags(PceCpuFlags::Overflow);
}
void PceCpu::SEC()
{
SetFlags(PceCpuFlags::Carry);
}
void PceCpu::SED()
{
SetFlags(PceCpuFlags::Decimal);
}
void PceCpu::SEI()
{
SetFlags(PceCpuFlags::Interrupt);
}
void PceCpu::SET()
{
SetFlags(PceCpuFlags::Memory);
}
void PceCpu::BRK()
{
ProcessIrq(true);
}
void PceCpu::RTI()
{
Idle();
SetPS(Pop());
SetPC(PopWord());
Idle();
}
void PceCpu::NOP()
{
//NOP
}
void PceCpu::BSR()
{
int8_t relAddr = (int8_t)GetOperand();
Idle();
Push((uint16_t)(PC() - 1));
Idle();
Idle();
Idle();
SetPC(PC() + relAddr);
}
void PceCpu::BRA()
{
int8_t offset = (int8_t)GetOperand();
Idle();
Idle();
SetPC(PC() + offset);
}
void PceCpu::SXY()
{
Idle();
std::swap(_state.X, _state.Y);
}
void PceCpu::SAX()
{
Idle();
std::swap(_state.A, _state.X);
}
void PceCpu::SAY()
{
Idle();
std::swap(_state.A, _state.Y);
}
void PceCpu::CLA()
{
_state.A = 0;
}
void PceCpu::CLX()
{
_state.X = 0;
}
void PceCpu::CLY()
{
_state.Y = 0;
}
void PceCpu::ST0()
{
#ifndef DUMMYCPU
Idle();
ProcessCpuCycle(); //1 write cycle
_memoryManager->WriteVdc(0, _operand);
#endif
}
void PceCpu::ST1()
{
#ifndef DUMMYCPU
Idle();
ProcessCpuCycle(); //1 write cycle
_memoryManager->WriteVdc(2, _operand);
#endif
}
void PceCpu::ST2()
{
#ifndef DUMMYCPU
Idle();
ProcessCpuCycle(); //1 write cycle
_memoryManager->WriteVdc(3, _operand);
#endif
}
void PceCpu::TMA()
{
Idle();
Idle();
#ifndef DUMMYCPU
_state.A = _memoryManager->GetMprValue(GetOperand());
#endif
}
void PceCpu::TAM()
{
Idle();
Idle();
Idle();
#ifndef DUMMYCPU
_memoryManager->SetMprValue(GetOperand(), A());
#endif
}
void PceCpu::StartBlockTransfer()
{
DummyRead();
Idle();
Push(Y());
Push(A());
Push(X());
_operand = ReadWord();
_operand2 = ReadWord();
_operand3 = ReadWord();
Idle();
}
void PceCpu::EndBlockTransfer()
{
Idle();
_state.X = Pop();
_state.A = Pop();
_state.Y = Pop();
}
void PceCpu::TAI()
{
StartBlockTransfer();
uint16_t src = _operand;
uint16_t dst = _operand2;
uint16_t length = _operand3;
uint32_t count = 0;
do {
Idle();
uint8_t value = MemoryRead(src);
Idle();
MemoryWrite(dst, value);
Idle();
Idle();
src += (count & 0x01) ? -1 : 1;
dst++;
count++;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::TDD()
{
StartBlockTransfer();
uint16_t src = _operand;
uint16_t dst = _operand2;
uint16_t length = _operand3;
do {
Idle();
uint8_t value = MemoryRead(src);
Idle();
MemoryWrite(dst, value);
Idle();
Idle();
src--;
dst--;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::TIA()
{
StartBlockTransfer();
uint16_t src = _operand;
uint16_t dst = _operand2;
uint16_t length = _operand3;
uint32_t count = 0;
do {
Idle();
uint8_t value = MemoryRead(src);
Idle();
MemoryWrite(dst, value);
Idle();
Idle();
src++;
dst += (count & 0x01) ? -1 : 1;
count++;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::TII()
{
StartBlockTransfer();
uint16_t src = _operand;
uint16_t dst = _operand2;
uint16_t length = _operand3;
do {
Idle();
uint8_t value = MemoryRead(src);
Idle();
MemoryWrite(dst, value);
Idle();
Idle();
src++;
dst++;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::TIN()
{
StartBlockTransfer();
uint16_t src = _operand;
uint16_t dst = _operand2;
uint16_t length = _operand3;
do {
Idle();
uint8_t value = MemoryRead(src);
Idle();
MemoryWrite(dst, value);
Idle();
Idle();
src++;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::BBR(uint8_t bit)
{
uint8_t addr = ReadByte();
Idle();
int8_t offset = (int8_t)ReadByte();
Idle();
uint8_t value = MemoryRead(PceCpu::ZeroPage + addr);
if((value & (1 << bit)) == 0) {
Idle();
Idle();
SetPC(PC() + offset);
}
}
void PceCpu::BBS(uint8_t bit)
{
uint8_t addr = ReadByte();
Idle();
int8_t offset = (int8_t)ReadByte();
Idle();
uint8_t value = MemoryRead(PceCpu::ZeroPage + addr);
if((value & (1 << bit)) != 0) {
Idle();
Idle();
SetPC(PC() + offset);
}
}
void PceCpu::RMB(uint8_t bit)
{
uint8_t value = MemoryRead(_operand);
value &= ~(1 << bit);
Idle();
Idle();
MemoryWrite(_operand, value);
}
void PceCpu::SMB(uint8_t bit)
{
uint8_t value = MemoryRead(_operand);
value |= (1 << bit);
Idle();
Idle();
MemoryWrite(_operand, value);
}