2019-12-05 21:51:03 -05:00
|
|
|
|
#include "stdafx.h"
|
2019-07-25 22:22:09 -04:00
|
|
|
|
#include "../Utilities/Serializer.h"
|
2019-02-11 19:18:47 -05:00
|
|
|
|
#include "CpuTypes.h"
|
|
|
|
|
#include "Cpu.h"
|
2019-03-07 20:12:32 -05:00
|
|
|
|
#include "Console.h"
|
2019-02-11 22:41:34 -05:00
|
|
|
|
#include "MemoryManager.h"
|
2019-04-04 17:49:47 -04:00
|
|
|
|
#include "DmaController.h"
|
2019-03-07 20:12:32 -05:00
|
|
|
|
#include "EventType.h"
|
2019-07-25 22:22:09 -04:00
|
|
|
|
#include "Cpu.Instructions.h"
|
|
|
|
|
#include "Cpu.Shared.h"
|
2019-02-11 19:18:47 -05:00
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
|
Cpu::Cpu(Console *console)
|
2019-02-11 19:18:47 -05:00
|
|
|
|
{
|
2019-03-07 20:12:32 -05:00
|
|
|
|
_console = console;
|
|
|
|
|
_memoryManager = console->GetMemoryManager().get();
|
2019-04-04 17:49:47 -04:00
|
|
|
|
_dmaController = console->GetDmaController().get();
|
2019-03-22 21:12:58 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cpu::~Cpu()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-11 19:18:47 -05:00
|
|
|
|
void Cpu::Exec()
|
|
|
|
|
{
|
2019-02-21 22:10:41 -05:00
|
|
|
|
_immediateMode = false;
|
|
|
|
|
|
2019-03-09 16:03:48 -05:00
|
|
|
|
switch(_state.StopState) {
|
2019-03-09 11:57:15 -05:00
|
|
|
|
case CpuStopState::Running: RunOp(); break;
|
|
|
|
|
case CpuStopState::Stopped:
|
|
|
|
|
//STP was executed, CPU no longer executes any code
|
2019-07-25 22:22:09 -04:00
|
|
|
|
#ifndef DUMMYCPU
|
2019-07-12 23:55:18 -04:00
|
|
|
|
_memoryManager->IncMasterClock4();
|
2019-07-25 22:22:09 -04:00
|
|
|
|
#endif
|
2019-03-09 11:57:15 -05:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case CpuStopState::WaitingForIrq:
|
|
|
|
|
//WAI
|
2019-12-05 21:51:03 -05:00
|
|
|
|
Idle();
|
|
|
|
|
if(_state.IrqSource || _state.NeedNmi) {
|
2020-01-18 13:11:24 -05:00
|
|
|
|
Idle();
|
2019-03-09 11:57:15 -05:00
|
|
|
|
Idle();
|
2019-03-09 16:03:48 -05:00
|
|
|
|
_state.StopState = CpuStopState::Running;
|
2019-03-09 11:57:15 -05:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-06 09:14:49 -04:00
|
|
|
|
#ifndef DUMMYCPU
|
2019-03-09 11:57:15 -05:00
|
|
|
|
//Use the state of the IRQ/NMI flags on the previous cycle to determine if an IRQ is processed or not
|
2019-12-05 21:51:03 -05:00
|
|
|
|
if(_state.PrevNeedNmi) {
|
|
|
|
|
_state.NeedNmi = false;
|
2019-06-30 19:47:12 -04:00
|
|
|
|
uint32_t originalPc = GetProgramAddress(_state.PC);
|
|
|
|
|
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector, true);
|
2019-07-25 22:22:09 -04:00
|
|
|
|
_console->ProcessInterrupt<CpuType::Cpu>(originalPc, GetProgramAddress(_state.PC), true);
|
2019-06-30 19:47:12 -04:00
|
|
|
|
} else if(_state.PrevIrqSource) {
|
|
|
|
|
uint32_t originalPc = GetProgramAddress(_state.PC);
|
|
|
|
|
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector, true);
|
2019-07-25 22:22:09 -04:00
|
|
|
|
_console->ProcessInterrupt<CpuType::Cpu>(originalPc, GetProgramAddress(_state.PC), false);
|
2019-03-09 11:57:15 -05:00
|
|
|
|
}
|
2019-04-06 09:14:49 -04:00
|
|
|
|
#endif
|
2019-03-09 11:57:15 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 22:10:41 -05:00
|
|
|
|
void Cpu::Idle()
|
2019-02-11 19:18:47 -05:00
|
|
|
|
{
|
2019-02-28 16:53:04 -05:00
|
|
|
|
#ifndef DUMMYCPU
|
2019-04-20 09:30:51 -04:00
|
|
|
|
_memoryManager->SetCpuSpeed(6);
|
2019-07-05 19:18:30 -04:00
|
|
|
|
ProcessCpuCycle();
|
2019-07-12 23:55:18 -04:00
|
|
|
|
_memoryManager->IncMasterClock6();
|
2019-12-05 21:51:03 -05:00
|
|
|
|
UpdateIrqNmiFlags();
|
2019-02-28 16:53:04 -05:00
|
|
|
|
#endif
|
2019-02-11 19:18:47 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 22:22:09 -04:00
|
|
|
|
void Cpu::IdleEndJump()
|
2019-02-11 19:18:47 -05:00
|
|
|
|
{
|
2019-07-25 22:22:09 -04:00
|
|
|
|
//Used by SA1
|
2019-02-11 19:18:47 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 22:22:09 -04:00
|
|
|
|
void Cpu::IdleTakeBranch()
|
2019-02-11 19:18:47 -05:00
|
|
|
|
{
|
2019-07-25 22:22:09 -04:00
|
|
|
|
//Used by SA1
|
2019-02-11 19:18:47 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-05 19:18:30 -04:00
|
|
|
|
void Cpu::ProcessCpuCycle()
|
2019-02-11 19:18:47 -05:00
|
|
|
|
{
|
2019-02-13 13:32:21 -05:00
|
|
|
|
_state.CycleCount++;
|
2019-12-05 21:51:03 -05:00
|
|
|
|
DetectNmiSignalEdge();
|
|
|
|
|
_state.IrqLock = _dmaController->ProcessPendingTransfers();
|
2019-07-05 19:18:30 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t Cpu::Read(uint32_t addr, MemoryOperationType type)
|
|
|
|
|
{
|
2019-02-28 16:53:04 -05:00
|
|
|
|
#ifdef DUMMYCPU
|
|
|
|
|
uint8_t value = _memoryManager->Peek(addr);
|
|
|
|
|
LogRead(addr, value);
|
|
|
|
|
return value;
|
|
|
|
|
#else
|
2019-04-20 09:30:51 -04:00
|
|
|
|
_memoryManager->SetCpuSpeed(_memoryManager->GetCpuSpeed(addr));
|
2019-07-05 19:18:30 -04:00
|
|
|
|
ProcessCpuCycle();
|
2019-12-05 21:51:03 -05:00
|
|
|
|
uint8_t value = _memoryManager->Read(addr, type);
|
|
|
|
|
UpdateIrqNmiFlags();
|
|
|
|
|
return value;
|
2019-02-28 16:53:04 -05:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-11 19:18:47 -05:00
|
|
|
|
void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
|
|
|
|
|
{
|
2019-02-28 16:53:04 -05:00
|
|
|
|
#ifdef DUMMYCPU
|
|
|
|
|
LogWrite(addr, value);
|
|
|
|
|
#else
|
2019-04-20 09:30:51 -04:00
|
|
|
|
_memoryManager->SetCpuSpeed(_memoryManager->GetCpuSpeed(addr));
|
2019-07-05 19:18:30 -04:00
|
|
|
|
ProcessCpuCycle();
|
2019-02-12 22:13:09 -05:00
|
|
|
|
_memoryManager->Write(addr, value, type);
|
2019-12-05 21:51:03 -05:00
|
|
|
|
UpdateIrqNmiFlags();
|
2019-02-28 16:53:04 -05:00
|
|
|
|
#endif
|
2019-02-11 19:18:47 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 22:22:09 -04:00
|
|
|
|
uint16_t Cpu::GetResetVector()
|
2019-03-12 09:15:57 -04:00
|
|
|
|
{
|
2019-07-25 22:22:09 -04:00
|
|
|
|
return _memoryManager->PeekWord(Cpu::ResetVector);
|
2019-03-12 09:15:57 -04:00
|
|
|
|
}
|