Fixed CPU page crossing cycles
This commit is contained in:
parent
5574f1c4bf
commit
16b6ebeb84
2 changed files with 61 additions and 53 deletions
63
Core/CPU.cpp
63
Core/CPU.cpp
|
@ -27,27 +27,47 @@ CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
|
||||||
&CPU::BEQ, &CPU::SBC_IndY, nullptr, nullptr, nullptr, &CPU::SBC_ZeroX, &CPU::INC_ZeroX, nullptr, &CPU::SED, &CPU::SBC_AbsY, nullptr, nullptr, nullptr, &CPU::SBC_AbsX, &CPU::INC_AbsX, nullptr //F
|
&CPU::BEQ, &CPU::SBC_IndY, nullptr, nullptr, nullptr, &CPU::SBC_ZeroX, &CPU::INC_ZeroX, nullptr, &CPU::SED, &CPU::SBC_AbsY, nullptr, nullptr, nullptr, &CPU::SBC_AbsX, &CPU::INC_AbsX, nullptr //F
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t cycles[] = {
|
uint8_t cycles[] {
|
||||||
7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
|
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
|
||||||
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7,
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||||
6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
|
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
|
||||||
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7,
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||||
6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
|
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
|
||||||
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7,
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||||
6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
|
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
|
||||||
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7,
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||||
2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
||||||
2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
|
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
|
||||||
2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
||||||
2,5,2,5,4,4,4,4,2,4,2,5,4,4,4,4,
|
2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4,
|
||||||
2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
|
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
||||||
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7,
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||||
2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
|
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
||||||
2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t cyclesPageCrossed[] {
|
||||||
|
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
|
||||||
|
2, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
||||||
|
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
|
||||||
|
2, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
||||||
|
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
|
||||||
|
2, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
||||||
|
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
|
||||||
|
2, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
||||||
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
||||||
|
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
|
||||||
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
|
||||||
|
2, 6, 2, 5, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
|
||||||
|
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
||||||
|
2, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
||||||
|
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
||||||
|
2, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(_opTable, opTable, sizeof(Func) * 256);
|
memcpy(_opTable, opTable, sizeof(Func) * 256);
|
||||||
memcpy(_cycles, cycles, sizeof(uint8_t) * 256);
|
memcpy(_cycles, cycles, sizeof(uint8_t) * 256);
|
||||||
|
memcpy(_cyclesPageCrossed, cyclesPageCrossed, sizeof(uint8_t) * 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Reset()
|
void CPU::Reset()
|
||||||
|
@ -63,11 +83,15 @@ void CPU::Reset()
|
||||||
|
|
||||||
void CPU::Exec()
|
void CPU::Exec()
|
||||||
{
|
{
|
||||||
if(!CPU::NMIFlag) {
|
if(!_runNMI) {
|
||||||
|
if(CPU::NMIFlag) {
|
||||||
|
_runNMI = true;
|
||||||
|
}
|
||||||
uint8_t opCode = ReadByte();
|
uint8_t opCode = ReadByte();
|
||||||
if(_opTable[opCode] != nullptr) {
|
if(_opTable[opCode] != nullptr) {
|
||||||
(this->*_opTable[opCode])();
|
(this->*_opTable[opCode])();
|
||||||
CPU::CycleCount += this->_cycles[opCode];
|
|
||||||
|
CPU::CycleCount += GetPageCrossed() ? this->_cyclesPageCrossed[opCode] : this->_cycles[opCode];
|
||||||
} else {
|
} else {
|
||||||
//std::cout << "Invalid opcode: " << std::hex << (short)opCode;
|
//std::cout << "Invalid opcode: " << std::hex << (short)opCode;
|
||||||
//throw exception("Invalid opcode");
|
//throw exception("Invalid opcode");
|
||||||
|
@ -75,6 +99,7 @@ void CPU::Exec()
|
||||||
} else {
|
} else {
|
||||||
NMI();
|
NMI();
|
||||||
CPU::CycleCount += 7;
|
CPU::CycleCount += 7;
|
||||||
|
_runNMI = false;
|
||||||
CPU::NMIFlag = false;
|
CPU::NMIFlag = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
51
Core/CPU.h
51
Core/CPU.h
|
@ -35,6 +35,7 @@ private:
|
||||||
|
|
||||||
Func _opTable[256];
|
Func _opTable[256];
|
||||||
uint8_t _cycles[256];
|
uint8_t _cycles[256];
|
||||||
|
uint8_t _cyclesPageCrossed[256];
|
||||||
|
|
||||||
State _state;
|
State _state;
|
||||||
|
|
||||||
|
@ -42,9 +43,10 @@ private:
|
||||||
|
|
||||||
static uint64_t CycleCount;
|
static uint64_t CycleCount;
|
||||||
static bool NMIFlag;
|
static bool NMIFlag;
|
||||||
|
bool _runNMI = false;
|
||||||
|
|
||||||
uint16_t _currentPC = 0;
|
uint16_t _currentPC = 0;
|
||||||
uint8_t _cyclePenalty = 0;
|
bool _pageCrossed = false;
|
||||||
|
|
||||||
uint8_t ReadByte()
|
uint8_t ReadByte()
|
||||||
{
|
{
|
||||||
|
@ -82,21 +84,14 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPageCrossed(uint16_t valA, uint8_t valB)
|
bool IsPageCrossed(uint16_t valA, int8_t valB)
|
||||||
{
|
{
|
||||||
return (uint8_t)valA + valB >= 0x100;
|
return ((valA + valB) & 0xFF00) != (valA & 0xFF00);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(uint16_t addr, uint8_t value)
|
void MemoryWrite(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
_memoryManager->Write(addr, value);
|
_memoryManager->Write(addr, value);
|
||||||
/*if(addr == 0x200) {
|
|
||||||
std::cout << "------------------" << std::endl;
|
|
||||||
std::cout << "(0x" << std::hex << (short)_currentPC << ") TEST NUMBER: " << std::dec << (int)value << std::endl;
|
|
||||||
std::cout << "------------------" << std::endl;
|
|
||||||
} else {
|
|
||||||
//std::cout << "(0x" << std::hex << (short)_currentPC << ") W: 0x" << std::hex << (short)addr << " = 0x" << std::hex << (short)value << std::endl;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t MemoryRead(uint16_t addr) {
|
uint8_t MemoryRead(uint16_t addr) {
|
||||||
|
@ -165,7 +160,7 @@ private:
|
||||||
uint16_t GetAbsXAddr() {
|
uint16_t GetAbsXAddr() {
|
||||||
uint16_t baseAddr = ReadWord();
|
uint16_t baseAddr = ReadWord();
|
||||||
if(IsPageCrossed(baseAddr, X())) {
|
if(IsPageCrossed(baseAddr, X())) {
|
||||||
SetCyclePenalty(1);
|
SetPageCrossed();
|
||||||
}
|
}
|
||||||
return baseAddr + X();
|
return baseAddr + X();
|
||||||
}
|
}
|
||||||
|
@ -174,7 +169,7 @@ private:
|
||||||
uint16_t GetAbsYAddr() {
|
uint16_t GetAbsYAddr() {
|
||||||
uint16_t baseAddr = ReadWord();
|
uint16_t baseAddr = ReadWord();
|
||||||
if(IsPageCrossed(baseAddr, Y())) {
|
if(IsPageCrossed(baseAddr, Y())) {
|
||||||
SetCyclePenalty(1);
|
SetPageCrossed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseAddr + Y();
|
return baseAddr + Y();
|
||||||
|
@ -213,7 +208,7 @@ private:
|
||||||
addr = MemoryReadWord(zero);
|
addr = MemoryReadWord(zero);
|
||||||
}
|
}
|
||||||
if(IsPageCrossed(addr, Y())) {
|
if(IsPageCrossed(addr, Y())) {
|
||||||
SetCyclePenalty(1);
|
SetPageCrossed();
|
||||||
}
|
}
|
||||||
return addr + Y();
|
return addr + Y();
|
||||||
}
|
}
|
||||||
|
@ -341,7 +336,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void JMP(uint16_t addr) {
|
void JMP(uint16_t addr) {
|
||||||
//std::cout << "JMP from 0x" << std::hex << _currentPC << " to " << addr << std::endl;
|
|
||||||
SetPC(addr);
|
SetPC(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,20 +343,11 @@ private:
|
||||||
int8_t offset = GetImmediate();
|
int8_t offset = GetImmediate();
|
||||||
if(branch) {
|
if(branch) {
|
||||||
if(IsPageCrossed(PC(), offset)) {
|
if(IsPageCrossed(PC(), offset)) {
|
||||||
SetCyclePenalty(2);
|
SetPageCrossed();
|
||||||
} else {
|
|
||||||
SetCyclePenalty(1);
|
|
||||||
}
|
}
|
||||||
SetPC(PC() + offset);
|
CPU::CycleCount++;
|
||||||
|
|
||||||
if(_currentPC == PC()) {
|
SetPC(PC() + offset);
|
||||||
if(_currentPC != 0x33a7) {
|
|
||||||
std::cout << "Infinite loop at: 0x" << std::hex << (short)_currentPC;
|
|
||||||
std::cout << std::endl;
|
|
||||||
} else {
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,14 +364,14 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCyclePenalty(uint8_t penalty) {
|
void SetPageCrossed() {
|
||||||
_cyclePenalty = penalty;
|
_pageCrossed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t GetCyclePenalty() {
|
bool GetPageCrossed() {
|
||||||
uint8_t penalty = _cyclePenalty;
|
bool pageCrossed = _pageCrossed;
|
||||||
_cyclePenalty = 0;
|
_pageCrossed = false;
|
||||||
return penalty;
|
return pageCrossed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region OP Codes
|
#pragma region OP Codes
|
||||||
|
@ -555,13 +540,11 @@ private:
|
||||||
void JMP_Ind() { JMP(GetInd()); }
|
void JMP_Ind() { JMP(GetInd()); }
|
||||||
void JSR() {
|
void JSR() {
|
||||||
uint16_t addr = GetAbsAddr();
|
uint16_t addr = GetAbsAddr();
|
||||||
//std::cout << "JSR from 0x" << std::hex << _currentPC << " to " << addr;
|
|
||||||
Push((uint16_t)(PC() - 1));
|
Push((uint16_t)(PC() - 1));
|
||||||
JMP(addr);
|
JMP(addr);
|
||||||
}
|
}
|
||||||
void RTS() {
|
void RTS() {
|
||||||
uint16_t addr = PopWord();
|
uint16_t addr = PopWord();
|
||||||
//std::cout << "RTS from 0x" << std::hex << _currentPC << " to " << addr;
|
|
||||||
SetPC(addr + 1);
|
SetPC(addr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue