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.cc191
1 files changed, 126 insertions, 65 deletions
diff --git a/src/arch/x86/decoder.cc b/src/arch/x86/decoder.cc
index f42fb28bf..59f2e0f4f 100644
--- a/src/arch/x86/decoder.cc
+++ b/src/arch/x86/decoder.cc
@@ -48,9 +48,8 @@ Decoder::doResetState()
emi.rex = 0;
emi.legacy = 0;
- emi.opcode.num = 0;
+ emi.opcode.type = BadOpcode;
emi.opcode.op = 0;
- emi.opcode.prefixA = emi.opcode.prefixB = 0;
immediateCollected = 0;
emi.immediate = 0;
@@ -94,8 +93,17 @@ Decoder::process()
case PrefixState:
state = doPrefixState(nextByte);
break;
- case OpcodeState:
- state = doOpcodeState(nextByte);
+ case OneByteOpcodeState:
+ state = doOneByteOpcodeState(nextByte);
+ break;
+ case TwoByteOpcodeState:
+ state = doTwoByteOpcodeState(nextByte);
+ break;
+ case ThreeByte0F38OpcodeState:
+ state = doThreeByte0F38OpcodeState(nextByte);
+ break;
+ case ThreeByte0F3AOpcodeState:
+ state = doThreeByte0F3AOpcodeState(nextByte);
break;
case ModRMState:
state = doModRMState(nextByte);
@@ -199,7 +207,7 @@ Decoder::doPrefixState(uint8_t nextByte)
emi.rex = nextByte;
break;
case 0:
- nextState = OpcodeState;
+ nextState = OneByteOpcodeState;
break;
default:
panic("Unrecognized prefix %#x\n", nextByte);
@@ -207,79 +215,132 @@ Decoder::doPrefixState(uint8_t nextByte)
return nextState;
}
-//Load all the opcodes (currently up to 2) and then figure out
-//what immediate and/or ModRM is needed.
+// Load the first opcode byte. Determine if there are more opcode bytes, and
+// if not, what immediate and/or ModRM is needed.
Decoder::State
-Decoder::doOpcodeState(uint8_t nextByte)
+Decoder::doOneByteOpcodeState(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;
+ if (nextByte == 0x0f) {
+ nextState = TwoByteOpcodeState;
+ DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte);
+ } else {
+ DPRINTF(Decoder, "Found one byte opcode %#x.\n", nextByte);
+ emi.opcode.type = OneByteOpcode;
+ emi.opcode.op = nextByte;
+
+ nextState = processOpcode(ImmediateTypeOneByte, UsesModRMOneByte,
+ nextByte >= 0xA0 && nextByte <= 0xA3);
}
- else
- {
- DPRINTF(Decoder, "Found opcode %#x.\n", nextByte);
+ return nextState;
+}
+
+// Load the second opcode byte. Determine if there are more opcode bytes, and
+// if not, what immediate and/or ModRM is needed.
+Decoder::State
+Decoder::doTwoByteOpcodeState(uint8_t nextByte)
+{
+ State nextState = ErrorState;
+ consumeByte();
+ if (nextByte == 0x38) {
+ nextState = ThreeByte0F38OpcodeState;
+ DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte);
+ } else if (nextByte == 0x3a) {
+ nextState = ThreeByte0F3AOpcodeState;
+ DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte);
+ } else {
+ DPRINTF(Decoder, "Found two byte opcode %#x.\n", nextByte);
+ emi.opcode.type = TwoByteOpcode;
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 = altOp;
- else
- logOpSize = defOp;
+ nextState = processOpcode(ImmediateTypeTwoByte, UsesModRMTwoByte);
+ }
+ return nextState;
+}
- //Set the actual op size
- emi.opSize = 1 << logOpSize;
+// Load the third opcode byte and determine what immediate and/or ModRM is
+// needed.
+Decoder::State
+Decoder::doThreeByte0F38OpcodeState(uint8_t nextByte)
+{
+ consumeByte();
- //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 = altAddr;
- else
- logAddrSize = defAddr;
+ DPRINTF(Decoder, "Found three byte 0F38 opcode %#x.\n", nextByte);
+ emi.opcode.type = ThreeByte0F38Opcode;
+ emi.opcode.op = nextByte;
- //Set the actual address size
- emi.addrSize = 1 << logAddrSize;
+ return processOpcode(ImmediateTypeThreeByte0F38, UsesModRMThreeByte0F38);
+}
- //Figure out the effective stack width. This can be overriden to
- //a fixed value at the decoder level.
- emi.stackSize = 1 << stack;
+// Load the third opcode byte and determine what immediate and/or ModRM is
+// needed.
+Decoder::State
+Decoder::doThreeByte0F3AOpcodeState(uint8_t nextByte)
+{
+ consumeByte();
- //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];
+ DPRINTF(Decoder, "Found three byte 0F3A opcode %#x.\n", nextByte);
+ emi.opcode.type = ThreeByte0F3AOpcode;
+ emi.opcode.op = nextByte;
+
+ return processOpcode(ImmediateTypeThreeByte0F3A, UsesModRMThreeByte0F3A);
+}
+
+// Generic opcode processing which determines the immediate size, and whether
+// or not there's a modrm byte.
+Decoder::State
+Decoder::processOpcode(ByteTable &immTable, ByteTable &modrmTable,
+ bool addrSizedImm)
+{
+ State nextState = ErrorState;
+ const uint8_t opcode = emi.opcode.op;
+
+ //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 = altOp;
+ else
+ logOpSize = defOp;
- //Determine what to expect next
- if (UsesModRM[emi.opcode.num - 1][nextByte]) {
- nextState = ModRMState;
+ //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 = altAddr;
+ else
+ logAddrSize = 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 << stack;
+
+ //Figure out how big of an immediate we'll retreive based
+ //on the opcode.
+ int immType = immTable[opcode];
+ if (addrSizedImm)
+ immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
+ else
+ immediateSize = SizeTypeToSize[logOpSize - 1][immType];
+
+ //Determine what to expect next
+ if (modrmTable[opcode]) {
+ nextState = ModRMState;
+ } else {
+ if(immediateSize) {
+ nextState = ImmediateState;
} else {
- if(immediateSize) {
- nextState = ImmediateState;
- } else {
- instDone = true;
- nextState = ResetState;
- }
+ instDone = true;
+ nextState = ResetState;
}
}
return nextState;
@@ -315,7 +376,7 @@ Decoder::doModRMState(uint8_t nextByte)
// 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.type == OneByteOpcode && (modRM.reg & 0x6) == 0) {
if (emi.opcode.op == 0xF6)
immediateSize = 1;
else if (emi.opcode.op == 0xF7)