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 ¤t, 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 ¤t, 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__
|