From 075df1469f0244f1800b261b65eeac8bb3f460b9 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 15 Mar 2007 15:29:39 +0000 Subject: [PATCH 1/2] Added immediate value support, and fixed alot of bugs. This won't support 3 byte opcodes. --HG-- extra : convert_revision : 4c79bff2592a668e1154916875f019ecafe67022 --- src/arch/x86/predecoder.hh | 65 ++++++++++++++----------- src/arch/x86/predecoder_tables.cc | 79 +++++++++++++++++++++++++++++++ src/arch/x86/types.hh | 6 ++- 3 files changed, 122 insertions(+), 28 deletions(-) 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; From 6cdd434f7f94afc81aa09c411c00969cd80cc833 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 15 Mar 2007 16:13:40 +0000 Subject: [PATCH 2/2] Changed warns to DPRINTFs and multiply by 8 where needed. --HG-- extra : convert_revision : 9db0bc2420ceb5828a79881fa0b420a2d5e5f358 --- src/arch/x86/predecoder.hh | 69 +++++++++++++++++--------------------- src/base/traceflags.py | 1 + 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh index 062025a61..f1dee6bf4 100644 --- a/src/arch/x86/predecoder.hh +++ b/src/arch/x86/predecoder.hh @@ -61,6 +61,7 @@ #include "arch/x86/types.hh" #include "base/bitfield.hh" #include "base/misc.hh" +#include "base/trace.hh" #include "sim/host.hh" class ThreadContext; @@ -136,7 +137,6 @@ namespace X86ISA void process() { - warn("About to process some bytes\n"); assert(!outOfBytes); assert(!emiIsReady); while(!emiIsReady && !outOfBytes) @@ -146,58 +146,48 @@ namespace X86ISA { case Prefix: uint8_t prefix = Prefixes[nextByte]; + if(prefix) + offset++; switch(prefix) { //Operand size override prefixes case OperandSizeOverride: - warn("Found operand size override prefix!\n"); - offset++; + DPRINTF(Predecoder, "Found operand size override prefix.\n"); break; case AddressSizeOverride: - warn("Found address size override prefix!\n"); - offset++; + DPRINTF(Predecoder, "Found address size override prefix.\n"); break; //Segment override prefixes case CSOverride: - warn("Found cs segment override!\n"); - offset++; + DPRINTF(Predecoder, "Found cs segment override.\n"); break; case DSOverride: - warn("Found ds segment override!\n"); - offset++; + DPRINTF(Predecoder, "Found ds segment override.\n"); break; case ESOverride: - warn("Found es segment override!\n"); - offset++; + DPRINTF(Predecoder, "Found es segment override.\n"); break; case FSOverride: - warn("Found fs segment override!\n"); - offset++; + DPRINTF(Predecoder, "Found fs segment override.\n"); break; case GSOverride: - warn("Found gs segment override!\n"); - offset++; + DPRINTF(Predecoder, "Found gs segment override.\n"); break; case SSOverride: - warn("Found ss segment override!\n"); - offset++; + DPRINTF(Predecoder, "Found ss segment override.\n"); break; case Lock: - warn("Found lock prefix!\n"); - offset++; + DPRINTF(Predecoder, "Found lock prefix.\n"); break; case Rep: - warn("Found rep prefix!\n"); - offset++; + DPRINTF(Predecoder, "Found rep prefix.\n"); break; case Repne: - warn("Found repne prefix!\n"); - offset++; + DPRINTF(Predecoder, "Found repne prefix.\n"); break; case Rex: - warn("Found Rex prefix %#x!\n", nextByte); + DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte); emi.rexPrefix = nextByte; - offset++; break; case 0: emi.numOpcodes = 0; @@ -212,7 +202,7 @@ namespace X86ISA assert(emi.numOpcodes < 2); if(nextByte == 0xf0) { - warn("Found two byte opcode!\n"); + DPRINTF(Predecoder, "Found two byte opcode.\n"); } else { @@ -228,7 +218,7 @@ namespace X86ISA immediateSize = ImmediateTypeToSize[1][immType]; else //64 bit mode immediateSize = ImmediateTypeToSize[2][immType]; - warn("Found opcode %#x!\n", nextByte); + DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte); if (UsesModRM[emi.numOpcodes - 1][nextByte]) { state = ModRM; } else if(immediateSize) { @@ -241,7 +231,7 @@ namespace X86ISA offset++; break; case ModRM: - warn("Found modrm byte %#x!\n", nextByte); + DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte); if (0) {//in 16 bit mode //figure out 16 bit displacement size if(nextByte & 0xC7 == 0x06 || @@ -279,7 +269,7 @@ namespace X86ISA offset++; break; case SIB: - warn("Found SIB byte %#x!\n", nextByte); + DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte); offset++; if(displacementSize) { state = Displacement; @@ -303,18 +293,18 @@ namespace X86ISA toGet = toGet > remaining ? remaining : toGet; //Shift the bytes we want to be all the way to the right - partialDisp = fetchChunk >> offset; + partialDisp = fetchChunk >> (offset * 8); //Mask off what we don't want partialDisp &= mask(toGet * 8); //Shift it over to overlay with our displacement. - partialDisp <<= displacementCollected; + partialDisp <<= (displacementCollected * 8); //Put it into our displacement 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); + DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n", + displacementSize, displacementCollected); if(displacementSize == displacementCollected) { //Sign extend the displacement @@ -332,6 +322,8 @@ namespace X86ISA default: panic("Undefined displacement size!\n"); } + DPRINTF(Predecoder, "Collected displacement %#x.\n", + emi.displacement); if(immediateSize) { state = Immediate; } else { @@ -353,21 +345,23 @@ namespace X86ISA toGet = toGet > remaining ? remaining : toGet; //Shift the bytes we want to be all the way to the right - partialDisp = fetchChunk >> offset; + partialDisp = fetchChunk >> (offset * 8); //Mask off what we don't want partialDisp &= mask(toGet * 8); //Shift it over to overlay with our immediate. - partialDisp <<= immediateCollected; + partialDisp <<= (immediateCollected * 8); //Put it into our immediate emi.immediate |= partialDisp; //Update how many bytes we've collected. immediateCollected += toGet; offset += toGet; - warn("Collecting %d byte immediate, got %d bytes!\n", - immediateSize, toGet); + DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n", + immediateSize, immediateCollected); if(immediateSize == immediateCollected) { + DPRINTF(Predecoder, "Collected immediate %#x.\n", + emi.immediate); emiIsReady = true; state = Prefix; } @@ -389,7 +383,6 @@ namespace X86ISA fetchChunk = data; assert(off < sizeof(MachInst)); outOfBytes = false; - warn("About to call process.\n"); process(); } diff --git a/src/base/traceflags.py b/src/base/traceflags.py index a36db1963..e57bfa350 100644 --- a/src/base/traceflags.py +++ b/src/base/traceflags.py @@ -137,6 +137,7 @@ baseFlags = [ 'PciConfigAll', 'Pipeline', 'Printf', + 'Predecoder', 'Quiesce', 'ROB', 'Regs',