blob: a1f5e60d7a15dd60d21f6d7be0d815866f295ee3 [file] [log] [blame]
/*
* Copyright (c) 2006-2007 The Regents of The University of Michigan
* All rights reserved
* Copyright 2017 Google Inc.
*
* 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/sparc/insts/static_inst.hh"
namespace SparcISA
{
const char *CondTestAbbrev[] =
{
[Never] = "nev",
[Equal] = "e",
[LessOrEqual] = "le",
[Less] = "l",
[LessOrEqualUnsigned] = "leu",
[CarrySet] = "c",
[Negative] = "n",
[OverflowSet] = "o",
[Always] = "a",
[NotEqual] = "ne",
[Greater] = "g",
[GreaterOrEqual] = "ge",
[GreaterUnsigned] = "gu",
[CarryClear] = "cc",
[Positive] = "p",
[OverflowClear] = "oc"
};
void
SparcStaticInst::printMnemonic(std::ostream &os, const char *mnemonic)
{
ccprintf(os, "\t%s ", mnemonic);
}
void
SparcStaticInst::printRegArray(std::ostream &os, const RegId indexArray[],
int num) const
{
if (num <= 0)
return;
printReg(os, indexArray[0]);
for (int x = 1; x < num; x++) {
os << ", ";
printReg(os, indexArray[x]);
}
}
void
SparcStaticInst::advancePC(SparcISA::PCState &pcState) const
{
pcState.advance();
}
void
SparcStaticInst::printSrcReg(std::ostream &os, int reg) const
{
if (_numSrcRegs > reg)
printReg(os, _srcRegIdx[reg]);
}
void
SparcStaticInst::printDestReg(std::ostream &os, int reg) const
{
if (_numDestRegs > reg)
printReg(os, _destRegIdx[reg]);
}
void
SparcStaticInst::printReg(std::ostream &os, RegId reg)
{
const int MaxGlobal = 8;
const int MaxOutput = 16;
const int MaxLocal = 24;
const int MaxInput = 32;
const int MaxMicroReg = 40;
RegIndex reg_idx = reg.index();
if (reg.isIntReg()) {
// If we used a register from the next or previous window,
// take out the offset.
while (reg_idx >= MaxMicroReg)
reg_idx -= MaxMicroReg;
if (reg_idx == FramePointerReg)
ccprintf(os, "%%fp");
else if (reg_idx == StackPointerReg)
ccprintf(os, "%%sp");
else if (reg_idx < MaxGlobal)
ccprintf(os, "%%g%d", reg_idx);
else if (reg_idx < MaxOutput)
ccprintf(os, "%%o%d", reg_idx - MaxGlobal);
else if (reg_idx < MaxLocal)
ccprintf(os, "%%l%d", reg_idx - MaxOutput);
else if (reg_idx < MaxInput)
ccprintf(os, "%%i%d", reg_idx - MaxLocal);
else if (reg_idx < MaxMicroReg)
ccprintf(os, "%%u%d", reg_idx - MaxInput);
// The fake int regs that are really control regs
else {
switch (reg_idx - MaxMicroReg) {
case 1:
ccprintf(os, "%%y");
break;
case 2:
ccprintf(os, "%%ccr");
break;
case 3:
ccprintf(os, "%%cansave");
break;
case 4:
ccprintf(os, "%%canrestore");
break;
case 5:
ccprintf(os, "%%cleanwin");
break;
case 6:
ccprintf(os, "%%otherwin");
break;
case 7:
ccprintf(os, "%%wstate");
break;
}
}
} else if (reg.isFloatReg()) {
ccprintf(os, "%%f%d", reg_idx);
} else {
switch (reg_idx) {
case MISCREG_ASI:
ccprintf(os, "%%asi");
break;
case MISCREG_FPRS:
ccprintf(os, "%%fprs");
break;
case MISCREG_PCR:
ccprintf(os, "%%pcr");
break;
case MISCREG_PIC:
ccprintf(os, "%%pic");
break;
case MISCREG_GSR:
ccprintf(os, "%%gsr");
break;
case MISCREG_SOFTINT:
ccprintf(os, "%%softint");
break;
case MISCREG_SOFTINT_SET:
ccprintf(os, "%%softint_set");
break;
case MISCREG_SOFTINT_CLR:
ccprintf(os, "%%softint_clr");
break;
case MISCREG_TICK_CMPR:
ccprintf(os, "%%tick_cmpr");
break;
case MISCREG_STICK:
ccprintf(os, "%%stick");
break;
case MISCREG_STICK_CMPR:
ccprintf(os, "%%stick_cmpr");
break;
case MISCREG_TPC:
ccprintf(os, "%%tpc");
break;
case MISCREG_TNPC:
ccprintf(os, "%%tnpc");
break;
case MISCREG_TSTATE:
ccprintf(os, "%%tstate");
break;
case MISCREG_TT:
ccprintf(os, "%%tt");
break;
case MISCREG_TICK:
ccprintf(os, "%%tick");
break;
case MISCREG_TBA:
ccprintf(os, "%%tba");
break;
case MISCREG_PSTATE:
ccprintf(os, "%%pstate");
break;
case MISCREG_TL:
ccprintf(os, "%%tl");
break;
case MISCREG_PIL:
ccprintf(os, "%%pil");
break;
case MISCREG_CWP:
ccprintf(os, "%%cwp");
break;
case MISCREG_GL:
ccprintf(os, "%%gl");
break;
case MISCREG_HPSTATE:
ccprintf(os, "%%hpstate");
break;
case MISCREG_HTSTATE:
ccprintf(os, "%%htstate");
break;
case MISCREG_HINTP:
ccprintf(os, "%%hintp");
break;
case MISCREG_HTBA:
ccprintf(os, "%%htba");
break;
case MISCREG_HSTICK_CMPR:
ccprintf(os, "%%hstick_cmpr");
break;
case MISCREG_HVER:
ccprintf(os, "%%hver");
break;
case MISCREG_STRAND_STS_REG:
ccprintf(os, "%%strand_sts_reg");
break;
case MISCREG_FSR:
ccprintf(os, "%%fsr");
break;
default:
ccprintf(os, "%%ctrl%d", reg_idx);
}
}
}
std::string
SparcStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
printMnemonic(ss, mnemonic);
// just print the first two source regs... if there's
// a third one, it's a read-modify-write dest (Rc),
// e.g. for CMOVxx
if (_numSrcRegs > 0)
printReg(ss, _srcRegIdx[0]);
if (_numSrcRegs > 1) {
ss << ",";
printReg(ss, _srcRegIdx[1]);
}
// just print the first dest... if there's a second one,
// it's generally implicit
if (_numDestRegs > 0) {
if (_numSrcRegs > 0)
ss << ",";
printReg(ss, _destRegIdx[0]);
}
return ss.str();
}
bool
SparcStaticInst::passesFpCondition(uint32_t fcc, uint32_t condition)
{
bool u = (fcc == 3);
bool g = (fcc == 2);
bool l = (fcc == 1);
bool e = (fcc == 0);
switch (condition) {
case FAlways:
return 1;
case FNever:
return 0;
case FUnordered:
return u;
case FGreater:
return g;
case FUnorderedOrGreater:
return u || g;
case FLess:
return l;
case FUnorderedOrLess:
return u || l;
case FLessOrGreater:
return l || g;
case FNotEqual:
return l || g || u;
case FEqual:
return e;
case FUnorderedOrEqual:
return u || e;
case FGreaterOrEqual:
return g || e;
case FUnorderedOrGreaterOrEqual:
return u || g || e;
case FLessOrEqual:
return l || e;
case FUnorderedOrLessOrEqual:
return u || l || e;
case FOrdered:
return e || l || g;
}
panic("Tried testing condition nonexistant condition code %d", condition);
}
bool
SparcStaticInst::passesCondition(uint32_t codes, uint32_t condition)
{
BitUnion32(CondCodes)
Bitfield<0> c;
Bitfield<1> v;
Bitfield<2> z;
Bitfield<3> n;
EndBitUnion(CondCodes)
CondCodes condCodes = codes;
switch (condition) {
case Always:
return true;
case Never:
return false;
case NotEqual:
return !condCodes.z;
case Equal:
return condCodes.z;
case Greater:
return !(condCodes.z | (condCodes.n ^ condCodes.v));
case LessOrEqual:
return condCodes.z | (condCodes.n ^ condCodes.v);
case GreaterOrEqual:
return !(condCodes.n ^ condCodes.v);
case Less:
return (condCodes.n ^ condCodes.v);
case GreaterUnsigned:
return !(condCodes.c | condCodes.z);
case LessOrEqualUnsigned:
return (condCodes.c | condCodes.z);
case CarryClear:
return !condCodes.c;
case CarrySet:
return condCodes.c;
case Positive:
return !condCodes.n;
case Negative:
return condCodes.n;
case OverflowClear:
return !condCodes.v;
case OverflowSet:
return condCodes.v;
}
panic("Tried testing condition nonexistant "
"condition code %d", condition);
}
}