CPU: Fixed timing issues with some instructions

This commit is contained in:
Sour 2019-06-30 12:36:15 -04:00
parent e8fb04634b
commit a36a09df32
3 changed files with 116 additions and 77 deletions

View file

@ -216,13 +216,12 @@ void Cpu::BVS()
void Cpu::BranchRelative(bool branch)
{
int8_t offset = _operand;
if(branch) {
int8_t offset = _operand;
Idle();
if(_state.EmulationMode) {
if(((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00)) {
Idle();
}
if(_state.EmulationMode && ((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00)) {
//Extra cycle in emulation mode if crossing a page
Idle();
}
_state.PC = (uint16_t)(_state.PC + offset);
}
@ -455,10 +454,13 @@ void Cpu::RTS()
/**********
Interrupts
***********/
void Cpu::ProcessInterrupt(uint16_t vector)
void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt)
{
ReadCode(_state.PC);
Idle();
if(forHardwareInterrupt) {
//IRQ/NMI waste 2 cycles here. BRK/COP do not (because they do those 2 cycles while loading the OP code + signature byte)
ReadCode(_state.PC);
Idle();
}
if(_state.EmulationMode) {
PushWord(_state.PC);
@ -484,12 +486,12 @@ void Cpu::ProcessInterrupt(uint16_t vector)
void Cpu::BRK()
{
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::BreakVector);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::BreakVector, false);
}
void Cpu::COP()
{
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyCoprocessorVector : Cpu::CoprocessorVector);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyCoprocessorVector : Cpu::CoprocessorVector, false);
}
/******************
@ -585,11 +587,13 @@ void Cpu::ASL_Acc()
void Cpu::ASL()
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, ShiftLeft<uint8_t>(GetByteValue()));
Write(_operand, ShiftLeft<uint8_t>(value));
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, ShiftLeft<uint16_t>(GetWordValue()));
WriteWord(_operand, ShiftLeft<uint16_t>(value));
}
}
@ -605,11 +609,13 @@ void Cpu::LSR_Acc()
void Cpu::LSR()
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, ShiftRight<uint8_t>(GetByteValue()));
Write(_operand, ShiftRight<uint8_t>(value));
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, ShiftRight<uint16_t>(GetWordValue()));
WriteWord(_operand, ShiftRight<uint16_t>(value));
}
}
@ -625,11 +631,13 @@ void Cpu::ROL_Acc()
void Cpu::ROL()
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, RollLeft<uint8_t>(GetByteValue()));
Write(_operand, RollLeft<uint8_t>(value));
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, RollLeft<uint16_t>(GetWordValue()));
WriteWord(_operand, RollLeft<uint16_t>(value));
}
}
@ -645,11 +653,13 @@ void Cpu::ROR_Acc()
void Cpu::ROR()
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
uint8_t value = GetByteValue();
Idle();
Write(_operand, RollRight<uint8_t>(GetByteValue()));
Write(_operand, RollRight<uint8_t>(value));
} else {
uint16_t value = GetWordValue();
Idle();
WriteWord(_operand, RollRight<uint16_t>(GetWordValue()));
WriteWord(_operand, RollRight<uint16_t>(value));
}
}
@ -722,14 +732,12 @@ void Cpu::PEA()
void Cpu::PEI()
{
//Push Effective Indirect address
Idle();
PushWord(ReadDataWord(_operand));
}
void Cpu::PER()
{
//Push Effective Relative address
Idle();
PushWord((uint16_t)((int16_t)_operand + _state.PC));
}
@ -951,18 +959,20 @@ void Cpu::BIT()
void Cpu::TRB()
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
TestBits<uint8_t>(GetByteValue(), true);
uint8_t value = GetByteValue();
TestBits<uint8_t>(value, true);
uint8_t value = ReadData(_operand);
value &= ~_state.A;
Idle();
Write(_operand, value);
} else {
TestBits<uint16_t>(GetWordValue(), true);
uint16_t value = GetWordValue();
TestBits<uint16_t>(value, true);
uint16_t value = ReadDataWord(_operand);
value &= ~_state.A;
Idle();
WriteWord(_operand, value);
}
}
@ -970,16 +980,20 @@ void Cpu::TRB()
void Cpu::TSB()
{
if(CheckFlag(ProcFlags::MemoryMode8)) {
TestBits<uint8_t>(GetByteValue(), true);
uint8_t value = GetByteValue();
TestBits<uint8_t>(value, true);
uint8_t value = ReadData(_operand);
value |= _state.A;
Idle();
Write(_operand, value);
} else {
TestBits<uint16_t>(GetWordValue(), true);
uint16_t value = GetWordValue();
TestBits<uint16_t>(value, true);
uint16_t value = ReadDataWord(_operand);
value |= _state.A;
Idle();
WriteWord(_operand, value);
}
}
@ -1106,16 +1120,22 @@ void Cpu::AddrMode_Abs()
_operand = GetDataAddress(ReadOperandWord());
}
void Cpu::AddrMode_AbsIdxX()
void Cpu::AddrMode_AbsIdxX(bool isWrite)
{
_operand = (GetDataAddress(ReadOperandWord()) + _state.X) & 0xFFFFFF;
Idle();
uint32_t baseAddr = GetDataAddress(ReadOperandWord());
_operand = (baseAddr + _state.X) & 0xFFFFFF;
if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) {
Idle();
}
}
void Cpu::AddrMode_AbsIdxY()
void Cpu::AddrMode_AbsIdxY(bool isWrite)
{
_operand = (GetDataAddress(ReadOperandWord()) + _state.Y) & 0xFFFFFF;
Idle();
uint32_t baseAddr = GetDataAddress(ReadOperandWord());
_operand = (baseAddr + _state.Y) & 0xFFFFFF;
if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) {
Idle();
}
}
void Cpu::AddrMode_AbsLng()
@ -1203,10 +1223,14 @@ void Cpu::AddrMode_DirIdxIndX()
_operand = GetDataAddress(GetDirectAddressIndirectWord(operandByte + _state.X));
}
void Cpu::AddrMode_DirIndIdxY()
void Cpu::AddrMode_DirIndIdxY(bool isWrite)
{
_operand = (GetDataAddress(GetDirectAddressIndirectWord(ReadDirectOperandByte())) + _state.Y) & 0xFFFFFF;
Idle();
uint32_t baseAddr = GetDataAddress(GetDirectAddressIndirectWord(ReadDirectOperandByte()));
_operand = (baseAddr + _state.Y) & 0xFFFFFF;
if(isWrite || !CheckFlag(ProcFlags::IndexMode8) || (_operand & 0xFF00) != (baseAddr & 0xFF00)) {
Idle();
}
}
void Cpu::AddrMode_DirIndLng()

View file

@ -77,12 +77,12 @@ void Cpu::Exec()
if(!_dmaController->HasNmiIrqDelay()) {
if(_state.PrevNmiFlag) {
uint32_t originalPc = GetProgramAddress(_state.PC);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector, true);
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true);
_state.NmiFlag = false;
} else if(_state.PrevIrqSource) {
uint32_t originalPc = GetProgramAddress(_state.PC);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector, true);
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false);
}
}
@ -109,7 +109,7 @@ void Cpu::RunOp()
case 0x0E: AddrMode_Abs(); ASL(); break;
case 0x0F: AddrMode_AbsLng(); ORA(); break;
case 0x10: AddrMode_Rel(); BPL(); break;
case 0x11: AddrMode_DirIndIdxY(); ORA(); break;
case 0x11: AddrMode_DirIndIdxY(false); ORA(); break;
case 0x12: AddrMode_DirInd(); ORA(); break;
case 0x13: AddrMode_StkRelIndIdxY(); ORA(); break;
case 0x14: AddrMode_Dir(); TRB(); break;
@ -117,12 +117,12 @@ void Cpu::RunOp()
case 0x16: AddrMode_DirIdxX(); ASL(); break;
case 0x17: AddrMode_DirIndLngIdxY(); ORA(); break;
case 0x18: AddrMode_Imp(); CLC(); break;
case 0x19: AddrMode_AbsIdxY(); ORA(); break;
case 0x19: AddrMode_AbsIdxY(false); ORA(); break;
case 0x1A: AddrMode_Acc(); INC_Acc(); break;
case 0x1B: AddrMode_Imp(); TCS(); break;
case 0x1C: AddrMode_Abs(); TRB(); break;
case 0x1D: AddrMode_AbsIdxX(); ORA(); break;
case 0x1E: AddrMode_AbsIdxX(); ASL(); break;
case 0x1D: AddrMode_AbsIdxX(false); ORA(); break;
case 0x1E: AddrMode_AbsIdxX(true); ASL(); break;
case 0x1F: AddrMode_AbsLngIdxX(); ORA(); break;
case 0x20: AddrMode_AbsJmp(); Idle(); JSR(); break;
case 0x21: AddrMode_DirIdxIndX(); AND(); break;
@ -141,7 +141,7 @@ void Cpu::RunOp()
case 0x2E: AddrMode_Abs(); ROL(); break;
case 0x2F: AddrMode_AbsLng(); AND(); break;
case 0x30: AddrMode_Rel(); BMI(); break;
case 0x31: AddrMode_DirIndIdxY(); AND(); break;
case 0x31: AddrMode_DirIndIdxY(false); AND(); break;
case 0x32: AddrMode_DirInd(); AND(); break;
case 0x33: AddrMode_StkRelIndIdxY(); AND(); break;
case 0x34: AddrMode_DirIdxX(); BIT(); break;
@ -149,12 +149,12 @@ void Cpu::RunOp()
case 0x36: AddrMode_DirIdxX(); ROL(); break;
case 0x37: AddrMode_DirIndLngIdxY(); AND(); break;
case 0x38: AddrMode_Imp(); SEC(); break;
case 0x39: AddrMode_AbsIdxY(); AND(); break;
case 0x39: AddrMode_AbsIdxY(false); AND(); break;
case 0x3A: AddrMode_Acc(); DEC_Acc(); break;
case 0x3B: AddrMode_Imp(); TSC(); break;
case 0x3C: AddrMode_AbsIdxX(); BIT(); break;
case 0x3D: AddrMode_AbsIdxX(); AND(); break;
case 0x3E: AddrMode_AbsIdxX(); ROL(); break;
case 0x3C: AddrMode_AbsIdxX(false); BIT(); break;
case 0x3D: AddrMode_AbsIdxX(false); AND(); break;
case 0x3E: AddrMode_AbsIdxX(true); ROL(); break;
case 0x3F: AddrMode_AbsLngIdxX(); AND(); break;
case 0x40: RTI(); break;
case 0x41: AddrMode_DirIdxIndX(); EOR(); break;
@ -173,7 +173,7 @@ void Cpu::RunOp()
case 0x4E: AddrMode_Abs(); LSR(); break;
case 0x4F: AddrMode_AbsLng(); EOR(); break;
case 0x50: AddrMode_Rel(); BVC(); break;
case 0x51: AddrMode_DirIndIdxY(); EOR(); break;
case 0x51: AddrMode_DirIndIdxY(false); EOR(); break;
case 0x52: AddrMode_DirInd(); EOR(); break;
case 0x53: AddrMode_StkRelIndIdxY(); EOR(); break;
case 0x54: AddrMode_BlkMov(); MVN(); break;
@ -181,12 +181,12 @@ void Cpu::RunOp()
case 0x56: AddrMode_DirIdxX(); LSR(); break;
case 0x57: AddrMode_DirIndLngIdxY(); EOR(); break;
case 0x58: AddrMode_Imp(); CLI(); break;
case 0x59: AddrMode_AbsIdxY(); EOR(); break;
case 0x59: AddrMode_AbsIdxY(false); EOR(); break;
case 0x5A: PHY(); break;
case 0x5B: AddrMode_Imp(); TCD(); break;
case 0x5C: AddrMode_AbsLngJmp(); JML(); break;
case 0x5D: AddrMode_AbsIdxX(); EOR(); break;
case 0x5E: AddrMode_AbsIdxX(); LSR(); break;
case 0x5D: AddrMode_AbsIdxX(false); EOR(); break;
case 0x5E: AddrMode_AbsIdxX(true); LSR(); break;
case 0x5F: AddrMode_AbsLngIdxX(); EOR(); break;
case 0x60: RTS(); break;
case 0x61: AddrMode_DirIdxIndX(); ADC(); break;
@ -205,7 +205,7 @@ void Cpu::RunOp()
case 0x6E: AddrMode_Abs(); ROR(); break;
case 0x6F: AddrMode_AbsLng(); ADC(); break;
case 0x70: AddrMode_Rel(); BVS(); break;
case 0x71: AddrMode_DirIndIdxY(); ADC(); break;
case 0x71: AddrMode_DirIndIdxY(false); ADC(); break;
case 0x72: AddrMode_DirInd(); ADC(); break;
case 0x73: AddrMode_StkRelIndIdxY(); ADC(); break;
case 0x74: AddrMode_DirIdxX(); STZ(); break;
@ -213,12 +213,12 @@ void Cpu::RunOp()
case 0x76: AddrMode_DirIdxX(); ROR(); break;
case 0x77: AddrMode_DirIndLngIdxY(); ADC(); break;
case 0x78: AddrMode_Imp(); SEI(); break;
case 0x79: AddrMode_AbsIdxY(); ADC(); break;
case 0x79: AddrMode_AbsIdxY(false); ADC(); break;
case 0x7A: PLY(); break;
case 0x7B: AddrMode_Imp(); TDC(); break;
case 0x7C: AddrMode_AbsIdxXInd(); JMP(); break;
case 0x7D: AddrMode_AbsIdxX(); ADC(); break;
case 0x7E: AddrMode_AbsIdxX(); ROR(); break;
case 0x7D: AddrMode_AbsIdxX(false); ADC(); break;
case 0x7E: AddrMode_AbsIdxX(true); ROR(); break;
case 0x7F: AddrMode_AbsLngIdxX(); ADC(); break;
case 0x80: AddrMode_Rel(); BRA(); break;
case 0x81: AddrMode_DirIdxIndX(); STA(); break;
@ -237,7 +237,7 @@ void Cpu::RunOp()
case 0x8E: AddrMode_Abs(); STX(); break;
case 0x8F: AddrMode_AbsLng(); STA(); break;
case 0x90: AddrMode_Rel(); BCC(); break;
case 0x91: AddrMode_DirIndIdxY(); STA(); break;
case 0x91: AddrMode_DirIndIdxY(true); STA(); break;
case 0x92: AddrMode_DirInd(); STA(); break;
case 0x93: AddrMode_StkRelIndIdxY(); STA(); break;
case 0x94: AddrMode_DirIdxX(); STY(); break;
@ -245,12 +245,12 @@ void Cpu::RunOp()
case 0x96: AddrMode_DirIdxY(); STX(); break;
case 0x97: AddrMode_DirIndLngIdxY(); STA(); break;
case 0x98: AddrMode_Imp(); TYA(); break;
case 0x99: AddrMode_AbsIdxY(); STA(); break;
case 0x99: AddrMode_AbsIdxY(true); STA(); break;
case 0x9A: AddrMode_Imp(); TXS(); break;
case 0x9B: AddrMode_Imp(); TXY(); break;
case 0x9C: AddrMode_Abs(); STZ(); break;
case 0x9D: AddrMode_AbsIdxX(); STA(); break;
case 0x9E: AddrMode_AbsIdxX(); STZ(); break;
case 0x9D: AddrMode_AbsIdxX(true); STA(); break;
case 0x9E: AddrMode_AbsIdxX(true); STZ(); break;
case 0x9F: AddrMode_AbsLngIdxX(); STA(); break;
case 0xA0: AddrMode_ImmX(); LDY(); break;
case 0xA1: AddrMode_DirIdxIndX(); LDA(); break;
@ -269,7 +269,7 @@ void Cpu::RunOp()
case 0xAE: AddrMode_Abs(); LDX(); break;
case 0xAF: AddrMode_AbsLng(); LDA(); break;
case 0xB0: AddrMode_Rel(); BCS(); break;
case 0xB1: AddrMode_DirIndIdxY(); LDA(); break;
case 0xB1: AddrMode_DirIndIdxY(false); LDA(); break;
case 0xB2: AddrMode_DirInd(); LDA(); break;
case 0xB3: AddrMode_StkRelIndIdxY(); LDA(); break;
case 0xB4: AddrMode_DirIdxX(); LDY(); break;
@ -277,12 +277,12 @@ void Cpu::RunOp()
case 0xB6: AddrMode_DirIdxY(); LDX(); break;
case 0xB7: AddrMode_DirIndLngIdxY(); LDA(); break;
case 0xB8: AddrMode_Imp(); CLV(); break;
case 0xB9: AddrMode_AbsIdxY(); LDA(); break;
case 0xB9: AddrMode_AbsIdxY(false); LDA(); break;
case 0xBA: AddrMode_Imp(); TSX(); break;
case 0xBB: AddrMode_Imp(); TYX(); break;
case 0xBC: AddrMode_AbsIdxX(); LDY(); break;
case 0xBD: AddrMode_AbsIdxX(); LDA(); break;
case 0xBE: AddrMode_AbsIdxY(); LDX(); break;
case 0xBC: AddrMode_AbsIdxX(false); LDY(); break;
case 0xBD: AddrMode_AbsIdxX(false); LDA(); break;
case 0xBE: AddrMode_AbsIdxY(false); LDX(); break;
case 0xBF: AddrMode_AbsLngIdxX(); LDA(); break;
case 0xC0: AddrMode_ImmX(); CPY(); break;
case 0xC1: AddrMode_DirIdxIndX(); CMP(); break;
@ -301,7 +301,7 @@ void Cpu::RunOp()
case 0xCE: AddrMode_Abs(); DEC(); break;
case 0xCF: AddrMode_AbsLng(); CMP(); break;
case 0xD0: AddrMode_Rel(); BNE(); break;
case 0xD1: AddrMode_DirIndIdxY(); CMP(); break;
case 0xD1: AddrMode_DirIndIdxY(false); CMP(); break;
case 0xD2: AddrMode_DirInd(); CMP(); break;
case 0xD3: AddrMode_StkRelIndIdxY(); CMP(); break;
case 0xD4: AddrMode_Dir(); PEI(); break;
@ -309,12 +309,12 @@ void Cpu::RunOp()
case 0xD6: AddrMode_DirIdxX(); DEC(); break;
case 0xD7: AddrMode_DirIndLngIdxY(); CMP(); break;
case 0xD8: AddrMode_Imp(); CLD(); break;
case 0xD9: AddrMode_AbsIdxY(); CMP(); break;
case 0xD9: AddrMode_AbsIdxY(false); CMP(); break;
case 0xDA: PHX(); break;
case 0xDB: AddrMode_Imp(); STP(); break;
case 0xDC: AddrMode_AbsIndLng(); JML(); break;
case 0xDD: AddrMode_AbsIdxX(); CMP(); break;
case 0xDE: AddrMode_AbsIdxX(); DEC(); break;
case 0xDD: AddrMode_AbsIdxX(false); CMP(); break;
case 0xDE: AddrMode_AbsIdxX(true); DEC(); break;
case 0xDF: AddrMode_AbsLngIdxX(); CMP(); break;
case 0xE0: AddrMode_ImmX(); CPX(); break;
case 0xE1: AddrMode_DirIdxIndX(); SBC(); break;
@ -333,7 +333,7 @@ void Cpu::RunOp()
case 0xEE: AddrMode_Abs(); INC(); break;
case 0xEF: AddrMode_AbsLng(); SBC(); break;
case 0xF0: AddrMode_Rel(); BEQ(); break;
case 0xF1: AddrMode_DirIndIdxY(); SBC(); break;
case 0xF1: AddrMode_DirIndIdxY(false); SBC(); break;
case 0xF2: AddrMode_DirInd(); SBC(); break;
case 0xF3: AddrMode_StkRelIndIdxY(); SBC(); break;
case 0xF4: AddrMode_Imm16(); PEA(); break;
@ -341,12 +341,12 @@ void Cpu::RunOp()
case 0xF6: AddrMode_DirIdxX(); INC(); break;
case 0xF7: AddrMode_DirIndLngIdxY(); SBC(); break;
case 0xF8: AddrMode_Imp(); SED(); break;
case 0xF9: AddrMode_AbsIdxY(); SBC(); break;
case 0xF9: AddrMode_AbsIdxY(false); SBC(); break;
case 0xFA: PLX(); break;
case 0xFB: AddrMode_Imp(); XCE(); break;
case 0xFC: AddrMode_AbsIdxXInd(); JSR(); break;
case 0xFD: AddrMode_AbsIdxX(); SBC(); break;
case 0xFE: AddrMode_AbsIdxX(); INC(); break;
case 0xFD: AddrMode_AbsIdxX(false); SBC(); break;
case 0xFE: AddrMode_AbsIdxX(true); INC(); break;
case 0xFF: AddrMode_AbsLngIdxX(); SBC(); break;
}
}

View file

@ -154,7 +154,7 @@ private:
void RTS();
//Interrupts
void ProcessInterrupt(uint16_t vector);
void ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt);
void BRK();
void COP();
@ -249,10 +249,15 @@ private:
void WAI();
//Addressing modes
//Absolute: a
void AddrMode_Abs();
void AddrMode_AbsIdxX();
void AddrMode_AbsIdxY();
//Absolute Indexed: a,x
void AddrMode_AbsIdxX(bool isWrite);
//Absolute Indexed: a,y
void AddrMode_AbsIdxY(bool isWrite);
//Absolute Long: al
void AddrMode_AbsLng();
//Absolute Long Indexed: al,x
void AddrMode_AbsLngIdxX();
void AddrMode_AbsJmp();
@ -266,13 +271,23 @@ private:
void AddrMode_BlkMov();
uint8_t ReadDirectOperandByte();
//Direct: d
void AddrMode_Dir();
//Direct Indexed: d,x
void AddrMode_DirIdxX();
//Direct Indexed: d,y
void AddrMode_DirIdxY();
//Direct Indirect: (d)
void AddrMode_DirInd();
//Direct Indexed Indirect: (d,x)
void AddrMode_DirIdxIndX();
void AddrMode_DirIndIdxY();
//Direct Indirect Indexed: (d),y
void AddrMode_DirIndIdxY(bool isWrite);
//Direct Indirect Long: [d]
void AddrMode_DirIndLng();
//Direct Indirect Indexed Long: [d],y
void AddrMode_DirIndLngIdxY();
void AddrMode_Imm8();