decoder.hh revision 10593:a39de7b8d2c9
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 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 ¤t, 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, 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); 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); 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__ 341