decoder.cc revision 10593
19022Sgblack@eecs.umich.edu/* 29022Sgblack@eecs.umich.edu * Copyright (c) 2011 Google 39022Sgblack@eecs.umich.edu * All rights reserved. 49022Sgblack@eecs.umich.edu * 59022Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 69022Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 79022Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 89022Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 99022Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 109022Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 119022Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 129022Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 139022Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 149022Sgblack@eecs.umich.edu * this software without specific prior written permission. 159022Sgblack@eecs.umich.edu * 169022Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 179022Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 189022Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 199022Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 209022Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 219022Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 229022Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239022Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249022Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259022Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 269022Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279022Sgblack@eecs.umich.edu * 289022Sgblack@eecs.umich.edu * Authors: Gabe Black 299022Sgblack@eecs.umich.edu */ 309022Sgblack@eecs.umich.edu 319022Sgblack@eecs.umich.edu#include "arch/x86/decoder.hh" 329023Sgblack@eecs.umich.edu#include "arch/x86/regs/misc.hh" 339023Sgblack@eecs.umich.edu#include "base/misc.hh" 349023Sgblack@eecs.umich.edu#include "base/trace.hh" 359023Sgblack@eecs.umich.edu#include "base/types.hh" 369023Sgblack@eecs.umich.edu#include "debug/Decoder.hh" 379022Sgblack@eecs.umich.edu 389022Sgblack@eecs.umich.edunamespace X86ISA 399022Sgblack@eecs.umich.edu{ 409376Sgblack@eecs.umich.edu 419376Sgblack@eecs.umich.eduDecoder::State 429376Sgblack@eecs.umich.eduDecoder::doResetState() 439023Sgblack@eecs.umich.edu{ 449023Sgblack@eecs.umich.edu origPC = basePC + offset; 459023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Setting origPC to %#x\n", origPC); 469376Sgblack@eecs.umich.edu instBytes = &decodePages->lookup(origPC); 479376Sgblack@eecs.umich.edu chunkIdx = 0; 489376Sgblack@eecs.umich.edu 499023Sgblack@eecs.umich.edu emi.rex = 0; 509023Sgblack@eecs.umich.edu emi.legacy = 0; 5110593Sgabeblack@google.com emi.opcode.type = BadOpcode; 529023Sgblack@eecs.umich.edu emi.opcode.op = 0; 539023Sgblack@eecs.umich.edu 549023Sgblack@eecs.umich.edu immediateCollected = 0; 559023Sgblack@eecs.umich.edu emi.immediate = 0; 569023Sgblack@eecs.umich.edu emi.displacement = 0; 579023Sgblack@eecs.umich.edu emi.dispSize = 0; 589023Sgblack@eecs.umich.edu 599023Sgblack@eecs.umich.edu emi.modRM = 0; 609023Sgblack@eecs.umich.edu emi.sib = 0; 619376Sgblack@eecs.umich.edu 629376Sgblack@eecs.umich.edu if (instBytes->si) { 639376Sgblack@eecs.umich.edu return FromCacheState; 649376Sgblack@eecs.umich.edu } else { 659376Sgblack@eecs.umich.edu instBytes->chunks.clear(); 669376Sgblack@eecs.umich.edu return PrefixState; 679376Sgblack@eecs.umich.edu } 689023Sgblack@eecs.umich.edu} 699023Sgblack@eecs.umich.edu 709376Sgblack@eecs.umich.eduvoid 719376Sgblack@eecs.umich.eduDecoder::process() 729023Sgblack@eecs.umich.edu{ 739023Sgblack@eecs.umich.edu //This function drives the decoder state machine. 749023Sgblack@eecs.umich.edu 759023Sgblack@eecs.umich.edu //Some sanity checks. You shouldn't try to process more bytes if 769023Sgblack@eecs.umich.edu //there aren't any, and you shouldn't overwrite an already 779023Sgblack@eecs.umich.edu //decoder ExtMachInst. 789023Sgblack@eecs.umich.edu assert(!outOfBytes); 799023Sgblack@eecs.umich.edu assert(!instDone); 809023Sgblack@eecs.umich.edu 819376Sgblack@eecs.umich.edu if (state == ResetState) 829376Sgblack@eecs.umich.edu state = doResetState(); 839376Sgblack@eecs.umich.edu if (state == FromCacheState) { 849376Sgblack@eecs.umich.edu state = doFromCacheState(); 859376Sgblack@eecs.umich.edu } else { 869376Sgblack@eecs.umich.edu instBytes->chunks.push_back(fetchChunk); 879376Sgblack@eecs.umich.edu } 889376Sgblack@eecs.umich.edu 899023Sgblack@eecs.umich.edu //While there's still something to do... 909376Sgblack@eecs.umich.edu while (!instDone && !outOfBytes) { 919023Sgblack@eecs.umich.edu uint8_t nextByte = getNextByte(); 929376Sgblack@eecs.umich.edu switch (state) { 939023Sgblack@eecs.umich.edu case PrefixState: 949023Sgblack@eecs.umich.edu state = doPrefixState(nextByte); 959023Sgblack@eecs.umich.edu break; 9610593Sgabeblack@google.com case OneByteOpcodeState: 9710593Sgabeblack@google.com state = doOneByteOpcodeState(nextByte); 9810593Sgabeblack@google.com break; 9910593Sgabeblack@google.com case TwoByteOpcodeState: 10010593Sgabeblack@google.com state = doTwoByteOpcodeState(nextByte); 10110593Sgabeblack@google.com break; 10210593Sgabeblack@google.com case ThreeByte0F38OpcodeState: 10310593Sgabeblack@google.com state = doThreeByte0F38OpcodeState(nextByte); 10410593Sgabeblack@google.com break; 10510593Sgabeblack@google.com case ThreeByte0F3AOpcodeState: 10610593Sgabeblack@google.com state = doThreeByte0F3AOpcodeState(nextByte); 1079023Sgblack@eecs.umich.edu break; 1089023Sgblack@eecs.umich.edu case ModRMState: 1099023Sgblack@eecs.umich.edu state = doModRMState(nextByte); 1109023Sgblack@eecs.umich.edu break; 1119023Sgblack@eecs.umich.edu case SIBState: 1129023Sgblack@eecs.umich.edu state = doSIBState(nextByte); 1139023Sgblack@eecs.umich.edu break; 1149023Sgblack@eecs.umich.edu case DisplacementState: 1159023Sgblack@eecs.umich.edu state = doDisplacementState(); 1169023Sgblack@eecs.umich.edu break; 1179023Sgblack@eecs.umich.edu case ImmediateState: 1189023Sgblack@eecs.umich.edu state = doImmediateState(); 1199023Sgblack@eecs.umich.edu break; 1209023Sgblack@eecs.umich.edu case ErrorState: 1219023Sgblack@eecs.umich.edu panic("Went to the error state in the decoder.\n"); 1229023Sgblack@eecs.umich.edu default: 1239023Sgblack@eecs.umich.edu panic("Unrecognized state! %d\n", state); 1249023Sgblack@eecs.umich.edu } 1259023Sgblack@eecs.umich.edu } 1269023Sgblack@eecs.umich.edu} 1279023Sgblack@eecs.umich.edu 1289376Sgblack@eecs.umich.eduDecoder::State 1299376Sgblack@eecs.umich.eduDecoder::doFromCacheState() 1309376Sgblack@eecs.umich.edu{ 1319376Sgblack@eecs.umich.edu DPRINTF(Decoder, "Looking at cache state.\n"); 1329376Sgblack@eecs.umich.edu if ((fetchChunk & instBytes->masks[chunkIdx]) != 1339376Sgblack@eecs.umich.edu instBytes->chunks[chunkIdx]) { 1349376Sgblack@eecs.umich.edu DPRINTF(Decoder, "Decode cache miss.\n"); 1359376Sgblack@eecs.umich.edu // The chached chunks didn't match what was fetched. Fall back to the 1369376Sgblack@eecs.umich.edu // predecoder. 1379376Sgblack@eecs.umich.edu instBytes->chunks[chunkIdx] = fetchChunk; 1389376Sgblack@eecs.umich.edu instBytes->chunks.resize(chunkIdx + 1); 1399376Sgblack@eecs.umich.edu instBytes->si = NULL; 1409376Sgblack@eecs.umich.edu chunkIdx = 0; 1419376Sgblack@eecs.umich.edu fetchChunk = instBytes->chunks[0]; 1429376Sgblack@eecs.umich.edu offset = origPC % sizeof(MachInst); 1439376Sgblack@eecs.umich.edu basePC = origPC - offset; 1449376Sgblack@eecs.umich.edu return PrefixState; 1459376Sgblack@eecs.umich.edu } else if (chunkIdx == instBytes->chunks.size() - 1) { 1469376Sgblack@eecs.umich.edu // We matched the cache, so use its value. 1479376Sgblack@eecs.umich.edu instDone = true; 1489376Sgblack@eecs.umich.edu offset = instBytes->lastOffset; 1499376Sgblack@eecs.umich.edu if (offset == sizeof(MachInst)) 1509376Sgblack@eecs.umich.edu outOfBytes = true; 1519376Sgblack@eecs.umich.edu return ResetState; 1529376Sgblack@eecs.umich.edu } else { 1539376Sgblack@eecs.umich.edu // We matched so far, but need to check more chunks. 1549376Sgblack@eecs.umich.edu chunkIdx++; 1559376Sgblack@eecs.umich.edu outOfBytes = true; 1569376Sgblack@eecs.umich.edu return FromCacheState; 1579376Sgblack@eecs.umich.edu } 1589376Sgblack@eecs.umich.edu} 1599376Sgblack@eecs.umich.edu 1609023Sgblack@eecs.umich.edu//Either get a prefix and record it in the ExtMachInst, or send the 1619023Sgblack@eecs.umich.edu//state machine on to get the opcode(s). 1629376Sgblack@eecs.umich.eduDecoder::State 1639376Sgblack@eecs.umich.eduDecoder::doPrefixState(uint8_t nextByte) 1649023Sgblack@eecs.umich.edu{ 1659023Sgblack@eecs.umich.edu uint8_t prefix = Prefixes[nextByte]; 1669023Sgblack@eecs.umich.edu State nextState = PrefixState; 1679023Sgblack@eecs.umich.edu // REX prefixes are only recognized in 64 bit mode. 1689023Sgblack@eecs.umich.edu if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode) 1699023Sgblack@eecs.umich.edu prefix = 0; 1709023Sgblack@eecs.umich.edu if (prefix) 1719023Sgblack@eecs.umich.edu consumeByte(); 1729023Sgblack@eecs.umich.edu switch(prefix) 1739023Sgblack@eecs.umich.edu { 1749023Sgblack@eecs.umich.edu //Operand size override prefixes 1759023Sgblack@eecs.umich.edu case OperandSizeOverride: 1769023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found operand size override prefix.\n"); 1779023Sgblack@eecs.umich.edu emi.legacy.op = true; 1789023Sgblack@eecs.umich.edu break; 1799023Sgblack@eecs.umich.edu case AddressSizeOverride: 1809023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found address size override prefix.\n"); 1819023Sgblack@eecs.umich.edu emi.legacy.addr = true; 1829023Sgblack@eecs.umich.edu break; 1839023Sgblack@eecs.umich.edu //Segment override prefixes 1849023Sgblack@eecs.umich.edu case CSOverride: 1859023Sgblack@eecs.umich.edu case DSOverride: 1869023Sgblack@eecs.umich.edu case ESOverride: 1879023Sgblack@eecs.umich.edu case FSOverride: 1889023Sgblack@eecs.umich.edu case GSOverride: 1899023Sgblack@eecs.umich.edu case SSOverride: 1909023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found segment override.\n"); 1919023Sgblack@eecs.umich.edu emi.legacy.seg = prefix; 1929023Sgblack@eecs.umich.edu break; 1939023Sgblack@eecs.umich.edu case Lock: 1949023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found lock prefix.\n"); 1959023Sgblack@eecs.umich.edu emi.legacy.lock = true; 1969023Sgblack@eecs.umich.edu break; 1979023Sgblack@eecs.umich.edu case Rep: 1989023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found rep prefix.\n"); 1999023Sgblack@eecs.umich.edu emi.legacy.rep = true; 2009023Sgblack@eecs.umich.edu break; 2019023Sgblack@eecs.umich.edu case Repne: 2029023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found repne prefix.\n"); 2039023Sgblack@eecs.umich.edu emi.legacy.repne = true; 2049023Sgblack@eecs.umich.edu break; 2059023Sgblack@eecs.umich.edu case RexPrefix: 2069023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte); 2079023Sgblack@eecs.umich.edu emi.rex = nextByte; 2089023Sgblack@eecs.umich.edu break; 2099023Sgblack@eecs.umich.edu case 0: 21010593Sgabeblack@google.com nextState = OneByteOpcodeState; 2119023Sgblack@eecs.umich.edu break; 2129023Sgblack@eecs.umich.edu default: 2139023Sgblack@eecs.umich.edu panic("Unrecognized prefix %#x\n", nextByte); 2149023Sgblack@eecs.umich.edu } 2159023Sgblack@eecs.umich.edu return nextState; 2169023Sgblack@eecs.umich.edu} 2179023Sgblack@eecs.umich.edu 21810593Sgabeblack@google.com// Load the first opcode byte. Determine if there are more opcode bytes, and 21910593Sgabeblack@google.com// if not, what immediate and/or ModRM is needed. 2209376Sgblack@eecs.umich.eduDecoder::State 22110593Sgabeblack@google.comDecoder::doOneByteOpcodeState(uint8_t nextByte) 2229023Sgblack@eecs.umich.edu{ 2239023Sgblack@eecs.umich.edu State nextState = ErrorState; 2249023Sgblack@eecs.umich.edu consumeByte(); 22510593Sgabeblack@google.com if (nextByte == 0x0f) { 22610593Sgabeblack@google.com nextState = TwoByteOpcodeState; 22710593Sgabeblack@google.com DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte); 22810593Sgabeblack@google.com } else { 22910593Sgabeblack@google.com DPRINTF(Decoder, "Found one byte opcode %#x.\n", nextByte); 23010593Sgabeblack@google.com emi.opcode.type = OneByteOpcode; 2319023Sgblack@eecs.umich.edu emi.opcode.op = nextByte; 2329023Sgblack@eecs.umich.edu 23310593Sgabeblack@google.com nextState = processOpcode(ImmediateTypeOneByte, UsesModRMOneByte, 23410593Sgabeblack@google.com nextByte >= 0xA0 && nextByte <= 0xA3); 23510593Sgabeblack@google.com } 23610593Sgabeblack@google.com return nextState; 23710593Sgabeblack@google.com} 2389023Sgblack@eecs.umich.edu 23910593Sgabeblack@google.com// Load the second opcode byte. Determine if there are more opcode bytes, and 24010593Sgabeblack@google.com// if not, what immediate and/or ModRM is needed. 24110593Sgabeblack@google.comDecoder::State 24210593Sgabeblack@google.comDecoder::doTwoByteOpcodeState(uint8_t nextByte) 24310593Sgabeblack@google.com{ 24410593Sgabeblack@google.com State nextState = ErrorState; 24510593Sgabeblack@google.com consumeByte(); 24610593Sgabeblack@google.com if (nextByte == 0x38) { 24710593Sgabeblack@google.com nextState = ThreeByte0F38OpcodeState; 24810593Sgabeblack@google.com DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte); 24910593Sgabeblack@google.com } else if (nextByte == 0x3a) { 25010593Sgabeblack@google.com nextState = ThreeByte0F3AOpcodeState; 25110593Sgabeblack@google.com DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte); 25210593Sgabeblack@google.com } else { 25310593Sgabeblack@google.com DPRINTF(Decoder, "Found two byte opcode %#x.\n", nextByte); 25410593Sgabeblack@google.com emi.opcode.type = TwoByteOpcode; 25510593Sgabeblack@google.com emi.opcode.op = nextByte; 2569023Sgblack@eecs.umich.edu 25710593Sgabeblack@google.com nextState = processOpcode(ImmediateTypeTwoByte, UsesModRMTwoByte); 25810593Sgabeblack@google.com } 25910593Sgabeblack@google.com return nextState; 26010593Sgabeblack@google.com} 2619023Sgblack@eecs.umich.edu 26210593Sgabeblack@google.com// Load the third opcode byte and determine what immediate and/or ModRM is 26310593Sgabeblack@google.com// needed. 26410593Sgabeblack@google.comDecoder::State 26510593Sgabeblack@google.comDecoder::doThreeByte0F38OpcodeState(uint8_t nextByte) 26610593Sgabeblack@google.com{ 26710593Sgabeblack@google.com consumeByte(); 2689023Sgblack@eecs.umich.edu 26910593Sgabeblack@google.com DPRINTF(Decoder, "Found three byte 0F38 opcode %#x.\n", nextByte); 27010593Sgabeblack@google.com emi.opcode.type = ThreeByte0F38Opcode; 27110593Sgabeblack@google.com emi.opcode.op = nextByte; 2729023Sgblack@eecs.umich.edu 27310593Sgabeblack@google.com return processOpcode(ImmediateTypeThreeByte0F38, UsesModRMThreeByte0F38); 27410593Sgabeblack@google.com} 2759023Sgblack@eecs.umich.edu 27610593Sgabeblack@google.com// Load the third opcode byte and determine what immediate and/or ModRM is 27710593Sgabeblack@google.com// needed. 27810593Sgabeblack@google.comDecoder::State 27910593Sgabeblack@google.comDecoder::doThreeByte0F3AOpcodeState(uint8_t nextByte) 28010593Sgabeblack@google.com{ 28110593Sgabeblack@google.com consumeByte(); 28210593Sgabeblack@google.com 28310593Sgabeblack@google.com DPRINTF(Decoder, "Found three byte 0F3A opcode %#x.\n", nextByte); 28410593Sgabeblack@google.com emi.opcode.type = ThreeByte0F3AOpcode; 28510593Sgabeblack@google.com emi.opcode.op = nextByte; 28610593Sgabeblack@google.com 28710593Sgabeblack@google.com return processOpcode(ImmediateTypeThreeByte0F3A, UsesModRMThreeByte0F3A); 28810593Sgabeblack@google.com} 28910593Sgabeblack@google.com 29010593Sgabeblack@google.com// Generic opcode processing which determines the immediate size, and whether 29110593Sgabeblack@google.com// or not there's a modrm byte. 29210593Sgabeblack@google.comDecoder::State 29310593Sgabeblack@google.comDecoder::processOpcode(ByteTable &immTable, ByteTable &modrmTable, 29410593Sgabeblack@google.com bool addrSizedImm) 29510593Sgabeblack@google.com{ 29610593Sgabeblack@google.com State nextState = ErrorState; 29710593Sgabeblack@google.com const uint8_t opcode = emi.opcode.op; 29810593Sgabeblack@google.com 29910593Sgabeblack@google.com //Figure out the effective operand size. This can be overriden to 30010593Sgabeblack@google.com //a fixed value at the decoder level. 30110593Sgabeblack@google.com int logOpSize; 30210593Sgabeblack@google.com if (emi.rex.w) 30310593Sgabeblack@google.com logOpSize = 3; // 64 bit operand size 30410593Sgabeblack@google.com else if (emi.legacy.op) 30510593Sgabeblack@google.com logOpSize = altOp; 30610593Sgabeblack@google.com else 30710593Sgabeblack@google.com logOpSize = defOp; 30810593Sgabeblack@google.com 30910593Sgabeblack@google.com //Set the actual op size 31010593Sgabeblack@google.com emi.opSize = 1 << logOpSize; 31110593Sgabeblack@google.com 31210593Sgabeblack@google.com //Figure out the effective address size. This can be overriden to 31310593Sgabeblack@google.com //a fixed value at the decoder level. 31410593Sgabeblack@google.com int logAddrSize; 31510593Sgabeblack@google.com if(emi.legacy.addr) 31610593Sgabeblack@google.com logAddrSize = altAddr; 31710593Sgabeblack@google.com else 31810593Sgabeblack@google.com logAddrSize = defAddr; 31910593Sgabeblack@google.com 32010593Sgabeblack@google.com //Set the actual address size 32110593Sgabeblack@google.com emi.addrSize = 1 << logAddrSize; 32210593Sgabeblack@google.com 32310593Sgabeblack@google.com //Figure out the effective stack width. This can be overriden to 32410593Sgabeblack@google.com //a fixed value at the decoder level. 32510593Sgabeblack@google.com emi.stackSize = 1 << stack; 32610593Sgabeblack@google.com 32710593Sgabeblack@google.com //Figure out how big of an immediate we'll retreive based 32810593Sgabeblack@google.com //on the opcode. 32910593Sgabeblack@google.com int immType = immTable[opcode]; 33010593Sgabeblack@google.com if (addrSizedImm) 33110593Sgabeblack@google.com immediateSize = SizeTypeToSize[logAddrSize - 1][immType]; 33210593Sgabeblack@google.com else 33310593Sgabeblack@google.com immediateSize = SizeTypeToSize[logOpSize - 1][immType]; 33410593Sgabeblack@google.com 33510593Sgabeblack@google.com //Determine what to expect next 33610593Sgabeblack@google.com if (modrmTable[opcode]) { 33710593Sgabeblack@google.com nextState = ModRMState; 33810593Sgabeblack@google.com } else { 33910593Sgabeblack@google.com if(immediateSize) { 34010593Sgabeblack@google.com nextState = ImmediateState; 3419023Sgblack@eecs.umich.edu } else { 34210593Sgabeblack@google.com instDone = true; 34310593Sgabeblack@google.com nextState = ResetState; 3449023Sgblack@eecs.umich.edu } 3459023Sgblack@eecs.umich.edu } 3469023Sgblack@eecs.umich.edu return nextState; 3479023Sgblack@eecs.umich.edu} 3489023Sgblack@eecs.umich.edu 3499023Sgblack@eecs.umich.edu//Get the ModRM byte and determine what displacement, if any, there is. 3509023Sgblack@eecs.umich.edu//Also determine whether or not to get the SIB byte, displacement, or 3519023Sgblack@eecs.umich.edu//immediate next. 3529376Sgblack@eecs.umich.eduDecoder::State 3539376Sgblack@eecs.umich.eduDecoder::doModRMState(uint8_t nextByte) 3549023Sgblack@eecs.umich.edu{ 3559023Sgblack@eecs.umich.edu State nextState = ErrorState; 3569023Sgblack@eecs.umich.edu ModRM modRM; 3579023Sgblack@eecs.umich.edu modRM = nextByte; 3589023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte); 3599376Sgblack@eecs.umich.edu if (defOp == 1) { 3609023Sgblack@eecs.umich.edu //figure out 16 bit displacement size 3619023Sgblack@eecs.umich.edu if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2) 3629023Sgblack@eecs.umich.edu displacementSize = 2; 3639023Sgblack@eecs.umich.edu else if (modRM.mod == 1) 3649023Sgblack@eecs.umich.edu displacementSize = 1; 3659023Sgblack@eecs.umich.edu else 3669023Sgblack@eecs.umich.edu displacementSize = 0; 3679023Sgblack@eecs.umich.edu } else { 3689023Sgblack@eecs.umich.edu //figure out 32/64 bit displacement size 3699023Sgblack@eecs.umich.edu if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2) 3709023Sgblack@eecs.umich.edu displacementSize = 4; 3719023Sgblack@eecs.umich.edu else if (modRM.mod == 1) 3729023Sgblack@eecs.umich.edu displacementSize = 1; 3739023Sgblack@eecs.umich.edu else 3749023Sgblack@eecs.umich.edu displacementSize = 0; 3759023Sgblack@eecs.umich.edu } 3769023Sgblack@eecs.umich.edu 3779023Sgblack@eecs.umich.edu // The "test" instruction in group 3 needs an immediate, even though 3789023Sgblack@eecs.umich.edu // the other instructions with the same actual opcode don't. 37910593Sgabeblack@google.com if (emi.opcode.type == OneByteOpcode && (modRM.reg & 0x6) == 0) { 3809023Sgblack@eecs.umich.edu if (emi.opcode.op == 0xF6) 3819023Sgblack@eecs.umich.edu immediateSize = 1; 3829023Sgblack@eecs.umich.edu else if (emi.opcode.op == 0xF7) 3839023Sgblack@eecs.umich.edu immediateSize = (emi.opSize == 8) ? 4 : emi.opSize; 3849023Sgblack@eecs.umich.edu } 3859023Sgblack@eecs.umich.edu 3869023Sgblack@eecs.umich.edu //If there's an SIB, get that next. 3879023Sgblack@eecs.umich.edu //There is no SIB in 16 bit mode. 3889023Sgblack@eecs.umich.edu if (modRM.rm == 4 && modRM.mod != 3) { 3899023Sgblack@eecs.umich.edu // && in 32/64 bit mode) 3909023Sgblack@eecs.umich.edu nextState = SIBState; 3919023Sgblack@eecs.umich.edu } else if(displacementSize) { 3929023Sgblack@eecs.umich.edu nextState = DisplacementState; 3939023Sgblack@eecs.umich.edu } else if(immediateSize) { 3949023Sgblack@eecs.umich.edu nextState = ImmediateState; 3959023Sgblack@eecs.umich.edu } else { 3969023Sgblack@eecs.umich.edu instDone = true; 3979023Sgblack@eecs.umich.edu nextState = ResetState; 3989023Sgblack@eecs.umich.edu } 3999023Sgblack@eecs.umich.edu //The ModRM byte is consumed no matter what 4009023Sgblack@eecs.umich.edu consumeByte(); 4019023Sgblack@eecs.umich.edu emi.modRM = modRM; 4029023Sgblack@eecs.umich.edu return nextState; 4039023Sgblack@eecs.umich.edu} 4049023Sgblack@eecs.umich.edu 4059023Sgblack@eecs.umich.edu//Get the SIB byte. We don't do anything with it at this point, other 4069023Sgblack@eecs.umich.edu//than storing it in the ExtMachInst. Determine if we need to get a 4079023Sgblack@eecs.umich.edu//displacement or immediate next. 4089376Sgblack@eecs.umich.eduDecoder::State 4099376Sgblack@eecs.umich.eduDecoder::doSIBState(uint8_t nextByte) 4109023Sgblack@eecs.umich.edu{ 4119023Sgblack@eecs.umich.edu State nextState = ErrorState; 4129023Sgblack@eecs.umich.edu emi.sib = nextByte; 4139023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte); 4149023Sgblack@eecs.umich.edu consumeByte(); 4159023Sgblack@eecs.umich.edu if (emi.modRM.mod == 0 && emi.sib.base == 5) 4169023Sgblack@eecs.umich.edu displacementSize = 4; 4179023Sgblack@eecs.umich.edu if (displacementSize) { 4189023Sgblack@eecs.umich.edu nextState = DisplacementState; 4199023Sgblack@eecs.umich.edu } else if(immediateSize) { 4209023Sgblack@eecs.umich.edu nextState = ImmediateState; 4219023Sgblack@eecs.umich.edu } else { 4229023Sgblack@eecs.umich.edu instDone = true; 4239023Sgblack@eecs.umich.edu nextState = ResetState; 4249023Sgblack@eecs.umich.edu } 4259023Sgblack@eecs.umich.edu return nextState; 4269023Sgblack@eecs.umich.edu} 4279023Sgblack@eecs.umich.edu 4289023Sgblack@eecs.umich.edu//Gather up the displacement, or at least as much of it 4299023Sgblack@eecs.umich.edu//as we can get. 4309376Sgblack@eecs.umich.eduDecoder::State 4319376Sgblack@eecs.umich.eduDecoder::doDisplacementState() 4329023Sgblack@eecs.umich.edu{ 4339023Sgblack@eecs.umich.edu State nextState = ErrorState; 4349023Sgblack@eecs.umich.edu 4359023Sgblack@eecs.umich.edu getImmediate(immediateCollected, 4369023Sgblack@eecs.umich.edu emi.displacement, 4379023Sgblack@eecs.umich.edu displacementSize); 4389023Sgblack@eecs.umich.edu 4399023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n", 4409023Sgblack@eecs.umich.edu displacementSize, immediateCollected); 4419023Sgblack@eecs.umich.edu 4429023Sgblack@eecs.umich.edu if(displacementSize == immediateCollected) { 4439023Sgblack@eecs.umich.edu //Reset this for other immediates. 4449023Sgblack@eecs.umich.edu immediateCollected = 0; 4459023Sgblack@eecs.umich.edu //Sign extend the displacement 4469023Sgblack@eecs.umich.edu switch(displacementSize) 4479023Sgblack@eecs.umich.edu { 4489023Sgblack@eecs.umich.edu case 1: 4499023Sgblack@eecs.umich.edu emi.displacement = sext<8>(emi.displacement); 4509023Sgblack@eecs.umich.edu break; 4519023Sgblack@eecs.umich.edu case 2: 4529023Sgblack@eecs.umich.edu emi.displacement = sext<16>(emi.displacement); 4539023Sgblack@eecs.umich.edu break; 4549023Sgblack@eecs.umich.edu case 4: 4559023Sgblack@eecs.umich.edu emi.displacement = sext<32>(emi.displacement); 4569023Sgblack@eecs.umich.edu break; 4579023Sgblack@eecs.umich.edu default: 4589023Sgblack@eecs.umich.edu panic("Undefined displacement size!\n"); 4599023Sgblack@eecs.umich.edu } 4609023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collected displacement %#x.\n", 4619023Sgblack@eecs.umich.edu emi.displacement); 4629023Sgblack@eecs.umich.edu if(immediateSize) { 4639023Sgblack@eecs.umich.edu nextState = ImmediateState; 4649023Sgblack@eecs.umich.edu } else { 4659023Sgblack@eecs.umich.edu instDone = true; 4669023Sgblack@eecs.umich.edu nextState = ResetState; 4679023Sgblack@eecs.umich.edu } 4689023Sgblack@eecs.umich.edu 4699023Sgblack@eecs.umich.edu emi.dispSize = displacementSize; 4709023Sgblack@eecs.umich.edu } 4719023Sgblack@eecs.umich.edu else 4729023Sgblack@eecs.umich.edu nextState = DisplacementState; 4739023Sgblack@eecs.umich.edu return nextState; 4749023Sgblack@eecs.umich.edu} 4759023Sgblack@eecs.umich.edu 4769023Sgblack@eecs.umich.edu//Gather up the immediate, or at least as much of it 4779023Sgblack@eecs.umich.edu//as we can get 4789376Sgblack@eecs.umich.eduDecoder::State 4799376Sgblack@eecs.umich.eduDecoder::doImmediateState() 4809023Sgblack@eecs.umich.edu{ 4819023Sgblack@eecs.umich.edu State nextState = ErrorState; 4829023Sgblack@eecs.umich.edu 4839023Sgblack@eecs.umich.edu getImmediate(immediateCollected, 4849023Sgblack@eecs.umich.edu emi.immediate, 4859023Sgblack@eecs.umich.edu immediateSize); 4869023Sgblack@eecs.umich.edu 4879023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n", 4889023Sgblack@eecs.umich.edu immediateSize, immediateCollected); 4899023Sgblack@eecs.umich.edu 4909023Sgblack@eecs.umich.edu if(immediateSize == immediateCollected) 4919023Sgblack@eecs.umich.edu { 4929023Sgblack@eecs.umich.edu //Reset this for other immediates. 4939023Sgblack@eecs.umich.edu immediateCollected = 0; 4949023Sgblack@eecs.umich.edu 4959023Sgblack@eecs.umich.edu //XXX Warning! The following is an observed pattern and might 4969023Sgblack@eecs.umich.edu //not always be true! 4979023Sgblack@eecs.umich.edu 4989023Sgblack@eecs.umich.edu //Instructions which use 64 bit operands but 32 bit immediates 4999023Sgblack@eecs.umich.edu //need to have the immediate sign extended to 64 bits. 5009023Sgblack@eecs.umich.edu //Instructions which use true 64 bit immediates won't be 5019023Sgblack@eecs.umich.edu //affected, and instructions that use true 32 bit immediates 5029023Sgblack@eecs.umich.edu //won't notice. 5039023Sgblack@eecs.umich.edu switch(immediateSize) 5049023Sgblack@eecs.umich.edu { 5059023Sgblack@eecs.umich.edu case 4: 5069023Sgblack@eecs.umich.edu emi.immediate = sext<32>(emi.immediate); 5079023Sgblack@eecs.umich.edu break; 5089023Sgblack@eecs.umich.edu case 1: 5099023Sgblack@eecs.umich.edu emi.immediate = sext<8>(emi.immediate); 5109023Sgblack@eecs.umich.edu } 5119023Sgblack@eecs.umich.edu 5129023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collected immediate %#x.\n", 5139023Sgblack@eecs.umich.edu emi.immediate); 5149023Sgblack@eecs.umich.edu instDone = true; 5159023Sgblack@eecs.umich.edu nextState = ResetState; 5169023Sgblack@eecs.umich.edu } 5179023Sgblack@eecs.umich.edu else 5189023Sgblack@eecs.umich.edu nextState = ImmediateState; 5199023Sgblack@eecs.umich.edu return nextState; 5209023Sgblack@eecs.umich.edu} 5219022Sgblack@eecs.umich.edu 5229376Sgblack@eecs.umich.eduDecoder::InstBytes Decoder::dummy; 5239376Sgblack@eecs.umich.eduDecoder::InstCacheMap Decoder::instCacheMap; 5249024Sgblack@eecs.umich.edu 5259024Sgblack@eecs.umich.eduStaticInstPtr 5269024Sgblack@eecs.umich.eduDecoder::decode(ExtMachInst mach_inst, Addr addr) 5279024Sgblack@eecs.umich.edu{ 5289376Sgblack@eecs.umich.edu DecodeCache::InstMap::iterator iter = instMap->find(mach_inst); 5299376Sgblack@eecs.umich.edu if (iter != instMap->end()) 5309376Sgblack@eecs.umich.edu return iter->second; 5319376Sgblack@eecs.umich.edu 5329376Sgblack@eecs.umich.edu StaticInstPtr si = decodeInst(mach_inst); 5339376Sgblack@eecs.umich.edu (*instMap)[mach_inst] = si; 5349376Sgblack@eecs.umich.edu return si; 5359376Sgblack@eecs.umich.edu} 5369376Sgblack@eecs.umich.edu 5379376Sgblack@eecs.umich.eduStaticInstPtr 5389376Sgblack@eecs.umich.eduDecoder::decode(PCState &nextPC) 5399376Sgblack@eecs.umich.edu{ 5409376Sgblack@eecs.umich.edu if (!instDone) 5419376Sgblack@eecs.umich.edu return NULL; 5429376Sgblack@eecs.umich.edu instDone = false; 5439376Sgblack@eecs.umich.edu updateNPC(nextPC); 5449376Sgblack@eecs.umich.edu 5459376Sgblack@eecs.umich.edu StaticInstPtr &si = instBytes->si; 5469376Sgblack@eecs.umich.edu if (si) 5479024Sgblack@eecs.umich.edu return si; 5489024Sgblack@eecs.umich.edu 5499376Sgblack@eecs.umich.edu // We didn't match in the AddrMap, but we still populated an entry. Fix 5509376Sgblack@eecs.umich.edu // up its byte masks. 5519376Sgblack@eecs.umich.edu const int chunkSize = sizeof(MachInst); 5529376Sgblack@eecs.umich.edu 5539376Sgblack@eecs.umich.edu instBytes->lastOffset = offset; 5549376Sgblack@eecs.umich.edu 5559376Sgblack@eecs.umich.edu Addr firstBasePC = basePC - (instBytes->chunks.size() - 1) * chunkSize; 5569376Sgblack@eecs.umich.edu Addr firstOffset = origPC - firstBasePC; 5579376Sgblack@eecs.umich.edu Addr totalSize = instBytes->lastOffset - firstOffset + 5589376Sgblack@eecs.umich.edu (instBytes->chunks.size() - 1) * chunkSize; 5599376Sgblack@eecs.umich.edu int start = firstOffset; 5609376Sgblack@eecs.umich.edu instBytes->masks.clear(); 5619376Sgblack@eecs.umich.edu 5629376Sgblack@eecs.umich.edu while (totalSize) { 5639376Sgblack@eecs.umich.edu int end = start + totalSize; 5649376Sgblack@eecs.umich.edu end = (chunkSize < end) ? chunkSize : end; 5659376Sgblack@eecs.umich.edu int size = end - start; 5669376Sgblack@eecs.umich.edu int idx = instBytes->masks.size(); 5679376Sgblack@eecs.umich.edu 5689376Sgblack@eecs.umich.edu MachInst maskVal = mask(size * 8) << (start * 8); 5699376Sgblack@eecs.umich.edu assert(maskVal); 5709376Sgblack@eecs.umich.edu 5719376Sgblack@eecs.umich.edu instBytes->masks.push_back(maskVal); 5729376Sgblack@eecs.umich.edu instBytes->chunks[idx] &= instBytes->masks[idx]; 5739376Sgblack@eecs.umich.edu totalSize -= size; 5749376Sgblack@eecs.umich.edu start = 0; 5759024Sgblack@eecs.umich.edu } 5769024Sgblack@eecs.umich.edu 5779376Sgblack@eecs.umich.edu si = decode(emi, origPC); 5789024Sgblack@eecs.umich.edu return si; 5799024Sgblack@eecs.umich.edu} 5809022Sgblack@eecs.umich.edu 5819022Sgblack@eecs.umich.edu} 582