#if (defined(DUMMYCPU) && !defined(__DUMMYWsCpu__H)) || (!defined(DUMMYCPU) && !defined(__WsCpu__H)) #ifdef DUMMYCPU #define __DUMMYWsCpu__H #else #define __WsCpu__H #endif #include "pch.h" #include "WS/WsCpuPrefetch.h" #include "WS/WsTypes.h" #include "Shared/MemoryOperationType.h" #include "Utilities/ISerializable.h" class Emulator; class WsMemoryManager; class WsCpu final : public ISerializable { private: struct ModRmState { uint16_t Segment; uint16_t Offset; uint8_t Mode; uint8_t Register; uint8_t Rm; }; enum class WsRepMode : uint8_t { None, Zero, NotZero }; enum class AluOp : uint8_t { Add = 0, Or, Adc, Sbb, And, Sub, Xor, Cmp }; enum class Grp2Mode { One, CL, Immediate }; struct PrefixState { uint16_t PrefixCount; WsSegment Segment; WsRepMode Rep; bool Lock; bool Preserve; }; static WsCpuParityTable _parity; Emulator* _emu = nullptr; WsMemoryManager* _memoryManager = nullptr; WsCpuState _state = {}; ModRmState _modRm = {}; PrefixState _prefix = {}; uint64_t _suppressIrqClock = 0; uint64_t _suppressTrapClock = 0; #ifndef DUMMYCPU WsCpuPrefetch _prefetch; #endif uint16_t* _modRegLut8[4] = { &_state.AX, &_state.CX, &_state.DX, &_state.BX }; uint16_t* _modSegLut16[4] = { &_state.ES, &_state.CS, &_state.SS, &_state.DS }; uint16_t* _modRegLut16[8] = { &_state.AX, &_state.CX, &_state.DX, &_state.BX, &_state.SP, &_state.BP, &_state.SI, &_state.DI }; //Used to re-fill prefetch buffer with last opcode when REP prefix is used uint8_t _opCode = 0; //Divisions/AAM set carry/overflow to the last carry/overflow produced by the previous MUL operation bool _mulOverflow = false; template __forceinline T ReadPort(uint16_t port); template __forceinline void WritePort(uint16_t port, T value); __forceinline void ProcessMemoryAccess(uint32_t addr); __forceinline void ProcessPortAccess(uint16_t port); __forceinline uint8_t ReadCodeByte(bool forOpCode = false); __forceinline uint16_t ReadCodeWord(); template __forceinline T ReadImmediate(); template __forceinline T ReadMemory(uint16_t seg, uint16_t offset); template __forceinline void WriteMemory(uint16_t seg, uint16_t offset, T value); template __forceinline void Idle(); template constexpr uint32_t GetMaxValue(); template constexpr uint32_t GetBitCount(); template constexpr uint32_t GetSign(); void Move(uint16_t& dst, uint16_t src); void MoveLo(uint16_t& dst, uint8_t src); void MoveHi(uint16_t& dst, uint8_t src); void Push(uint16_t value); void PushSP(); void Pop(uint16_t& dst); void PushSegment(uint16_t value); void PopSegment(uint16_t& dst); void PushFlags(); void PopFlags(); void SetFlags(uint16_t flags); void PopMemory(); void PopAll(); void PushAll(); uint16_t GetSegment(WsSegment defaultSegment); __forceinline void ReadModRmByte(); template T GetModRegister(uint8_t reg) = delete; template void SetModRegister(uint8_t reg, T value) = delete; uint16_t GetModSegRegister(uint8_t reg); void SetModSegRegister(uint8_t reg, uint16_t value); template T GetModRm(); template void SetModRm(T value); template void Grp1ModRm(); template void Grp2ModRm(); template void Grp3ModRm(); template void Grp45ModRm(); template void TestModRm(); template void TestImmediate(); template void ExchangeModRm(); void Exchange(uint16_t& x, uint16_t& y); template void MoveModRm(); template void MoveSegment(); template void MoveAccumulator(); template void MoveImmediate(); template void ProcessAluModRm(); template void ProcessAluImm(); template T GetAluResult(AluOp op, T param1, T param2); template void Inc(T& dst); template void Dec(T& dst); template T Add(T x, T y, uint8_t carry); template T Sub(T x, T y, uint8_t borrow); template void MultSignedModRm(); template void MulSigned(T x, T y); template int32_t GetMultiplyResult(T x, T y); template void MulUnsigned(T x, T y); template void DivSigned(T y); template void DivUnsigned(T y); void ProcessInvalidDiv(); template void UpdateFlags(T result); template T And(T x, T y); template T Or(T x, T y); template T Xor(T x, T y); template T ROL(T x, uint8_t shift); template T ROR(T x, uint8_t shift); template T RCL(T x, uint8_t shift); template T RCR(T x, uint8_t shift); template T SHL(T x, uint8_t shift); template T SHR(T x, uint8_t shift); template T SAR(T x, uint8_t shift); void JumpFar(); void Jump(bool condition); void JumpNearWord(); void Call(uint16_t offset); void CallNearWord(); void CallFar(); void CallFar(uint16_t segment, uint16_t offset); void Loop(); void LoopIf(bool condition); void Ret(); void RetImm(); void RetFar(); void RetFarImm(); void RetInterrupt(); void Interrupt(uint8_t vector, bool pushFirstPrefix = false); void InterruptOverflow(); void Enter(); void Leave(); void NOP(); void FP01(); void BOUND(); void SALC(); void CBW(); void CWD(); void LAHF(); void SAHF(); void LdsLesLeaModRm(); uint16_t LoadSegment(); void LDS(); void LES(); void LEA(); void XLAT(); void AdjustAscii(bool forSub); void AAA(); void AAS(); void AAD(); void AAM(); void AdjustDecimal(bool forSub); void DAA(); void DAS(); template void Out(uint16_t port, T data); template void InStoreAx(uint16_t port); template void INS(); template void OUTS(); template void ProcessStringOperation(bool incSi, bool incDi); template void ProcessStringCmpOperation(bool incSi); template void MOVS(); template void STOS(); template void LODS(); template void CMPS(); template void SCAS(); void Undefined(); void Wait(); void Halt(); void SuppressIrq(bool suppressTrap); void SetFlagValue(bool& flag, bool value); void SetIrqFlag(); public: WsCpu(Emulator* emu, WsMemoryManager* memoryManager); WsCpuState& GetState() { return _state; } uint64_t GetCycleCount() { return _state.CycleCount; } void ProcessCpuCycle(); __forceinline void IncCycleCount() { _state.CycleCount++; } void ClearPrefetch(); uint32_t GetProgramCounter(bool adjustForRepLoop = false); void Exec(); void ExecOpCode(); void Serialize(Serializer& s) override; #ifdef DUMMYCPU private: uint32_t _memOpCounter = 0; MemoryOperationInfo _memOperations[32] = {}; bool _memWordAccess[32] = {}; public: void SetDummyState(WsCpuState& state); uint32_t GetOperationCount(); void LogMemoryOperation(uint32_t addr, uint16_t value, MemoryOperationType type, MemoryType memType, bool isWordAccess); MemoryOperationInfo GetOperationInfo(uint32_t index); bool IsWordAccess(uint32_t index); #endif }; template<> uint8_t WsCpu::GetModRegister(uint8_t reg); template<> uint16_t WsCpu::GetModRegister(uint8_t reg); template<> void WsCpu::SetModRegister(uint8_t reg, uint8_t value); template<> void WsCpu::SetModRegister(uint8_t reg, uint16_t value); #endif