mirror of
https://github.com/libretro/MesenCE.git
synced 2026-11-10 11:11:32 -10:00
* Code: Add auto-formatting rules for C++ projects (clang-format) and enforce code style via "clang-format" and "dotnet format" * fix ui format warnings
1015 lines
14 KiB
C++
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);
|
|
}
|