decoder.hh (9037:2f84b98634ff) decoder.hh (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>
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>
35
36#include "arch/x86/regs/misc.hh"
37#include "arch/x86/types.hh"
38#include "base/bitfield.hh"
39#include "base/misc.hh"
40#include "base/trace.hh"
41#include "base/types.hh"
42#include "cpu/decode_cache.hh"
43#include "cpu/static_inst.hh"
44#include "debug/Decoder.hh"
45
46class ThreadContext;
47
48namespace X86ISA
49{
50
51class Decoder
52{
53 private:
54 //These are defined and documented in decoder_tables.cc
55 static const uint8_t Prefixes[256];
56 static const uint8_t UsesModRM[2][256];
57 static const uint8_t ImmediateType[2][256];
58 static const uint8_t SizeTypeToSize[3][10];
59
60 protected:
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
61 ThreadContext * tc;
62 //The bytes to be predecoded
63 MachInst fetchChunk;
75 ThreadContext * tc;
76 //The bytes to be predecoded
77 MachInst fetchChunk;
78 InstBytes *instBytes;
79 int chunkIdx;
64 //The pc of the start of fetchChunk
65 Addr basePC;
66 //The pc the current instruction started at
67 Addr origPC;
68 //The offset into fetchChunk of current processing
69 int offset;
70 //The extended machine instruction being generated
71 ExtMachInst emi;
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;
72 HandyM5Reg m5Reg;
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;
73
96
74 inline uint8_t getNextByte()
97 uint8_t getNextByte()
75 {
76 return ((uint8_t *)&fetchChunk)[offset];
77 }
78
79 void getImmediate(int &collected, uint64_t &current, int size)
80 {
81 //Figure out how many bytes we still need to get for the
82 //immediate.
83 int toGet = size - collected;
84 //Figure out how many bytes are left in our "buffer"
85 int remaining = sizeof(MachInst) - offset;
86 //Get as much as we need, up to the amount available.
87 toGet = toGet > remaining ? remaining : toGet;
88
89 //Shift the bytes we want to be all the way to the right
90 uint64_t partialImm = fetchChunk >> (offset * 8);
91 //Mask off what we don't want
92 partialImm &= mask(toGet * 8);
93 //Shift it over to overlay with our displacement.
94 partialImm <<= (immediateCollected * 8);
95 //Put it into our displacement
96 current |= partialImm;
97 //Update how many bytes we've collected.
98 collected += toGet;
99 consumeBytes(toGet);
100 }
101
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
102 inline void consumeByte()
125 void updateOffsetState()
103 {
126 {
104 offset++;
105 assert(offset <= sizeof(MachInst));
127 assert(offset <= sizeof(MachInst));
106 if(offset == sizeof(MachInst))
107 outOfBytes = true;
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 }
108 }
109
140 }
141
110 inline void consumeBytes(int numBytes)
142 void consumeByte()
111 {
143 {
144 offset++;
145 updateOffsetState();
146 }
147
148 void consumeBytes(int numBytes)
149 {
112 offset += numBytes;
150 offset += numBytes;
113 assert(offset <= sizeof(MachInst));
114 if(offset == sizeof(MachInst))
115 outOfBytes = true;
151 updateOffsetState();
116 }
117
152 }
153
118 void doReset();
119
120 //State machine state
121 protected:
122 //Whether or not we're out of bytes
123 bool outOfBytes;
124 //Whether we've completed generating an ExtMachInst
125 bool instDone;
126 //The size of the displacement value
127 int displacementSize;
128 //The size of the immediate value
129 int immediateSize;
130 //This is how much of any immediate value we've gotten. This is used
131 //for both the actual immediate and the displacement.
132 int immediateCollected;
133
134 enum State {
135 ResetState,
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,
136 PrefixState,
137 OpcodeState,
138 ModRMState,
139 SIBState,
140 DisplacementState,
141 ImmediateState,
142 //We should never get to this state. Getting here is an error.
143 ErrorState
144 };
145
146 State state;
147
148 //Functions to handle each of the states
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();
149 State doPrefixState(uint8_t);
150 State doOpcodeState(uint8_t);
151 State doModRMState(uint8_t);
152 State doSIBState(uint8_t);
153 State doDisplacementState();
154 State doImmediateState();
155
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
156 public:
157 Decoder(ThreadContext * _tc) :
158 tc(_tc), basePC(0), origPC(0), offset(0),
159 outOfBytes(true), instDone(false),
160 state(ResetState)
161 {
162 memset(&emi, 0, sizeof(emi));
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));
163 emi.mode.mode = LongMode;
164 emi.mode.submode = SixtyFourBitMode;
165 m5Reg = 0;
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;
166 }
167
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
168 void reset()
169 {
170 state = ResetState;
171 }
172
173 ThreadContext * getTC()
174 {
175 return tc;
176 }
177
178 void setTC(ThreadContext * _tc)
179 {
180 tc = _tc;
181 }
182
183 void process();
184
185 //Use this to give data to the decoder. This should be used
186 //when there is control flow.
187 void moreBytes(const PCState &pc, Addr fetchPC, MachInst data)
188 {
189 DPRINTF(Decoder, "Getting more bytes.\n");
190 basePC = fetchPC;
191 offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
192 fetchChunk = data;
193 outOfBytes = false;
194 process();
195 }
196
197 bool needMoreBytes()
198 {
199 return outOfBytes;
200 }
201
202 bool instReady()
203 {
204 return instDone;
205 }
206
207 void
208 updateNPC(X86ISA::PCState &nextPC)
209 {
210 if (!nextPC.size()) {
211 int size = basePC + offset - origPC;
212 DPRINTF(Decoder,
213 "Calculating the instruction size: "
214 "basePC: %#x offset: %#x origPC: %#x size: %d\n",
215 basePC, offset, origPC, size);
216 nextPC.size(size);
217 nextPC.npc(nextPC.pc() + size);
218 }
219 }
220
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
221 protected:
222 /// Caching for decoded instruction objects.
223 static DecodeCache::InstMap instMap;
224 static DecodeCache::AddrMap<StaticInstPtr> decodePages;
225
226 public:
227 StaticInstPtr decodeInst(ExtMachInst mach_inst);
228
229 /// Decode a machine instruction.
230 /// @param mach_inst The binary instruction to decode.
231 /// @retval A pointer to the corresponding StaticInst object.
232 StaticInstPtr decode(ExtMachInst mach_inst, Addr addr);
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);
233
234 StaticInstPtr
235 decode(X86ISA::PCState &nextPC)
236 {
237 if (!instDone)
238 return NULL;
239 instDone = false;
240 updateNPC(nextPC);
241 return decode(emi, origPC);
242 }
317 StaticInstPtr decode(X86ISA::PCState &nextPC);
243};
244
245} // namespace X86ISA
246
247#endif // __ARCH_X86_DECODER_HH__
318};
319
320} // namespace X86ISA
321
322#endif // __ARCH_X86_DECODER_HH__