decoder.cc revision 10924
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; 5110924Snilay@cs.wisc.edu emi.vex = 0; 5210924Snilay@cs.wisc.edu 5310593Sgabeblack@google.com emi.opcode.type = BadOpcode; 549023Sgblack@eecs.umich.edu emi.opcode.op = 0; 559023Sgblack@eecs.umich.edu 569023Sgblack@eecs.umich.edu immediateCollected = 0; 579023Sgblack@eecs.umich.edu emi.immediate = 0; 589023Sgblack@eecs.umich.edu emi.displacement = 0; 599023Sgblack@eecs.umich.edu emi.dispSize = 0; 609023Sgblack@eecs.umich.edu 619023Sgblack@eecs.umich.edu emi.modRM = 0; 629023Sgblack@eecs.umich.edu emi.sib = 0; 639376Sgblack@eecs.umich.edu 649376Sgblack@eecs.umich.edu if (instBytes->si) { 659376Sgblack@eecs.umich.edu return FromCacheState; 669376Sgblack@eecs.umich.edu } else { 679376Sgblack@eecs.umich.edu instBytes->chunks.clear(); 689376Sgblack@eecs.umich.edu return PrefixState; 699376Sgblack@eecs.umich.edu } 709023Sgblack@eecs.umich.edu} 719023Sgblack@eecs.umich.edu 729376Sgblack@eecs.umich.eduvoid 739376Sgblack@eecs.umich.eduDecoder::process() 749023Sgblack@eecs.umich.edu{ 759023Sgblack@eecs.umich.edu //This function drives the decoder state machine. 769023Sgblack@eecs.umich.edu 779023Sgblack@eecs.umich.edu //Some sanity checks. You shouldn't try to process more bytes if 789023Sgblack@eecs.umich.edu //there aren't any, and you shouldn't overwrite an already 799023Sgblack@eecs.umich.edu //decoder ExtMachInst. 809023Sgblack@eecs.umich.edu assert(!outOfBytes); 819023Sgblack@eecs.umich.edu assert(!instDone); 829023Sgblack@eecs.umich.edu 839376Sgblack@eecs.umich.edu if (state == ResetState) 849376Sgblack@eecs.umich.edu state = doResetState(); 859376Sgblack@eecs.umich.edu if (state == FromCacheState) { 869376Sgblack@eecs.umich.edu state = doFromCacheState(); 879376Sgblack@eecs.umich.edu } else { 889376Sgblack@eecs.umich.edu instBytes->chunks.push_back(fetchChunk); 899376Sgblack@eecs.umich.edu } 909376Sgblack@eecs.umich.edu 919023Sgblack@eecs.umich.edu //While there's still something to do... 929376Sgblack@eecs.umich.edu while (!instDone && !outOfBytes) { 939023Sgblack@eecs.umich.edu uint8_t nextByte = getNextByte(); 949376Sgblack@eecs.umich.edu switch (state) { 959023Sgblack@eecs.umich.edu case PrefixState: 969023Sgblack@eecs.umich.edu state = doPrefixState(nextByte); 979023Sgblack@eecs.umich.edu break; 9810924Snilay@cs.wisc.edu 9910924Snilay@cs.wisc.edu case TwoByteVexState: 10010924Snilay@cs.wisc.edu state = doTwoByteVexState(nextByte); 10110924Snilay@cs.wisc.edu break; 10210924Snilay@cs.wisc.edu 10310924Snilay@cs.wisc.edu case ThreeByteVexFirstState: 10410924Snilay@cs.wisc.edu state = doThreeByteVexFirstState(nextByte); 10510924Snilay@cs.wisc.edu break; 10610924Snilay@cs.wisc.edu 10710924Snilay@cs.wisc.edu case ThreeByteVexSecondState: 10810924Snilay@cs.wisc.edu state = doThreeByteVexSecondState(nextByte); 10910924Snilay@cs.wisc.edu break; 11010924Snilay@cs.wisc.edu 11110593Sgabeblack@google.com case OneByteOpcodeState: 11210593Sgabeblack@google.com state = doOneByteOpcodeState(nextByte); 11310593Sgabeblack@google.com break; 11410593Sgabeblack@google.com case TwoByteOpcodeState: 11510593Sgabeblack@google.com state = doTwoByteOpcodeState(nextByte); 11610593Sgabeblack@google.com break; 11710593Sgabeblack@google.com case ThreeByte0F38OpcodeState: 11810593Sgabeblack@google.com state = doThreeByte0F38OpcodeState(nextByte); 11910593Sgabeblack@google.com break; 12010593Sgabeblack@google.com case ThreeByte0F3AOpcodeState: 12110593Sgabeblack@google.com state = doThreeByte0F3AOpcodeState(nextByte); 1229023Sgblack@eecs.umich.edu break; 1239023Sgblack@eecs.umich.edu case ModRMState: 1249023Sgblack@eecs.umich.edu state = doModRMState(nextByte); 1259023Sgblack@eecs.umich.edu break; 1269023Sgblack@eecs.umich.edu case SIBState: 1279023Sgblack@eecs.umich.edu state = doSIBState(nextByte); 1289023Sgblack@eecs.umich.edu break; 1299023Sgblack@eecs.umich.edu case DisplacementState: 1309023Sgblack@eecs.umich.edu state = doDisplacementState(); 1319023Sgblack@eecs.umich.edu break; 1329023Sgblack@eecs.umich.edu case ImmediateState: 1339023Sgblack@eecs.umich.edu state = doImmediateState(); 1349023Sgblack@eecs.umich.edu break; 1359023Sgblack@eecs.umich.edu case ErrorState: 1369023Sgblack@eecs.umich.edu panic("Went to the error state in the decoder.\n"); 1379023Sgblack@eecs.umich.edu default: 1389023Sgblack@eecs.umich.edu panic("Unrecognized state! %d\n", state); 1399023Sgblack@eecs.umich.edu } 1409023Sgblack@eecs.umich.edu } 1419023Sgblack@eecs.umich.edu} 1429023Sgblack@eecs.umich.edu 1439376Sgblack@eecs.umich.eduDecoder::State 1449376Sgblack@eecs.umich.eduDecoder::doFromCacheState() 1459376Sgblack@eecs.umich.edu{ 1469376Sgblack@eecs.umich.edu DPRINTF(Decoder, "Looking at cache state.\n"); 1479376Sgblack@eecs.umich.edu if ((fetchChunk & instBytes->masks[chunkIdx]) != 1489376Sgblack@eecs.umich.edu instBytes->chunks[chunkIdx]) { 1499376Sgblack@eecs.umich.edu DPRINTF(Decoder, "Decode cache miss.\n"); 1509376Sgblack@eecs.umich.edu // The chached chunks didn't match what was fetched. Fall back to the 1519376Sgblack@eecs.umich.edu // predecoder. 1529376Sgblack@eecs.umich.edu instBytes->chunks[chunkIdx] = fetchChunk; 1539376Sgblack@eecs.umich.edu instBytes->chunks.resize(chunkIdx + 1); 1549376Sgblack@eecs.umich.edu instBytes->si = NULL; 1559376Sgblack@eecs.umich.edu chunkIdx = 0; 1569376Sgblack@eecs.umich.edu fetchChunk = instBytes->chunks[0]; 1579376Sgblack@eecs.umich.edu offset = origPC % sizeof(MachInst); 1589376Sgblack@eecs.umich.edu basePC = origPC - offset; 1599376Sgblack@eecs.umich.edu return PrefixState; 1609376Sgblack@eecs.umich.edu } else if (chunkIdx == instBytes->chunks.size() - 1) { 1619376Sgblack@eecs.umich.edu // We matched the cache, so use its value. 1629376Sgblack@eecs.umich.edu instDone = true; 1639376Sgblack@eecs.umich.edu offset = instBytes->lastOffset; 1649376Sgblack@eecs.umich.edu if (offset == sizeof(MachInst)) 1659376Sgblack@eecs.umich.edu outOfBytes = true; 1669376Sgblack@eecs.umich.edu return ResetState; 1679376Sgblack@eecs.umich.edu } else { 1689376Sgblack@eecs.umich.edu // We matched so far, but need to check more chunks. 1699376Sgblack@eecs.umich.edu chunkIdx++; 1709376Sgblack@eecs.umich.edu outOfBytes = true; 1719376Sgblack@eecs.umich.edu return FromCacheState; 1729376Sgblack@eecs.umich.edu } 1739376Sgblack@eecs.umich.edu} 1749376Sgblack@eecs.umich.edu 1759023Sgblack@eecs.umich.edu//Either get a prefix and record it in the ExtMachInst, or send the 1769023Sgblack@eecs.umich.edu//state machine on to get the opcode(s). 1779376Sgblack@eecs.umich.eduDecoder::State 1789376Sgblack@eecs.umich.eduDecoder::doPrefixState(uint8_t nextByte) 1799023Sgblack@eecs.umich.edu{ 1809023Sgblack@eecs.umich.edu uint8_t prefix = Prefixes[nextByte]; 1819023Sgblack@eecs.umich.edu State nextState = PrefixState; 1829023Sgblack@eecs.umich.edu // REX prefixes are only recognized in 64 bit mode. 1839023Sgblack@eecs.umich.edu if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode) 1849023Sgblack@eecs.umich.edu prefix = 0; 1859023Sgblack@eecs.umich.edu if (prefix) 1869023Sgblack@eecs.umich.edu consumeByte(); 1879023Sgblack@eecs.umich.edu switch(prefix) 1889023Sgblack@eecs.umich.edu { 1899023Sgblack@eecs.umich.edu //Operand size override prefixes 1909023Sgblack@eecs.umich.edu case OperandSizeOverride: 1919023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found operand size override prefix.\n"); 1929023Sgblack@eecs.umich.edu emi.legacy.op = true; 1939023Sgblack@eecs.umich.edu break; 1949023Sgblack@eecs.umich.edu case AddressSizeOverride: 1959023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found address size override prefix.\n"); 1969023Sgblack@eecs.umich.edu emi.legacy.addr = true; 1979023Sgblack@eecs.umich.edu break; 1989023Sgblack@eecs.umich.edu //Segment override prefixes 1999023Sgblack@eecs.umich.edu case CSOverride: 2009023Sgblack@eecs.umich.edu case DSOverride: 2019023Sgblack@eecs.umich.edu case ESOverride: 2029023Sgblack@eecs.umich.edu case FSOverride: 2039023Sgblack@eecs.umich.edu case GSOverride: 2049023Sgblack@eecs.umich.edu case SSOverride: 2059023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found segment override.\n"); 2069023Sgblack@eecs.umich.edu emi.legacy.seg = prefix; 2079023Sgblack@eecs.umich.edu break; 2089023Sgblack@eecs.umich.edu case Lock: 2099023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found lock prefix.\n"); 2109023Sgblack@eecs.umich.edu emi.legacy.lock = true; 2119023Sgblack@eecs.umich.edu break; 2129023Sgblack@eecs.umich.edu case Rep: 2139023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found rep prefix.\n"); 2149023Sgblack@eecs.umich.edu emi.legacy.rep = true; 2159023Sgblack@eecs.umich.edu break; 2169023Sgblack@eecs.umich.edu case Repne: 2179023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found repne prefix.\n"); 2189023Sgblack@eecs.umich.edu emi.legacy.repne = true; 2199023Sgblack@eecs.umich.edu break; 2209023Sgblack@eecs.umich.edu case RexPrefix: 2219023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte); 2229023Sgblack@eecs.umich.edu emi.rex = nextByte; 2239023Sgblack@eecs.umich.edu break; 22410924Snilay@cs.wisc.edu 22510924Snilay@cs.wisc.edu case Vex2Prefix: 22610924Snilay@cs.wisc.edu DPRINTF(Decoder, "Found VEX two-byte prefix %#x.\n", nextByte); 22710924Snilay@cs.wisc.edu emi.vex.zero = nextByte; 22810924Snilay@cs.wisc.edu nextState = TwoByteVexState; 22910924Snilay@cs.wisc.edu break; 23010924Snilay@cs.wisc.edu 23110924Snilay@cs.wisc.edu case Vex3Prefix: 23210924Snilay@cs.wisc.edu DPRINTF(Decoder, "Found VEX three-byte prefix %#x.\n", nextByte); 23310924Snilay@cs.wisc.edu emi.vex.zero = nextByte; 23410924Snilay@cs.wisc.edu nextState = ThreeByteVexFirstState; 23510924Snilay@cs.wisc.edu break; 23610924Snilay@cs.wisc.edu 2379023Sgblack@eecs.umich.edu case 0: 23810593Sgabeblack@google.com nextState = OneByteOpcodeState; 2399023Sgblack@eecs.umich.edu break; 24010924Snilay@cs.wisc.edu 2419023Sgblack@eecs.umich.edu default: 2429023Sgblack@eecs.umich.edu panic("Unrecognized prefix %#x\n", nextByte); 2439023Sgblack@eecs.umich.edu } 2449023Sgblack@eecs.umich.edu return nextState; 2459023Sgblack@eecs.umich.edu} 2469023Sgblack@eecs.umich.edu 24710924Snilay@cs.wisc.eduDecoder::State 24810924Snilay@cs.wisc.eduDecoder::doTwoByteVexState(uint8_t nextByte) 24910924Snilay@cs.wisc.edu{ 25010924Snilay@cs.wisc.edu assert(emi.vex.zero == 0xc5); 25110924Snilay@cs.wisc.edu consumeByte(); 25210924Snilay@cs.wisc.edu TwoByteVex tbe = 0; 25310924Snilay@cs.wisc.edu tbe.first = nextByte; 25410924Snilay@cs.wisc.edu 25510924Snilay@cs.wisc.edu emi.vex.first.r = tbe.first.r; 25610924Snilay@cs.wisc.edu emi.vex.first.x = 1; 25710924Snilay@cs.wisc.edu emi.vex.first.b = 1; 25810924Snilay@cs.wisc.edu emi.vex.first.map_select = 1; 25910924Snilay@cs.wisc.edu 26010924Snilay@cs.wisc.edu emi.vex.second.w = 0; 26110924Snilay@cs.wisc.edu emi.vex.second.vvvv = tbe.first.vvvv; 26210924Snilay@cs.wisc.edu emi.vex.second.l = tbe.first.l; 26310924Snilay@cs.wisc.edu emi.vex.second.pp = tbe.first.pp; 26410924Snilay@cs.wisc.edu 26510924Snilay@cs.wisc.edu emi.opcode.type = Vex; 26610924Snilay@cs.wisc.edu return OneByteOpcodeState; 26710924Snilay@cs.wisc.edu} 26810924Snilay@cs.wisc.edu 26910924Snilay@cs.wisc.eduDecoder::State 27010924Snilay@cs.wisc.eduDecoder::doThreeByteVexFirstState(uint8_t nextByte) 27110924Snilay@cs.wisc.edu{ 27210924Snilay@cs.wisc.edu consumeByte(); 27310924Snilay@cs.wisc.edu emi.vex.first = nextByte; 27410924Snilay@cs.wisc.edu return ThreeByteVexSecondState; 27510924Snilay@cs.wisc.edu} 27610924Snilay@cs.wisc.edu 27710924Snilay@cs.wisc.eduDecoder::State 27810924Snilay@cs.wisc.eduDecoder::doThreeByteVexSecondState(uint8_t nextByte) 27910924Snilay@cs.wisc.edu{ 28010924Snilay@cs.wisc.edu consumeByte(); 28110924Snilay@cs.wisc.edu emi.vex.second = nextByte; 28210924Snilay@cs.wisc.edu emi.opcode.type = Vex; 28310924Snilay@cs.wisc.edu return OneByteOpcodeState; 28410924Snilay@cs.wisc.edu} 28510924Snilay@cs.wisc.edu 28610593Sgabeblack@google.com// Load the first opcode byte. Determine if there are more opcode bytes, and 28710593Sgabeblack@google.com// if not, what immediate and/or ModRM is needed. 2889376Sgblack@eecs.umich.eduDecoder::State 28910593Sgabeblack@google.comDecoder::doOneByteOpcodeState(uint8_t nextByte) 2909023Sgblack@eecs.umich.edu{ 2919023Sgblack@eecs.umich.edu State nextState = ErrorState; 2929023Sgblack@eecs.umich.edu consumeByte(); 29310924Snilay@cs.wisc.edu 29410924Snilay@cs.wisc.edu if (emi.vex.zero != 0) { 29510924Snilay@cs.wisc.edu DPRINTF(Decoder, "Found VEX opcode %#x.\n", nextByte); 29610924Snilay@cs.wisc.edu emi.opcode.op = nextByte; 29710924Snilay@cs.wisc.edu const uint8_t opcode_map = emi.vex.first.map_select; 29810924Snilay@cs.wisc.edu nextState = processExtendedOpcode(ImmediateTypeVex[opcode_map]); 29910924Snilay@cs.wisc.edu } else if (nextByte == 0x0f) { 30010593Sgabeblack@google.com nextState = TwoByteOpcodeState; 30110593Sgabeblack@google.com DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte); 30210593Sgabeblack@google.com } else { 30310593Sgabeblack@google.com DPRINTF(Decoder, "Found one byte opcode %#x.\n", nextByte); 30410593Sgabeblack@google.com emi.opcode.type = OneByteOpcode; 3059023Sgblack@eecs.umich.edu emi.opcode.op = nextByte; 3069023Sgblack@eecs.umich.edu 30710593Sgabeblack@google.com nextState = processOpcode(ImmediateTypeOneByte, UsesModRMOneByte, 30810593Sgabeblack@google.com nextByte >= 0xA0 && nextByte <= 0xA3); 30910593Sgabeblack@google.com } 31010593Sgabeblack@google.com return nextState; 31110593Sgabeblack@google.com} 3129023Sgblack@eecs.umich.edu 31310593Sgabeblack@google.com// Load the second opcode byte. Determine if there are more opcode bytes, and 31410593Sgabeblack@google.com// if not, what immediate and/or ModRM is needed. 31510593Sgabeblack@google.comDecoder::State 31610593Sgabeblack@google.comDecoder::doTwoByteOpcodeState(uint8_t nextByte) 31710593Sgabeblack@google.com{ 31810593Sgabeblack@google.com State nextState = ErrorState; 31910593Sgabeblack@google.com consumeByte(); 32010593Sgabeblack@google.com if (nextByte == 0x38) { 32110593Sgabeblack@google.com nextState = ThreeByte0F38OpcodeState; 32210593Sgabeblack@google.com DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte); 32310593Sgabeblack@google.com } else if (nextByte == 0x3a) { 32410593Sgabeblack@google.com nextState = ThreeByte0F3AOpcodeState; 32510593Sgabeblack@google.com DPRINTF(Decoder, "Found opcode escape byte %#x.\n", nextByte); 32610593Sgabeblack@google.com } else { 32710593Sgabeblack@google.com DPRINTF(Decoder, "Found two byte opcode %#x.\n", nextByte); 32810593Sgabeblack@google.com emi.opcode.type = TwoByteOpcode; 32910593Sgabeblack@google.com emi.opcode.op = nextByte; 3309023Sgblack@eecs.umich.edu 33110593Sgabeblack@google.com nextState = processOpcode(ImmediateTypeTwoByte, UsesModRMTwoByte); 33210593Sgabeblack@google.com } 33310593Sgabeblack@google.com return nextState; 33410593Sgabeblack@google.com} 3359023Sgblack@eecs.umich.edu 33610593Sgabeblack@google.com// Load the third opcode byte and determine what immediate and/or ModRM is 33710593Sgabeblack@google.com// needed. 33810593Sgabeblack@google.comDecoder::State 33910593Sgabeblack@google.comDecoder::doThreeByte0F38OpcodeState(uint8_t nextByte) 34010593Sgabeblack@google.com{ 34110593Sgabeblack@google.com consumeByte(); 3429023Sgblack@eecs.umich.edu 34310593Sgabeblack@google.com DPRINTF(Decoder, "Found three byte 0F38 opcode %#x.\n", nextByte); 34410593Sgabeblack@google.com emi.opcode.type = ThreeByte0F38Opcode; 34510593Sgabeblack@google.com emi.opcode.op = nextByte; 3469023Sgblack@eecs.umich.edu 34710593Sgabeblack@google.com return processOpcode(ImmediateTypeThreeByte0F38, UsesModRMThreeByte0F38); 34810593Sgabeblack@google.com} 3499023Sgblack@eecs.umich.edu 35010593Sgabeblack@google.com// Load the third opcode byte and determine what immediate and/or ModRM is 35110593Sgabeblack@google.com// needed. 35210593Sgabeblack@google.comDecoder::State 35310593Sgabeblack@google.comDecoder::doThreeByte0F3AOpcodeState(uint8_t nextByte) 35410593Sgabeblack@google.com{ 35510593Sgabeblack@google.com consumeByte(); 35610593Sgabeblack@google.com 35710593Sgabeblack@google.com DPRINTF(Decoder, "Found three byte 0F3A opcode %#x.\n", nextByte); 35810593Sgabeblack@google.com emi.opcode.type = ThreeByte0F3AOpcode; 35910593Sgabeblack@google.com emi.opcode.op = nextByte; 36010593Sgabeblack@google.com 36110593Sgabeblack@google.com return processOpcode(ImmediateTypeThreeByte0F3A, UsesModRMThreeByte0F3A); 36210593Sgabeblack@google.com} 36310593Sgabeblack@google.com 36410593Sgabeblack@google.com// Generic opcode processing which determines the immediate size, and whether 36510593Sgabeblack@google.com// or not there's a modrm byte. 36610593Sgabeblack@google.comDecoder::State 36710593Sgabeblack@google.comDecoder::processOpcode(ByteTable &immTable, ByteTable &modrmTable, 36810593Sgabeblack@google.com bool addrSizedImm) 36910593Sgabeblack@google.com{ 37010593Sgabeblack@google.com State nextState = ErrorState; 37110593Sgabeblack@google.com const uint8_t opcode = emi.opcode.op; 37210593Sgabeblack@google.com 37310593Sgabeblack@google.com //Figure out the effective operand size. This can be overriden to 37410593Sgabeblack@google.com //a fixed value at the decoder level. 37510593Sgabeblack@google.com int logOpSize; 37610593Sgabeblack@google.com if (emi.rex.w) 37710593Sgabeblack@google.com logOpSize = 3; // 64 bit operand size 37810593Sgabeblack@google.com else if (emi.legacy.op) 37910593Sgabeblack@google.com logOpSize = altOp; 38010593Sgabeblack@google.com else 38110593Sgabeblack@google.com logOpSize = defOp; 38210593Sgabeblack@google.com 38310593Sgabeblack@google.com //Set the actual op size 38410593Sgabeblack@google.com emi.opSize = 1 << logOpSize; 38510593Sgabeblack@google.com 38610593Sgabeblack@google.com //Figure out the effective address size. This can be overriden to 38710593Sgabeblack@google.com //a fixed value at the decoder level. 38810593Sgabeblack@google.com int logAddrSize; 38910593Sgabeblack@google.com if(emi.legacy.addr) 39010593Sgabeblack@google.com logAddrSize = altAddr; 39110593Sgabeblack@google.com else 39210593Sgabeblack@google.com logAddrSize = defAddr; 39310593Sgabeblack@google.com 39410593Sgabeblack@google.com //Set the actual address size 39510593Sgabeblack@google.com emi.addrSize = 1 << logAddrSize; 39610593Sgabeblack@google.com 39710593Sgabeblack@google.com //Figure out the effective stack width. This can be overriden to 39810593Sgabeblack@google.com //a fixed value at the decoder level. 39910593Sgabeblack@google.com emi.stackSize = 1 << stack; 40010593Sgabeblack@google.com 40110593Sgabeblack@google.com //Figure out how big of an immediate we'll retreive based 40210593Sgabeblack@google.com //on the opcode. 40310593Sgabeblack@google.com int immType = immTable[opcode]; 40410593Sgabeblack@google.com if (addrSizedImm) 40510593Sgabeblack@google.com immediateSize = SizeTypeToSize[logAddrSize - 1][immType]; 40610593Sgabeblack@google.com else 40710593Sgabeblack@google.com immediateSize = SizeTypeToSize[logOpSize - 1][immType]; 40810593Sgabeblack@google.com 40910593Sgabeblack@google.com //Determine what to expect next 41010593Sgabeblack@google.com if (modrmTable[opcode]) { 41110593Sgabeblack@google.com nextState = ModRMState; 41210593Sgabeblack@google.com } else { 41310593Sgabeblack@google.com if(immediateSize) { 41410593Sgabeblack@google.com nextState = ImmediateState; 4159023Sgblack@eecs.umich.edu } else { 41610593Sgabeblack@google.com instDone = true; 41710593Sgabeblack@google.com nextState = ResetState; 4189023Sgblack@eecs.umich.edu } 4199023Sgblack@eecs.umich.edu } 4209023Sgblack@eecs.umich.edu return nextState; 4219023Sgblack@eecs.umich.edu} 4229023Sgblack@eecs.umich.edu 42310924Snilay@cs.wisc.eduDecoder::State 42410924Snilay@cs.wisc.eduDecoder::processExtendedOpcode(ByteTable &immTable) 42510924Snilay@cs.wisc.edu{ 42610924Snilay@cs.wisc.edu //Figure out the effective operand size. This can be overriden to 42710924Snilay@cs.wisc.edu //a fixed value at the decoder level. 42810924Snilay@cs.wisc.edu int logOpSize; 42910924Snilay@cs.wisc.edu if (emi.vex.second.w) 43010924Snilay@cs.wisc.edu logOpSize = 3; // 64 bit operand size 43110924Snilay@cs.wisc.edu else if (emi.vex.second.pp == 1) 43210924Snilay@cs.wisc.edu logOpSize = altOp; 43310924Snilay@cs.wisc.edu else 43410924Snilay@cs.wisc.edu logOpSize = defOp; 43510924Snilay@cs.wisc.edu 43610924Snilay@cs.wisc.edu //Set the actual op size 43710924Snilay@cs.wisc.edu emi.opSize = 1 << logOpSize; 43810924Snilay@cs.wisc.edu 43910924Snilay@cs.wisc.edu //Figure out the effective address size. This can be overriden to 44010924Snilay@cs.wisc.edu //a fixed value at the decoder level. 44110924Snilay@cs.wisc.edu int logAddrSize; 44210924Snilay@cs.wisc.edu if(emi.legacy.addr) 44310924Snilay@cs.wisc.edu logAddrSize = altAddr; 44410924Snilay@cs.wisc.edu else 44510924Snilay@cs.wisc.edu logAddrSize = defAddr; 44610924Snilay@cs.wisc.edu 44710924Snilay@cs.wisc.edu //Set the actual address size 44810924Snilay@cs.wisc.edu emi.addrSize = 1 << logAddrSize; 44910924Snilay@cs.wisc.edu 45010924Snilay@cs.wisc.edu //Figure out the effective stack width. This can be overriden to 45110924Snilay@cs.wisc.edu //a fixed value at the decoder level. 45210924Snilay@cs.wisc.edu emi.stackSize = 1 << stack; 45310924Snilay@cs.wisc.edu 45410924Snilay@cs.wisc.edu //Figure out how big of an immediate we'll retreive based 45510924Snilay@cs.wisc.edu //on the opcode. 45610924Snilay@cs.wisc.edu const uint8_t opcode = emi.opcode.op; 45710924Snilay@cs.wisc.edu 45810924Snilay@cs.wisc.edu if (emi.vex.zero == 0xc5 || emi.vex.zero == 0xc4) { 45910924Snilay@cs.wisc.edu int immType = immTable[opcode]; 46010924Snilay@cs.wisc.edu // Assume 64-bit mode; 46110924Snilay@cs.wisc.edu immediateSize = SizeTypeToSize[2][immType]; 46210924Snilay@cs.wisc.edu } 46310924Snilay@cs.wisc.edu 46410924Snilay@cs.wisc.edu if (opcode == 0x77) { 46510924Snilay@cs.wisc.edu instDone = true; 46610924Snilay@cs.wisc.edu return ResetState; 46710924Snilay@cs.wisc.edu } 46810924Snilay@cs.wisc.edu return ModRMState; 46910924Snilay@cs.wisc.edu} 47010924Snilay@cs.wisc.edu 4719023Sgblack@eecs.umich.edu//Get the ModRM byte and determine what displacement, if any, there is. 4729023Sgblack@eecs.umich.edu//Also determine whether or not to get the SIB byte, displacement, or 4739023Sgblack@eecs.umich.edu//immediate next. 4749376Sgblack@eecs.umich.eduDecoder::State 4759376Sgblack@eecs.umich.eduDecoder::doModRMState(uint8_t nextByte) 4769023Sgblack@eecs.umich.edu{ 4779023Sgblack@eecs.umich.edu State nextState = ErrorState; 47810924Snilay@cs.wisc.edu ModRM modRM = nextByte; 4799023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte); 4809376Sgblack@eecs.umich.edu if (defOp == 1) { 4819023Sgblack@eecs.umich.edu //figure out 16 bit displacement size 4829023Sgblack@eecs.umich.edu if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2) 4839023Sgblack@eecs.umich.edu displacementSize = 2; 4849023Sgblack@eecs.umich.edu else if (modRM.mod == 1) 4859023Sgblack@eecs.umich.edu displacementSize = 1; 4869023Sgblack@eecs.umich.edu else 4879023Sgblack@eecs.umich.edu displacementSize = 0; 4889023Sgblack@eecs.umich.edu } else { 4899023Sgblack@eecs.umich.edu //figure out 32/64 bit displacement size 4909023Sgblack@eecs.umich.edu if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2) 4919023Sgblack@eecs.umich.edu displacementSize = 4; 4929023Sgblack@eecs.umich.edu else if (modRM.mod == 1) 4939023Sgblack@eecs.umich.edu displacementSize = 1; 4949023Sgblack@eecs.umich.edu else 4959023Sgblack@eecs.umich.edu displacementSize = 0; 4969023Sgblack@eecs.umich.edu } 4979023Sgblack@eecs.umich.edu 4989023Sgblack@eecs.umich.edu // The "test" instruction in group 3 needs an immediate, even though 4999023Sgblack@eecs.umich.edu // the other instructions with the same actual opcode don't. 50010593Sgabeblack@google.com if (emi.opcode.type == OneByteOpcode && (modRM.reg & 0x6) == 0) { 5019023Sgblack@eecs.umich.edu if (emi.opcode.op == 0xF6) 5029023Sgblack@eecs.umich.edu immediateSize = 1; 5039023Sgblack@eecs.umich.edu else if (emi.opcode.op == 0xF7) 5049023Sgblack@eecs.umich.edu immediateSize = (emi.opSize == 8) ? 4 : emi.opSize; 5059023Sgblack@eecs.umich.edu } 5069023Sgblack@eecs.umich.edu 5079023Sgblack@eecs.umich.edu //If there's an SIB, get that next. 5089023Sgblack@eecs.umich.edu //There is no SIB in 16 bit mode. 5099023Sgblack@eecs.umich.edu if (modRM.rm == 4 && modRM.mod != 3) { 5109023Sgblack@eecs.umich.edu // && in 32/64 bit mode) 5119023Sgblack@eecs.umich.edu nextState = SIBState; 5129023Sgblack@eecs.umich.edu } else if(displacementSize) { 5139023Sgblack@eecs.umich.edu nextState = DisplacementState; 5149023Sgblack@eecs.umich.edu } else if(immediateSize) { 5159023Sgblack@eecs.umich.edu nextState = ImmediateState; 5169023Sgblack@eecs.umich.edu } else { 5179023Sgblack@eecs.umich.edu instDone = true; 5189023Sgblack@eecs.umich.edu nextState = ResetState; 5199023Sgblack@eecs.umich.edu } 5209023Sgblack@eecs.umich.edu //The ModRM byte is consumed no matter what 5219023Sgblack@eecs.umich.edu consumeByte(); 5229023Sgblack@eecs.umich.edu emi.modRM = modRM; 5239023Sgblack@eecs.umich.edu return nextState; 5249023Sgblack@eecs.umich.edu} 5259023Sgblack@eecs.umich.edu 5269023Sgblack@eecs.umich.edu//Get the SIB byte. We don't do anything with it at this point, other 5279023Sgblack@eecs.umich.edu//than storing it in the ExtMachInst. Determine if we need to get a 5289023Sgblack@eecs.umich.edu//displacement or immediate next. 5299376Sgblack@eecs.umich.eduDecoder::State 5309376Sgblack@eecs.umich.eduDecoder::doSIBState(uint8_t nextByte) 5319023Sgblack@eecs.umich.edu{ 5329023Sgblack@eecs.umich.edu State nextState = ErrorState; 5339023Sgblack@eecs.umich.edu emi.sib = nextByte; 5349023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte); 5359023Sgblack@eecs.umich.edu consumeByte(); 5369023Sgblack@eecs.umich.edu if (emi.modRM.mod == 0 && emi.sib.base == 5) 5379023Sgblack@eecs.umich.edu displacementSize = 4; 5389023Sgblack@eecs.umich.edu if (displacementSize) { 5399023Sgblack@eecs.umich.edu nextState = DisplacementState; 5409023Sgblack@eecs.umich.edu } else if(immediateSize) { 5419023Sgblack@eecs.umich.edu nextState = ImmediateState; 5429023Sgblack@eecs.umich.edu } else { 5439023Sgblack@eecs.umich.edu instDone = true; 5449023Sgblack@eecs.umich.edu nextState = ResetState; 5459023Sgblack@eecs.umich.edu } 5469023Sgblack@eecs.umich.edu return nextState; 5479023Sgblack@eecs.umich.edu} 5489023Sgblack@eecs.umich.edu 5499023Sgblack@eecs.umich.edu//Gather up the displacement, or at least as much of it 5509023Sgblack@eecs.umich.edu//as we can get. 5519376Sgblack@eecs.umich.eduDecoder::State 5529376Sgblack@eecs.umich.eduDecoder::doDisplacementState() 5539023Sgblack@eecs.umich.edu{ 5549023Sgblack@eecs.umich.edu State nextState = ErrorState; 5559023Sgblack@eecs.umich.edu 5569023Sgblack@eecs.umich.edu getImmediate(immediateCollected, 5579023Sgblack@eecs.umich.edu emi.displacement, 5589023Sgblack@eecs.umich.edu displacementSize); 5599023Sgblack@eecs.umich.edu 5609023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n", 5619023Sgblack@eecs.umich.edu displacementSize, immediateCollected); 5629023Sgblack@eecs.umich.edu 5639023Sgblack@eecs.umich.edu if(displacementSize == immediateCollected) { 5649023Sgblack@eecs.umich.edu //Reset this for other immediates. 5659023Sgblack@eecs.umich.edu immediateCollected = 0; 5669023Sgblack@eecs.umich.edu //Sign extend the displacement 5679023Sgblack@eecs.umich.edu switch(displacementSize) 5689023Sgblack@eecs.umich.edu { 5699023Sgblack@eecs.umich.edu case 1: 5709023Sgblack@eecs.umich.edu emi.displacement = sext<8>(emi.displacement); 5719023Sgblack@eecs.umich.edu break; 5729023Sgblack@eecs.umich.edu case 2: 5739023Sgblack@eecs.umich.edu emi.displacement = sext<16>(emi.displacement); 5749023Sgblack@eecs.umich.edu break; 5759023Sgblack@eecs.umich.edu case 4: 5769023Sgblack@eecs.umich.edu emi.displacement = sext<32>(emi.displacement); 5779023Sgblack@eecs.umich.edu break; 5789023Sgblack@eecs.umich.edu default: 5799023Sgblack@eecs.umich.edu panic("Undefined displacement size!\n"); 5809023Sgblack@eecs.umich.edu } 5819023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collected displacement %#x.\n", 5829023Sgblack@eecs.umich.edu emi.displacement); 5839023Sgblack@eecs.umich.edu if(immediateSize) { 5849023Sgblack@eecs.umich.edu nextState = ImmediateState; 5859023Sgblack@eecs.umich.edu } else { 5869023Sgblack@eecs.umich.edu instDone = true; 5879023Sgblack@eecs.umich.edu nextState = ResetState; 5889023Sgblack@eecs.umich.edu } 5899023Sgblack@eecs.umich.edu 5909023Sgblack@eecs.umich.edu emi.dispSize = displacementSize; 5919023Sgblack@eecs.umich.edu } 5929023Sgblack@eecs.umich.edu else 5939023Sgblack@eecs.umich.edu nextState = DisplacementState; 5949023Sgblack@eecs.umich.edu return nextState; 5959023Sgblack@eecs.umich.edu} 5969023Sgblack@eecs.umich.edu 5979023Sgblack@eecs.umich.edu//Gather up the immediate, or at least as much of it 5989023Sgblack@eecs.umich.edu//as we can get 5999376Sgblack@eecs.umich.eduDecoder::State 6009376Sgblack@eecs.umich.eduDecoder::doImmediateState() 6019023Sgblack@eecs.umich.edu{ 6029023Sgblack@eecs.umich.edu State nextState = ErrorState; 6039023Sgblack@eecs.umich.edu 6049023Sgblack@eecs.umich.edu getImmediate(immediateCollected, 6059023Sgblack@eecs.umich.edu emi.immediate, 6069023Sgblack@eecs.umich.edu immediateSize); 6079023Sgblack@eecs.umich.edu 6089023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n", 6099023Sgblack@eecs.umich.edu immediateSize, immediateCollected); 6109023Sgblack@eecs.umich.edu 6119023Sgblack@eecs.umich.edu if(immediateSize == immediateCollected) 6129023Sgblack@eecs.umich.edu { 6139023Sgblack@eecs.umich.edu //Reset this for other immediates. 6149023Sgblack@eecs.umich.edu immediateCollected = 0; 6159023Sgblack@eecs.umich.edu 6169023Sgblack@eecs.umich.edu //XXX Warning! The following is an observed pattern and might 6179023Sgblack@eecs.umich.edu //not always be true! 6189023Sgblack@eecs.umich.edu 6199023Sgblack@eecs.umich.edu //Instructions which use 64 bit operands but 32 bit immediates 6209023Sgblack@eecs.umich.edu //need to have the immediate sign extended to 64 bits. 6219023Sgblack@eecs.umich.edu //Instructions which use true 64 bit immediates won't be 6229023Sgblack@eecs.umich.edu //affected, and instructions that use true 32 bit immediates 6239023Sgblack@eecs.umich.edu //won't notice. 6249023Sgblack@eecs.umich.edu switch(immediateSize) 6259023Sgblack@eecs.umich.edu { 6269023Sgblack@eecs.umich.edu case 4: 6279023Sgblack@eecs.umich.edu emi.immediate = sext<32>(emi.immediate); 6289023Sgblack@eecs.umich.edu break; 6299023Sgblack@eecs.umich.edu case 1: 6309023Sgblack@eecs.umich.edu emi.immediate = sext<8>(emi.immediate); 6319023Sgblack@eecs.umich.edu } 6329023Sgblack@eecs.umich.edu 6339023Sgblack@eecs.umich.edu DPRINTF(Decoder, "Collected immediate %#x.\n", 6349023Sgblack@eecs.umich.edu emi.immediate); 6359023Sgblack@eecs.umich.edu instDone = true; 6369023Sgblack@eecs.umich.edu nextState = ResetState; 6379023Sgblack@eecs.umich.edu } 6389023Sgblack@eecs.umich.edu else 6399023Sgblack@eecs.umich.edu nextState = ImmediateState; 6409023Sgblack@eecs.umich.edu return nextState; 6419023Sgblack@eecs.umich.edu} 6429022Sgblack@eecs.umich.edu 6439376Sgblack@eecs.umich.eduDecoder::InstBytes Decoder::dummy; 6449376Sgblack@eecs.umich.eduDecoder::InstCacheMap Decoder::instCacheMap; 6459024Sgblack@eecs.umich.edu 6469024Sgblack@eecs.umich.eduStaticInstPtr 6479024Sgblack@eecs.umich.eduDecoder::decode(ExtMachInst mach_inst, Addr addr) 6489024Sgblack@eecs.umich.edu{ 6499376Sgblack@eecs.umich.edu DecodeCache::InstMap::iterator iter = instMap->find(mach_inst); 6509376Sgblack@eecs.umich.edu if (iter != instMap->end()) 6519376Sgblack@eecs.umich.edu return iter->second; 6529376Sgblack@eecs.umich.edu 6539376Sgblack@eecs.umich.edu StaticInstPtr si = decodeInst(mach_inst); 6549376Sgblack@eecs.umich.edu (*instMap)[mach_inst] = si; 6559376Sgblack@eecs.umich.edu return si; 6569376Sgblack@eecs.umich.edu} 6579376Sgblack@eecs.umich.edu 6589376Sgblack@eecs.umich.eduStaticInstPtr 6599376Sgblack@eecs.umich.eduDecoder::decode(PCState &nextPC) 6609376Sgblack@eecs.umich.edu{ 6619376Sgblack@eecs.umich.edu if (!instDone) 6629376Sgblack@eecs.umich.edu return NULL; 6639376Sgblack@eecs.umich.edu instDone = false; 6649376Sgblack@eecs.umich.edu updateNPC(nextPC); 6659376Sgblack@eecs.umich.edu 6669376Sgblack@eecs.umich.edu StaticInstPtr &si = instBytes->si; 6679376Sgblack@eecs.umich.edu if (si) 6689024Sgblack@eecs.umich.edu return si; 6699024Sgblack@eecs.umich.edu 6709376Sgblack@eecs.umich.edu // We didn't match in the AddrMap, but we still populated an entry. Fix 6719376Sgblack@eecs.umich.edu // up its byte masks. 6729376Sgblack@eecs.umich.edu const int chunkSize = sizeof(MachInst); 6739376Sgblack@eecs.umich.edu 6749376Sgblack@eecs.umich.edu instBytes->lastOffset = offset; 6759376Sgblack@eecs.umich.edu 6769376Sgblack@eecs.umich.edu Addr firstBasePC = basePC - (instBytes->chunks.size() - 1) * chunkSize; 6779376Sgblack@eecs.umich.edu Addr firstOffset = origPC - firstBasePC; 6789376Sgblack@eecs.umich.edu Addr totalSize = instBytes->lastOffset - firstOffset + 6799376Sgblack@eecs.umich.edu (instBytes->chunks.size() - 1) * chunkSize; 6809376Sgblack@eecs.umich.edu int start = firstOffset; 6819376Sgblack@eecs.umich.edu instBytes->masks.clear(); 6829376Sgblack@eecs.umich.edu 6839376Sgblack@eecs.umich.edu while (totalSize) { 6849376Sgblack@eecs.umich.edu int end = start + totalSize; 6859376Sgblack@eecs.umich.edu end = (chunkSize < end) ? chunkSize : end; 6869376Sgblack@eecs.umich.edu int size = end - start; 6879376Sgblack@eecs.umich.edu int idx = instBytes->masks.size(); 6889376Sgblack@eecs.umich.edu 6899376Sgblack@eecs.umich.edu MachInst maskVal = mask(size * 8) << (start * 8); 6909376Sgblack@eecs.umich.edu assert(maskVal); 6919376Sgblack@eecs.umich.edu 6929376Sgblack@eecs.umich.edu instBytes->masks.push_back(maskVal); 6939376Sgblack@eecs.umich.edu instBytes->chunks[idx] &= instBytes->masks[idx]; 6949376Sgblack@eecs.umich.edu totalSize -= size; 6959376Sgblack@eecs.umich.edu start = 0; 6969024Sgblack@eecs.umich.edu } 6979024Sgblack@eecs.umich.edu 6989376Sgblack@eecs.umich.edu si = decode(emi, origPC); 6999024Sgblack@eecs.umich.edu return si; 7009024Sgblack@eecs.umich.edu} 7019022Sgblack@eecs.umich.edu 7029022Sgblack@eecs.umich.edu} 703