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