decoder.hh revision 9478
19020Sgblack@eecs.umich.edu/*
29020Sgblack@eecs.umich.edu * Copyright (c) 2012 Google
39020Sgblack@eecs.umich.edu * All rights reserved.
49020Sgblack@eecs.umich.edu *
59020Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
69020Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
79020Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
89020Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
99020Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
109020Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
119020Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
129020Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
139020Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
149020Sgblack@eecs.umich.edu * this software without specific prior written permission.
159020Sgblack@eecs.umich.edu *
169020Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179020Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189020Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199020Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209020Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219020Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229020Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239020Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249020Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259020Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269020Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279020Sgblack@eecs.umich.edu *
289020Sgblack@eecs.umich.edu * Authors: Gabe Black
299020Sgblack@eecs.umich.edu */
309020Sgblack@eecs.umich.edu
319020Sgblack@eecs.umich.edu#ifndef __ARCH_X86_DECODER_HH__
329020Sgblack@eecs.umich.edu#define __ARCH_X86_DECODER_HH__
339020Sgblack@eecs.umich.edu
349023Sgblack@eecs.umich.edu#include <cassert>
359376Sgblack@eecs.umich.edu#include <vector>
369023Sgblack@eecs.umich.edu
379023Sgblack@eecs.umich.edu#include "arch/x86/regs/misc.hh"
389023Sgblack@eecs.umich.edu#include "arch/x86/types.hh"
399023Sgblack@eecs.umich.edu#include "base/bitfield.hh"
409023Sgblack@eecs.umich.edu#include "base/misc.hh"
419023Sgblack@eecs.umich.edu#include "base/trace.hh"
429023Sgblack@eecs.umich.edu#include "base/types.hh"
439022Sgblack@eecs.umich.edu#include "cpu/decode_cache.hh"
449024Sgblack@eecs.umich.edu#include "cpu/static_inst.hh"
459023Sgblack@eecs.umich.edu#include "debug/Decoder.hh"
469023Sgblack@eecs.umich.edu
479020Sgblack@eecs.umich.edunamespace X86ISA
489020Sgblack@eecs.umich.edu{
499020Sgblack@eecs.umich.edu
509022Sgblack@eecs.umich.educlass Decoder
519022Sgblack@eecs.umich.edu{
529023Sgblack@eecs.umich.edu  private:
539023Sgblack@eecs.umich.edu    //These are defined and documented in decoder_tables.cc
549023Sgblack@eecs.umich.edu    static const uint8_t Prefixes[256];
559023Sgblack@eecs.umich.edu    static const uint8_t UsesModRM[2][256];
569023Sgblack@eecs.umich.edu    static const uint8_t ImmediateType[2][256];
579023Sgblack@eecs.umich.edu    static const uint8_t SizeTypeToSize[3][10];
589023Sgblack@eecs.umich.edu
599023Sgblack@eecs.umich.edu  protected:
609376Sgblack@eecs.umich.edu    struct InstBytes
619376Sgblack@eecs.umich.edu    {
629376Sgblack@eecs.umich.edu        StaticInstPtr si;
639376Sgblack@eecs.umich.edu        std::vector<MachInst> chunks;
649376Sgblack@eecs.umich.edu        std::vector<MachInst> masks;
659376Sgblack@eecs.umich.edu        int lastOffset;
669376Sgblack@eecs.umich.edu
679376Sgblack@eecs.umich.edu        InstBytes() : lastOffset(0)
689376Sgblack@eecs.umich.edu        {}
699376Sgblack@eecs.umich.edu    };
709376Sgblack@eecs.umich.edu
719376Sgblack@eecs.umich.edu    static InstBytes dummy;
729376Sgblack@eecs.umich.edu
739023Sgblack@eecs.umich.edu    //The bytes to be predecoded
749023Sgblack@eecs.umich.edu    MachInst fetchChunk;
759376Sgblack@eecs.umich.edu    InstBytes *instBytes;
769376Sgblack@eecs.umich.edu    int chunkIdx;
779023Sgblack@eecs.umich.edu    //The pc of the start of fetchChunk
789023Sgblack@eecs.umich.edu    Addr basePC;
799023Sgblack@eecs.umich.edu    //The pc the current instruction started at
809023Sgblack@eecs.umich.edu    Addr origPC;
819023Sgblack@eecs.umich.edu    //The offset into fetchChunk of current processing
829023Sgblack@eecs.umich.edu    int offset;
839023Sgblack@eecs.umich.edu    //The extended machine instruction being generated
849023Sgblack@eecs.umich.edu    ExtMachInst emi;
859376Sgblack@eecs.umich.edu    //Predecoding state
869376Sgblack@eecs.umich.edu    X86Mode mode;
879376Sgblack@eecs.umich.edu    X86SubMode submode;
889376Sgblack@eecs.umich.edu    uint8_t altOp;
899376Sgblack@eecs.umich.edu    uint8_t defOp;
909376Sgblack@eecs.umich.edu    uint8_t altAddr;
919376Sgblack@eecs.umich.edu    uint8_t defAddr;
929376Sgblack@eecs.umich.edu    uint8_t stack;
939023Sgblack@eecs.umich.edu
949376Sgblack@eecs.umich.edu    uint8_t getNextByte()
959023Sgblack@eecs.umich.edu    {
969023Sgblack@eecs.umich.edu        return ((uint8_t *)&fetchChunk)[offset];
979023Sgblack@eecs.umich.edu    }
989023Sgblack@eecs.umich.edu
999023Sgblack@eecs.umich.edu    void getImmediate(int &collected, uint64_t &current, int size)
1009023Sgblack@eecs.umich.edu    {
1019023Sgblack@eecs.umich.edu        //Figure out how many bytes we still need to get for the
1029023Sgblack@eecs.umich.edu        //immediate.
1039023Sgblack@eecs.umich.edu        int toGet = size - collected;
1049023Sgblack@eecs.umich.edu        //Figure out how many bytes are left in our "buffer"
1059023Sgblack@eecs.umich.edu        int remaining = sizeof(MachInst) - offset;
1069023Sgblack@eecs.umich.edu        //Get as much as we need, up to the amount available.
1079023Sgblack@eecs.umich.edu        toGet = toGet > remaining ? remaining : toGet;
1089023Sgblack@eecs.umich.edu
1099023Sgblack@eecs.umich.edu        //Shift the bytes we want to be all the way to the right
1109023Sgblack@eecs.umich.edu        uint64_t partialImm = fetchChunk >> (offset * 8);
1119023Sgblack@eecs.umich.edu        //Mask off what we don't want
1129023Sgblack@eecs.umich.edu        partialImm &= mask(toGet * 8);
1139023Sgblack@eecs.umich.edu        //Shift it over to overlay with our displacement.
1149023Sgblack@eecs.umich.edu        partialImm <<= (immediateCollected * 8);
1159023Sgblack@eecs.umich.edu        //Put it into our displacement
1169023Sgblack@eecs.umich.edu        current |= partialImm;
1179023Sgblack@eecs.umich.edu        //Update how many bytes we've collected.
1189023Sgblack@eecs.umich.edu        collected += toGet;
1199023Sgblack@eecs.umich.edu        consumeBytes(toGet);
1209023Sgblack@eecs.umich.edu    }
1219023Sgblack@eecs.umich.edu
1229376Sgblack@eecs.umich.edu    void updateOffsetState()
1239376Sgblack@eecs.umich.edu    {
1249376Sgblack@eecs.umich.edu        assert(offset <= sizeof(MachInst));
1259376Sgblack@eecs.umich.edu        if (offset == sizeof(MachInst)) {
1269376Sgblack@eecs.umich.edu            DPRINTF(Decoder, "At the end of a chunk, idx = %d, chunks = %d.\n",
1279376Sgblack@eecs.umich.edu                    chunkIdx, instBytes->chunks.size());
1289376Sgblack@eecs.umich.edu            chunkIdx++;
1299376Sgblack@eecs.umich.edu            if (chunkIdx == instBytes->chunks.size()) {
1309376Sgblack@eecs.umich.edu                outOfBytes = true;
1319376Sgblack@eecs.umich.edu            } else {
1329376Sgblack@eecs.umich.edu                offset = 0;
1339376Sgblack@eecs.umich.edu                fetchChunk = instBytes->chunks[chunkIdx];
1349376Sgblack@eecs.umich.edu                basePC += sizeof(MachInst);
1359376Sgblack@eecs.umich.edu            }
1369376Sgblack@eecs.umich.edu        }
1379376Sgblack@eecs.umich.edu    }
1389376Sgblack@eecs.umich.edu
1399376Sgblack@eecs.umich.edu    void consumeByte()
1409023Sgblack@eecs.umich.edu    {
1419023Sgblack@eecs.umich.edu        offset++;
1429376Sgblack@eecs.umich.edu        updateOffsetState();
1439023Sgblack@eecs.umich.edu    }
1449023Sgblack@eecs.umich.edu
1459376Sgblack@eecs.umich.edu    void consumeBytes(int numBytes)
1469023Sgblack@eecs.umich.edu    {
1479023Sgblack@eecs.umich.edu        offset += numBytes;
1489376Sgblack@eecs.umich.edu        updateOffsetState();
1499023Sgblack@eecs.umich.edu    }
1509023Sgblack@eecs.umich.edu
1519023Sgblack@eecs.umich.edu    //State machine state
1529023Sgblack@eecs.umich.edu  protected:
1539023Sgblack@eecs.umich.edu    //Whether or not we're out of bytes
1549023Sgblack@eecs.umich.edu    bool outOfBytes;
1559023Sgblack@eecs.umich.edu    //Whether we've completed generating an ExtMachInst
1569023Sgblack@eecs.umich.edu    bool instDone;
1579023Sgblack@eecs.umich.edu    //The size of the displacement value
1589023Sgblack@eecs.umich.edu    int displacementSize;
1599023Sgblack@eecs.umich.edu    //The size of the immediate value
1609023Sgblack@eecs.umich.edu    int immediateSize;
1619023Sgblack@eecs.umich.edu    //This is how much of any immediate value we've gotten. This is used
1629023Sgblack@eecs.umich.edu    //for both the actual immediate and the displacement.
1639023Sgblack@eecs.umich.edu    int immediateCollected;
1649023Sgblack@eecs.umich.edu
1659023Sgblack@eecs.umich.edu    enum State {
1669023Sgblack@eecs.umich.edu        ResetState,
1679376Sgblack@eecs.umich.edu        FromCacheState,
1689023Sgblack@eecs.umich.edu        PrefixState,
1699023Sgblack@eecs.umich.edu        OpcodeState,
1709023Sgblack@eecs.umich.edu        ModRMState,
1719023Sgblack@eecs.umich.edu        SIBState,
1729023Sgblack@eecs.umich.edu        DisplacementState,
1739023Sgblack@eecs.umich.edu        ImmediateState,
1749023Sgblack@eecs.umich.edu        //We should never get to this state. Getting here is an error.
1759023Sgblack@eecs.umich.edu        ErrorState
1769023Sgblack@eecs.umich.edu    };
1779023Sgblack@eecs.umich.edu
1789023Sgblack@eecs.umich.edu    State state;
1799023Sgblack@eecs.umich.edu
1809023Sgblack@eecs.umich.edu    //Functions to handle each of the states
1819376Sgblack@eecs.umich.edu    State doResetState();
1829376Sgblack@eecs.umich.edu    State doFromCacheState();
1839023Sgblack@eecs.umich.edu    State doPrefixState(uint8_t);
1849023Sgblack@eecs.umich.edu    State doOpcodeState(uint8_t);
1859023Sgblack@eecs.umich.edu    State doModRMState(uint8_t);
1869023Sgblack@eecs.umich.edu    State doSIBState(uint8_t);
1879023Sgblack@eecs.umich.edu    State doDisplacementState();
1889023Sgblack@eecs.umich.edu    State doImmediateState();
1899023Sgblack@eecs.umich.edu
1909376Sgblack@eecs.umich.edu  protected:
1919376Sgblack@eecs.umich.edu    /// Caching for decoded instruction objects.
1929376Sgblack@eecs.umich.edu
1939376Sgblack@eecs.umich.edu    typedef MiscReg CacheKey;
1949376Sgblack@eecs.umich.edu
1959376Sgblack@eecs.umich.edu    typedef DecodeCache::AddrMap<Decoder::InstBytes> DecodePages;
1969376Sgblack@eecs.umich.edu    DecodePages *decodePages;
1979376Sgblack@eecs.umich.edu    typedef m5::hash_map<CacheKey, DecodePages *> AddrCacheMap;
1989376Sgblack@eecs.umich.edu    AddrCacheMap addrCacheMap;
1999376Sgblack@eecs.umich.edu
2009376Sgblack@eecs.umich.edu    DecodeCache::InstMap *instMap;
2019376Sgblack@eecs.umich.edu    typedef m5::hash_map<CacheKey, DecodeCache::InstMap *> InstCacheMap;
2029376Sgblack@eecs.umich.edu    static InstCacheMap instCacheMap;
2039376Sgblack@eecs.umich.edu
2049023Sgblack@eecs.umich.edu  public:
2059377Sgblack@eecs.umich.edu    Decoder() : basePC(0), origPC(0), offset(0),
2069023Sgblack@eecs.umich.edu        outOfBytes(true), instDone(false),
2079023Sgblack@eecs.umich.edu        state(ResetState)
2089023Sgblack@eecs.umich.edu    {
2099037Sgblack@eecs.umich.edu        memset(&emi, 0, sizeof(emi));
2109376Sgblack@eecs.umich.edu        mode = LongMode;
2119376Sgblack@eecs.umich.edu        submode = SixtyFourBitMode;
2129376Sgblack@eecs.umich.edu        emi.mode.mode = mode;
2139376Sgblack@eecs.umich.edu        emi.mode.submode = submode;
2149376Sgblack@eecs.umich.edu        altOp = 0;
2159376Sgblack@eecs.umich.edu        defOp = 0;
2169376Sgblack@eecs.umich.edu        altAddr = 0;
2179376Sgblack@eecs.umich.edu        defAddr = 0;
2189376Sgblack@eecs.umich.edu        stack = 0;
2199376Sgblack@eecs.umich.edu        instBytes = &dummy;
2209376Sgblack@eecs.umich.edu        decodePages = NULL;
2219376Sgblack@eecs.umich.edu        instMap = NULL;
2229376Sgblack@eecs.umich.edu    }
2239376Sgblack@eecs.umich.edu
2249376Sgblack@eecs.umich.edu    void setM5Reg(HandyM5Reg m5Reg)
2259376Sgblack@eecs.umich.edu    {
2269376Sgblack@eecs.umich.edu        mode = (X86Mode)(uint64_t)m5Reg.mode;
2279376Sgblack@eecs.umich.edu        submode = (X86SubMode)(uint64_t)m5Reg.submode;
2289376Sgblack@eecs.umich.edu        emi.mode.mode = mode;
2299376Sgblack@eecs.umich.edu        emi.mode.submode = submode;
2309376Sgblack@eecs.umich.edu        altOp = m5Reg.altOp;
2319376Sgblack@eecs.umich.edu        defOp = m5Reg.defOp;
2329376Sgblack@eecs.umich.edu        altAddr = m5Reg.altAddr;
2339376Sgblack@eecs.umich.edu        defAddr = m5Reg.defAddr;
2349376Sgblack@eecs.umich.edu        stack = m5Reg.stack;
2359376Sgblack@eecs.umich.edu
2369376Sgblack@eecs.umich.edu        AddrCacheMap::iterator amIter = addrCacheMap.find(m5Reg);
2379376Sgblack@eecs.umich.edu        if (amIter != addrCacheMap.end()) {
2389376Sgblack@eecs.umich.edu            decodePages = amIter->second;
2399376Sgblack@eecs.umich.edu        } else {
2409376Sgblack@eecs.umich.edu            decodePages = new DecodePages;
2419376Sgblack@eecs.umich.edu            addrCacheMap[m5Reg] = decodePages;
2429376Sgblack@eecs.umich.edu        }
2439376Sgblack@eecs.umich.edu
2449376Sgblack@eecs.umich.edu        InstCacheMap::iterator imIter = instCacheMap.find(m5Reg);
2459376Sgblack@eecs.umich.edu        if (imIter != instCacheMap.end()) {
2469376Sgblack@eecs.umich.edu            instMap = imIter->second;
2479376Sgblack@eecs.umich.edu        } else {
2489376Sgblack@eecs.umich.edu            instMap = new DecodeCache::InstMap;
2499376Sgblack@eecs.umich.edu            instCacheMap[m5Reg] = instMap;
2509376Sgblack@eecs.umich.edu        }
2519023Sgblack@eecs.umich.edu    }
2529023Sgblack@eecs.umich.edu
2539478Snilay@cs.wisc.edu    void takeOverFrom(Decoder *old)
2549478Snilay@cs.wisc.edu    {
2559478Snilay@cs.wisc.edu        mode = old->mode;
2569478Snilay@cs.wisc.edu        submode = old->submode;
2579478Snilay@cs.wisc.edu        emi.mode.mode = mode;
2589478Snilay@cs.wisc.edu        emi.mode.submode = submode;
2599478Snilay@cs.wisc.edu        altOp = old->altOp;
2609478Snilay@cs.wisc.edu        defOp = old->defOp;
2619478Snilay@cs.wisc.edu        altAddr = old->altAddr;
2629478Snilay@cs.wisc.edu        defAddr = old->defAddr;
2639478Snilay@cs.wisc.edu        stack = old->stack;
2649478Snilay@cs.wisc.edu    }
2659478Snilay@cs.wisc.edu
2669023Sgblack@eecs.umich.edu    void reset()
2679023Sgblack@eecs.umich.edu    {
2689023Sgblack@eecs.umich.edu        state = ResetState;
2699023Sgblack@eecs.umich.edu    }
2709023Sgblack@eecs.umich.edu
2719023Sgblack@eecs.umich.edu    void process();
2729023Sgblack@eecs.umich.edu
2739023Sgblack@eecs.umich.edu    //Use this to give data to the decoder. This should be used
2749023Sgblack@eecs.umich.edu    //when there is control flow.
2759023Sgblack@eecs.umich.edu    void moreBytes(const PCState &pc, Addr fetchPC, MachInst data)
2769023Sgblack@eecs.umich.edu    {
2779023Sgblack@eecs.umich.edu        DPRINTF(Decoder, "Getting more bytes.\n");
2789023Sgblack@eecs.umich.edu        basePC = fetchPC;
2799023Sgblack@eecs.umich.edu        offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
2809023Sgblack@eecs.umich.edu        fetchChunk = data;
2819023Sgblack@eecs.umich.edu        outOfBytes = false;
2829023Sgblack@eecs.umich.edu        process();
2839023Sgblack@eecs.umich.edu    }
2849023Sgblack@eecs.umich.edu
2859023Sgblack@eecs.umich.edu    bool needMoreBytes()
2869023Sgblack@eecs.umich.edu    {
2879023Sgblack@eecs.umich.edu        return outOfBytes;
2889023Sgblack@eecs.umich.edu    }
2899023Sgblack@eecs.umich.edu
2909023Sgblack@eecs.umich.edu    bool instReady()
2919023Sgblack@eecs.umich.edu    {
2929023Sgblack@eecs.umich.edu        return instDone;
2939023Sgblack@eecs.umich.edu    }
2949023Sgblack@eecs.umich.edu
2959023Sgblack@eecs.umich.edu    void
2969023Sgblack@eecs.umich.edu    updateNPC(X86ISA::PCState &nextPC)
2979023Sgblack@eecs.umich.edu    {
2989023Sgblack@eecs.umich.edu        if (!nextPC.size()) {
2999023Sgblack@eecs.umich.edu            int size = basePC + offset - origPC;
3009023Sgblack@eecs.umich.edu            DPRINTF(Decoder,
3019023Sgblack@eecs.umich.edu                    "Calculating the instruction size: "
3029023Sgblack@eecs.umich.edu                    "basePC: %#x offset: %#x origPC: %#x size: %d\n",
3039023Sgblack@eecs.umich.edu                    basePC, offset, origPC, size);
3049023Sgblack@eecs.umich.edu            nextPC.size(size);
3059023Sgblack@eecs.umich.edu            nextPC.npc(nextPC.pc() + size);
3069023Sgblack@eecs.umich.edu        }
3079023Sgblack@eecs.umich.edu    }
3089023Sgblack@eecs.umich.edu
3099022Sgblack@eecs.umich.edu  public:
3109022Sgblack@eecs.umich.edu    StaticInstPtr decodeInst(ExtMachInst mach_inst);
3119022Sgblack@eecs.umich.edu
3129022Sgblack@eecs.umich.edu    /// Decode a machine instruction.
3139022Sgblack@eecs.umich.edu    /// @param mach_inst The binary instruction to decode.
3149022Sgblack@eecs.umich.edu    /// @retval A pointer to the corresponding StaticInst object.
3159024Sgblack@eecs.umich.edu    StaticInstPtr decode(ExtMachInst mach_inst, Addr addr);
3169376Sgblack@eecs.umich.edu    StaticInstPtr decode(X86ISA::PCState &nextPC);
3179022Sgblack@eecs.umich.edu};
3189020Sgblack@eecs.umich.edu
3199020Sgblack@eecs.umich.edu} // namespace X86ISA
3209020Sgblack@eecs.umich.edu
3219020Sgblack@eecs.umich.edu#endif // __ARCH_X86_DECODER_HH__
322