summaryrefslogtreecommitdiff
path: root/src/arch/x86/decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/decoder.cc')
-rw-r--r--src/arch/x86/decoder.cc375
1 files changed, 375 insertions, 0 deletions
diff --git a/src/arch/x86/decoder.cc b/src/arch/x86/decoder.cc
index 469858301..d7199fa82 100644
--- a/src/arch/x86/decoder.cc
+++ b/src/arch/x86/decoder.cc
@@ -29,9 +29,384 @@
*/
#include "arch/x86/decoder.hh"
+#include "arch/x86/regs/misc.hh"
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/types.hh"
+#include "cpu/thread_context.hh"
+#include "debug/Decoder.hh"
namespace X86ISA
{
+void Decoder::doReset()
+{
+ origPC = basePC + offset;
+ DPRINTF(Decoder, "Setting origPC to %#x\n", origPC);
+ emi.rex = 0;
+ emi.legacy = 0;
+ emi.opcode.num = 0;
+ emi.opcode.op = 0;
+ emi.opcode.prefixA = emi.opcode.prefixB = 0;
+
+ immediateCollected = 0;
+ emi.immediate = 0;
+ emi.displacement = 0;
+ emi.dispSize = 0;
+
+ emi.modRM = 0;
+ emi.sib = 0;
+ m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+ emi.mode.mode = m5Reg.mode;
+ emi.mode.submode = m5Reg.submode;
+}
+
+void Decoder::process()
+{
+ //This function drives the decoder state machine.
+
+ //Some sanity checks. You shouldn't try to process more bytes if
+ //there aren't any, and you shouldn't overwrite an already
+ //decoder ExtMachInst.
+ assert(!outOfBytes);
+ assert(!instDone);
+
+ //While there's still something to do...
+ while(!instDone && !outOfBytes)
+ {
+ uint8_t nextByte = getNextByte();
+ switch(state)
+ {
+ case ResetState:
+ doReset();
+ state = PrefixState;
+ case PrefixState:
+ state = doPrefixState(nextByte);
+ break;
+ case OpcodeState:
+ state = doOpcodeState(nextByte);
+ break;
+ case ModRMState:
+ state = doModRMState(nextByte);
+ break;
+ case SIBState:
+ state = doSIBState(nextByte);
+ break;
+ case DisplacementState:
+ state = doDisplacementState();
+ break;
+ case ImmediateState:
+ state = doImmediateState();
+ break;
+ case ErrorState:
+ panic("Went to the error state in the decoder.\n");
+ default:
+ panic("Unrecognized state! %d\n", state);
+ }
+ }
+}
+
+//Either get a prefix and record it in the ExtMachInst, or send the
+//state machine on to get the opcode(s).
+Decoder::State Decoder::doPrefixState(uint8_t nextByte)
+{
+ uint8_t prefix = Prefixes[nextByte];
+ State nextState = PrefixState;
+ // REX prefixes are only recognized in 64 bit mode.
+ if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
+ prefix = 0;
+ if (prefix)
+ consumeByte();
+ switch(prefix)
+ {
+ //Operand size override prefixes
+ case OperandSizeOverride:
+ DPRINTF(Decoder, "Found operand size override prefix.\n");
+ emi.legacy.op = true;
+ break;
+ case AddressSizeOverride:
+ DPRINTF(Decoder, "Found address size override prefix.\n");
+ emi.legacy.addr = true;
+ break;
+ //Segment override prefixes
+ case CSOverride:
+ case DSOverride:
+ case ESOverride:
+ case FSOverride:
+ case GSOverride:
+ case SSOverride:
+ DPRINTF(Decoder, "Found segment override.\n");
+ emi.legacy.seg = prefix;
+ break;
+ case Lock:
+ DPRINTF(Decoder, "Found lock prefix.\n");
+ emi.legacy.lock = true;
+ break;
+ case Rep:
+ DPRINTF(Decoder, "Found rep prefix.\n");
+ emi.legacy.rep = true;
+ break;
+ case Repne:
+ DPRINTF(Decoder, "Found repne prefix.\n");
+ emi.legacy.repne = true;
+ break;
+ case RexPrefix:
+ DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte);
+ emi.rex = nextByte;
+ break;
+ case 0:
+ nextState = OpcodeState;
+ break;
+ default:
+ panic("Unrecognized prefix %#x\n", nextByte);
+ }
+ return nextState;
+}
+
+//Load all the opcodes (currently up to 2) and then figure out
+//what immediate and/or ModRM is needed.
+Decoder::State Decoder::doOpcodeState(uint8_t nextByte)
+{
+ State nextState = ErrorState;
+ emi.opcode.num++;
+ //We can't handle 3+ byte opcodes right now
+ assert(emi.opcode.num < 4);
+ consumeByte();
+ if(emi.opcode.num == 1 && nextByte == 0x0f)
+ {
+ nextState = OpcodeState;
+ DPRINTF(Decoder, "Found two byte opcode.\n");
+ emi.opcode.prefixA = nextByte;
+ }
+ else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
+ {
+ nextState = OpcodeState;
+ DPRINTF(Decoder, "Found three byte opcode.\n");
+ emi.opcode.prefixB = nextByte;
+ }
+ else
+ {
+ DPRINTF(Decoder, "Found opcode %#x.\n", nextByte);
+ emi.opcode.op = nextByte;
+
+ //Figure out the effective operand size. This can be overriden to
+ //a fixed value at the decoder level.
+ int logOpSize;
+ if (emi.rex.w)
+ logOpSize = 3; // 64 bit operand size
+ else if (emi.legacy.op)
+ logOpSize = m5Reg.altOp;
+ else
+ logOpSize = m5Reg.defOp;
+
+ //Set the actual op size
+ emi.opSize = 1 << logOpSize;
+
+ //Figure out the effective address size. This can be overriden to
+ //a fixed value at the decoder level.
+ int logAddrSize;
+ if(emi.legacy.addr)
+ logAddrSize = m5Reg.altAddr;
+ else
+ logAddrSize = m5Reg.defAddr;
+
+ //Set the actual address size
+ emi.addrSize = 1 << logAddrSize;
+
+ //Figure out the effective stack width. This can be overriden to
+ //a fixed value at the decoder level.
+ emi.stackSize = 1 << m5Reg.stack;
+
+ //Figure out how big of an immediate we'll retreive based
+ //on the opcode.
+ int immType = ImmediateType[emi.opcode.num - 1][nextByte];
+ if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
+ immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
+ else
+ immediateSize = SizeTypeToSize[logOpSize - 1][immType];
+
+ //Determine what to expect next
+ if (UsesModRM[emi.opcode.num - 1][nextByte]) {
+ nextState = ModRMState;
+ } else {
+ if(immediateSize) {
+ nextState = ImmediateState;
+ } else {
+ instDone = true;
+ nextState = ResetState;
+ }
+ }
+ }
+ return nextState;
+}
+
+//Get the ModRM byte and determine what displacement, if any, there is.
+//Also determine whether or not to get the SIB byte, displacement, or
+//immediate next.
+Decoder::State Decoder::doModRMState(uint8_t nextByte)
+{
+ State nextState = ErrorState;
+ ModRM modRM;
+ modRM = nextByte;
+ DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte);
+ if (m5Reg.defOp == 1) {
+ //figure out 16 bit displacement size
+ if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
+ displacementSize = 2;
+ else if (modRM.mod == 1)
+ displacementSize = 1;
+ else
+ displacementSize = 0;
+ } else {
+ //figure out 32/64 bit displacement size
+ if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
+ displacementSize = 4;
+ else if (modRM.mod == 1)
+ displacementSize = 1;
+ else
+ displacementSize = 0;
+ }
+
+ // The "test" instruction in group 3 needs an immediate, even though
+ // the other instructions with the same actual opcode don't.
+ if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
+ if (emi.opcode.op == 0xF6)
+ immediateSize = 1;
+ else if (emi.opcode.op == 0xF7)
+ immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
+ }
+
+ //If there's an SIB, get that next.
+ //There is no SIB in 16 bit mode.
+ if (modRM.rm == 4 && modRM.mod != 3) {
+ // && in 32/64 bit mode)
+ nextState = SIBState;
+ } else if(displacementSize) {
+ nextState = DisplacementState;
+ } else if(immediateSize) {
+ nextState = ImmediateState;
+ } else {
+ instDone = true;
+ nextState = ResetState;
+ }
+ //The ModRM byte is consumed no matter what
+ consumeByte();
+ emi.modRM = modRM;
+ return nextState;
+}
+
+//Get the SIB byte. We don't do anything with it at this point, other
+//than storing it in the ExtMachInst. Determine if we need to get a
+//displacement or immediate next.
+Decoder::State Decoder::doSIBState(uint8_t nextByte)
+{
+ State nextState = ErrorState;
+ emi.sib = nextByte;
+ DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte);
+ consumeByte();
+ if (emi.modRM.mod == 0 && emi.sib.base == 5)
+ displacementSize = 4;
+ if (displacementSize) {
+ nextState = DisplacementState;
+ } else if(immediateSize) {
+ nextState = ImmediateState;
+ } else {
+ instDone = true;
+ nextState = ResetState;
+ }
+ return nextState;
+}
+
+//Gather up the displacement, or at least as much of it
+//as we can get.
+Decoder::State Decoder::doDisplacementState()
+{
+ State nextState = ErrorState;
+
+ getImmediate(immediateCollected,
+ emi.displacement,
+ displacementSize);
+
+ DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n",
+ displacementSize, immediateCollected);
+
+ if(displacementSize == immediateCollected) {
+ //Reset this for other immediates.
+ immediateCollected = 0;
+ //Sign extend the displacement
+ switch(displacementSize)
+ {
+ case 1:
+ emi.displacement = sext<8>(emi.displacement);
+ break;
+ case 2:
+ emi.displacement = sext<16>(emi.displacement);
+ break;
+ case 4:
+ emi.displacement = sext<32>(emi.displacement);
+ break;
+ default:
+ panic("Undefined displacement size!\n");
+ }
+ DPRINTF(Decoder, "Collected displacement %#x.\n",
+ emi.displacement);
+ if(immediateSize) {
+ nextState = ImmediateState;
+ } else {
+ instDone = true;
+ nextState = ResetState;
+ }
+
+ emi.dispSize = displacementSize;
+ }
+ else
+ nextState = DisplacementState;
+ return nextState;
+}
+
+//Gather up the immediate, or at least as much of it
+//as we can get
+Decoder::State Decoder::doImmediateState()
+{
+ State nextState = ErrorState;
+
+ getImmediate(immediateCollected,
+ emi.immediate,
+ immediateSize);
+
+ DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n",
+ immediateSize, immediateCollected);
+
+ if(immediateSize == immediateCollected)
+ {
+ //Reset this for other immediates.
+ immediateCollected = 0;
+
+ //XXX Warning! The following is an observed pattern and might
+ //not always be true!
+
+ //Instructions which use 64 bit operands but 32 bit immediates
+ //need to have the immediate sign extended to 64 bits.
+ //Instructions which use true 64 bit immediates won't be
+ //affected, and instructions that use true 32 bit immediates
+ //won't notice.
+ switch(immediateSize)
+ {
+ case 4:
+ emi.immediate = sext<32>(emi.immediate);
+ break;
+ case 1:
+ emi.immediate = sext<8>(emi.immediate);
+ }
+
+ DPRINTF(Decoder, "Collected immediate %#x.\n",
+ emi.immediate);
+ instDone = true;
+ nextState = ResetState;
+ }
+ else
+ nextState = ImmediateState;
+ return nextState;
+}
DecodeCache Decoder::defaultCache;