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