blob: 3b02f58de1d2958c45eefa6fef16cbca080535cb [file] [log] [blame]
// 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
////////////////////////////////////////////////////////////////////
//
// Mem utility templates and functions
//
output header {{
/**
* Base class for memory operations.
*/
class Mem : public SparcStaticInst
{
protected:
// Constructor
Mem(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
SparcStaticInst(mnem, _machInst, __opClass)
{
}
std::string generateDisassembly(Addr pc,
const SymbolTable *symtab) const;
};
/**
* Class for memory operations which use an immediate offset.
*/
class MemImm : public Mem
{
protected:
// Constructor
MemImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
Mem(mnem, _machInst, __opClass), imm(sext<13>(SIMM13))
{}
std::string generateDisassembly(Addr pc,
const SymbolTable *symtab) const;
const int32_t imm;
};
}};
output decoder {{
std::string Mem::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
{
std::stringstream response;
bool load = flags[IsLoad];
bool store = flags[IsStore];
printMnemonic(response, mnemonic);
if(store)
{
printReg(response, _srcRegIdx[0]);
ccprintf(response, ", ");
}
ccprintf(response, "[");
if(_srcRegIdx[!store ? 0 : 1] != 0)
{
printSrcReg(response, !store ? 0 : 1);
ccprintf(response, " + ");
}
printSrcReg(response, !store ? 1 : 2);
ccprintf(response, "]");
if(load)
{
ccprintf(response, ", ");
printReg(response, _destRegIdx[0]);
}
return response.str();
}
std::string MemImm::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
{
std::stringstream response;
bool load = flags[IsLoad];
bool save = flags[IsStore];
printMnemonic(response, mnemonic);
if(save)
{
printReg(response, _srcRegIdx[0]);
ccprintf(response, ", ");
}
ccprintf(response, "[");
if(_srcRegIdx[!save ? 0 : 1] != 0)
{
printReg(response, _srcRegIdx[!save ? 0 : 1]);
ccprintf(response, " + ");
}
if(imm >= 0)
ccprintf(response, "0x%x]", imm);
else
ccprintf(response, "-0x%x]", -imm);
if(load)
{
ccprintf(response, ", ");
printReg(response, _destRegIdx[0]);
}
return response.str();
}
}};
//This template provides the execute functions for a load
def template LoadExecute {{
Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const
{
Fault fault = NoFault;
Addr EA;
%(fp_enable_check)s;
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
DPRINTF(Sparc, "The address is 0x%x\n", EA);
%(fault_check)s;
if(fault == NoFault)
{
fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, %(asi_val)s);
}
if(fault == NoFault)
{
%(code)s;
}
if(fault == NoFault)
{
//Write the resulting state to the execution context
%(op_wb)s;
}
return fault;
}
Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
Fault fault = NoFault;
Addr EA;
uint%(mem_acc_size)s_t Mem;
%(fp_enable_check)s;
%(ea_decl)s;
%(ea_rd)s;
%(ea_code)s;
%(fault_check)s;
if(fault == NoFault)
{
fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, %(asi_val)s);
}
return fault;
}
Fault %(class_name)s::completeAcc(PacketPtr pkt, %(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
Fault fault = NoFault;
%(code_decl)s;
%(code_rd)s;
Mem = pkt->get<typeof(Mem)>();
%(code)s;
if(fault == NoFault)
{
%(code_wb)s;
}
return fault;
}
}};
//This template provides the execute functions for a store
def template StoreExecute {{
Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const
{
Fault fault = NoFault;
//This is to support the conditional store in cas instructions.
//It should be optomized out in all the others
bool storeCond = true;
Addr EA;
%(fp_enable_check)s;
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
DPRINTF(Sparc, "The address is 0x%x\n", EA);
%(fault_check)s;
if(fault == NoFault)
{
%(code)s;
}
if(storeCond && fault == NoFault)
{
fault = xc->write((uint%(mem_acc_size)s_t)Mem,
EA, %(asi_val)s, 0);
}
if(fault == NoFault)
{
//Write the resulting state to the execution context
%(op_wb)s;
}
return fault;
}
Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
Fault fault = NoFault;
bool storeCond = true;
Addr EA;
%(fp_enable_check)s;
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
DPRINTF(Sparc, "The address is 0x%x\n", EA);
%(fault_check)s;
if(fault == NoFault)
{
%(code)s;
}
if(storeCond && fault == NoFault)
{
fault = xc->write((uint%(mem_acc_size)s_t)Mem,
EA, %(asi_val)s, 0);
}
if(fault == NoFault)
{
//Write the resulting state to the execution context
%(op_wb)s;
}
return fault;
}
Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
return NoFault;
}
}};
//This delcares the initiateAcc function in memory operations
def template InitiateAccDeclare {{
Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const;
}};
//This declares the completeAcc function in memory operations
def template CompleteAccDeclare {{
Fault completeAcc(PacketPtr, %(CPU_exec_context)s *, Trace::InstRecord *) const;
}};
//Here are some code snippets which check for various fault conditions
let {{
# The LSB can be zero, since it's really the MSB in doubles and quads
# and we're dealing with doubles
BlockAlignmentFaultCheck = '''
if(RD & 0xe)
fault = new IllegalInstruction;
else if(EA & 0x3f)
fault = new MemAddressNotAligned;
'''
TwinAlignmentFaultCheck = '''
if(RD & 0x1)
fault = new IllegalInstruction;
else if(EA & 0xf)
fault = new MemAddressNotAligned;
'''
# XXX Need to take care of pstate.hpriv as well. The lower ASIs
# are split into ones that are available in priv and hpriv, and
# those that are only available in hpriv
AlternateASIPrivFaultCheck = '''
if(!bits(Pstate,2,2) && !bits(Hpstate,2,2) && !AsiIsUnPriv((ASI)EXT_ASI) ||
!bits(Hpstate,2,2) && AsiIsHPriv((ASI)EXT_ASI))
fault = new PrivilegedAction;
else if(AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2))
fault = new PrivilegedAction;
'''
}};
//A simple function to generate the name of the macro op of a certain
//instruction at a certain micropc
let {{
def makeMicroName(name, microPc):
return name + "::" + name + "_" + str(microPc)
}};
//This function properly generates the execute functions for one of the
//templates above. This is needed because in one case, ea computation,
//fault checks and the actual code all occur in the same function,
//and in the other they're distributed across two. Also note that for
//execute functions, the name of the base class doesn't matter.
let {{
def doSplitExecute(code, execute, name, Name, asi, opt_flags, microParam):
microParam["asi_val"] = asi;
codeParam = microParam.copy()
codeParam["ea_code"] = ''
codeIop = InstObjParams(name, Name, '', code, opt_flags, codeParam)
eaIop = InstObjParams(name, Name, '', microParam["ea_code"],
opt_flags, microParam)
iop = InstObjParams(name, Name, '', code, opt_flags, microParam)
(iop.ea_decl,
iop.ea_rd,
iop.ea_wb) = (eaIop.op_decl, eaIop.op_rd, eaIop.op_wb)
(iop.code_decl,
iop.code_rd,
iop.code_wb) = (codeIop.op_decl, codeIop.op_rd, codeIop.op_wb)
return execute.subst(iop)
def doDualSplitExecute(code, eaRegCode, eaImmCode, execute,
faultCode, nameReg, nameImm, NameReg, NameImm, asi, opt_flags):
executeCode = ''
for (eaCode, name, Name) in (
(eaRegCode, nameReg, NameReg),
(eaImmCode, nameImm, NameImm)):
microParams = {"ea_code" : eaCode, "fault_check": faultCode}
executeCode += doSplitExecute(code, execute, name, Name,
asi, opt_flags, microParams)
return executeCode
}};