/*
 * Copyright (c) 2011 Google
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/decoder.hh"
#include "arch/x86/regs/misc.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "debug/Decoder.hh"

namespace X86ISA
{
void Decoder::doReset()
{
    origPC = basePC + offset;
    DPRINTF(Decoder, "Setting origPC to %#x\n", origPC);
    emi.rex = 0;
    emi.legacy = 0;
    emi.opcode.num = 0;
    emi.opcode.op = 0;
    emi.opcode.prefixA = emi.opcode.prefixB = 0;

    immediateCollected = 0;
    emi.immediate = 0;
    emi.displacement = 0;
    emi.dispSize = 0;

    emi.modRM = 0;
    emi.sib = 0;
    m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
    emi.mode.mode = m5Reg.mode;
    emi.mode.submode = m5Reg.submode;
}

void Decoder::process()
{
    //This function drives the decoder state machine.

    //Some sanity checks. You shouldn't try to process more bytes if
    //there aren't any, and you shouldn't overwrite an already
    //decoder ExtMachInst.
    assert(!outOfBytes);
    assert(!instDone);

    //While there's still something to do...
    while(!instDone && !outOfBytes)
    {
        uint8_t nextByte = getNextByte();
        switch(state)
        {
          case ResetState:
            doReset();
            state = PrefixState;
          case PrefixState:
            state = doPrefixState(nextByte);
            break;
          case OpcodeState:
            state = doOpcodeState(nextByte);
            break;
          case ModRMState:
            state = doModRMState(nextByte);
            break;
          case SIBState:
            state = doSIBState(nextByte);
            break;
          case DisplacementState:
            state = doDisplacementState();
            break;
          case ImmediateState:
            state = doImmediateState();
            break;
          case ErrorState:
            panic("Went to the error state in the decoder.\n");
          default:
            panic("Unrecognized state! %d\n", state);
        }
    }
}

//Either get a prefix and record it in the ExtMachInst, or send the
//state machine on to get the opcode(s).
Decoder::State Decoder::doPrefixState(uint8_t nextByte)
{
    uint8_t prefix = Prefixes[nextByte];
    State nextState = PrefixState;
    // REX prefixes are only recognized in 64 bit mode.
    if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
        prefix = 0;
    if (prefix)
        consumeByte();
    switch(prefix)
    {
        //Operand size override prefixes
      case OperandSizeOverride:
        DPRINTF(Decoder, "Found operand size override prefix.\n");
        emi.legacy.op = true;
        break;
      case AddressSizeOverride:
        DPRINTF(Decoder, "Found address size override prefix.\n");
        emi.legacy.addr = true;
        break;
        //Segment override prefixes
      case CSOverride:
      case DSOverride:
      case ESOverride:
      case FSOverride:
      case GSOverride:
      case SSOverride:
        DPRINTF(Decoder, "Found segment override.\n");
        emi.legacy.seg = prefix;
        break;
      case Lock:
        DPRINTF(Decoder, "Found lock prefix.\n");
        emi.legacy.lock = true;
        break;
      case Rep:
        DPRINTF(Decoder, "Found rep prefix.\n");
        emi.legacy.rep = true;
        break;
      case Repne:
        DPRINTF(Decoder, "Found repne prefix.\n");
        emi.legacy.repne = true;
        break;
      case RexPrefix:
        DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte);
        emi.rex = nextByte;
        break;
      case 0:
        nextState = OpcodeState;
        break;
      default:
        panic("Unrecognized prefix %#x\n", nextByte);
    }
    return nextState;
}

//Load all the opcodes (currently up to 2) and then figure out
//what immediate and/or ModRM is needed.
Decoder::State Decoder::doOpcodeState(uint8_t nextByte)
{
    State nextState = ErrorState;
    emi.opcode.num++;
    //We can't handle 3+ byte opcodes right now
    assert(emi.opcode.num < 4);
    consumeByte();
    if(emi.opcode.num == 1 && nextByte == 0x0f)
    {
        nextState = OpcodeState;
        DPRINTF(Decoder, "Found two byte opcode.\n");
        emi.opcode.prefixA = nextByte;
    }
    else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
    {
        nextState = OpcodeState;
        DPRINTF(Decoder, "Found three byte opcode.\n");
        emi.opcode.prefixB = nextByte;
    }
    else
    {
        DPRINTF(Decoder, "Found opcode %#x.\n", nextByte);
        emi.opcode.op = nextByte;

        //Figure out the effective operand size. This can be overriden to
        //a fixed value at the decoder level.
        int logOpSize;
        if (emi.rex.w)
            logOpSize = 3; // 64 bit operand size
        else if (emi.legacy.op)
            logOpSize = m5Reg.altOp;
        else
            logOpSize = m5Reg.defOp;

        //Set the actual op size
        emi.opSize = 1 << logOpSize;

        //Figure out the effective address size. This can be overriden to
        //a fixed value at the decoder level.
        int logAddrSize;
        if(emi.legacy.addr)
            logAddrSize = m5Reg.altAddr;
        else
            logAddrSize = m5Reg.defAddr;

        //Set the actual address size
        emi.addrSize = 1 << logAddrSize;

        //Figure out the effective stack width. This can be overriden to
        //a fixed value at the decoder level.
        emi.stackSize = 1 << m5Reg.stack;

        //Figure out how big of an immediate we'll retreive based
        //on the opcode.
        int immType = ImmediateType[emi.opcode.num - 1][nextByte];
        if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
            immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
        else
            immediateSize = SizeTypeToSize[logOpSize - 1][immType];

        //Determine what to expect next
        if (UsesModRM[emi.opcode.num - 1][nextByte]) {
            nextState = ModRMState;
        } else {
            if(immediateSize) {
                nextState = ImmediateState;
            } else {
                instDone = true;
                nextState = ResetState;
            }
        }
    }
    return nextState;
}

//Get the ModRM byte and determine what displacement, if any, there is.
//Also determine whether or not to get the SIB byte, displacement, or
//immediate next.
Decoder::State Decoder::doModRMState(uint8_t nextByte)
{
    State nextState = ErrorState;
    ModRM modRM;
    modRM = nextByte;
    DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte);
    if (m5Reg.defOp == 1) {
        //figure out 16 bit displacement size
        if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
            displacementSize = 2;
        else if (modRM.mod == 1)
            displacementSize = 1;
        else
            displacementSize = 0;
    } else {
        //figure out 32/64 bit displacement size
        if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
            displacementSize = 4;
        else if (modRM.mod == 1)
            displacementSize = 1;
        else
            displacementSize = 0;
    }

    // The "test" instruction in group 3 needs an immediate, even though
    // the other instructions with the same actual opcode don't.
    if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
       if (emi.opcode.op == 0xF6)
           immediateSize = 1;
       else if (emi.opcode.op == 0xF7)
           immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
    }

    //If there's an SIB, get that next.
    //There is no SIB in 16 bit mode.
    if (modRM.rm == 4 && modRM.mod != 3) {
            // && in 32/64 bit mode)
        nextState = SIBState;
    } else if(displacementSize) {
        nextState = DisplacementState;
    } else if(immediateSize) {
        nextState = ImmediateState;
    } else {
        instDone = true;
        nextState = ResetState;
    }
    //The ModRM byte is consumed no matter what
    consumeByte();
    emi.modRM = modRM;
    return nextState;
}

//Get the SIB byte. We don't do anything with it at this point, other
//than storing it in the ExtMachInst. Determine if we need to get a
//displacement or immediate next.
Decoder::State Decoder::doSIBState(uint8_t nextByte)
{
    State nextState = ErrorState;
    emi.sib = nextByte;
    DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte);
    consumeByte();
    if (emi.modRM.mod == 0 && emi.sib.base == 5)
        displacementSize = 4;
    if (displacementSize) {
        nextState = DisplacementState;
    } else if(immediateSize) {
        nextState = ImmediateState;
    } else {
        instDone = true;
        nextState = ResetState;
    }
    return nextState;
}

//Gather up the displacement, or at least as much of it
//as we can get.
Decoder::State Decoder::doDisplacementState()
{
    State nextState = ErrorState;

    getImmediate(immediateCollected,
            emi.displacement,
            displacementSize);

    DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n",
            displacementSize, immediateCollected);

    if(displacementSize == immediateCollected) {
        //Reset this for other immediates.
        immediateCollected = 0;
        //Sign extend the displacement
        switch(displacementSize)
        {
          case 1:
            emi.displacement = sext<8>(emi.displacement);
            break;
          case 2:
            emi.displacement = sext<16>(emi.displacement);
            break;
          case 4:
            emi.displacement = sext<32>(emi.displacement);
            break;
          default:
            panic("Undefined displacement size!\n");
        }
        DPRINTF(Decoder, "Collected displacement %#x.\n",
                emi.displacement);
        if(immediateSize) {
            nextState = ImmediateState;
        } else {
            instDone = true;
            nextState = ResetState;
        }

        emi.dispSize = displacementSize;
    }
    else
        nextState = DisplacementState;
    return nextState;
}

//Gather up the immediate, or at least as much of it
//as we can get
Decoder::State Decoder::doImmediateState()
{
    State nextState = ErrorState;

    getImmediate(immediateCollected,
            emi.immediate,
            immediateSize);

    DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n",
            immediateSize, immediateCollected);

    if(immediateSize == immediateCollected)
    {
        //Reset this for other immediates.
        immediateCollected = 0;

        //XXX Warning! The following is an observed pattern and might
        //not always be true!

        //Instructions which use 64 bit operands but 32 bit immediates
        //need to have the immediate sign extended to 64 bits.
        //Instructions which use true 64 bit immediates won't be
        //affected, and instructions that use true 32 bit immediates
        //won't notice.
        switch(immediateSize)
        {
          case 4:
            emi.immediate = sext<32>(emi.immediate);
            break;
          case 1:
            emi.immediate = sext<8>(emi.immediate);
        }

        DPRINTF(Decoder, "Collected immediate %#x.\n",
                emi.immediate);
        instDone = true;
        nextState = ResetState;
    }
    else
        nextState = ImmediateState;
    return nextState;
}

DecodeCache::InstMap Decoder::instMap;
DecodeCache::AddrMap<StaticInstPtr> Decoder::decodePages;

StaticInstPtr
Decoder::decode(ExtMachInst mach_inst, Addr addr)
{
    StaticInstPtr &si = decodePages.lookup(addr);
    if (si && (si->machInst == mach_inst))
        return si;

    DecodeCache::InstMap::iterator iter = instMap.find(mach_inst);
    if (iter != instMap.end()) {
        si = iter->second;
        return si;
    }

    si = decodeInst(mach_inst);
    instMap[mach_inst] = si;
    return si;
}

}