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