Mesen2/Core/GBA/GbaCpu.h
Sour 8d6830a70a SNES: Add support for ST018 coprocessor
Used by a single game: Hayazashi Nidan Morita Shougi 2
2024-12-29 23:41:52 +09:00

237 lines
6 KiB
C++

#if (defined(DUMMYCPU) && !defined(__DUMMYGBACPU__H)) || (!defined(DUMMYCPU) && !defined(__GBACPU__H))
#ifdef DUMMYCPU
#define __DUMMYGBACPU__H
#else
#define __GBACPU__H
#endif
#include "pch.h"
#include "GBA/GbaTypes.h"
#include "GBA/GbaMemoryManager.h"
#include "Shared/Emulator.h"
#include "Debugger/DebugTypes.h"
#include "Utilities/ISerializable.h"
class GbaMemoryManager;
class GbaRomPrefetch;
class Emulator;
class GbaCpu : public ISerializable
{
private:
uint32_t _opCode = 0;
GbaCpuState _state = {};
GbaMemoryManager* _memoryManager = nullptr;
GbaRomPrefetch* _prefetch = nullptr;
Emulator* _emu = nullptr;
typedef void(GbaCpu::* Func)();
static Func _armTable[0x1000];
static Func _thumbTable[0x100];
static ArmOpCategory _armCategory[0x1000];
static GbaThumbOpCategory _thumbCategory[0x100];
uint32_t Add(uint32_t op1, uint32_t op2, bool carry, bool updateFlags);
uint32_t Sub(uint32_t op1, uint32_t op2, bool carry, bool updateFlags);
uint32_t LogicalOp(uint32_t result, bool carry, bool updateFlags);
uint32_t RotateRight(uint32_t value, uint32_t shift);
uint32_t RotateRight(uint32_t value, uint32_t shift, bool& carry);
uint32_t ShiftLsl(uint32_t value, uint8_t shift, bool& carry);
uint32_t ShiftLsr(uint32_t value, uint8_t shift, bool& carry);
uint32_t ShiftAsr(uint32_t value, uint8_t shift, bool& carry);
uint32_t ShiftRor(uint32_t value, uint8_t shift, bool& carry);
uint32_t ShiftRrx(uint32_t value, bool& carry);
uint32_t R(uint8_t reg);
void SetR(uint8_t reg, uint32_t value)
{
_state.R[reg] = value;
if(reg == 15) {
_state.Pipeline.ReloadRequested = true;
}
}
GbaCpuFlags& GetSpsr();
static void InitArmOpTable();
void ArmBranchExchangeRegister();
void ArmBranch();
void ArmMsr();
void ArmMrs();
void ArmDataProcessing();
void ArmMultiply();
void ArmMultiplyLong();
void ArmSingleDataTransfer();
void ArmSignedHalfDataTransfer();
void ArmBlockDataTransfer();
void ArmSingleDataSwap();
void ArmSoftwareInterrupt();
void ArmInvalidOp();
bool CheckConditions(uint32_t condCode);
static void InitThumbOpTable();
void ThumbMoveShiftedRegister();
void ThumbAddSubtract();
void ThumbMoveCmpAddSub();
void ThumbAluOperation();
void ThumbHiRegBranchExch();
void ThumbPcRelLoad();
void ThumbLoadStoreRegOffset();
void ThumbLoadStoreSignExtended();
void ThumbLoadStoreImmOffset();
void ThumbLoadStoreHalfWord();
void ThumbSpRelLoadStore();
void ThumbLoadAddress();
void ThumbAddOffsetToSp();
void ThumbPushPopReg();
void ThumbMultipleLoadStore();
void ThumbConditionalBranch();
void ThumbSoftwareInterrupt();
void ThumbUnconditionalBranch();
void ThumbLongBranchLink();
void SwitchMode(GbaCpuMode mode);
void ReloadPipeline();
__forceinline void ProcessPipeline()
{
GbaCpuPipeline& pipe = _state.Pipeline;
if(pipe.ReloadRequested) {
ReloadPipeline();
}
pipe.Execute = pipe.Decode;
pipe.Decode = pipe.Fetch;
pipe.Fetch.Address = _state.R[15] = _state.CPSR.Thumb ? (_state.R[15] + 2) : (_state.R[15] + 4);
pipe.Fetch.OpCode = ReadCode(pipe.Mode, pipe.Fetch.Address);
}
uint32_t ReadCode(GbaAccessModeVal mode, uint32_t addr);
uint32_t Read(GbaAccessModeVal mode, uint32_t addr);
void Write(GbaAccessModeVal mode, uint32_t addr, uint32_t value);
void Idle();
void Idle(uint8_t cycleCount);
void ProcessException(GbaCpuMode mode, GbaCpuVector vector);
void CheckForIrqs();
public:
virtual ~GbaCpu();
static void StaticInit();
void Init(Emulator* emu, GbaMemoryManager* memoryManager, GbaRomPrefetch* prefetch);
static ArmOpCategory GetArmOpCategory(uint32_t opCode);
static GbaThumbOpCategory GetThumbOpCategory(uint16_t opCode);
GbaCpuState& GetState();
uint32_t GetProgramCounter() { return _state.R[15]; }
void SetProgramCounter(uint32_t addr, bool thumb);
template<bool debuggerEnabled>
__noinline bool ProcessHaltMode()
{
return InlineProcessHaltMode<debuggerEnabled>();
}
template<bool debuggerEnabled>
__forceinline bool InlineProcessHaltMode()
{
if constexpr(debuggerEnabled) {
_emu->ProcessHaltedCpu<CpuType::Gba>();
}
bool isHaltOver = _memoryManager->IsHaltOver();
bool processIrq = !_state.CPSR.IrqDisable && _memoryManager->ProcessIrq();
if(_memoryManager->IsSystemStopped()) {
_memoryManager->ProcessStoppedCycle();
} else {
_memoryManager->ProcessInternalCycle<true>();
}
if(isHaltOver) {
_memoryManager->ProcessInternalCycle<true>();
_state.Stopped = false;
if(processIrq) {
CheckForIrqs();
}
return false;
} else {
return true;
}
}
template<bool inlineHalt, bool debuggerEnabled>
__forceinline void Exec()
{
#ifndef DUMMYCPU
if constexpr(inlineHalt) {
if(_state.Stopped && InlineProcessHaltMode<debuggerEnabled>()) {
return;
}
} else {
if(_state.Stopped && ProcessHaltMode<debuggerEnabled>()) {
return;
}
}
if constexpr(debuggerEnabled) {
_emu->ProcessInstruction<CpuType::Gba>();
}
#endif
_opCode = _state.Pipeline.Execute.OpCode;
if(_state.CPSR.Thumb) {
(this->*_thumbTable[(_opCode >> 8) & 0xFF])();
} else {
#ifndef DUMMYCPU
if(CheckConditions(_opCode >> 28)) {
#else
{
#endif
uint16_t opType = ((_opCode & 0x0FF00000) >> 16) | ((_opCode & 0xF0) >> 4);
(this->*_armTable[opType])();
}
}
#ifndef DUMMYCPU
bool checkIrq = !_state.CPSR.IrqDisable && _memoryManager->ProcessIrq();
ProcessPipeline();
if(checkIrq) {
CheckForIrqs();
}
#endif
}
void SetStopFlag() { _state.Stopped = true; }
void ClearSequentialFlag() { _state.Pipeline.Mode &= ~GbaAccessMode::Sequential; }
void SetSequentialFlag() { _state.Pipeline.Mode |= GbaAccessMode::Sequential; }
void PowerOn();
void Serialize(Serializer& s) override;
#ifdef DUMMYCPU
private:
uint32_t _memOpCounter = 0;
MemoryOperationInfo _memOperations[32] = {};
GbaAccessModeVal _memAccessMode[32] = {};
public:
void SetDummyState(GbaCpuState& state);
uint32_t GetOperationCount();
void LogMemoryOperation(uint32_t addr, uint32_t value, GbaAccessModeVal mode, MemoryOperationType type);
MemoryOperationInfo GetOperationInfo(uint32_t index);
GbaAccessModeVal GetOperationMode(uint32_t index);
#endif
};
#endif