gem5/src/arch/sparc/isa/base.isa
2007-04-11 12:25:00 +00:00

579 lines
19 KiB
Text

// Copyright (c) 2006-2007 The Regents of The University of Michigan
// 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: Ali Saidi
// Gabe Black
// Steve Reinhardt
////////////////////////////////////////////////////////////////////
//
// Base class for sparc instructions, and some support functions
//
output header {{
union CondCodes
{
struct
{
uint8_t c:1;
uint8_t v:1;
uint8_t z:1;
uint8_t n:1;
};
uint32_t bits;
};
enum CondTest
{
Always=0x8,
Never=0x0,
NotEqual=0x9,
Equal=0x1,
Greater=0xA,
LessOrEqual=0x2,
GreaterOrEqual=0xB,
Less=0x3,
GreaterUnsigned=0xC,
LessOrEqualUnsigned=0x4,
CarryClear=0xD,
CarrySet=0x5,
Positive=0xE,
Negative=0x6,
OverflowClear=0xF,
OverflowSet=0x7
};
enum FpCondTest
{
FAlways=0x8,
FNever=0x0,
FUnordered=0x7,
FGreater=0x6,
FUnorderedOrGreater=0x5,
FLess=0x4,
FUnorderedOrLess=0x3,
FLessOrGreater=0x2,
FNotEqual=0x1,
FEqual=0x9,
FUnorderedOrEqual=0xA,
FGreaterOrEqual=0xB,
FUnorderedOrGreaterOrEqual=0xC,
FLessOrEqual=0xD,
FUnorderedOrLessOrEqual=0xE,
FOrdered=0xF
};
extern char * CondTestAbbrev[];
/**
* Base class for all SPARC static instructions.
*/
class SparcStaticInst : public StaticInst
{
protected:
// Constructor.
SparcStaticInst(const char *mnem,
ExtMachInst _machInst, OpClass __opClass)
: StaticInst(mnem, _machInst, __opClass)
{
}
std::string generateDisassembly(Addr pc,
const SymbolTable *symtab) const;
void printReg(std::ostream &os, int reg) const;
void printSrcReg(std::ostream &os, int reg) const;
void printDestReg(std::ostream &os, int reg) const;
void printRegArray(std::ostream &os,
const RegIndex indexArray[], int num) const;
};
bool passesFpCondition(uint32_t fcc, uint32_t condition);
bool passesCondition(uint32_t codes, uint32_t condition);
inline int64_t sign_ext(uint64_t data, int origWidth)
{
int shiftAmount = 64 - origWidth;
return (((int64_t)data) << shiftAmount) >> shiftAmount;
}
}};
output decoder {{
char * CondTestAbbrev[] =
{
"nev", //Never
"e", //Equal
"le", //Less or Equal
"l", //Less
"leu", //Less or Equal Unsigned
"c", //Carry set
"n", //Negative
"o", //Overflow set
"a", //Always
"ne", //Not Equal
"g", //Greater
"ge", //Greater or Equal
"gu", //Greater Unsigned
"cc", //Carry clear
"p", //Positive
"oc" //Overflow Clear
};
}};
def template ROrImmDecode {{
{
return (I ? (SparcStaticInst *)(new %(class_name)sImm(machInst))
: (SparcStaticInst *)(new %(class_name)s(machInst)));
}
}};
output header {{
union DoubleSingle
{
double d;
uint64_t ui;
uint32_t s[2];
DoubleSingle(double _d) : d(_d)
{}
DoubleSingle(uint64_t _ui) : ui(_ui)
{}
DoubleSingle(uint32_t _s0, uint32_t _s1)
{
s[0] = _s0;
s[1] = _s1;
}
};
}};
let {{
def filterDoubles(code):
assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
for opName in ("Frd", "Frs1", "Frs2", "Frd_N"):
next_pos = 0
operandsREString = (r'''
(?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix
(?![\w\.]) # neg. lookahead assertion: prevent partial matches
''' % opName)
operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE)
is_src = False
is_dest = False
extension = None
foundOne = False
while 1:
match = operandsRE.search(code, next_pos)
if not match:
break
foundOne = True
op = match.groups()
(op_full, op_base, op_ext) = op
is_dest_local = (assignRE.match(code, match.end()) != None)
is_dest = is_dest or is_dest_local
is_src = is_src or not is_dest_local
if extension and extension != op_ext:
raise Exception, "Inconsistent extensions in double filter."
extension = op_ext
next_pos = match.end()
if foundOne:
# Get rid of any unwanted extension
code = operandsRE.sub(op_base, code)
is_int = False
member = "d"
if extension in ("sb", "ub", "shw", "uhw", "sw", "uw", "sdw", "udw"):
is_int = True
member = "ui"
if is_src:
code = ("%s = DoubleSingle(%s_high, %s_low).%s;" % \
(opName, opName, opName, member)) + code
if is_dest:
code += '''
%s_low = DoubleSingle(%s).s[1];
%s_high = DoubleSingle(%s).s[0];''' % \
(opName, opName, opName, opName)
if is_int:
code = ("uint64_t %s;" % opName) + code
else:
code = ("double %s;" % opName) + code
return code
}};
let {{
def splitOutImm(code):
matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>\.\w+)?')
rOrImmMatch = matcher.search(code)
if (rOrImmMatch == None):
return (False, code, '', '', '')
rString = rOrImmMatch.group("rNum")
if (rOrImmMatch.group("typeQual") != None):
rString += rOrImmMatch.group("typeQual")
iString = rOrImmMatch.group("iNum")
orig_code = code
code = matcher.sub('Rs' + rString, orig_code)
imm_code = matcher.sub('imm', orig_code)
return (True, code, imm_code, rString, iString)
}};
output decoder {{
inline void printMnemonic(std::ostream &os, const char * mnemonic)
{
ccprintf(os, "\t%s ", mnemonic);
}
void SparcStaticInst::printRegArray(std::ostream &os,
const RegIndex 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::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, int reg) const
{
const int MaxGlobal = 8;
const int MaxOutput = 16;
const int MaxLocal = 24;
const int MaxInput = 32;
const int MaxMicroReg = 40;
if (reg < FP_Base_DepTag) {
//If we used a register from the next or previous window,
//take out the offset.
while (reg >= MaxMicroReg)
reg -= MaxMicroReg;
if (reg == FramePointerReg)
ccprintf(os, "%%fp");
else if (reg == StackPointerReg)
ccprintf(os, "%%sp");
else if(reg < MaxGlobal)
ccprintf(os, "%%g%d", reg);
else if(reg < MaxOutput)
ccprintf(os, "%%o%d", reg - MaxGlobal);
else if(reg < MaxLocal)
ccprintf(os, "%%l%d", reg - MaxOutput);
else if(reg < MaxInput)
ccprintf(os, "%%i%d", reg - MaxLocal);
else if(reg < MaxMicroReg)
ccprintf(os, "%%u%d", reg - MaxInput);
//The fake int regs that are really control regs
else {
switch (reg - 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 < Ctrl_Base_DepTag) {
ccprintf(os, "%%f%d", reg - FP_Base_DepTag);
} else {
switch (reg - Ctrl_Base_DepTag) {
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 - Ctrl_Base_DepTag);
}
}
}
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 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 passesCondition(uint32_t codes, uint32_t condition)
{
CondCodes condCodes;
condCodes.bits = 0;
condCodes.c = codes & 0x1 ? 1 : 0;
condCodes.v = codes & 0x2 ? 1 : 0;
condCodes.z = codes & 0x4 ? 1 : 0;
condCodes.n = codes & 0x8 ? 1 : 0;
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);
}
}};
output exec {{
/// Check "FP enabled" machine status bit. Called when executing any FP
/// instruction in full-system mode.
/// @retval Full-system mode: NoFault if FP is enabled, FpDisabled
/// if not. Non-full-system mode: always returns NoFault.
#if FULL_SYSTEM
inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
{
Fault fault = NoFault; // dummy... this ipr access should not fault
if (xc->readMiscReg(MISCREG_PSTATE) & PSTATE::pef &&
xc->readMiscReg(MISCREG_FPRS) & 0x4)
return NoFault;
else
return new FpDisabled;
}
#else
inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
{
return NoFault;
}
#endif
}};