mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 11:00:19 +02:00
This has the Frontend and OpcodeDispatcher select their operating mode depending on the incoming code segment long-mode flag. Adds some asserts since currently it is unexpected if the configuration changes at runtime. This is fairly straightforward for an initial setup but isn't fully fleshed out. Right now FEX's x86 tables aren't setup in a way to support choosing a different instruction decoding depending on runtime operating mode change, so that would break in interesting ways. Primarily this just gets FEX setup to start piping the operating mode through from the frontend to the backend. This is a long term task, so it is going to take a long time to iron out all the issues.
122 lines
4.0 KiB
C++
122 lines
4.0 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#pragma once
|
|
|
|
#include "Interface/Core/X86Tables/X86Tables.h"
|
|
|
|
#include <FEXCore/HLE/SyscallHandler.h>
|
|
#include <FEXCore/Utils/Telemetry.h>
|
|
#include <FEXCore/fextl/set.h>
|
|
#include <FEXCore/fextl/vector.h>
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <stddef.h>
|
|
|
|
namespace FEXCore::Context {
|
|
class ContextImpl;
|
|
}
|
|
|
|
namespace FEXCore::Frontend {
|
|
class Decoder final {
|
|
public:
|
|
// New Frontend decoding
|
|
struct DecodedBlocks final {
|
|
uint64_t Entry{};
|
|
uint64_t NumInstructions{};
|
|
FEXCore::X86Tables::DecodedInst *DecodedInstructions;
|
|
bool HasInvalidInstruction{};
|
|
};
|
|
|
|
struct DecodedBlockInformation final {
|
|
uint64_t TotalInstructionCount;
|
|
bool Is64BitMode{};
|
|
fextl::vector<DecodedBlocks> Blocks;
|
|
};
|
|
|
|
Decoder(FEXCore::Context::ContextImpl *ctx);
|
|
~Decoder();
|
|
void DecodeInstructionsAtEntry(FEXCore::Core::InternalThreadState *Thread, uint8_t const* InstStream, uint64_t PC, uint64_t MaxInst, std::function<void(uint64_t BlockEntry, uint64_t Start, uint64_t Length)> AddContainedCodePage);
|
|
|
|
DecodedBlockInformation const *GetDecodedBlockInfo() const {
|
|
return &BlockInfo;
|
|
}
|
|
|
|
uint64_t DecodedMinAddress {};
|
|
uint64_t DecodedMaxAddress {~0ULL};
|
|
|
|
void SetSectionMaxAddress(uint64_t v) { SectionMaxAddress = v; }
|
|
void SetExternalBranches(fextl::set<uint64_t> *v) { ExternalBranches = v; }
|
|
|
|
void DelayedDisownBuffer() {
|
|
PoolObject.DelayedDisownBuffer();
|
|
}
|
|
|
|
private:
|
|
// To pass any information from instruction prefixes
|
|
// down into the actual instruction handling machinery.
|
|
struct DecodedHeader {
|
|
uint8_t vvvv; // Encoded operand in a VEX prefix.
|
|
bool w; // VEX.W bit.
|
|
bool L; // VEX.L bit (if set then 256 bit operation, if unset then scalar or 128-bit operation)
|
|
};
|
|
|
|
FEXCore::Context::ContextImpl *CTX;
|
|
const FEXCore::HLE::SyscallOSABI OSABI{};
|
|
|
|
bool DecodeInstruction(uint64_t PC);
|
|
|
|
void BranchTargetInMultiblockRange();
|
|
bool BranchTargetCanContinue(bool FinalInstruction) const;
|
|
|
|
uint8_t ReadByte();
|
|
uint8_t PeekByte(uint8_t Offset) const;
|
|
uint64_t ReadData(uint8_t Size);
|
|
void SkipBytes(uint8_t Size) { InstructionSize += Size; }
|
|
|
|
bool NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op, DecodedHeader Options = {});
|
|
bool NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op);
|
|
|
|
static constexpr size_t DefaultDecodedBufferSize = 0x10000;
|
|
FEXCore::X86Tables::DecodedInst *DecodedBuffer{};
|
|
Utils::FixedSizePooledAllocation<FEXCore::X86Tables::DecodedInst*, 5000, 500> PoolObject;
|
|
size_t DecodedSize {};
|
|
|
|
uint8_t const *InstStream;
|
|
uint8_t GetGPRSize() const { return BlockInfo.Is64BitMode ? 8 : 4; }
|
|
|
|
static constexpr size_t MAX_INST_SIZE = 15;
|
|
uint8_t InstructionSize;
|
|
std::array<uint8_t, MAX_INST_SIZE> Instruction;
|
|
FEXCore::X86Tables::DecodedInst *DecodeInst;
|
|
|
|
// This is for multiblock data tracking
|
|
bool SymbolAvailable {false};
|
|
uint64_t EntryPoint {};
|
|
uint64_t MaxCondBranchForward {};
|
|
uint64_t MaxCondBranchBackwards {~0ULL};
|
|
uint64_t SymbolMaxAddress {};
|
|
uint64_t SymbolMinAddress {~0ULL};
|
|
uint64_t SectionMaxAddress {~0ULL};
|
|
|
|
DecodedBlockInformation BlockInfo;
|
|
fextl::set<uint64_t> BlocksToDecode;
|
|
fextl::set<uint64_t> HasBlocks;
|
|
fextl::set<uint64_t> *ExternalBranches {nullptr};
|
|
|
|
// ModRM rm decoding
|
|
using DecodeModRMPtr = void (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM);
|
|
void DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM);
|
|
void DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM);
|
|
|
|
static constexpr std::array<DecodeModRMPtr, 2> DecodeModRMs_Disp{
|
|
&FEXCore::Frontend::Decoder::DecodeModRM_64,
|
|
&FEXCore::Frontend::Decoder::DecodeModRM_16,
|
|
};
|
|
|
|
const uint8_t *AdjustAddrForSpecialRegion(uint8_t const* _InstStream, uint64_t EntryPoint, uint64_t RIP);
|
|
|
|
FEXCORE_TELEMETRY_INIT(VEXOpTelem, TYPE_USES_VEX_OPS);
|
|
FEXCORE_TELEMETRY_INIT(EVEXOpTelem, TYPE_USES_EVEX_OPS);
|
|
};
|
|
}
|