Mesen2/Core/PCE/PceCpu.Instructions.cpp
2023-11-21 20:05:27 +09:00

823 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) {
DummyRead();
uint8_t value = MemoryRead(PceCpu::ZeroPage + X());
WriteMemoryModeValue(value & GetOperandValue());
} else {
SetA(A() & GetOperandValue());
}
}
void PceCpu::EOR()
{
if(_memoryFlag) {
DummyRead();
uint8_t value = MemoryRead(PceCpu::ZeroPage + X());
WriteMemoryModeValue(value ^ GetOperandValue());
} else {
SetA(A() ^ GetOperandValue());
}
}
void PceCpu::ORA()
{
if(_memoryFlag) {
DummyRead();
uint8_t value = MemoryRead(PceCpu::ZeroPage + X());
WriteMemoryModeValue(value | GetOperandValue());
} else {
SetA(A() | GetOperandValue());
}
}
void PceCpu::ADD(uint8_t value)
{
uint8_t source;
if(_memoryFlag) {
DummyRead();
source = MemoryRead(PceCpu::ZeroPage + X());
} else {
source = A();
}
uint16_t result;
if(CheckFlag(PceCpuFlags::Decimal)) {
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)) {
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);
DummyRead();
value++;
SetZeroNegativeFlags(value);
MemoryWrite(addr, value);
}
void PceCpu::DEC()
{
uint16_t addr = GetOperand();
ClearFlags(PceCpuFlags::Negative | PceCpuFlags::Zero);
uint8_t value = MemoryRead(addr);
DummyRead();
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);
DummyRead();
MemoryWrite(addr, ASL(value));
}
void PceCpu::LSRAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
DummyRead();
MemoryWrite(addr, LSR(value));
}
void PceCpu::ROLAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
DummyRead();
MemoryWrite(addr, ROL(value));
}
void PceCpu::RORAddr()
{
uint16_t addr = GetOperand();
uint8_t value = MemoryRead(addr);
DummyRead();
MemoryWrite(addr, ROR(value));
}
void PceCpu::BranchRelative(bool branch)
{
int8_t offset = (int8_t)GetOperand();
if(branch) {
DummyRead();
DummyRead();
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);
}
DummyRead();
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);
}
DummyRead();
MemoryWrite(_operand, value);
}
void PceCpu::TST()
{
DummyRead();
DummyRead();
uint8_t value = MemoryRead(_operand2);
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()
{
//CSH/CSL take 3 cycles
DummyRead();
#ifndef DUMMYCPU
_memoryManager->SetSpeed(true);
#endif
}
void PceCpu::CSH()
{
//CSH/CSL take 3 cycles
DummyRead();
#ifndef DUMMYCPU
_memoryManager->SetSpeed(false);
#endif
}
//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()
{
DummyRead();
SetA(Pop());
}
void PceCpu::PLP()
{
DummyRead();
SetPS(Pop());
}
void PceCpu::PLX()
{
DummyRead();
SetX(Pop());
}
void PceCpu::PLY()
{
DummyRead();
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
DummyRead();
DummyRead();
SetPC(MemoryReadWord(_operand));
}
void PceCpu::JMP_AbsX()
{
DummyRead();
SetPC(MemoryReadWord(_operand));
}
void PceCpu::JSR()
{
uint16_t addr = GetOperand();
DummyRead();
Push((uint16_t)(PC() - 1));
SetPC(addr);
}
void PceCpu::RTS()
{
DummyRead();
uint16_t addr = PopWord();
DummyRead();
DummyRead();
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()
{
DummyRead();
SetPS(Pop());
DummyRead();
SetPC(PopWord());
}
void PceCpu::NOP()
{
//NOP
}
void PceCpu::BSR()
{
int8_t relAddr = (int8_t)GetOperand();
DummyRead();
DummyRead();
Push((uint16_t)(PC() - 1));
DummyRead();
DummyRead();
SetPC(PC() + relAddr);
}
void PceCpu::BRA()
{
BranchRelative(true);
}
void PceCpu::SXY()
{
DummyRead();
std::swap(_state.X, _state.Y);
}
void PceCpu::SAX()
{
DummyRead();
std::swap(_state.A, _state.X);
}
void PceCpu::SAY()
{
DummyRead();
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()
{
DummyRead(); //1 dummy read
#ifndef DUMMYCPU
ProcessCpuCycle(); //1 write cycle
_memoryManager->WriteVdc(0, _operand);
#endif
}
void PceCpu::ST1()
{
DummyRead(); //1 dummy read
#ifndef DUMMYCPU
ProcessCpuCycle(); //1 write cycle
_memoryManager->WriteVdc(2, _operand);
#endif
}
void PceCpu::ST2()
{
DummyRead(); //1 dummy read
#ifndef DUMMYCPU
ProcessCpuCycle(); //1 write cycle
_memoryManager->WriteVdc(3, _operand);
#endif
}
void PceCpu::TMA()
{
DummyRead();
DummyRead();
#ifndef DUMMYCPU
SetA(_memoryManager->GetMprValue(GetOperand()));
#endif
}
void PceCpu::TAM()
{
DummyRead();
DummyRead();
DummyRead();
#ifndef DUMMYCPU
_memoryManager->SetMprValue(GetOperand(), A());
#endif
}
void PceCpu::StartBlockTransfer()
{
DummyRead();
Push(Y());
DummyRead();
Push(X());
DummyRead();
Push(A());
DummyRead();
}
void PceCpu::EndBlockTransfer()
{
_state.A = Pop();
_state.X = 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 {
DummyRead();
uint8_t value = MemoryRead(src);
DummyRead();
DummyRead();
MemoryWrite(dst, value);
DummyRead();
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 {
DummyRead();
uint8_t value = MemoryRead(src);
DummyRead();
DummyRead();
MemoryWrite(dst, value);
DummyRead();
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 {
DummyRead();
uint8_t value = MemoryRead(src);
DummyRead();
DummyRead();
MemoryWrite(dst, value);
DummyRead();
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 {
DummyRead();
uint8_t value = MemoryRead(src);
DummyRead();
DummyRead();
MemoryWrite(dst, value);
DummyRead();
src++;
dst++;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::TIN()
{
StartBlockTransfer();
uint16_t src = _operand;
uint16_t dst = _operand2;
uint16_t length = _operand3;
do {
DummyRead();
uint8_t value = MemoryRead(src);
DummyRead();
DummyRead();
MemoryWrite(dst, value);
DummyRead();
src++;
length--;
} while(length);
EndBlockTransfer();
}
void PceCpu::BBR(uint8_t bit)
{
DummyRead();
DummyRead();
uint8_t value = MemoryRead(PceCpu::ZeroPage + (_operand & 0xFF));
if((value & (1 << bit)) == 0) {
DummyRead();
DummyRead();
SetPC(PC() + (int8_t)(_operand >> 8));
}
}
void PceCpu::BBS(uint8_t bit)
{
DummyRead();
DummyRead();
uint8_t value = MemoryRead(PceCpu::ZeroPage + (_operand & 0xFF));
if((value & (1 << bit)) != 0) {
DummyRead();
DummyRead();
SetPC(PC() + (int8_t)(_operand >> 8));
}
}
void PceCpu::RMB(uint8_t bit)
{
uint8_t value = MemoryRead(_operand);
value &= ~(1 << bit);
DummyRead();
DummyRead();
MemoryWrite(_operand, value);
}
void PceCpu::SMB(uint8_t bit)
{
uint8_t value = MemoryRead(_operand);
value |= (1 << bit);
DummyRead();
DummyRead();
MemoryWrite(_operand, value);
}