diff options
Diffstat (limited to 'src/arch/x86/predecoder.hh')
-rw-r--r-- | src/arch/x86/predecoder.hh | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh new file mode 100644 index 000000000..371ce9db9 --- /dev/null +++ b/src/arch/x86/predecoder.hh @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_PREDECODER_HH__ +#define __ARCH_X86_PREDECODER_HH__ + +#include "arch/x86/types.hh" +#include "base/bitfield.hh" +#include "base/misc.hh" +#include "sim/host.hh" + +class ThreadContext; + +namespace X86ISA +{ + class Predecoder + { + private: + static const uint8_t Prefixes[256]; + static const uint8_t UsesModRM[2][256]; + + protected: + ThreadContext * tc; + //The bytes to be predecoded + MachInst fetchChunk; + //The pc of the start of fetchChunk + Addr basePC; + //The offset into fetchChunk of current processing + int offset; + //The extended machine instruction being generated + ExtMachInst emi; + + //State machine state + protected: + //Whether or not we're out of bytes + bool outOfBytes; + //Whether we've completed generating an ExtMachInst + bool emiIsReady; + //The size of the displacement value + int displacementSize; + int displacementCollected; + //The size of the immediate value + int immediateSize; + int immediateCollected; + + //These are local to some of the states. I need to turn the states + //into inline functions to clean things up a bit. + int toGet; + int remaining; + MachInst partialDisp; + + enum State { + Prefix, + Opcode, + ModRM, + SIB, + Displacement, + Immediate + }; + + State state; + + public: + Predecoder(ThreadContext * _tc) : + tc(_tc), basePC(0), offset(0), + outOfBytes(true), emiIsReady(false), + state(Prefix) + {} + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process() + { + warn("About to process some bytes\n"); + assert(!outOfBytes); + assert(!emiIsReady); + while(!emiIsReady && !outOfBytes) + { + uint8_t nextByte = (fetchChunk >> (offset * 8)) & 0xff; + switch(state) + { + case Prefix: + uint8_t prefix = Prefixes[nextByte]; + switch(prefix) + { + //Operand size override prefixes + case OperandSizeOverride: + warn("Found operand size override prefix!\n"); + offset++; + break; + case AddressSizeOverride: + warn("Found address size override prefix!\n"); + offset++; + break; + //Segment override prefixes + case CSOverride: + warn("Found cs segment override!\n"); + offset++; + break; + case DSOverride: + warn("Found ds segment override!\n"); + offset++; + break; + case ESOverride: + warn("Found es segment override!\n"); + offset++; + break; + case FSOverride: + warn("Found fs segment override!\n"); + offset++; + break; + case GSOverride: + warn("Found gs segment override!\n"); + offset++; + break; + case SSOverride: + warn("Found ss segment override!\n"); + offset++; + break; + case Lock: + warn("Found lock prefix!\n"); + offset++; + break; + case Rep: + warn("Found rep prefix!\n"); + offset++; + break; + case Repne: + warn("Found repne prefix!\n"); + offset++; + break; + case Rex: + warn("Found Rex prefix %#x!\n", nextByte); + offset++; + break; + case 0: + emi.twoByteOpcode = false; + state = Opcode; + break; + default: + panic("Unrecognized prefix %#x\n", nextByte); + } + break; + case Opcode: + if(nextByte == 0xf0) + { + warn("Found two byte opcode!\n"); + emi.twoByteOpcode = true; + } + else + { + warn("Found opcode %#x!\n", nextByte); + if (UsesModRM[emi.twoByteOpcode ? 1 : 0][nextByte]) { + state = ModRM; + } else if(0 /* uses immediate */) { + //Figure out how big the immediate should be + immediateCollected = 0; + emi.immediate = 0; + state = Immediate; + } else { + emiIsReady = true; + state = Prefix; + } + } + offset++; + break; + case ModRM: + warn("Found modrm byte %#x!\n", nextByte); + 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) + displacementSize = 2; + else + displacementSize = 0; + } else { + //figure out 32/64 bit displacement size + if(nextByte & 0xC7 == 0x06 || + nextByte & 0xC0 == 0x40) + displacementSize = 4; + else if(nextByte & 0xC7 == 0x80) + displacementSize = 2; + else + displacementSize = 4; + } + //If there's an SIB, get that next. + //There is no SIB in 16 bit mode. + if(nextByte & 0x7 == 4 && + nextByte & 0xC0 != 0xC0) { + // && 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; + state = Prefix; + } + //The ModRM byte is consumed no matter what + offset++; + break; + case SIB: + 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; + state = Prefix; + } + break; + case Displacement: + //Gather up the displacement, or at least as much of it + //as we can get. + + //Figure out how many bytes we still need to get for the + //displacement. + toGet = displacementSize - displacementCollected; + //Figure out how many bytes are left in our "buffer" + 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 + partialDisp = fetchChunk >> offset; + //Mask off what we don't want + partialDisp &= mask(toGet * 8); + //Shift it over to overlay with our displacement. + partialDisp <<= displacementCollected; + //Put it into our displacement + emi.displacement |= partialDisp; + //Update how many bytes we've collected. + displacementCollected += toGet; + + if(displacementSize == displacementCollected) { + //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"); + } + if(immediateSize) { + immediateCollected = 0; + emi.immediate = 0; + state = Immediate; + } else { + emiIsReady = true; + state = Prefix; + } + } + break; + case Immediate: + //Gather up the displacement, or at least as much of it + //as we can get + + //Figure out how many bytes we still need to get for the + //immediate. + toGet = immediateSize - immediateCollected; + //Figure out how many bytes are left in our "buffer" + 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 + partialDisp = fetchChunk >> offset; + //Mask off what we don't want + partialDisp &= mask(toGet * 8); + //Shift it over to overlay with our immediate. + partialDisp <<= displacementCollected; + //Put it into our immediate + emi.displacement |= partialDisp; + //Update how many bytes we've collected. + displacementCollected += toGet; + if(immediateSize == immediateCollected) + { + emiIsReady = true; + state = Prefix; + } + break; + default: + panic("Unrecognized state! %d\n", state); + } + if(offset == sizeof(MachInst)) + outOfBytes = true; + } + } + + //Use this to give data to the predecoder. This should be used + //when there is control flow. + void moreBytes(Addr currPC, Addr off, MachInst data) + { + basePC = currPC; + offset = off; + fetchChunk = data; + assert(off < sizeof(MachInst)); + outOfBytes = false; + warn("About to call process.\n"); + process(); + } + + //Use this to give data to the predecoder. This should be used + //when instructions are executed in order. + void moreBytes(MachInst machInst) + { + moreBytes(basePC + sizeof(machInst), 0, machInst); + } + + bool needMoreBytes() + { + return outOfBytes; + } + + bool extMachInstReady() + { + return emiIsReady; + } + + //This returns a constant reference to the ExtMachInst to avoid a copy + const ExtMachInst & getExtMachInst() + { + assert(emiIsReady); + emiIsReady = false; + return emi; + } + }; +}; + +#endif // __ARCH_X86_PREDECODER_HH__ |