decoder.hh revision 10593:a39de7b8d2c9
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
47namespace X86ISA
48{
49
50class Decoder
51{
52  private:
53    //These are defined and documented in decoder_tables.cc
54    static const uint8_t SizeTypeToSize[3][10];
55    typedef const uint8_t ByteTable[256];
56    static ByteTable Prefixes;
57
58    static ByteTable UsesModRMOneByte;
59    static ByteTable UsesModRMTwoByte;
60    static ByteTable UsesModRMThreeByte0F38;
61    static ByteTable UsesModRMThreeByte0F3A;
62
63    static ByteTable ImmediateTypeOneByte;
64    static ByteTable ImmediateTypeTwoByte;
65    static ByteTable ImmediateTypeThreeByte0F38;
66    static ByteTable ImmediateTypeThreeByte0F3A;
67
68  protected:
69    struct InstBytes
70    {
71        StaticInstPtr si;
72        std::vector<MachInst> chunks;
73        std::vector<MachInst> masks;
74        int lastOffset;
75
76        InstBytes() : lastOffset(0)
77        {}
78    };
79
80    static InstBytes dummy;
81
82    //The bytes to be predecoded
83    MachInst fetchChunk;
84    InstBytes *instBytes;
85    int chunkIdx;
86    //The pc of the start of fetchChunk
87    Addr basePC;
88    //The pc the current instruction started at
89    Addr origPC;
90    //The offset into fetchChunk of current processing
91    int offset;
92    //The extended machine instruction being generated
93    ExtMachInst emi;
94    //Predecoding state
95    X86Mode mode;
96    X86SubMode submode;
97    uint8_t altOp;
98    uint8_t defOp;
99    uint8_t altAddr;
100    uint8_t defAddr;
101    uint8_t stack;
102
103    uint8_t getNextByte()
104    {
105        return ((uint8_t *)&fetchChunk)[offset];
106    }
107
108    void getImmediate(int &collected, uint64_t &current, int size)
109    {
110        //Figure out how many bytes we still need to get for the
111        //immediate.
112        int toGet = size - collected;
113        //Figure out how many bytes are left in our "buffer"
114        int remaining = sizeof(MachInst) - offset;
115        //Get as much as we need, up to the amount available.
116        toGet = toGet > remaining ? remaining : toGet;
117
118        //Shift the bytes we want to be all the way to the right
119        uint64_t partialImm = fetchChunk >> (offset * 8);
120        //Mask off what we don't want
121        partialImm &= mask(toGet * 8);
122        //Shift it over to overlay with our displacement.
123        partialImm <<= (immediateCollected * 8);
124        //Put it into our displacement
125        current |= partialImm;
126        //Update how many bytes we've collected.
127        collected += toGet;
128        consumeBytes(toGet);
129    }
130
131    void updateOffsetState()
132    {
133        assert(offset <= sizeof(MachInst));
134        if (offset == sizeof(MachInst)) {
135            DPRINTF(Decoder, "At the end of a chunk, idx = %d, chunks = %d.\n",
136                    chunkIdx, instBytes->chunks.size());
137            chunkIdx++;
138            if (chunkIdx == instBytes->chunks.size()) {
139                outOfBytes = true;
140            } else {
141                offset = 0;
142                fetchChunk = instBytes->chunks[chunkIdx];
143                basePC += sizeof(MachInst);
144            }
145        }
146    }
147
148    void consumeByte()
149    {
150        offset++;
151        updateOffsetState();
152    }
153
154    void consumeBytes(int numBytes)
155    {
156        offset += numBytes;
157        updateOffsetState();
158    }
159
160    //State machine state
161  protected:
162    //Whether or not we're out of bytes
163    bool outOfBytes;
164    //Whether we've completed generating an ExtMachInst
165    bool instDone;
166    //The size of the displacement value
167    int displacementSize;
168    //The size of the immediate value
169    int immediateSize;
170    //This is how much of any immediate value we've gotten. This is used
171    //for both the actual immediate and the displacement.
172    int immediateCollected;
173
174    enum State {
175        ResetState,
176        FromCacheState,
177        PrefixState,
178        OneByteOpcodeState,
179        TwoByteOpcodeState,
180        ThreeByte0F38OpcodeState,
181        ThreeByte0F3AOpcodeState,
182        ModRMState,
183        SIBState,
184        DisplacementState,
185        ImmediateState,
186        //We should never get to this state. Getting here is an error.
187        ErrorState
188    };
189
190    State state;
191
192    //Functions to handle each of the states
193    State doResetState();
194    State doFromCacheState();
195    State doPrefixState(uint8_t);
196    State doOneByteOpcodeState(uint8_t);
197    State doTwoByteOpcodeState(uint8_t);
198    State doThreeByte0F38OpcodeState(uint8_t);
199    State doThreeByte0F3AOpcodeState(uint8_t);
200    State doModRMState(uint8_t);
201    State doSIBState(uint8_t);
202    State doDisplacementState();
203    State doImmediateState();
204
205    //Process the actual opcode found earlier, using the supplied tables.
206    State processOpcode(ByteTable &immTable, ByteTable &modrmTable,
207                        bool addrSizedImm = false);
208
209  protected:
210    /// Caching for decoded instruction objects.
211
212    typedef MiscReg CacheKey;
213
214    typedef DecodeCache::AddrMap<Decoder::InstBytes> DecodePages;
215    DecodePages *decodePages;
216    typedef m5::hash_map<CacheKey, DecodePages *> AddrCacheMap;
217    AddrCacheMap addrCacheMap;
218
219    DecodeCache::InstMap *instMap;
220    typedef m5::hash_map<CacheKey, DecodeCache::InstMap *> InstCacheMap;
221    static InstCacheMap instCacheMap;
222
223  public:
224    Decoder() : basePC(0), origPC(0), offset(0),
225        outOfBytes(true), instDone(false),
226        state(ResetState)
227    {
228        memset(&emi, 0, sizeof(emi));
229        mode = LongMode;
230        submode = SixtyFourBitMode;
231        emi.mode.mode = mode;
232        emi.mode.submode = submode;
233        altOp = 0;
234        defOp = 0;
235        altAddr = 0;
236        defAddr = 0;
237        stack = 0;
238        instBytes = &dummy;
239        decodePages = NULL;
240        instMap = NULL;
241    }
242
243    void setM5Reg(HandyM5Reg m5Reg)
244    {
245        mode = (X86Mode)(uint64_t)m5Reg.mode;
246        submode = (X86SubMode)(uint64_t)m5Reg.submode;
247        emi.mode.mode = mode;
248        emi.mode.submode = submode;
249        altOp = m5Reg.altOp;
250        defOp = m5Reg.defOp;
251        altAddr = m5Reg.altAddr;
252        defAddr = m5Reg.defAddr;
253        stack = m5Reg.stack;
254
255        AddrCacheMap::iterator amIter = addrCacheMap.find(m5Reg);
256        if (amIter != addrCacheMap.end()) {
257            decodePages = amIter->second;
258        } else {
259            decodePages = new DecodePages;
260            addrCacheMap[m5Reg] = decodePages;
261        }
262
263        InstCacheMap::iterator imIter = instCacheMap.find(m5Reg);
264        if (imIter != instCacheMap.end()) {
265            instMap = imIter->second;
266        } else {
267            instMap = new DecodeCache::InstMap;
268            instCacheMap[m5Reg] = instMap;
269        }
270    }
271
272    void takeOverFrom(Decoder *old)
273    {
274        mode = old->mode;
275        submode = old->submode;
276        emi.mode.mode = mode;
277        emi.mode.submode = submode;
278        altOp = old->altOp;
279        defOp = old->defOp;
280        altAddr = old->altAddr;
281        defAddr = old->defAddr;
282        stack = old->stack;
283    }
284
285    void reset()
286    {
287        state = ResetState;
288    }
289
290    void process();
291
292    //Use this to give data to the decoder. This should be used
293    //when there is control flow.
294    void moreBytes(const PCState &pc, Addr fetchPC, MachInst data)
295    {
296        DPRINTF(Decoder, "Getting more bytes.\n");
297        basePC = fetchPC;
298        offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
299        fetchChunk = data;
300        outOfBytes = false;
301        process();
302    }
303
304    bool needMoreBytes()
305    {
306        return outOfBytes;
307    }
308
309    bool instReady()
310    {
311        return instDone;
312    }
313
314    void
315    updateNPC(X86ISA::PCState &nextPC)
316    {
317        if (!nextPC.size()) {
318            int size = basePC + offset - origPC;
319            DPRINTF(Decoder,
320                    "Calculating the instruction size: "
321                    "basePC: %#x offset: %#x origPC: %#x size: %d\n",
322                    basePC, offset, origPC, size);
323            nextPC.size(size);
324            nextPC.npc(nextPC.pc() + size);
325        }
326    }
327
328  public:
329    StaticInstPtr decodeInst(ExtMachInst mach_inst);
330
331    /// Decode a machine instruction.
332    /// @param mach_inst The binary instruction to decode.
333    /// @retval A pointer to the corresponding StaticInst object.
334    StaticInstPtr decode(ExtMachInst mach_inst, Addr addr);
335    StaticInstPtr decode(X86ISA::PCState &nextPC);
336};
337
338} // namespace X86ISA
339
340#endif // __ARCH_X86_DECODER_HH__
341