decoder.hh revision 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; 67 static ByteTable ImmediateTypeVex[10]; 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 ¤t, 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, 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); 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); 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__ 350