diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh index 371ce9db9..062025a61 100644 --- a/src/arch/x86/predecoder.hh +++ b/src/arch/x86/predecoder.hh @@ -70,8 +70,11 @@ namespace X86ISA class Predecoder { private: + //These are defined and documented in predecoder_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 ImmediateTypeToSize[3][10]; protected: ThreadContext * tc; @@ -193,10 +196,11 @@ namespace X86ISA break; case Rex: warn("Found Rex prefix %#x!\n", nextByte); + emi.rexPrefix = nextByte; offset++; break; case 0: - emi.twoByteOpcode = false; + emi.numOpcodes = 0; state = Opcode; break; default: @@ -204,20 +208,30 @@ namespace X86ISA } break; case Opcode: + emi.numOpcodes++; + assert(emi.numOpcodes < 2); if(nextByte == 0xf0) { warn("Found two byte opcode!\n"); - emi.twoByteOpcode = true; } else { + immediateCollected = 0; + displacementCollected = 0; + emi.immediate = 0; + emi.displacement = 0; + int immType = ImmediateType[ + emi.numOpcodes - 1][nextByte]; + if(0) //16 bit mode + immediateSize = ImmediateTypeToSize[0][immType]; + else if(!(emi.rexPrefix & 0x4)) //32 bit mode + immediateSize = ImmediateTypeToSize[1][immType]; + else //64 bit mode + immediateSize = ImmediateTypeToSize[2][immType]; warn("Found opcode %#x!\n", nextByte); - if (UsesModRM[emi.twoByteOpcode ? 1 : 0][nextByte]) { + if (UsesModRM[emi.numOpcodes - 1][nextByte]) { state = ModRM; - } else if(0 /* uses immediate */) { - //Figure out how big the immediate should be - immediateCollected = 0; - emi.immediate = 0; + } else if(immediateSize) { state = Immediate; } else { emiIsReady = true; @@ -231,21 +245,21 @@ namespace X86ISA if (0) {//in 16 bit mode //figure out 16 bit displacement size if(nextByte & 0xC7 == 0x06 || - nextByte & 0xC0 == 0x40) - displacementSize = 1; - else if(nextByte & 0xC7 == 0x80) + nextByte & 0xC0 == 0x80) displacementSize = 2; + else if(nextByte & 0xC0 == 0x40) + displacementSize = 1; else displacementSize = 0; } else { //figure out 32/64 bit displacement size - if(nextByte & 0xC7 == 0x06 || - nextByte & 0xC0 == 0x40) + if(nextByte & 0xC7 == 0x05 || + nextByte & 0xC0 == 0x80) displacementSize = 4; - else if(nextByte & 0xC7 == 0x80) + else if(nextByte & 0xC0 == 0x40) displacementSize = 2; else - displacementSize = 4; + displacementSize = 0; } //If there's an SIB, get that next. //There is no SIB in 16 bit mode. @@ -254,12 +268,8 @@ namespace X86ISA // && in 32/64 bit mode) state = SIB; } else if(displacementSize) { - displacementCollected = 0; - emi.displacement = 0; state = Displacement; } else if(immediateSize) { - immediateCollected = 0; - emi.immediate = 0; state = Immediate; } else { emiIsReady = true; @@ -272,12 +282,8 @@ namespace X86ISA warn("Found SIB byte %#x!\n", nextByte); offset++; if(displacementSize) { - displacementCollected = 0; - emi.displacement = 0; state = Displacement; } else if(immediateSize) { - immediateCollected = 0; - emi.immediate = 0; state = Immediate; } else { emiIsReady = true; @@ -306,6 +312,9 @@ namespace X86ISA emi.displacement |= partialDisp; //Update how many bytes we've collected. displacementCollected += toGet; + offset += toGet; + warn("Collecting %d byte displacement, got %d bytes!\n", + displacementSize, toGet); if(displacementSize == displacementCollected) { //Sign extend the displacement @@ -324,8 +333,6 @@ namespace X86ISA panic("Undefined displacement size!\n"); } if(immediateSize) { - immediateCollected = 0; - emi.immediate = 0; state = Immediate; } else { emiIsReady = true; @@ -350,11 +357,15 @@ namespace X86ISA //Mask off what we don't want partialDisp &= mask(toGet * 8); //Shift it over to overlay with our immediate. - partialDisp <<= displacementCollected; + partialDisp <<= immediateCollected; //Put it into our immediate - emi.displacement |= partialDisp; + emi.immediate |= partialDisp; //Update how many bytes we've collected. - displacementCollected += toGet; + immediateCollected += toGet; + offset += toGet; + warn("Collecting %d byte immediate, got %d bytes!\n", + immediateSize, toGet); + if(immediateSize == immediateCollected) { emiIsReady = true; diff --git a/src/arch/x86/predecoder_tables.cc b/src/arch/x86/predecoder_tables.cc index 9304eee47..0cebef61a 100644 --- a/src/arch/x86/predecoder_tables.cc +++ b/src/arch/x86/predecoder_tables.cc @@ -140,4 +140,83 @@ namespace X86ISA /* F */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 } }; + + enum ImmediateTypes { + NoImm, + NI = NoImm, + ByteImm, + BY = ByteImm, + WordImm, + WO = WordImm, + DWordImm, + DW = DWordImm, + QWordImm, + QW = QWordImm, + OWordImm, + OW = OWordImm, + VWordImm, + VW = VWordImm, + ZWordImm, + ZW = ZWordImm, + Pointer, + PO = Pointer, + //The enter instruction takes -2- immediates for a total of 3 bytes + Enter, + EN = Enter + }; + + const uint8_t Predecoder::ImmediateTypeToSize[3][10] = + { +// noimm byte word dword qword oword vword zword enter + {0, 1, 2, 4, 8, 16, 2, 2, 3, 4}, //16 bit + {0, 1, 2, 4, 8, 16, 4, 4, 3, 6}, //32 bit + {0, 1, 2, 4, 8, 16, 4, 8, 3, 0} //64 bit + }; + + //This table determines the immediate type. The first index is the + //number of bytes in the instruction, and the second is the meaningful + //byte of the opcode. I didn't use the NI constant here for the sake + //of clarity. + const uint8_t Predecoder::ImmediateType[2][256] = + {//For one byte instructions + { //LSB +// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F +/* 0 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 1 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 2 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 3 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 4 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 5 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 6 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ZW, ZW, BY, BY, 0 , 0 , 0 , 0 , +/* 7 */ BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, +/* 8 */ BY, ZW, BY, BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 9 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* A */ BY, VW, BY, VW, 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , +/* B */ BY, BY, BY, BY, BY, BY, BY, BY, VW, VW, VW, VW, VW, VW, VW, VW, +/* C */ BY, BY, WO, 0 , 0 , 0 , BY, ZW, EN, 0 , WO, 0 , 0 , BY, 0 , 0 , +/* D */ 0 , 0 , 0 , 0 , BY, BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* E */ BY, BY, BY, BY, BY, BY, BY, BY, ZW, ZW, PO, BY, 0 , 0 , 0 , 0 , +/* F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 + }, + //For two byte instructions + { //LSB +// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F +/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 2 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 4 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 5 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 6 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 7 */ BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 8 */ ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, +/* 9 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* A */ 0 , 0 , 0 , 0 , BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , BY, 0 , 0 , 0 , +/* B */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ZW, 0 , BY, 0 , 0 , 0 , 0 , 0 , +/* C */ 0 , 0 , BY, 0 , BY, BY, BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* D */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* E */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 + } + }; } diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 68d95de94..583f03d55 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -94,7 +94,11 @@ namespace X86ISA uint8_t legacyPrefixes; uint8_t rexPrefix; - bool twoByteOpcode; + //Right now, we ignore that this can be 3 in + //some cases + uint8_t numOpcodes; + //This will need to be decoded specially later + bool is3dnow; uint8_t opcode; uint64_t immediate; uint64_t displacement;