decoder.hh revision 9376:270c9a75e91f
1/*
2 * Copyright (c) 2012 Google
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Gabe Black
29 */
30
31#ifndef __ARCH_X86_DECODER_HH__
32#define __ARCH_X86_DECODER_HH__
33
34#include <cassert>
35#include <vector>
36
37#include "arch/x86/regs/misc.hh"
38#include "arch/x86/types.hh"
39#include "base/bitfield.hh"
40#include "base/misc.hh"
41#include "base/trace.hh"
42#include "base/types.hh"
43#include "cpu/decode_cache.hh"
44#include "cpu/static_inst.hh"
45#include "debug/Decoder.hh"
46
47class ThreadContext;
48
49namespace X86ISA
50{
51
52class Decoder
53{
54  private:
55    //These are defined and documented in decoder_tables.cc
56    static const uint8_t Prefixes[256];
57    static const uint8_t UsesModRM[2][256];
58    static const uint8_t ImmediateType[2][256];
59    static const uint8_t SizeTypeToSize[3][10];
60
61  protected:
62    struct InstBytes
63    {
64        StaticInstPtr si;
65        std::vector<MachInst> chunks;
66        std::vector<MachInst> masks;
67        int lastOffset;
68
69        InstBytes() : lastOffset(0)
70        {}
71    };
72
73    static InstBytes dummy;
74
75    ThreadContext * tc;
76    //The bytes to be predecoded
77    MachInst fetchChunk;
78    InstBytes *instBytes;
79    int chunkIdx;
80    //The pc of the start of fetchChunk
81    Addr basePC;
82    //The pc the current instruction started at
83    Addr origPC;
84    //The offset into fetchChunk of current processing
85    int offset;
86    //The extended machine instruction being generated
87    ExtMachInst emi;
88    //Predecoding state
89    X86Mode mode;
90    X86SubMode submode;
91    uint8_t altOp;
92    uint8_t defOp;
93    uint8_t altAddr;
94    uint8_t defAddr;
95    uint8_t stack;
96
97    uint8_t getNextByte()
98    {
99        return ((uint8_t *)&fetchChunk)[offset];
100    }
101
102    void getImmediate(int &collected, uint64_t &current, int size)
103    {
104        //Figure out how many bytes we still need to get for the
105        //immediate.
106        int toGet = size - collected;
107        //Figure out how many bytes are left in our "buffer"
108        int remaining = sizeof(MachInst) - offset;
109        //Get as much as we need, up to the amount available.
110        toGet = toGet > remaining ? remaining : toGet;
111
112        //Shift the bytes we want to be all the way to the right
113        uint64_t partialImm = fetchChunk >> (offset * 8);
114        //Mask off what we don't want
115        partialImm &= mask(toGet * 8);
116        //Shift it over to overlay with our displacement.
117        partialImm <<= (immediateCollected * 8);
118        //Put it into our displacement
119        current |= partialImm;
120        //Update how many bytes we've collected.
121        collected += toGet;
122        consumeBytes(toGet);
123    }
124
125    void updateOffsetState()
126    {
127        assert(offset <= sizeof(MachInst));
128        if (offset == sizeof(MachInst)) {
129            DPRINTF(Decoder, "At the end of a chunk, idx = %d, chunks = %d.\n",
130                    chunkIdx, instBytes->chunks.size());
131            chunkIdx++;
132            if (chunkIdx == instBytes->chunks.size()) {
133                outOfBytes = true;
134            } else {
135                offset = 0;
136                fetchChunk = instBytes->chunks[chunkIdx];
137                basePC += sizeof(MachInst);
138            }
139        }
140    }
141
142    void consumeByte()
143    {
144        offset++;
145        updateOffsetState();
146    }
147
148    void consumeBytes(int numBytes)
149    {
150        offset += numBytes;
151        updateOffsetState();
152    }
153
154    //State machine state
155  protected:
156    //Whether or not we're out of bytes
157    bool outOfBytes;
158    //Whether we've completed generating an ExtMachInst
159    bool instDone;
160    //The size of the displacement value
161    int displacementSize;
162    //The size of the immediate value
163    int immediateSize;
164    //This is how much of any immediate value we've gotten. This is used
165    //for both the actual immediate and the displacement.
166    int immediateCollected;
167
168    enum State {
169        ResetState,
170        FromCacheState,
171        PrefixState,
172        OpcodeState,
173        ModRMState,
174        SIBState,
175        DisplacementState,
176        ImmediateState,
177        //We should never get to this state. Getting here is an error.
178        ErrorState
179    };
180
181    State state;
182
183    //Functions to handle each of the states
184    State doResetState();
185    State doFromCacheState();
186    State doPrefixState(uint8_t);
187    State doOpcodeState(uint8_t);
188    State doModRMState(uint8_t);
189    State doSIBState(uint8_t);
190    State doDisplacementState();
191    State doImmediateState();
192
193  protected:
194    /// Caching for decoded instruction objects.
195
196    typedef MiscReg CacheKey;
197
198    typedef DecodeCache::AddrMap<Decoder::InstBytes> DecodePages;
199    DecodePages *decodePages;
200    typedef m5::hash_map<CacheKey, DecodePages *> AddrCacheMap;
201    AddrCacheMap addrCacheMap;
202
203    DecodeCache::InstMap *instMap;
204    typedef m5::hash_map<CacheKey, DecodeCache::InstMap *> InstCacheMap;
205    static InstCacheMap instCacheMap;
206
207  public:
208    Decoder(ThreadContext * _tc) :
209        tc(_tc), basePC(0), origPC(0), offset(0),
210        outOfBytes(true), instDone(false),
211        state(ResetState)
212    {
213        memset(&emi, 0, sizeof(emi));
214        mode = LongMode;
215        submode = SixtyFourBitMode;
216        emi.mode.mode = mode;
217        emi.mode.submode = submode;
218        altOp = 0;
219        defOp = 0;
220        altAddr = 0;
221        defAddr = 0;
222        stack = 0;
223        instBytes = &dummy;
224        decodePages = NULL;
225        instMap = NULL;
226    }
227
228    void setM5Reg(HandyM5Reg m5Reg)
229    {
230        mode = (X86Mode)(uint64_t)m5Reg.mode;
231        submode = (X86SubMode)(uint64_t)m5Reg.submode;
232        emi.mode.mode = mode;
233        emi.mode.submode = submode;
234        altOp = m5Reg.altOp;
235        defOp = m5Reg.defOp;
236        altAddr = m5Reg.altAddr;
237        defAddr = m5Reg.defAddr;
238        stack = m5Reg.stack;
239
240        AddrCacheMap::iterator amIter = addrCacheMap.find(m5Reg);
241        if (amIter != addrCacheMap.end()) {
242            decodePages = amIter->second;
243        } else {
244            decodePages = new DecodePages;
245            addrCacheMap[m5Reg] = decodePages;
246        }
247
248        InstCacheMap::iterator imIter = instCacheMap.find(m5Reg);
249        if (imIter != instCacheMap.end()) {
250            instMap = imIter->second;
251        } else {
252            instMap = new DecodeCache::InstMap;
253            instCacheMap[m5Reg] = instMap;
254        }
255    }
256
257    void reset()
258    {
259        state = ResetState;
260    }
261
262    ThreadContext * getTC()
263    {
264        return tc;
265    }
266
267    void setTC(ThreadContext * _tc)
268    {
269        tc = _tc;
270    }
271
272    void process();
273
274    //Use this to give data to the decoder. This should be used
275    //when there is control flow.
276    void moreBytes(const PCState &pc, Addr fetchPC, MachInst data)
277    {
278        DPRINTF(Decoder, "Getting more bytes.\n");
279        basePC = fetchPC;
280        offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
281        fetchChunk = data;
282        outOfBytes = false;
283        process();
284    }
285
286    bool needMoreBytes()
287    {
288        return outOfBytes;
289    }
290
291    bool instReady()
292    {
293        return instDone;
294    }
295
296    void
297    updateNPC(X86ISA::PCState &nextPC)
298    {
299        if (!nextPC.size()) {
300            int size = basePC + offset - origPC;
301            DPRINTF(Decoder,
302                    "Calculating the instruction size: "
303                    "basePC: %#x offset: %#x origPC: %#x size: %d\n",
304                    basePC, offset, origPC, size);
305            nextPC.size(size);
306            nextPC.npc(nextPC.pc() + size);
307        }
308    }
309
310  public:
311    StaticInstPtr decodeInst(ExtMachInst mach_inst);
312
313    /// Decode a machine instruction.
314    /// @param mach_inst The binary instruction to decode.
315    /// @retval A pointer to the corresponding StaticInst object.
316    StaticInstPtr decode(ExtMachInst mach_inst, Addr addr);
317    StaticInstPtr decode(X86ISA::PCState &nextPC);
318};
319
320} // namespace X86ISA
321
322#endif // __ARCH_X86_DECODER_HH__
323