From 0cba96ba6a5d7a4dab2a63b14149c49dfbfbb3bc Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 26 May 2012 13:44:46 -0700 Subject: CPU: Merge the predecoder and decoder. These classes are always used together, and merging them will give the ISAs more flexibility in how they cache things and manage the process. --HG-- rename : src/arch/x86/predecoder_tables.cc => src/arch/x86/decoder_tables.cc --- src/arch/x86/decoder.hh | 189 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) (limited to 'src/arch/x86/decoder.hh') diff --git a/src/arch/x86/decoder.hh b/src/arch/x86/decoder.hh index 769284adb..300e2238c 100644 --- a/src/arch/x86/decoder.hh +++ b/src/arch/x86/decoder.hh @@ -31,15 +31,192 @@ #ifndef __ARCH_X86_DECODER_HH__ #define __ARCH_X86_DECODER_HH__ -#include "arch/types.hh" +#include + +#include "arch/x86/regs/misc.hh" +#include "arch/x86/types.hh" +#include "base/bitfield.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/types.hh" #include "cpu/decode_cache.hh" #include "cpu/static_inst_fwd.hh" +#include "debug/Decoder.hh" + +class ThreadContext; namespace X86ISA { class Decoder { + private: + //These are defined and documented in decoder_tables.cc + static const uint8_t Prefixes[256]; + static const uint8_t UsesModRM[2][256]; + static const uint8_t ImmediateType[2][256]; + static const uint8_t SizeTypeToSize[3][10]; + + protected: + ThreadContext * tc; + //The bytes to be predecoded + MachInst fetchChunk; + //The pc of the start of fetchChunk + Addr basePC; + //The pc the current instruction started at + Addr origPC; + //The offset into fetchChunk of current processing + int offset; + //The extended machine instruction being generated + ExtMachInst emi; + HandyM5Reg m5Reg; + + inline uint8_t getNextByte() + { + return ((uint8_t *)&fetchChunk)[offset]; + } + + void getImmediate(int &collected, uint64_t ¤t, int size) + { + //Figure out how many bytes we still need to get for the + //immediate. + int toGet = size - collected; + //Figure out how many bytes are left in our "buffer" + int remaining = sizeof(MachInst) - offset; + //Get as much as we need, up to the amount available. + toGet = toGet > remaining ? remaining : toGet; + + //Shift the bytes we want to be all the way to the right + uint64_t partialImm = fetchChunk >> (offset * 8); + //Mask off what we don't want + partialImm &= mask(toGet * 8); + //Shift it over to overlay with our displacement. + partialImm <<= (immediateCollected * 8); + //Put it into our displacement + current |= partialImm; + //Update how many bytes we've collected. + collected += toGet; + consumeBytes(toGet); + } + + inline void consumeByte() + { + offset++; + assert(offset <= sizeof(MachInst)); + if(offset == sizeof(MachInst)) + outOfBytes = true; + } + + inline void consumeBytes(int numBytes) + { + offset += numBytes; + assert(offset <= sizeof(MachInst)); + if(offset == sizeof(MachInst)) + outOfBytes = true; + } + + void doReset(); + + //State machine state + protected: + //Whether or not we're out of bytes + bool outOfBytes; + //Whether we've completed generating an ExtMachInst + bool instDone; + //The size of the displacement value + int displacementSize; + //The size of the immediate value + int immediateSize; + //This is how much of any immediate value we've gotten. This is used + //for both the actual immediate and the displacement. + int immediateCollected; + + enum State { + ResetState, + PrefixState, + OpcodeState, + ModRMState, + SIBState, + DisplacementState, + ImmediateState, + //We should never get to this state. Getting here is an error. + ErrorState + }; + + State state; + + //Functions to handle each of the states + State doPrefixState(uint8_t); + State doOpcodeState(uint8_t); + State doModRMState(uint8_t); + State doSIBState(uint8_t); + State doDisplacementState(); + State doImmediateState(); + + public: + Decoder(ThreadContext * _tc) : + tc(_tc), basePC(0), origPC(0), offset(0), + outOfBytes(true), instDone(false), + state(ResetState) + { + emi.mode.mode = LongMode; + emi.mode.submode = SixtyFourBitMode; + m5Reg = 0; + } + + void reset() + { + state = ResetState; + } + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process(); + + //Use this to give data to the decoder. This should be used + //when there is control flow. + void moreBytes(const PCState &pc, Addr fetchPC, MachInst data) + { + DPRINTF(Decoder, "Getting more bytes.\n"); + basePC = fetchPC; + offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC; + fetchChunk = data; + outOfBytes = false; + process(); + } + + bool needMoreBytes() + { + return outOfBytes; + } + + bool instReady() + { + return instDone; + } + + void + updateNPC(X86ISA::PCState &nextPC) + { + if (!nextPC.size()) { + int size = basePC + offset - origPC; + DPRINTF(Decoder, + "Calculating the instruction size: " + "basePC: %#x offset: %#x origPC: %#x size: %d\n", + basePC, offset, origPC, size); + nextPC.size(size); + nextPC.npc(nextPC.pc() + size); + } + } + protected: /// A cache of decoded instruction objects. static DecodeCache defaultCache; @@ -55,6 +232,16 @@ class Decoder { return defaultCache.decode(this, mach_inst, addr); } + + StaticInstPtr + decode(X86ISA::PCState &nextPC) + { + if (!instDone) + return NULL; + instDone = false; + updateNPC(nextPC); + return decode(emi, origPC); + } }; } // namespace X86ISA -- cgit v1.2.3