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 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 |
75 ThreadContext * tc; 76 //The bytes to be predecoded 77 MachInst fetchChunk;
|
78 InstBytes *instBytes; 79 int chunkIdx; |
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; |
96
|
74 inline uint8_t getNextByte()
|
97 uint8_t getNextByte() |
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() |
126 {
|
104 offset++;
|
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 } |
140 } 141
|
110 inline void consumeBytes(int numBytes)
|
142 void consumeByte() |
143 {
|
144 offset++; 145 updateOffsetState(); 146 } 147 148 void consumeBytes(int numBytes) 149 { |
150 offset += numBytes;
|
113 assert(offset <= sizeof(MachInst));
114 if(offset == sizeof(MachInst))
115 outOfBytes = true;
|
151 updateOffsetState(); |
152 } 153
|
118 void doReset();
119
|
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, |
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(); |
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 |
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; |
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 |
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
|
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); |
318}; 319 320} // namespace X86ISA 321 322#endif // __ARCH_X86_DECODER_HH__
|