summaryrefslogtreecommitdiff
path: root/src/arch/x86/decoder.hh
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2012-05-26 13:44:46 -0700
committerGabe Black <gblack@eecs.umich.edu>2012-05-26 13:44:46 -0700
commit0cba96ba6a5d7a4dab2a63b14149c49dfbfbb3bc (patch)
tree1e4e1372b76ed021060d560c2ee1a474f4b22ef0 /src/arch/x86/decoder.hh
parenteae1e97fb002b44a9d8c46df2da1ddc1d0156ce4 (diff)
downloadgem5-0cba96ba6a5d7a4dab2a63b14149c49dfbfbb3bc.tar.xz
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
Diffstat (limited to 'src/arch/x86/decoder.hh')
-rw-r--r--src/arch/x86/decoder.hh189
1 files changed, 188 insertions, 1 deletions
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 <cassert>
+
+#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 &current, 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