Merge zizzer:/bk/newmem
into zower.eecs.umich.edu:/eecshome/m5/newmem src/arch/isa_parser.py: src/arch/sparc/isa/formats/mem/basicmem.isa: src/arch/sparc/isa/formats/mem/blockmem.isa: src/arch/sparc/isa/formats/mem/util.isa: src/arch/sparc/miscregfile.cc: src/arch/sparc/miscregfile.hh: src/cpu/o3/iew_impl.hh: Hand Merge --HG-- extra : convert_revision : ae1b25cde85ab8ec275a09d554acd372887d4d47
This commit is contained in:
commit
9d0ca61b7e
65 changed files with 1140 additions and 954 deletions
|
@ -189,6 +189,11 @@ namespace AlphaISA
|
|||
}
|
||||
};
|
||||
|
||||
static inline int flattenIntIndex(ThreadContext * tc, int reg)
|
||||
{
|
||||
return reg;
|
||||
}
|
||||
|
||||
void copyRegs(ThreadContext *src, ThreadContext *dest);
|
||||
|
||||
void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
|
||||
|
|
|
@ -32,54 +32,25 @@
|
|||
#ifndef __ARCH_ALPHA_SYSCALLRETURN_HH__
|
||||
#define __ARCH_ALPHA_SYSCALLRETURN_HH__
|
||||
|
||||
class SyscallReturn {
|
||||
public:
|
||||
template <class T>
|
||||
SyscallReturn(T v, bool s)
|
||||
{
|
||||
retval = (uint64_t)v;
|
||||
success = s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SyscallReturn(T v)
|
||||
{
|
||||
success = (v >= 0);
|
||||
retval = (uint64_t)v;
|
||||
}
|
||||
|
||||
~SyscallReturn() {}
|
||||
|
||||
SyscallReturn& operator=(const SyscallReturn& s) {
|
||||
retval = s.retval;
|
||||
success = s.success;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool successful() { return success; }
|
||||
uint64_t value() { return retval; }
|
||||
|
||||
|
||||
private:
|
||||
uint64_t retval;
|
||||
bool success;
|
||||
};
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "sim/syscallreturn.hh"
|
||||
|
||||
namespace AlphaISA
|
||||
{
|
||||
static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs)
|
||||
static inline void setSyscallReturn(SyscallReturn return_value,
|
||||
ThreadContext * tc)
|
||||
{
|
||||
// check for error condition. Alpha syscall convention is to
|
||||
// indicate success/failure in reg a3 (r19) and put the
|
||||
// return value itself in the standard return value reg (v0).
|
||||
if (return_value.successful()) {
|
||||
// no error
|
||||
regs->setIntReg(SyscallSuccessReg, 0);
|
||||
regs->setIntReg(ReturnValueReg, return_value.value());
|
||||
tc->setIntReg(SyscallSuccessReg, 0);
|
||||
tc->setIntReg(ReturnValueReg, return_value.value());
|
||||
} else {
|
||||
// got an error, return details
|
||||
regs->setIntReg(SyscallSuccessReg, (IntReg)-1);
|
||||
regs->setIntReg(ReturnValueReg, -return_value.value());
|
||||
tc->setIntReg(SyscallSuccessReg, (IntReg)-1);
|
||||
tc->setIntReg(ReturnValueReg, -return_value.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -808,8 +808,7 @@ class GenCode:
|
|||
# a defineInst() method that generates the code for an instruction
|
||||
# definition.
|
||||
|
||||
exportContextSymbols = ('InstObjParams', 'CodeBlock',
|
||||
'makeList', 're', 'string')
|
||||
exportContextSymbols = ('InstObjParams', 'makeList', 're', 'string')
|
||||
|
||||
exportContext = {}
|
||||
|
||||
|
@ -1003,11 +1002,72 @@ def substBitOps(code):
|
|||
# Template objects are format strings that allow substitution from
|
||||
# the attribute spaces of other objects (e.g. InstObjParams instances).
|
||||
|
||||
labelRE = re.compile(r'[^%]%\(([^\)]+)\)[sd]')
|
||||
|
||||
class Template:
|
||||
def __init__(self, t):
|
||||
self.template = t
|
||||
|
||||
def subst(self, d):
|
||||
myDict = None
|
||||
|
||||
# Protect non-Python-dict substitutions (e.g. if there's a printf
|
||||
# in the templated C++ code)
|
||||
template = protect_non_subst_percents(self.template)
|
||||
# CPU-model-specific substitutions are handled later (in GenCode).
|
||||
template = protect_cpu_symbols(template)
|
||||
|
||||
# if we're dealing with an InstObjParams object, we need to be a
|
||||
# little more sophisticated. Otherwise, just do what we've always
|
||||
# done
|
||||
if isinstance(d, InstObjParams):
|
||||
# The instruction wide parameters are already formed, but the
|
||||
# parameters which are only function wide still need to be
|
||||
# generated.
|
||||
perFuncNames = ['op_decl', 'op_src_decl', 'op_dest_decl', \
|
||||
'op_rd', 'op_wb', 'mem_acc_size', 'mem_acc_type']
|
||||
compositeCode = ''
|
||||
|
||||
myDict = templateMap.copy()
|
||||
myDict.update(d.__dict__)
|
||||
# The "operands" and "snippets" attributes of the InstObjParams
|
||||
# objects are for internal use and not substitution.
|
||||
del myDict['operands']
|
||||
del myDict['snippets']
|
||||
|
||||
for name in labelRE.findall(template):
|
||||
# Don't try to find a snippet to go with things that will
|
||||
# match against attributes of d, or that are other templates,
|
||||
# or that we're going to generate later, or that we've already
|
||||
# found.
|
||||
if not hasattr(d, name) and \
|
||||
not templateMap.has_key(name) and \
|
||||
not myDict.has_key(name) and \
|
||||
name not in perFuncNames:
|
||||
myDict[name] = d.snippets[name]
|
||||
if isinstance(myDict[name], str):
|
||||
myDict[name] = substMungedOpNames(substBitOps(myDict[name]))
|
||||
compositeCode += (" " + myDict[name])
|
||||
operands = SubOperandList(compositeCode, d.operands)
|
||||
|
||||
myDict['op_decl'] = operands.concatAttrStrings('op_decl')
|
||||
|
||||
is_src = lambda op: op.is_src
|
||||
is_dest = lambda op: op.is_dest
|
||||
|
||||
myDict['op_src_decl'] = \
|
||||
operands.concatSomeAttrStrings(is_src, 'op_src_decl')
|
||||
myDict['op_dest_decl'] = \
|
||||
operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
|
||||
|
||||
myDict['op_rd'] = operands.concatAttrStrings('op_rd')
|
||||
myDict['op_wb'] = operands.concatAttrStrings('op_wb')
|
||||
|
||||
if d.operands.memOperand:
|
||||
myDict['mem_acc_size'] = d.operands.memOperand.mem_acc_size
|
||||
myDict['mem_acc_type'] = d.operands.memOperand.mem_acc_type
|
||||
|
||||
else:
|
||||
# Start with the template namespace. Make a copy since we're
|
||||
# going to modify it.
|
||||
myDict = templateMap.copy()
|
||||
|
@ -1019,11 +1079,6 @@ class Template:
|
|||
myDict.update(d.__dict__)
|
||||
else:
|
||||
raise TypeError, "Template.subst() arg must be or have dictionary"
|
||||
# Protect non-Python-dict substitutions (e.g. if there's a printf
|
||||
# in the templated C++ code)
|
||||
template = protect_non_subst_percents(self.template)
|
||||
# CPU-model-specific substitutions are handled later (in GenCode).
|
||||
template = protect_cpu_symbols(template)
|
||||
return template % myDict
|
||||
|
||||
# Convert to string. This handles the case when a template with a
|
||||
|
@ -1296,10 +1351,10 @@ class ControlRegOperand(Operand):
|
|||
def makeConstructor(self):
|
||||
c = ''
|
||||
if self.is_src:
|
||||
c += '\n\t_srcRegIdx[%d] = %s;' % \
|
||||
c += '\n\t_srcRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
|
||||
(self.src_reg_idx, self.reg_spec)
|
||||
if self.is_dest:
|
||||
c += '\n\t_destRegIdx[%d] = %s;' % \
|
||||
c += '\n\t_destRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
|
||||
(self.dest_reg_idx, self.reg_spec)
|
||||
return c
|
||||
|
||||
|
@ -1307,7 +1362,7 @@ class ControlRegOperand(Operand):
|
|||
bit_select = 0
|
||||
if (self.ctype == 'float' or self.ctype == 'double'):
|
||||
error(0, 'Attempt to read control register as FP')
|
||||
base = 'xc->readMiscRegWithEffect(%s)' % self.reg_spec
|
||||
base = 'xc->readMiscRegOperandWithEffect(%s)' % self.reg_spec
|
||||
if self.size == self.dflt_size:
|
||||
return '%s = %s;\n' % (self.base_name, base)
|
||||
else:
|
||||
|
@ -1317,7 +1372,8 @@ class ControlRegOperand(Operand):
|
|||
def makeWrite(self):
|
||||
if (self.ctype == 'float' or self.ctype == 'double'):
|
||||
error(0, 'Attempt to write control register as FP')
|
||||
wb = 'xc->setMiscRegWithEffect(%s, %s);\n' % (self.reg_spec, self.base_name)
|
||||
wb = 'xc->setMiscRegOperandWithEffect(this, %s, %s);\n' % \
|
||||
(self.dest_reg_idx, self.base_name)
|
||||
wb += 'if (traceData) { traceData->setData(%s); }' % \
|
||||
self.base_name
|
||||
return wb
|
||||
|
@ -1550,6 +1606,48 @@ class OperandList:
|
|||
def sort(self):
|
||||
self.items.sort(lambda a, b: a.sort_pri - b.sort_pri)
|
||||
|
||||
class SubOperandList(OperandList):
|
||||
|
||||
# Find all the operands in the given code block. Returns an operand
|
||||
# descriptor list (instance of class OperandList).
|
||||
def __init__(self, code, master_list):
|
||||
self.items = []
|
||||
self.bases = {}
|
||||
# delete comments so we don't match on reg specifiers inside
|
||||
code = commentRE.sub('', code)
|
||||
# search for operands
|
||||
next_pos = 0
|
||||
while 1:
|
||||
match = operandsRE.search(code, next_pos)
|
||||
if not match:
|
||||
# no more matches: we're done
|
||||
break
|
||||
op = match.groups()
|
||||
# regexp groups are operand full name, base, and extension
|
||||
(op_full, op_base, op_ext) = op
|
||||
# find this op in the master list
|
||||
op_desc = master_list.find_base(op_base)
|
||||
if not op_desc:
|
||||
error(0, 'Found operand %s which is not in the master list!' \
|
||||
' This is an internal error' % \
|
||||
op_base)
|
||||
else:
|
||||
# See if we've already found this operand
|
||||
op_desc = self.find_base(op_base)
|
||||
if not op_desc:
|
||||
# if not, add a reference to it to this sub list
|
||||
self.append(master_list.bases[op_base])
|
||||
|
||||
# start next search after end of current match
|
||||
next_pos = match.end()
|
||||
self.sort()
|
||||
self.memOperand = None
|
||||
for op_desc in self.items:
|
||||
if op_desc.isMem():
|
||||
if self.memOperand:
|
||||
error(0, "Code block has more than one memory operand.")
|
||||
self.memOperand = op_desc
|
||||
|
||||
# Regular expression object to match C++ comments
|
||||
# (used in findOperands())
|
||||
commentRE = re.compile(r'//.*\n')
|
||||
|
@ -1583,11 +1681,28 @@ def makeFlagConstructor(flag_list):
|
|||
code = pre + string.join(flag_list, post + pre) + post
|
||||
return code
|
||||
|
||||
class CodeBlock:
|
||||
def __init__(self, code):
|
||||
self.orig_code = code
|
||||
self.operands = OperandList(code)
|
||||
self.code = substMungedOpNames(substBitOps(code))
|
||||
# Assume all instruction flags are of the form 'IsFoo'
|
||||
instFlagRE = re.compile(r'Is.*')
|
||||
|
||||
# OpClass constants end in 'Op' except No_OpClass
|
||||
opClassRE = re.compile(r'.*Op|No_OpClass')
|
||||
|
||||
class InstObjParams:
|
||||
def __init__(self, mnem, class_name, base_class = '',
|
||||
snippets = None, opt_args = []):
|
||||
self.mnemonic = mnem
|
||||
self.class_name = class_name
|
||||
self.base_class = base_class
|
||||
compositeCode = ''
|
||||
if snippets:
|
||||
if not isinstance(snippets, dict):
|
||||
snippets = {'code' : snippets}
|
||||
for snippet in snippets.values():
|
||||
if isinstance(snippet, str):
|
||||
compositeCode += (" " + snippet)
|
||||
self.snippets = snippets
|
||||
|
||||
self.operands = OperandList(compositeCode)
|
||||
self.constructor = self.operands.concatAttrStrings('constructor')
|
||||
self.constructor += \
|
||||
'\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs
|
||||
|
@ -1597,28 +1712,10 @@ class CodeBlock:
|
|||
'\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs
|
||||
self.constructor += \
|
||||
'\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs
|
||||
|
||||
self.op_decl = self.operands.concatAttrStrings('op_decl')
|
||||
|
||||
is_src = lambda op: op.is_src
|
||||
is_dest = lambda op: op.is_dest
|
||||
|
||||
self.op_src_decl = \
|
||||
self.operands.concatSomeAttrStrings(is_src, 'op_src_decl')
|
||||
self.op_dest_decl = \
|
||||
self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
|
||||
|
||||
self.op_rd = self.operands.concatAttrStrings('op_rd')
|
||||
self.op_wb = self.operands.concatAttrStrings('op_wb')
|
||||
|
||||
self.flags = self.operands.concatAttrLists('flags')
|
||||
|
||||
if self.operands.memOperand:
|
||||
self.mem_acc_size = self.operands.memOperand.mem_acc_size
|
||||
self.mem_acc_type = self.operands.memOperand.mem_acc_type
|
||||
|
||||
# Make a basic guess on the operand class (function unit type).
|
||||
# These are good enough for most cases, and will be overridden
|
||||
# These are good enough for most cases, and can be overridden
|
||||
# later otherwise.
|
||||
if 'IsStore' in self.flags:
|
||||
self.op_class = 'MemWriteOp'
|
||||
|
@ -1629,48 +1726,6 @@ class CodeBlock:
|
|||
else:
|
||||
self.op_class = 'IntAluOp'
|
||||
|
||||
# Assume all instruction flags are of the form 'IsFoo'
|
||||
instFlagRE = re.compile(r'Is.*')
|
||||
|
||||
# OpClass constants end in 'Op' except No_OpClass
|
||||
opClassRE = re.compile(r'.*Op|No_OpClass')
|
||||
|
||||
class InstObjParams:
|
||||
def __init__(self, mnem, class_name, base_class = '',
|
||||
code = None, opt_args = [], extras = {}):
|
||||
self.mnemonic = mnem
|
||||
self.class_name = class_name
|
||||
self.base_class = base_class
|
||||
if code:
|
||||
#If the user already made a CodeBlock, pick the parts from it
|
||||
if isinstance(code, CodeBlock):
|
||||
origCode = code.orig_code
|
||||
codeBlock = code
|
||||
else:
|
||||
origCode = code
|
||||
codeBlock = CodeBlock(code)
|
||||
stringExtras = {}
|
||||
otherExtras = {}
|
||||
for (k, v) in extras.items():
|
||||
if type(v) == str:
|
||||
stringExtras[k] = v
|
||||
else:
|
||||
otherExtras[k] = v
|
||||
compositeCode = "\n".join([origCode] + stringExtras.values())
|
||||
# compositeCode = '\n'.join([origCode] +
|
||||
# [pair[1] for pair in extras])
|
||||
compositeBlock = CodeBlock(compositeCode)
|
||||
for code_attr in compositeBlock.__dict__.keys():
|
||||
setattr(self, code_attr, getattr(compositeBlock, code_attr))
|
||||
for (key, snippet) in stringExtras.items():
|
||||
setattr(self, key, CodeBlock(snippet).code)
|
||||
for (key, item) in otherExtras.items():
|
||||
setattr(self, key, item)
|
||||
self.code = codeBlock.code
|
||||
self.orig_code = origCode
|
||||
else:
|
||||
self.constructor = ''
|
||||
self.flags = []
|
||||
# Optional arguments are assumed to be either StaticInst flags
|
||||
# or an OpClass value. To avoid having to import a complete
|
||||
# list of these values to match against, we do it ad-hoc
|
||||
|
|
|
@ -173,6 +173,11 @@ namespace MipsISA
|
|||
}
|
||||
};
|
||||
|
||||
static inline int flattenIntIndex(ThreadContext * tc, int reg)
|
||||
{
|
||||
return reg;
|
||||
}
|
||||
|
||||
void copyRegs(ThreadContext *src, ThreadContext *dest);
|
||||
|
||||
void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
|
||||
|
|
|
@ -32,51 +32,22 @@
|
|||
#ifndef __ARCH_MIPS_SYSCALLRETURN_HH__
|
||||
#define __ARCH_MIPS_SYSCALLRETURN_HH__
|
||||
|
||||
class SyscallReturn {
|
||||
public:
|
||||
template <class T>
|
||||
SyscallReturn(T v, bool s)
|
||||
{
|
||||
retval = (uint32_t)v;
|
||||
success = s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SyscallReturn(T v)
|
||||
{
|
||||
success = (v >= 0);
|
||||
retval = (uint32_t)v;
|
||||
}
|
||||
|
||||
~SyscallReturn() {}
|
||||
|
||||
SyscallReturn& operator=(const SyscallReturn& s) {
|
||||
retval = s.retval;
|
||||
success = s.success;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool successful() { return success; }
|
||||
uint64_t value() { return retval; }
|
||||
|
||||
|
||||
private:
|
||||
uint64_t retval;
|
||||
bool success;
|
||||
};
|
||||
#include "sim/syscallreturn.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
|
||||
namespace MipsISA
|
||||
{
|
||||
static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs)
|
||||
static inline void setSyscallReturn(SyscallReturn return_value,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
if (return_value.successful()) {
|
||||
// no error
|
||||
regs->setIntReg(SyscallSuccessReg, 0);
|
||||
regs->setIntReg(ReturnValueReg1, return_value.value());
|
||||
tc->setIntReg(SyscallSuccessReg, 0);
|
||||
tc->setIntReg(ReturnValueReg1, return_value.value());
|
||||
} else {
|
||||
// got an error, return details
|
||||
regs->setIntReg(SyscallSuccessReg, (IntReg) -1);
|
||||
regs->setIntReg(ReturnValueReg1, -return_value.value());
|
||||
tc->setIntReg(SyscallSuccessReg, (IntReg) -1);
|
||||
tc->setIntReg(ReturnValueReg1, -return_value.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -302,10 +302,12 @@ void doREDFault(ThreadContext *tc, TrapType tt)
|
|||
MiscReg TSTATE = tc->readMiscReg(MISCREG_TSTATE);
|
||||
MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE);
|
||||
MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
||||
MiscReg CCR = tc->readMiscReg(MISCREG_CCR);
|
||||
//MiscReg CCR = tc->readMiscReg(MISCREG_CCR);
|
||||
MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);
|
||||
MiscReg ASI = tc->readMiscReg(MISCREG_ASI);
|
||||
MiscReg CWP = tc->readMiscReg(MISCREG_CWP);
|
||||
MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
||||
//MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
||||
MiscReg CANSAVE = tc->readMiscReg(NumIntArchRegs + 3);
|
||||
MiscReg GL = tc->readMiscReg(MISCREG_GL);
|
||||
MiscReg PC = tc->readPC();
|
||||
MiscReg NPC = tc->readNextPC();
|
||||
|
@ -396,10 +398,12 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
|
|||
MiscReg TSTATE = tc->readMiscReg(MISCREG_TSTATE);
|
||||
MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE);
|
||||
MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
|
||||
MiscReg CCR = tc->readMiscReg(MISCREG_CCR);
|
||||
//MiscReg CCR = tc->readMiscReg(MISCREG_CCR);
|
||||
MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);
|
||||
MiscReg ASI = tc->readMiscReg(MISCREG_ASI);
|
||||
MiscReg CWP = tc->readMiscReg(MISCREG_CWP);
|
||||
MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
||||
//MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
|
||||
MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3);
|
||||
MiscReg GL = tc->readMiscReg(MISCREG_GL);
|
||||
MiscReg PC = tc->readPC();
|
||||
MiscReg NPC = tc->readNextPC();
|
||||
|
@ -679,19 +683,21 @@ void PageTableFault::invoke(ThreadContext *tc)
|
|||
{
|
||||
Process *p = tc->getProcessPtr();
|
||||
|
||||
// address is higher than the stack region or in the current stack region
|
||||
if (vaddr > p->stack_base || vaddr > p->stack_min)
|
||||
FaultBase::invoke(tc);
|
||||
|
||||
// We've accessed the next page
|
||||
if (vaddr > p->stack_min - PageBytes) {
|
||||
// We've accessed the next page of the stack, so extend the stack
|
||||
// to cover it.
|
||||
if(vaddr < p->stack_min && vaddr >= p->stack_min - PageBytes)
|
||||
{
|
||||
p->stack_min -= PageBytes;
|
||||
if(p->stack_base - p->stack_min > 8*1024*1024)
|
||||
fatal("Over max stack size for one thread\n");
|
||||
p->pTable->allocate(p->stack_min, PageBytes);
|
||||
warn("Increasing stack size by one page.");
|
||||
} else {
|
||||
FaultBase::invoke(tc);
|
||||
}
|
||||
// Otherwise, we have an unexpected page fault. Report that fact,
|
||||
// and what address was accessed to cause the fault.
|
||||
else
|
||||
{
|
||||
panic("Page table fault when accessing virtual address %#x\n", vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ void IntRegFile::clear()
|
|||
memset(regGlobals[x], 0, sizeof(IntReg) * RegsPerFrame);
|
||||
for(int x = 0; x < 2 * NWindows; x++)
|
||||
memset(regSegments[x], 0, sizeof(IntReg) * RegsPerFrame);
|
||||
memset(regs, 0, sizeof(IntReg) * NumIntRegs);
|
||||
}
|
||||
|
||||
IntRegFile::IntRegFile()
|
||||
|
@ -78,6 +79,8 @@ IntRegFile::IntRegFile()
|
|||
|
||||
IntReg IntRegFile::readReg(int intReg)
|
||||
{
|
||||
DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, regs[intReg]);
|
||||
return regs[intReg];
|
||||
IntReg val;
|
||||
if(intReg < NumIntArchRegs)
|
||||
val = regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask];
|
||||
|
@ -93,6 +96,12 @@ IntReg IntRegFile::readReg(int intReg)
|
|||
|
||||
void IntRegFile::setReg(int intReg, const IntReg &val)
|
||||
{
|
||||
if(intReg)
|
||||
{
|
||||
DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val);
|
||||
regs[intReg] = val;
|
||||
}
|
||||
return;
|
||||
if(intReg)
|
||||
{
|
||||
DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "arch/sparc/isa_traits.hh"
|
||||
#include "arch/sparc/types.hh"
|
||||
#include "base/bitfield.hh"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -54,15 +55,19 @@ namespace SparcISA
|
|||
private:
|
||||
friend class RegFile;
|
||||
protected:
|
||||
//The number of bits needed to index into each 8 register frame
|
||||
static const int FrameOffsetBits = 3;
|
||||
//The number of bits to choose between the 4 sets of 8 registers
|
||||
static const int FrameNumBits = 2;
|
||||
|
||||
//The number of registers per "frame" (8)
|
||||
static const int RegsPerFrame = 1 << FrameOffsetBits;
|
||||
static const int FrameNumMask =
|
||||
//A mask to get the frame number
|
||||
static const uint64_t FrameNumMask =
|
||||
(FrameNumBits == sizeof(int)) ?
|
||||
(unsigned int)(-1) :
|
||||
(1 << FrameNumBits) - 1;
|
||||
static const int FrameOffsetMask =
|
||||
static const uint64_t FrameOffsetMask =
|
||||
(FrameOffsetBits == sizeof(int)) ?
|
||||
(unsigned int)(-1) :
|
||||
(1 << FrameOffsetBits) - 1;
|
||||
|
@ -70,6 +75,7 @@ namespace SparcISA
|
|||
IntReg regGlobals[MaxGL+1][RegsPerFrame];
|
||||
IntReg regSegments[2 * NWindows][RegsPerFrame];
|
||||
IntReg microRegs[NumMicroIntRegs];
|
||||
IntReg regs[NumIntRegs];
|
||||
|
||||
enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames};
|
||||
|
||||
|
|
|
@ -76,9 +76,15 @@ decode OP default Unknown::unknown()
|
|||
}});
|
||||
0x2: bpccx(19, {{
|
||||
if(passesCondition(Ccr<7:4>, COND2))
|
||||
{
|
||||
//warn("Took branch!\n");
|
||||
NNPC = xc->readPC() + disp;
|
||||
}
|
||||
else
|
||||
{
|
||||
//warn("Didn't take branch!\n");
|
||||
handle_annul
|
||||
}
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
@ -247,16 +253,14 @@ decode OP default Unknown::unknown()
|
|||
((Rs1 & val2) | (carryin & (Rs1 | val2)))<0:>)<63:>}},
|
||||
{{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
|
||||
);
|
||||
0x1A: umulcc({{
|
||||
0x1A: IntOpCcRes::umulcc({{
|
||||
uint64_t resTemp;
|
||||
Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>;
|
||||
Y = resTemp<63:32>;}},
|
||||
{{0}},{{0}},{{0}},{{0}});
|
||||
0x1B: smulcc({{
|
||||
Y = resTemp<63:32>;}});
|
||||
0x1B: IntOpCcRes::smulcc({{
|
||||
int64_t resTemp;
|
||||
Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>;
|
||||
Y = resTemp<63:32>;}},
|
||||
{{0}},{{0}},{{0}},{{0}});
|
||||
Y = resTemp<63:32>;}});
|
||||
0x1C: subccc({{
|
||||
int64_t resTemp, val2 = Rs2_or_imm13;
|
||||
int64_t carryin = Ccr<0:0>;
|
||||
|
@ -266,10 +270,9 @@ decode OP default Unknown::unknown()
|
|||
{{(~((Rs1<63:1> + (~(val2 + carryin))<63:1>) + (Rs1<0:> + (~(val2+carryin))<0:> + 1)<63:1>))<63:>}},
|
||||
{{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}}
|
||||
);
|
||||
0x1D: udivxcc({{
|
||||
0x1D: IntOpCcRes::udivxcc({{
|
||||
if(Rs2_or_imm13.udw == 0) fault = new DivisionByZero;
|
||||
else Rd = Rs1.udw / Rs2_or_imm13.udw;}}
|
||||
,{{0}},{{0}},{{0}},{{0}});
|
||||
else Rd = Rs1.udw / Rs2_or_imm13.udw;}});
|
||||
0x1E: udivcc({{
|
||||
uint32_t resTemp, val2 = Rs2_or_imm13.udw;
|
||||
int32_t overflow = 0;
|
||||
|
@ -880,16 +883,11 @@ decode OP default Unknown::unknown()
|
|||
}
|
||||
}});
|
||||
0x39: Branch::return({{
|
||||
//If both MemAddressNotAligned and
|
||||
//a fill trap happen, it's not clear
|
||||
//which one should be returned.
|
||||
Addr target = Rs1 + Rs2_or_imm13;
|
||||
if(target & 0x3)
|
||||
fault = new MemAddressNotAligned;
|
||||
else
|
||||
NNPC = target;
|
||||
if(fault == NoFault)
|
||||
{
|
||||
//Check for fills which are higher priority than alignment
|
||||
//faults.
|
||||
if(Canrestore == 0)
|
||||
{
|
||||
if(Otherwin)
|
||||
|
@ -897,18 +895,15 @@ decode OP default Unknown::unknown()
|
|||
else
|
||||
fault = new FillNNormal(Wstate<2:0>);
|
||||
}
|
||||
//Check for alignment faults
|
||||
else if(target & 0x3)
|
||||
fault = new MemAddressNotAligned;
|
||||
else
|
||||
{
|
||||
//CWP should be set directly so that it always happens
|
||||
//Also, this will allow writing to the new window and
|
||||
//reading from the old one
|
||||
NNPC = target;
|
||||
Cwp = (Cwp - 1 + NWindows) % NWindows;
|
||||
Cansave = Cansave + 1;
|
||||
Canrestore = Canrestore - 1;
|
||||
//This is here to make sure the CWP is written
|
||||
//no matter what. This ensures that the results
|
||||
//are written in the new window as well.
|
||||
xc->setMiscRegWithEffect(MISCREG_CWP, Cwp);
|
||||
}
|
||||
}
|
||||
}});
|
||||
|
@ -926,7 +921,7 @@ decode OP default Unknown::unknown()
|
|||
xc->syscall(R1);
|
||||
#endif
|
||||
}
|
||||
}});
|
||||
}}, IsSerializeAfter, IsNonSpeculative);
|
||||
0x2: Trap::tccx({{
|
||||
if(passesCondition(Ccr<7:4>, COND2))
|
||||
{
|
||||
|
@ -939,36 +934,27 @@ decode OP default Unknown::unknown()
|
|||
xc->syscall(R1);
|
||||
#endif
|
||||
}
|
||||
}});
|
||||
}}, IsSerializeAfter, IsNonSpeculative);
|
||||
}
|
||||
0x3B: Nop::flush({{/*Instruction memory flush*/}});
|
||||
0x3C: save({{
|
||||
//CWP should be set directly so that it always happens
|
||||
//Also, this will allow writing to the new window and
|
||||
//reading from the old one
|
||||
if(Cansave == 0)
|
||||
{
|
||||
if(Otherwin)
|
||||
fault = new SpillNOther(Wstate<5:3>);
|
||||
else
|
||||
fault = new SpillNNormal(Wstate<2:0>);
|
||||
//Cwp = (Cwp + 2) % NWindows;
|
||||
}
|
||||
else if(Cleanwin - Canrestore == 0)
|
||||
{
|
||||
//Cwp = (Cwp + 1) % NWindows;
|
||||
fault = new CleanWindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cwp = (Cwp + 1) % NWindows;
|
||||
Rd = Rs1 + Rs2_or_imm13;
|
||||
Rd_next = Rs1 + Rs2_or_imm13;
|
||||
Cansave = Cansave - 1;
|
||||
Canrestore = Canrestore + 1;
|
||||
//This is here to make sure the CWP is written
|
||||
//no matter what. This ensures that the results
|
||||
//are written in the new window as well.
|
||||
xc->setMiscRegWithEffect(MISCREG_CWP, Cwp);
|
||||
}
|
||||
}});
|
||||
0x3D: restore({{
|
||||
|
@ -981,17 +967,10 @@ decode OP default Unknown::unknown()
|
|||
}
|
||||
else
|
||||
{
|
||||
//CWP should be set directly so that it always happens
|
||||
//Also, this will allow writing to the new window and
|
||||
//reading from the old one
|
||||
Cwp = (Cwp - 1 + NWindows) % NWindows;
|
||||
Rd = Rs1 + Rs2_or_imm13;
|
||||
Rd_prev = Rs1 + Rs2_or_imm13;
|
||||
Cansave = Cansave + 1;
|
||||
Canrestore = Canrestore - 1;
|
||||
//This is here to make sure the CWP is written
|
||||
//no matter what. This ensures that the results
|
||||
//are written in the new window as well.
|
||||
xc->setMiscRegWithEffect(MISCREG_CWP, Cwp);
|
||||
}
|
||||
}});
|
||||
0x3E: decode FCN {
|
||||
|
|
|
@ -95,8 +95,7 @@ def template BasicDecodeWithMnemonic {{
|
|||
|
||||
// The most basic instruction format... used only for a few misc. insts
|
||||
def format BasicOperate(code, *flags) {{
|
||||
iop = InstObjParams(name, Name, 'SparcStaticInst',
|
||||
CodeBlock(code), flags)
|
||||
iop = InstObjParams(name, Name, 'SparcStaticInst', code, flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
decode_block = BasicDecode.subst(iop)
|
||||
|
|
|
@ -170,7 +170,7 @@ output decoder {{
|
|||
printMnemonic(response, mnemonic);
|
||||
ccprintf(response, "0x%x", target);
|
||||
|
||||
if(symtab->findNearestSymbol(target, symbol, symbolAddr))
|
||||
if(symtab && symtab->findNearestSymbol(target, symbol, symbolAddr))
|
||||
{
|
||||
ccprintf(response, " <%s", symbol);
|
||||
if(symbolAddr != target)
|
||||
|
@ -178,6 +178,10 @@ output decoder {{
|
|||
else
|
||||
ccprintf(response, ">");
|
||||
}
|
||||
else
|
||||
{
|
||||
ccprintf(response, "<%d>", target);
|
||||
}
|
||||
|
||||
return response.str();
|
||||
}
|
||||
|
@ -244,7 +248,6 @@ def format Branch(code, *opt_flags) {{
|
|||
// Primary format for branch instructions:
|
||||
def format BranchN(bits, code, *opt_flags) {{
|
||||
code = re.sub(r'handle_annul', handle_annul, code)
|
||||
codeBlk = CodeBlock(code)
|
||||
new_opt_flags = []
|
||||
for flag in opt_flags:
|
||||
if flag == ',a':
|
||||
|
@ -252,7 +255,7 @@ def format BranchN(bits, code, *opt_flags) {{
|
|||
Name += 'Annul'
|
||||
else:
|
||||
new_opt_flags += flag
|
||||
iop = InstObjParams(name, Name, "BranchNBits<%d>" % bits, codeBlk, new_opt_flags)
|
||||
iop = InstObjParams(name, Name, "BranchNBits<%d>" % bits, code, new_opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
exec_output = BranchExecute.subst(iop)
|
||||
|
@ -262,8 +265,7 @@ def format BranchN(bits, code, *opt_flags) {{
|
|||
// Primary format for branch instructions:
|
||||
def format BranchSplit(code, *opt_flags) {{
|
||||
code = re.sub(r'handle_annul', handle_annul, code)
|
||||
codeBlk = CodeBlock(code)
|
||||
iop = InstObjParams(name, Name, 'BranchSplit', codeBlk, opt_flags)
|
||||
iop = InstObjParams(name, Name, 'BranchSplit', code, opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
exec_output = BranchExecute.subst(iop)
|
||||
|
|
|
@ -263,14 +263,15 @@ let {{
|
|||
def doIntFormat(code, ccCode, name, Name, opt_flags):
|
||||
(usesImm, code, immCode,
|
||||
rString, iString) = splitOutImm(code)
|
||||
iop = InstObjParams(name, Name, 'IntOp', code,
|
||||
opt_flags, {"cc_code": ccCode})
|
||||
iop = InstObjParams(name, Name, 'IntOp',
|
||||
{"code": code, "cc_code": ccCode},
|
||||
opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
exec_output = IntOpExecute.subst(iop)
|
||||
if usesImm:
|
||||
imm_iop = InstObjParams(name, Name + 'Imm', 'IntOpImm' + iString,
|
||||
immCode, opt_flags, {"cc_code": ccCode})
|
||||
{"code": immCode, "cc_code": ccCode}, opt_flags)
|
||||
header_output += BasicDeclare.subst(imm_iop)
|
||||
decoder_output += BasicConstructor.subst(imm_iop)
|
||||
exec_output += IntOpExecute.subst(imm_iop)
|
||||
|
@ -341,7 +342,7 @@ def format IntOpCcRes(code, *opt_flags) {{
|
|||
|
||||
def format SetHi(code, *opt_flags) {{
|
||||
iop = InstObjParams(name, Name, 'SetHi',
|
||||
code, opt_flags, {"cc_code": ''})
|
||||
{"code": code, "cc_code": ''}, opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
exec_output = IntOpExecute.subst(iop)
|
||||
|
|
|
@ -55,16 +55,20 @@ let {{
|
|||
def doMemFormat(code, execute, faultCode, name, Name, asi, opt_flags):
|
||||
addrCalcReg = 'EA = Rs1 + Rs2;'
|
||||
addrCalcImm = 'EA = Rs1 + imm;'
|
||||
iop = InstObjParams(name, Name, 'Mem', code,
|
||||
opt_flags, {"fault_check": faultCode, "ea_code": addrCalcReg})
|
||||
iop_imm = InstObjParams(name, Name + "Imm", 'MemImm', code,
|
||||
opt_flags, {"fault_check": faultCode, "ea_code": addrCalcImm})
|
||||
iop = InstObjParams(name, Name, 'Mem',
|
||||
{"code": code, "fault_check": faultCode,
|
||||
"ea_code": addrCalcReg},
|
||||
opt_flags)
|
||||
iop_imm = InstObjParams(name, Name + "Imm", 'MemImm',
|
||||
{"code": code, "fault_check": faultCode,
|
||||
"ea_code": addrCalcImm},
|
||||
opt_flags)
|
||||
header_output = MemDeclare.subst(iop) + MemDeclare.subst(iop_imm)
|
||||
decoder_output = BasicConstructor.subst(iop) + BasicConstructor.subst(iop_imm)
|
||||
decode_block = ROrImmDecode.subst(iop)
|
||||
exec_output = doDualSplitExecute(code, addrCalcReg, addrCalcImm,
|
||||
execute, faultCode, name, name + "Imm", Name, Name + "Imm",
|
||||
asi, opt_flags)
|
||||
execute, faultCode, name, name + "Imm",
|
||||
Name, Name + "Imm", opt_flags)
|
||||
return (header_output, decoder_output, exec_output, decode_block)
|
||||
}};
|
||||
|
||||
|
@ -72,7 +76,7 @@ def format LoadAlt(code, asi, *opt_flags) {{
|
|||
(header_output,
|
||||
decoder_output,
|
||||
exec_output,
|
||||
decode_block) = doMemFormat(code, LoadExecute,
|
||||
decode_block) = doMemFormat(code, LoadFuncs,
|
||||
AlternateASIPrivFaultCheck, name, Name, asi, opt_flags)
|
||||
}};
|
||||
|
||||
|
@ -80,7 +84,7 @@ def format StoreAlt(code, asi, *opt_flags) {{
|
|||
(header_output,
|
||||
decoder_output,
|
||||
exec_output,
|
||||
decode_block) = doMemFormat(code, StoreExecute,
|
||||
decode_block) = doMemFormat(code, StoreFuncs,
|
||||
AlternateASIPrivFaultCheck, name, Name, asi, opt_flags)
|
||||
}};
|
||||
|
||||
|
@ -89,7 +93,7 @@ def format Load(code, *opt_flags) {{
|
|||
decoder_output,
|
||||
exec_output,
|
||||
decode_block) = doMemFormat(code,
|
||||
LoadExecute, '', name, Name, 0, opt_flags)
|
||||
LoadFuncs, '', name, Name, 0, opt_flags)
|
||||
}};
|
||||
|
||||
def format Store(code, *opt_flags) {{
|
||||
|
@ -97,5 +101,5 @@ def format Store(code, *opt_flags) {{
|
|||
decoder_output,
|
||||
exec_output,
|
||||
decode_block) = doMemFormat(code,
|
||||
StoreExecute, '', name, Name, 0, opt_flags)
|
||||
StoreFuncs, '', name, Name, 0, opt_flags)
|
||||
}};
|
||||
|
|
|
@ -293,14 +293,14 @@ let {{
|
|||
else:
|
||||
flag_code = "flags[IsDelayedCommit] = true;"
|
||||
pcedCode = matcher.sub("Frd_%d" % microPc, code)
|
||||
iop = InstObjParams(name, Name, 'BlockMem', pcedCode,
|
||||
opt_flags, {"ea_code": addrCalcReg,
|
||||
iop = InstObjParams(name, Name, 'BlockMem',
|
||||
{"code": pcedCode, "ea_code": addrCalcReg,
|
||||
"fault_check": faultCode, "micro_pc": microPc,
|
||||
"set_flags": flag_code})
|
||||
iop_imm = InstObjParams(name, Name + 'Imm', 'BlockMemImm', pcedCode,
|
||||
opt_flags, {"ea_code": addrCalcImm,
|
||||
"set_flags": flag_code}, opt_flags)
|
||||
iop_imm = InstObjParams(name, Name + 'Imm', 'BlockMemImm',
|
||||
{"code": pcedCode, "ea_code": addrCalcImm,
|
||||
"fault_check": faultCode, "micro_pc": microPc,
|
||||
"set_flags": flag_code})
|
||||
"set_flags": flag_code}, opt_flags)
|
||||
decoder_output += BlockMemMicroConstructor.subst(iop)
|
||||
decoder_output += BlockMemMicroConstructor.subst(iop_imm)
|
||||
exec_output += doDualSplitExecute(
|
||||
|
@ -323,7 +323,7 @@ def format BlockLoad(code, asi, *opt_flags) {{
|
|||
decoder_output,
|
||||
exec_output,
|
||||
decode_block) = doBlockMemFormat(code, faultCode,
|
||||
LoadExecute, name, Name, asi, opt_flags)
|
||||
LoadFuncs, name, Name, asi, opt_flags)
|
||||
}};
|
||||
|
||||
def format BlockStore(code, asi, *opt_flags) {{
|
||||
|
@ -335,5 +335,5 @@ def format BlockStore(code, asi, *opt_flags) {{
|
|||
decoder_output,
|
||||
exec_output,
|
||||
decode_block) = doBlockMemFormat(code, faultCode,
|
||||
StoreExecute, name, Name, asi, opt_flags)
|
||||
StoreFuncs, name, Name, asi, opt_flags)
|
||||
}};
|
||||
|
|
|
@ -144,7 +144,7 @@ def template LoadExecute {{
|
|||
%(op_decl)s;
|
||||
%(op_rd)s;
|
||||
%(ea_code)s;
|
||||
DPRINTF(Sparc, "The address is 0x%x\n", EA);
|
||||
DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
|
||||
%(fault_check)s;
|
||||
if(fault == NoFault)
|
||||
{
|
||||
|
@ -162,16 +162,19 @@ def template LoadExecute {{
|
|||
|
||||
return fault;
|
||||
}
|
||||
}};
|
||||
|
||||
def template LoadInitiateAcc {{
|
||||
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;
|
||||
%(ea_decl)s;
|
||||
%(ea_rd)s;
|
||||
%(op_decl)s;
|
||||
%(op_rd)s;
|
||||
%(ea_code)s;
|
||||
DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
|
||||
%(fault_check)s;
|
||||
if(fault == NoFault)
|
||||
{
|
||||
|
@ -179,18 +182,20 @@ def template LoadExecute {{
|
|||
}
|
||||
return fault;
|
||||
}
|
||||
}};
|
||||
|
||||
def template LoadCompleteAcc {{
|
||||
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;
|
||||
%(op_decl)s;
|
||||
%(op_rd)s;
|
||||
Mem = pkt->get<typeof(Mem)>();
|
||||
%(code)s;
|
||||
if(fault == NoFault)
|
||||
{
|
||||
%(code_wb)s;
|
||||
%(op_wb)s;
|
||||
}
|
||||
return fault;
|
||||
}
|
||||
|
@ -209,7 +214,7 @@ def template StoreExecute {{
|
|||
%(op_decl)s;
|
||||
%(op_rd)s;
|
||||
%(ea_code)s;
|
||||
DPRINTF(Sparc, "The address is 0x%x\n", EA);
|
||||
DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
|
||||
%(fault_check)s;
|
||||
if(fault == NoFault)
|
||||
{
|
||||
|
@ -228,7 +233,9 @@ def template StoreExecute {{
|
|||
|
||||
return fault;
|
||||
}
|
||||
}};
|
||||
|
||||
def template StoreInitiateAcc {{
|
||||
Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s * xc,
|
||||
Trace::InstRecord * traceData) const
|
||||
{
|
||||
|
@ -238,7 +245,7 @@ def template StoreExecute {{
|
|||
%(op_decl)s;
|
||||
%(op_rd)s;
|
||||
%(ea_code)s;
|
||||
DPRINTF(Sparc, "The address is 0x%x\n", EA);
|
||||
DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
|
||||
%(fault_check)s;
|
||||
if(fault == NoFault)
|
||||
{
|
||||
|
@ -256,7 +263,9 @@ def template StoreExecute {{
|
|||
}
|
||||
return fault;
|
||||
}
|
||||
}};
|
||||
|
||||
def template StoreCompleteAcc {{
|
||||
Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc,
|
||||
Trace::InstRecord * traceData) const
|
||||
{
|
||||
|
@ -276,6 +285,8 @@ def template CompleteAccDeclare {{
|
|||
|
||||
//Here are some code snippets which check for various fault conditions
|
||||
let {{
|
||||
LoadFuncs = [LoadExecute, LoadInitiateAcc, LoadCompleteAcc]
|
||||
StoreFuncs = [StoreExecute, StoreInitiateAcc, StoreCompleteAcc]
|
||||
# The LSB can be zero, since it's really the MSB in doubles and quads
|
||||
# and we're dealing with doubles
|
||||
BlockAlignmentFaultCheck = '''
|
||||
|
@ -310,21 +321,11 @@ let {{
|
|||
//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):
|
||||
def doSplitExecute(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)
|
||||
iop = InstObjParams(name, Name, '', microParam, opt_flags)
|
||||
(execf, initf, compf) = execute
|
||||
return execf.subst(iop) + initf.subst(iop) + compf.subst(iop)
|
||||
|
||||
|
||||
def doDualSplitExecute(code, eaRegCode, eaImmCode, execute,
|
||||
|
@ -333,8 +334,9 @@ let {{
|
|||
for (eaCode, name, Name) in (
|
||||
(eaRegCode, nameReg, NameReg),
|
||||
(eaImmCode, nameImm, NameImm)):
|
||||
microParams = {"ea_code" : eaCode, "fault_check": faultCode}
|
||||
executeCode += doSplitExecute(code, execute, name, Name,
|
||||
microParams = {"code": code, "ea_code": eaCode,
|
||||
"fault_check": faultCode}
|
||||
executeCode += doSplitExecute(execute, name, Name,
|
||||
asi, opt_flags, microParams)
|
||||
return executeCode
|
||||
}};
|
||||
|
|
|
@ -88,9 +88,7 @@ def template NopExecute {{
|
|||
|
||||
// Primary format for integer operate instructions:
|
||||
def format Nop(code, *opt_flags) {{
|
||||
orig_code = code
|
||||
cblk = CodeBlock(code)
|
||||
iop = InstObjParams(name, Name, 'Nop', cblk, opt_flags)
|
||||
iop = InstObjParams(name, Name, 'Nop', code, opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
decode_block = BasicDecode.subst(iop)
|
||||
|
|
|
@ -235,8 +235,9 @@ let {{
|
|||
name = mnem
|
||||
regBase = 'WrPriv'
|
||||
break
|
||||
iop = InstObjParams(name, Name, regBase, code,
|
||||
opt_flags, {"check": checkCode, "reg_name": regName})
|
||||
iop = InstObjParams(name, Name, regBase,
|
||||
{"code": code, "check": checkCode, "reg_name": regName},
|
||||
opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
if regName == '':
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
|
@ -245,7 +246,8 @@ let {{
|
|||
exec_output = PrivExecute.subst(iop)
|
||||
if usesImm:
|
||||
imm_iop = InstObjParams(name, Name + 'Imm', regBase + 'Imm',
|
||||
immCode, opt_flags, {"check": checkCode, "reg_name": regName})
|
||||
{"code": immCode, "check": checkCode, "reg_name": regName},
|
||||
opt_flags)
|
||||
header_output += BasicDeclare.subst(imm_iop)
|
||||
if regName == '':
|
||||
decoder_output += BasicConstructor.subst(imm_iop)
|
||||
|
|
|
@ -83,9 +83,7 @@ def template TrapExecute {{
|
|||
}};
|
||||
|
||||
def format Trap(code, *opt_flags) {{
|
||||
orig_code = code
|
||||
cblk = CodeBlock(code)
|
||||
iop = InstObjParams(name, Name, 'Trap', cblk, opt_flags)
|
||||
iop = InstObjParams(name, Name, 'Trap', code, opt_flags)
|
||||
header_output = BasicDeclare.subst(iop)
|
||||
decoder_output = BasicConstructor.subst(iop)
|
||||
decode_block = BasicDecode.subst(iop)
|
||||
|
|
|
@ -37,12 +37,13 @@ output header {{
|
|||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "arch/sparc/faults.hh"
|
||||
#include "mem/request.hh" // some constructors use MemReq flags
|
||||
#include "mem/packet.hh"
|
||||
#include "arch/sparc/isa_traits.hh"
|
||||
#include "arch/sparc/regfile.hh"
|
||||
#include "base/misc.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/request.hh" // some constructors use MemReq flags
|
||||
}};
|
||||
|
||||
output decoder {{
|
||||
|
|
|
@ -56,12 +56,23 @@ def operands {{
|
|||
# Int regs default to unsigned, but code should not count on this.
|
||||
# For clarity, descriptions that depend on unsigned behavior should
|
||||
# explicitly specify '.uq'.
|
||||
|
||||
'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1),
|
||||
'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 2),
|
||||
'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 3),
|
||||
'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 4),
|
||||
'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 5),
|
||||
'uReg0': ('IntReg', 'udw', 'NumIntArchRegs', 'IsInteger', 6),
|
||||
# The Rd from the previous window
|
||||
'Rd_prev': ('IntReg', 'udw', 'RD + NumIntArchRegs + NumMicroIntRegs', 'IsInteger', 2),
|
||||
# The Rd from the next window
|
||||
'Rd_next': ('IntReg', 'udw', 'RD + 2 * NumIntArchRegs + NumMicroIntRegs', 'IsInteger', 3),
|
||||
# The low (even) register of a two register pair
|
||||
'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 4),
|
||||
# The high (odd) register of a two register pair
|
||||
'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 5),
|
||||
'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 6),
|
||||
'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 7),
|
||||
# A microcode register. Right now, this is the only one.
|
||||
'uReg0': ('IntReg', 'udw', 'NumIntArchRegs', 'IsInteger', 8),
|
||||
# Because double and quad precision register numbers are decoded
|
||||
# differently, they get different operands. The single precision versions
|
||||
# have an s post pended to their name.
|
||||
'Frds': ('FloatReg', 'sf', 'RD', 'IsFloating', 10),
|
||||
'Frd': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10),
|
||||
# Each Frd_N refers to the Nth double precision register from Frd.
|
||||
|
@ -80,14 +91,17 @@ def operands {{
|
|||
'Frs2': ('FloatReg', 'df', 'dfpr(RS2)', 'IsFloating', 12),
|
||||
'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 31),
|
||||
'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 32),
|
||||
# Registers which are used explicitly in instructions
|
||||
'R0': ('IntReg', 'udw', '0', None, 6),
|
||||
'R1': ('IntReg', 'udw', '1', None, 7),
|
||||
'R15': ('IntReg', 'udw', '15', 'IsInteger', 8),
|
||||
'R16': ('IntReg', 'udw', '16', None, 9),
|
||||
|
||||
# Control registers
|
||||
'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 40),
|
||||
'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 41),
|
||||
# 'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 40),
|
||||
# 'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 41),
|
||||
'Y': ('IntReg', 'udw', 'NumIntArchRegs + 1', None, 40),
|
||||
'Ccr': ('IntReg', 'udw', 'NumIntArchRegs + 2', None, 41),
|
||||
'Asi': ('ControlReg', 'udw', 'MISCREG_ASI', None, 42),
|
||||
'Fprs': ('ControlReg', 'udw', 'MISCREG_FPRS', None, 43),
|
||||
'Pcr': ('ControlReg', 'udw', 'MISCREG_PCR', None, 44),
|
||||
|
@ -109,12 +123,17 @@ def operands {{
|
|||
'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 59),
|
||||
'Tl': ('ControlReg', 'udw', 'MISCREG_TL', None, 60),
|
||||
'Pil': ('ControlReg', 'udw', 'MISCREG_PIL', None, 61),
|
||||
'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 62),
|
||||
'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 63),
|
||||
'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 64),
|
||||
'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 65),
|
||||
'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 66),
|
||||
'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 67),
|
||||
'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 62),
|
||||
# 'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 63),
|
||||
# 'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 64),
|
||||
# 'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 65),
|
||||
# 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 66),
|
||||
# 'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 67),
|
||||
'Cansave': ('IntReg', 'udw', 'NumIntArchRegs + 3', None, 63),
|
||||
'Canrestore': ('IntReg', 'udw', 'NumIntArchRegs + 4', None, 64),
|
||||
'Cleanwin': ('IntReg', 'udw', 'NumIntArchRegs + 5', None, 65),
|
||||
'Otherwin': ('IntReg', 'udw', 'NumIntArchRegs + 6', None, 66),
|
||||
'Wstate': ('IntReg', 'udw', 'NumIntArchRegs + 7', None, 67),
|
||||
'Gl': ('ControlReg', 'udw', 'MISCREG_GL', None, 68),
|
||||
|
||||
'Hpstate': ('ControlReg', 'udw', 'MISCREG_HPSTATE', None, 69),
|
||||
|
|
|
@ -58,8 +58,8 @@ namespace SparcISA
|
|||
|
||||
// These enumerate all the registers for dependence tracking.
|
||||
enum DependenceTags {
|
||||
FP_Base_DepTag = 33,
|
||||
Ctrl_Base_DepTag = 97,
|
||||
FP_Base_DepTag = 32*3+8,
|
||||
Ctrl_Base_DepTag = FP_Base_DepTag + 64,
|
||||
};
|
||||
|
||||
// semantically meaningful register indices
|
||||
|
|
|
@ -46,15 +46,9 @@ class Checkpoint;
|
|||
string SparcISA::getMiscRegName(RegIndex index)
|
||||
{
|
||||
static::string miscRegName[NumMiscRegs] =
|
||||
{"y", "ccr", "asi", "tick", "fprs", "pcr", "pic",
|
||||
"gsr", "softint_set", "softint_clr", "softint", "tick_cmpr",
|
||||
"stick", "stick_cmpr",
|
||||
"tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl",
|
||||
"pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
|
||||
"wstate", "gl",
|
||||
"hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg",
|
||||
"hstick_cmpr",
|
||||
"fsr"};
|
||||
{/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic",
|
||||
"pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin",
|
||||
"wstate",*/ "gl",
|
||||
return miscRegName[index];
|
||||
}
|
||||
|
||||
|
|
|
@ -47,8 +47,8 @@ namespace SparcISA
|
|||
enum MiscRegIndex
|
||||
{
|
||||
/** Ancillary State Registers */
|
||||
MISCREG_Y, /* 0 */
|
||||
MISCREG_CCR,
|
||||
// MISCREG_Y,
|
||||
// MISCREG_CCR,
|
||||
MISCREG_ASI,
|
||||
MISCREG_TICK,
|
||||
MISCREG_FPRS,
|
||||
|
@ -73,11 +73,11 @@ namespace SparcISA
|
|||
MISCREG_TL,
|
||||
MISCREG_PIL,
|
||||
MISCREG_CWP,
|
||||
MISCREG_CANSAVE,
|
||||
MISCREG_CANRESTORE,
|
||||
MISCREG_CLEANWIN,
|
||||
MISCREG_OTHERWIN,
|
||||
MISCREG_WSTATE,
|
||||
// MISCREG_CANSAVE,
|
||||
// MISCREG_CANRESTORE,
|
||||
// MISCREG_CLEANWIN,
|
||||
// MISCREG_OTHERWIN,
|
||||
// MISCREG_WSTATE,
|
||||
MISCREG_GL,
|
||||
|
||||
/** Hyper privileged registers */
|
||||
|
|
|
@ -95,17 +95,22 @@ SparcLiveProcess::startup()
|
|||
*/
|
||||
|
||||
//No windows contain info from other programs
|
||||
threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0);
|
||||
//threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0);
|
||||
threadContexts[0]->setIntReg(NumIntArchRegs + 6, 0);
|
||||
//There are no windows to pop
|
||||
threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0);
|
||||
//threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0);
|
||||
threadContexts[0]->setIntReg(NumIntArchRegs + 4, 0);
|
||||
//All windows are available to save into
|
||||
threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2);
|
||||
//threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2);
|
||||
threadContexts[0]->setIntReg(NumIntArchRegs + 3, NWindows - 2);
|
||||
//All windows are "clean"
|
||||
threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows);
|
||||
//threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows);
|
||||
threadContexts[0]->setIntReg(NumIntArchRegs + 5, NWindows);
|
||||
//Start with register window 0
|
||||
threadContexts[0]->setMiscReg(MISCREG_CWP, 0);
|
||||
//Always use spill and fill traps 0
|
||||
threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0);
|
||||
//threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0);
|
||||
threadContexts[0]->setIntReg(NumIntArchRegs + 7, 0);
|
||||
//Set the trap level to 0
|
||||
threadContexts[0]->setMiscReg(MISCREG_TL, 0);
|
||||
//Set the ASI register to something fixed
|
||||
|
|
|
@ -151,6 +151,72 @@ void RegFile::setIntReg(int intReg, const IntReg &val)
|
|||
intRegFile.setReg(intReg, val);
|
||||
}
|
||||
|
||||
int SparcISA::flattenIntIndex(ThreadContext * tc, int reg)
|
||||
{
|
||||
int gl = tc->readMiscReg(MISCREG_GL);
|
||||
int cwp = tc->readMiscReg(MISCREG_CWP);
|
||||
//DPRINTF(Sparc, "Global Level = %d, Current Window Pointer = %d\n", gl, cwp);
|
||||
int newReg;
|
||||
if(reg < 8)
|
||||
{
|
||||
//Global register
|
||||
//Put it in the appropriate set of globals
|
||||
newReg = reg + gl * 8;
|
||||
}
|
||||
else if(reg < NumIntArchRegs)
|
||||
{
|
||||
//Regular windowed register
|
||||
//Put it in the window pointed to by cwp
|
||||
newReg = MaxGL * 8 +
|
||||
((reg - 8 - cwp * 16 + NWindows * 16) % (NWindows * 16));
|
||||
}
|
||||
else if(reg < NumIntArchRegs + NumMicroIntRegs)
|
||||
{
|
||||
//Microcode register
|
||||
//Displace from the end of the regular registers
|
||||
newReg = reg - NumIntArchRegs + MaxGL * 8 + NWindows * 16;
|
||||
}
|
||||
else if(reg < 2 * NumIntArchRegs + NumMicroIntRegs)
|
||||
{
|
||||
reg -= (NumIntArchRegs + NumMicroIntRegs);
|
||||
if(reg < 8)
|
||||
{
|
||||
//Global register from the next window
|
||||
//Put it in the appropriate set of globals
|
||||
newReg = reg + gl * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Windowed register from the previous window
|
||||
//Put it in the window before the one pointed to by cwp
|
||||
newReg = MaxGL * 8 +
|
||||
((reg - 8 - (cwp - 1) * 16 + NWindows * 16) % (NWindows * 16));
|
||||
}
|
||||
}
|
||||
else if(reg < 3 * NumIntArchRegs + NumMicroIntRegs)
|
||||
{
|
||||
reg -= (2 * NumIntArchRegs + NumMicroIntRegs);
|
||||
if(reg < 8)
|
||||
{
|
||||
//Global register from the previous window
|
||||
//Put it in the appropriate set of globals
|
||||
newReg = reg + gl * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Windowed register from the next window
|
||||
//Put it in the window after the one pointed to by cwp
|
||||
newReg = MaxGL * 8 +
|
||||
((reg - 8 - (cwp + 1) * 16 + NWindows * 16) % (NWindows * 16));
|
||||
}
|
||||
}
|
||||
else
|
||||
panic("Tried to flatten invalid register index %d!\n", reg);
|
||||
DPRINTF(Sparc, "Flattened register %d to %d.\n", reg, newReg);
|
||||
return newReg;
|
||||
//return intRegFile.flattenIndex(reg);
|
||||
}
|
||||
|
||||
void RegFile::serialize(std::ostream &os)
|
||||
{
|
||||
intRegFile.serialize(os);
|
||||
|
@ -220,8 +286,8 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
|
|||
|
||||
|
||||
// ASRs
|
||||
dest->setMiscReg(MISCREG_Y, src->readMiscReg(MISCREG_Y));
|
||||
dest->setMiscReg(MISCREG_CCR, src->readMiscReg(MISCREG_CCR));
|
||||
// dest->setMiscReg(MISCREG_Y, src->readMiscReg(MISCREG_Y));
|
||||
// dest->setMiscReg(MISCREG_CCR, src->readMiscReg(MISCREG_CCR));
|
||||
dest->setMiscReg(MISCREG_ASI, src->readMiscReg(MISCREG_ASI));
|
||||
dest->setMiscReg(MISCREG_TICK, src->readMiscReg(MISCREG_TICK));
|
||||
dest->setMiscReg(MISCREG_FPRS, src->readMiscReg(MISCREG_FPRS));
|
||||
|
@ -236,11 +302,11 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
|
|||
dest->setMiscReg(MISCREG_PSTATE, src->readMiscReg(MISCREG_PSTATE));
|
||||
dest->setMiscReg(MISCREG_PIL, src->readMiscReg(MISCREG_PIL));
|
||||
dest->setMiscReg(MISCREG_CWP, src->readMiscReg(MISCREG_CWP));
|
||||
dest->setMiscReg(MISCREG_CANSAVE, src->readMiscReg(MISCREG_CANSAVE));
|
||||
dest->setMiscReg(MISCREG_CANRESTORE, src->readMiscReg(MISCREG_CANRESTORE));
|
||||
dest->setMiscReg(MISCREG_OTHERWIN, src->readMiscReg(MISCREG_OTHERWIN));
|
||||
dest->setMiscReg(MISCREG_CLEANWIN, src->readMiscReg(MISCREG_CLEANWIN));
|
||||
dest->setMiscReg(MISCREG_WSTATE, src->readMiscReg(MISCREG_WSTATE));
|
||||
// dest->setMiscReg(MISCREG_CANSAVE, src->readMiscReg(MISCREG_CANSAVE));
|
||||
// dest->setMiscReg(MISCREG_CANRESTORE, src->readMiscReg(MISCREG_CANRESTORE));
|
||||
// dest->setMiscReg(MISCREG_OTHERWIN, src->readMiscReg(MISCREG_OTHERWIN));
|
||||
// dest->setMiscReg(MISCREG_CLEANWIN, src->readMiscReg(MISCREG_CLEANWIN));
|
||||
// dest->setMiscReg(MISCREG_WSTATE, src->readMiscReg(MISCREG_WSTATE));
|
||||
dest->setMiscReg(MISCREG_GL, src->readMiscReg(MISCREG_GL));
|
||||
|
||||
// Hyperprivilged registers
|
||||
|
|
|
@ -120,6 +120,8 @@ namespace SparcISA
|
|||
void changeContext(RegContextParam param, RegContextVal val);
|
||||
};
|
||||
|
||||
int flattenIntIndex(ThreadContext * tc, int reg);
|
||||
|
||||
void copyRegs(ThreadContext *src, ThreadContext *dest);
|
||||
|
||||
void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
|
||||
|
|
|
@ -41,7 +41,8 @@ namespace SparcISA
|
|||
|
||||
// Number of register windows, can legally be 3 to 32
|
||||
const int NWindows = 8;
|
||||
const int NumMicroIntRegs = 1;
|
||||
//const int NumMicroIntRegs = 1;
|
||||
const int NumMicroIntRegs = 8;
|
||||
|
||||
// const int NumRegularIntRegs = MaxGL * 8 + NWindows * 16;
|
||||
// const int NumMicroIntRegs = 1;
|
||||
|
|
|
@ -33,58 +33,30 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "sim/syscallreturn.hh"
|
||||
#include "arch/sparc/regfile.hh"
|
||||
|
||||
class SyscallReturn
|
||||
{
|
||||
public:
|
||||
template <class T>
|
||||
SyscallReturn(T v, bool s)
|
||||
{
|
||||
retval = (uint64_t)v;
|
||||
success = s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SyscallReturn(T v)
|
||||
{
|
||||
success = (v >= 0);
|
||||
retval = (uint64_t)v;
|
||||
}
|
||||
|
||||
~SyscallReturn() {}
|
||||
|
||||
SyscallReturn& operator=(const SyscallReturn& s)
|
||||
{
|
||||
retval = s.retval;
|
||||
success = s.success;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool successful() { return success; }
|
||||
uint64_t value() { return retval; }
|
||||
|
||||
private:
|
||||
uint64_t retval;
|
||||
bool success;
|
||||
};
|
||||
#include "cpu/thread_context.hh"
|
||||
|
||||
namespace SparcISA
|
||||
{
|
||||
static inline void setSyscallReturn(SyscallReturn return_value,
|
||||
RegFile *regs)
|
||||
ThreadContext * tc)
|
||||
{
|
||||
// check for error condition. SPARC syscall convention is to
|
||||
// indicate success/failure in reg the carry bit of the ccr
|
||||
// and put the return value itself in the standard return value reg ().
|
||||
if (return_value.successful()) {
|
||||
// no error, clear XCC.C
|
||||
regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) & 0xEE);
|
||||
regs->setIntReg(ReturnValueReg, return_value.value());
|
||||
tc->setIntReg(NumIntArchRegs + 2,
|
||||
tc->readIntReg(NumIntArchRegs + 2) & 0xEE);
|
||||
//tc->setMiscReg(MISCREG_CCR, tc->readMiscReg(MISCREG_CCR) & 0xEE);
|
||||
tc->setIntReg(ReturnValueReg, return_value.value());
|
||||
} else {
|
||||
// got an error, set XCC.C
|
||||
regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) | 0x11);
|
||||
regs->setIntReg(ReturnValueReg, return_value.value());
|
||||
tc->setIntReg(NumIntArchRegs + 2,
|
||||
tc->readIntReg(NumIntArchRegs + 2) | 0x11);
|
||||
//tc->setMiscReg(MISCREG_CCR, tc->readMiscReg(MISCREG_CCR) | 0x11);
|
||||
tc->setIntReg(ReturnValueReg, -return_value.value());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "base/fast_alloc.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "cpu/o3/comm.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "cpu/op_class.hh"
|
||||
|
@ -62,10 +63,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
|||
typedef typename Impl::CPUType ImplCPU;
|
||||
typedef typename ImplCPU::ImplState ImplState;
|
||||
|
||||
// Binary machine instruction type.
|
||||
typedef TheISA::MachInst MachInst;
|
||||
// Extended machine instruction type
|
||||
typedef TheISA::ExtMachInst ExtMachInst;
|
||||
// Logical register index type.
|
||||
typedef TheISA::RegIndex RegIndex;
|
||||
// Integer register type.
|
||||
|
@ -224,6 +221,12 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
|||
/** Predicted next PC. */
|
||||
Addr predPC;
|
||||
|
||||
/** Predicted next NPC. */
|
||||
Addr predNPC;
|
||||
|
||||
/** If this is a branch that was predicted taken */
|
||||
bool predTaken;
|
||||
|
||||
/** Count of total number of dynamic instructions. */
|
||||
static int instcount;
|
||||
|
||||
|
@ -236,16 +239,116 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
|||
*/
|
||||
bool _readySrcRegIdx[MaxInstSrcRegs];
|
||||
|
||||
protected:
|
||||
/** Flattened register index of the destination registers of this
|
||||
* instruction.
|
||||
*/
|
||||
TheISA::RegIndex _flatDestRegIdx[TheISA::MaxInstDestRegs];
|
||||
|
||||
/** Flattened register index of the source registers of this
|
||||
* instruction.
|
||||
*/
|
||||
TheISA::RegIndex _flatSrcRegIdx[TheISA::MaxInstSrcRegs];
|
||||
|
||||
/** Physical register index of the destination registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _destRegIdx[TheISA::MaxInstDestRegs];
|
||||
|
||||
/** Physical register index of the source registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _srcRegIdx[TheISA::MaxInstSrcRegs];
|
||||
|
||||
/** Physical register index of the previous producers of the
|
||||
* architected destinations.
|
||||
*/
|
||||
PhysRegIndex _prevDestRegIdx[TheISA::MaxInstDestRegs];
|
||||
|
||||
public:
|
||||
|
||||
/** Returns the physical register index of the i'th destination
|
||||
* register.
|
||||
*/
|
||||
PhysRegIndex renamedDestRegIdx(int idx) const
|
||||
{
|
||||
return _destRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th source register. */
|
||||
PhysRegIndex renamedSrcRegIdx(int idx) const
|
||||
{
|
||||
return _srcRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the flattened register index of the i'th destination
|
||||
* register.
|
||||
*/
|
||||
TheISA::RegIndex flattenedDestRegIdx(int idx) const
|
||||
{
|
||||
return _flatDestRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the flattened register index of the i'th source register */
|
||||
TheISA::RegIndex flattenedSrcRegIdx(int idx) const
|
||||
{
|
||||
return _flatSrcRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the previous physical register
|
||||
* that remapped to the same logical register index.
|
||||
*/
|
||||
PhysRegIndex prevDestRegIdx(int idx) const
|
||||
{
|
||||
return _prevDestRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Renames a destination register to a physical register. Also records
|
||||
* the previous physical register that the logical register mapped to.
|
||||
*/
|
||||
void renameDestReg(int idx,
|
||||
PhysRegIndex renamed_dest,
|
||||
PhysRegIndex previous_rename)
|
||||
{
|
||||
_destRegIdx[idx] = renamed_dest;
|
||||
_prevDestRegIdx[idx] = previous_rename;
|
||||
}
|
||||
|
||||
/** Renames a source logical register to the physical register which
|
||||
* has/will produce that logical register's result.
|
||||
* @todo: add in whether or not the source register is ready.
|
||||
*/
|
||||
void renameSrcReg(int idx, PhysRegIndex renamed_src)
|
||||
{
|
||||
_srcRegIdx[idx] = renamed_src;
|
||||
}
|
||||
|
||||
/** Flattens a source architectural register index into a logical index.
|
||||
*/
|
||||
void flattenSrcReg(int idx, TheISA::RegIndex flattened_src)
|
||||
{
|
||||
_flatSrcRegIdx[idx] = flattened_src;
|
||||
}
|
||||
|
||||
/** Flattens a destination architectural register index into a logical
|
||||
* index.
|
||||
*/
|
||||
void flattenDestReg(int idx, TheISA::RegIndex flattened_dest)
|
||||
{
|
||||
_flatDestRegIdx[idx] = flattened_dest;
|
||||
}
|
||||
|
||||
/** BaseDynInst constructor given a binary instruction.
|
||||
* @param inst The binary instruction.
|
||||
* @param PC The PC of the instruction.
|
||||
* @param pred_PC The predicted next PC.
|
||||
* @param pred_NPC The predicted next NPC.
|
||||
* @param seq_num The sequence number of the instruction.
|
||||
* @param cpu Pointer to the instruction's CPU.
|
||||
*/
|
||||
BaseDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num,
|
||||
ImplCPU *cpu);
|
||||
BaseDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC,
|
||||
Addr pred_PC, Addr pred_NPC,
|
||||
InstSeqNum seq_num, ImplCPU *cpu);
|
||||
|
||||
/** BaseDynInst constructor given a StaticInst pointer.
|
||||
* @param _staticInst The StaticInst for this BaseDynInst.
|
||||
|
@ -290,26 +393,35 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
|||
Addr readNextNPC() { return nextNPC; }
|
||||
|
||||
/** Set the predicted target of this current instruction. */
|
||||
void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; }
|
||||
void setPredTarg(Addr predicted_PC, Addr predicted_NPC)
|
||||
{
|
||||
predPC = predicted_PC;
|
||||
predNPC = predicted_NPC;
|
||||
}
|
||||
|
||||
/** Returns the predicted target of the branch. */
|
||||
Addr readPredTarg() { return predPC; }
|
||||
/** Returns the predicted PC immediately after the branch. */
|
||||
Addr readPredPC() { return predPC; }
|
||||
|
||||
/** Returns the predicted PC two instructions after the branch */
|
||||
Addr readPredNPC() { return predNPC; }
|
||||
|
||||
/** Returns whether the instruction was predicted taken or not. */
|
||||
bool predTaken()
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
{ return predPC != (nextPC + sizeof(MachInst)); }
|
||||
#else
|
||||
{ return predPC != (PC + sizeof(MachInst)); }
|
||||
#endif
|
||||
bool readPredTaken()
|
||||
{
|
||||
return predTaken;
|
||||
}
|
||||
|
||||
void setPredTaken(bool predicted_taken)
|
||||
{
|
||||
predTaken = predicted_taken;
|
||||
}
|
||||
|
||||
/** Returns whether the instruction mispredicted. */
|
||||
bool mispredicted()
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
{ return predPC != nextNPC; }
|
||||
#else
|
||||
{ return predPC != nextPC; }
|
||||
#endif
|
||||
{
|
||||
return predPC != nextPC || predNPC != nextNPC;
|
||||
}
|
||||
|
||||
//
|
||||
// Instruction types. Forward checks to StaticInst object.
|
||||
//
|
||||
|
|
|
@ -62,17 +62,20 @@ my_hash_t thishash;
|
|||
#endif
|
||||
|
||||
template <class Impl>
|
||||
BaseDynInst<Impl>::BaseDynInst(TheISA::ExtMachInst machInst, Addr inst_PC,
|
||||
Addr pred_PC, InstSeqNum seq_num,
|
||||
ImplCPU *cpu)
|
||||
BaseDynInst<Impl>::BaseDynInst(TheISA::ExtMachInst machInst,
|
||||
Addr inst_PC, Addr inst_NPC,
|
||||
Addr pred_PC, Addr pred_NPC,
|
||||
InstSeqNum seq_num, ImplCPU *cpu)
|
||||
: staticInst(machInst), traceData(NULL), cpu(cpu)
|
||||
{
|
||||
seqNum = seq_num;
|
||||
|
||||
PC = inst_PC;
|
||||
nextPC = PC + sizeof(TheISA::MachInst);
|
||||
nextPC = inst_NPC;
|
||||
nextNPC = nextPC + sizeof(TheISA::MachInst);
|
||||
predPC = pred_PC;
|
||||
predNPC = pred_NPC;
|
||||
predTaken = false;
|
||||
|
||||
initVars();
|
||||
}
|
||||
|
|
|
@ -145,13 +145,15 @@ Trace::InstRecord::dump(ostream &outs)
|
|||
outs << hex;
|
||||
outs << "PC = " << thread->readNextPC();
|
||||
outs << " NPC = " << thread->readNextNPC();
|
||||
newVal = thread->readMiscReg(SparcISA::MISCREG_CCR);
|
||||
newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2);
|
||||
//newVal = thread->readMiscReg(SparcISA::MISCREG_CCR);
|
||||
if(newVal != ccr)
|
||||
{
|
||||
outs << " CCR = " << newVal;
|
||||
ccr = newVal;
|
||||
}
|
||||
newVal = thread->readMiscReg(SparcISA::MISCREG_Y);
|
||||
newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 1);
|
||||
//newVal = thread->readMiscReg(SparcISA::MISCREG_Y);
|
||||
if(newVal != y)
|
||||
{
|
||||
outs << " Y = " << newVal;
|
||||
|
@ -373,9 +375,13 @@ Trace::InstRecord::dump(ostream &outs)
|
|||
diffHtba = true;
|
||||
if(shared_data->pstate != thread->readMiscReg(MISCREG_PSTATE))
|
||||
diffPstate = true;
|
||||
if(shared_data->y != thread->readMiscReg(MISCREG_Y))
|
||||
//if(shared_data->y != thread->readMiscReg(MISCREG_Y))
|
||||
if(shared_data->y !=
|
||||
thread->readIntReg(NumIntArchRegs + 1))
|
||||
diffY = true;
|
||||
if(shared_data->ccr != thread->readMiscReg(MISCREG_CCR))
|
||||
//if(shared_data->ccr != thread->readMiscReg(MISCREG_CCR))
|
||||
if(shared_data->ccr !=
|
||||
thread->readIntReg(NumIntArchRegs + 2))
|
||||
diffCcr = true;
|
||||
if(shared_data->gl != thread->readMiscReg(MISCREG_GL))
|
||||
diffGl = true;
|
||||
|
@ -385,14 +391,22 @@ Trace::InstRecord::dump(ostream &outs)
|
|||
diffPil = true;
|
||||
if(shared_data->cwp != thread->readMiscReg(MISCREG_CWP))
|
||||
diffCwp = true;
|
||||
if(shared_data->cansave != thread->readMiscReg(MISCREG_CANSAVE))
|
||||
//if(shared_data->cansave != thread->readMiscReg(MISCREG_CANSAVE))
|
||||
if(shared_data->cansave !=
|
||||
thread->readIntReg(NumIntArchRegs + 3))
|
||||
diffCansave = true;
|
||||
//if(shared_data->canrestore !=
|
||||
// thread->readMiscReg(MISCREG_CANRESTORE))
|
||||
if(shared_data->canrestore !=
|
||||
thread->readMiscReg(MISCREG_CANRESTORE))
|
||||
thread->readMiscReg(NumIntArchRegs + 4))
|
||||
diffCanrestore = true;
|
||||
if(shared_data->otherwin != thread->readMiscReg(MISCREG_OTHERWIN))
|
||||
//if(shared_data->otherwin != thread->readMiscReg(MISCREG_OTHERWIN))
|
||||
if(shared_data->otherwin !=
|
||||
thread->readIntReg(NumIntArchRegs + 5))
|
||||
diffOtherwin = true;
|
||||
if(shared_data->cleanwin != thread->readMiscReg(MISCREG_CLEANWIN))
|
||||
//if(shared_data->cleanwin != thread->readMiscReg(MISCREG_CLEANWIN))
|
||||
if(shared_data->cleanwin !=
|
||||
thread->readMiscReg(NumIntArchRegs + 6))
|
||||
diffCleanwin = true;
|
||||
|
||||
if ((diffPC || diffCC || diffInst || diffRegs || diffTpc ||
|
||||
|
@ -493,10 +507,12 @@ Trace::InstRecord::dump(ostream &outs)
|
|||
thread->readMiscReg(MISCREG_PSTATE),
|
||||
shared_data->pstate);
|
||||
printRegPair(outs, "Y",
|
||||
thread->readMiscReg(MISCREG_Y),
|
||||
//thread->readMiscReg(MISCREG_Y),
|
||||
thread->readMiscReg(NumIntArchRegs + 1),
|
||||
shared_data->y);
|
||||
printRegPair(outs, "Ccr",
|
||||
thread->readMiscReg(MISCREG_CCR),
|
||||
//thread->readMiscReg(MISCREG_CCR),
|
||||
thread->readMiscReg(NumIntArchRegs + 2),
|
||||
shared_data->ccr);
|
||||
printRegPair(outs, "Tl",
|
||||
thread->readMiscReg(MISCREG_TL),
|
||||
|
@ -514,16 +530,20 @@ Trace::InstRecord::dump(ostream &outs)
|
|||
thread->readMiscReg(MISCREG_CWP),
|
||||
shared_data->cwp);
|
||||
printRegPair(outs, "Cansave",
|
||||
thread->readMiscReg(MISCREG_CANSAVE),
|
||||
//thread->readMiscReg(MISCREG_CANSAVE),
|
||||
thread->readIntReg(NumIntArchRegs + 3),
|
||||
shared_data->cansave);
|
||||
printRegPair(outs, "Canrestore",
|
||||
thread->readMiscReg(MISCREG_CANRESTORE),
|
||||
//thread->readMiscReg(MISCREG_CANRESTORE),
|
||||
thread->readIntReg(NumIntArchRegs + 4),
|
||||
shared_data->canrestore);
|
||||
printRegPair(outs, "Otherwin",
|
||||
thread->readMiscReg(MISCREG_OTHERWIN),
|
||||
//thread->readMiscReg(MISCREG_OTHERWIN),
|
||||
thread->readIntReg(NumIntArchRegs + 5),
|
||||
shared_data->otherwin);
|
||||
printRegPair(outs, "Cleanwin",
|
||||
thread->readMiscReg(MISCREG_CLEANWIN),
|
||||
//thread->readMiscReg(MISCREG_CLEANWIN),
|
||||
thread->readIntReg(NumIntArchRegs + 6),
|
||||
shared_data->cleanwin);
|
||||
outs << endl;
|
||||
for (int i = 1; i <= MaxTL; i++) {
|
||||
|
|
|
@ -37,12 +37,6 @@
|
|||
#include "cpu/o3/cpu.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
|
||||
namespace TheISA
|
||||
{
|
||||
class ITB;
|
||||
class DTB;
|
||||
}
|
||||
|
||||
class EndQuiesceEvent;
|
||||
namespace Kernel {
|
||||
class Statistics;
|
||||
|
@ -61,14 +55,6 @@ class TranslatingPort;
|
|||
template <class Impl>
|
||||
class AlphaO3CPU : public FullO3CPU<Impl>
|
||||
{
|
||||
protected:
|
||||
typedef TheISA::IntReg IntReg;
|
||||
typedef TheISA::FloatReg FloatReg;
|
||||
typedef TheISA::FloatRegBits FloatRegBits;
|
||||
typedef TheISA::MiscReg MiscReg;
|
||||
typedef TheISA::RegFile RegFile;
|
||||
typedef TheISA::MiscRegFile MiscRegFile;
|
||||
|
||||
public:
|
||||
typedef O3ThreadState<Impl> ImplState;
|
||||
typedef O3ThreadState<Impl> Thread;
|
||||
|
@ -77,13 +63,6 @@ class AlphaO3CPU : public FullO3CPU<Impl>
|
|||
/** Constructs an AlphaO3CPU with the given parameters. */
|
||||
AlphaO3CPU(Params *params);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
/** ITB pointer. */
|
||||
AlphaISA::ITB *itb;
|
||||
/** DTB pointer. */
|
||||
AlphaISA::DTB *dtb;
|
||||
#endif
|
||||
|
||||
/** Registers statistics. */
|
||||
void regStats();
|
||||
|
||||
|
@ -91,19 +70,19 @@ class AlphaO3CPU : public FullO3CPU<Impl>
|
|||
/** Translates instruction requestion. */
|
||||
Fault translateInstReq(RequestPtr &req, Thread *thread)
|
||||
{
|
||||
return itb->translate(req, thread->getTC());
|
||||
return this->itb->translate(req, thread->getTC());
|
||||
}
|
||||
|
||||
/** Translates data read request. */
|
||||
Fault translateDataReadReq(RequestPtr &req, Thread *thread)
|
||||
{
|
||||
return dtb->translate(req, thread->getTC(), false);
|
||||
return this->dtb->translate(req, thread->getTC(), false);
|
||||
}
|
||||
|
||||
/** Translates data write request. */
|
||||
Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
|
||||
{
|
||||
return dtb->translate(req, thread->getTC(), true);
|
||||
return this->dtb->translate(req, thread->getTC(), true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -127,20 +106,22 @@ class AlphaO3CPU : public FullO3CPU<Impl>
|
|||
|
||||
#endif
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscReg(int misc_reg, unsigned tid);
|
||||
TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
|
||||
|
||||
/** Reads a misc. register, including any side effects the read
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid);
|
||||
TheISA::MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid);
|
||||
|
||||
/** Sets a miscellaneous register. */
|
||||
void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid);
|
||||
void setMiscReg(int misc_reg, const TheISA::MiscReg &val,
|
||||
unsigned tid);
|
||||
|
||||
/** Sets a misc. register, including any side effects the write
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
void setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid);
|
||||
void setMiscRegWithEffect(int misc_reg, const TheISA::MiscReg &val,
|
||||
unsigned tid);
|
||||
|
||||
/** Initiates a squash of all in-flight instructions for a given
|
||||
* thread. The source of the squash is an external update of
|
||||
|
@ -175,10 +156,10 @@ class AlphaO3CPU : public FullO3CPU<Impl>
|
|||
*/
|
||||
void syscall(int64_t callnum, int tid);
|
||||
/** Gets a syscall argument. */
|
||||
IntReg getSyscallArg(int i, int tid);
|
||||
TheISA::IntReg getSyscallArg(int i, int tid);
|
||||
|
||||
/** Used to shift args for indirect syscall. */
|
||||
void setSyscallArg(int i, IntReg val, int tid);
|
||||
void setSyscallArg(int i, TheISA::IntReg val, int tid);
|
||||
|
||||
/** Sets the return value of a syscall. */
|
||||
void setSyscallReturn(SyscallReturn return_value, int tid);
|
||||
|
|
|
@ -55,12 +55,7 @@
|
|||
#endif
|
||||
|
||||
template <class Impl>
|
||||
AlphaO3CPU<Impl>::AlphaO3CPU(Params *params)
|
||||
#if FULL_SYSTEM
|
||||
: FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb)
|
||||
#else
|
||||
: FullO3CPU<Impl>(params)
|
||||
#endif
|
||||
AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) : FullO3CPU<Impl>(params)
|
||||
{
|
||||
DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n");
|
||||
|
||||
|
@ -173,15 +168,16 @@ AlphaO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid)
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
AlphaO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
|
||||
AlphaO3CPU<Impl>::setMiscReg(int misc_reg, const TheISA::MiscReg &val,
|
||||
unsigned tid)
|
||||
{
|
||||
this->regFile.setMiscReg(misc_reg, val, tid);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
AlphaO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val,
|
||||
unsigned tid)
|
||||
AlphaO3CPU<Impl>::setMiscRegWithEffect(int misc_reg,
|
||||
const TheISA::MiscReg &val, unsigned tid)
|
||||
{
|
||||
this->regFile.setMiscRegWithEffect(misc_reg, val, tid);
|
||||
}
|
||||
|
@ -315,7 +311,7 @@ AlphaO3CPU<Impl>::getSyscallArg(int i, int tid)
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
AlphaO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
|
||||
AlphaO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid)
|
||||
{
|
||||
this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid);
|
||||
}
|
||||
|
@ -324,17 +320,6 @@ template <class Impl>
|
|||
void
|
||||
AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
|
||||
{
|
||||
// check for error condition. Alpha syscall convention is to
|
||||
// indicate success/failure in reg a3 (r19) and put the
|
||||
// return value itself in the standard return value reg (v0).
|
||||
if (return_value.successful()) {
|
||||
// no error
|
||||
this->setArchIntReg(TheISA::SyscallSuccessReg, 0, tid);
|
||||
this->setArchIntReg(TheISA::ReturnValueReg, return_value.value(), tid);
|
||||
} else {
|
||||
// got an error, return details
|
||||
this->setArchIntReg(TheISA::SyscallSuccessReg, (IntReg) -1, tid);
|
||||
this->setArchIntReg(TheISA::ReturnValueReg, -return_value.value(), tid);
|
||||
}
|
||||
TheISA::setSyscallReturn(return_value, this->tcBase(tid));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -134,22 +134,6 @@ class AlphaDynInst : public BaseDynInst<Impl>
|
|||
void syscall(int64_t callnum);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/** Physical register index of the destination registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _destRegIdx[MaxInstDestRegs];
|
||||
|
||||
/** Physical register index of the source registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _srcRegIdx[MaxInstSrcRegs];
|
||||
|
||||
/** Physical register index of the previous producers of the
|
||||
* architected destinations.
|
||||
*/
|
||||
PhysRegIndex _prevDestRegIdx[MaxInstDestRegs];
|
||||
|
||||
public:
|
||||
|
||||
// The register accessor methods provide the index of the
|
||||
|
@ -165,28 +149,28 @@ class AlphaDynInst : public BaseDynInst<Impl>
|
|||
|
||||
uint64_t readIntRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readIntReg(_srcRegIdx[idx]);
|
||||
return this->cpu->readIntReg(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
|
||||
{
|
||||
return this->cpu->readFloatReg(_srcRegIdx[idx], width);
|
||||
return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatReg(_srcRegIdx[idx]);
|
||||
return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
int width)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(_srcRegIdx[idx], width);
|
||||
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(_srcRegIdx[idx]);
|
||||
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
/** @todo: Make results into arrays so they can handle multiple dest
|
||||
|
@ -194,79 +178,37 @@ class AlphaDynInst : public BaseDynInst<Impl>
|
|||
*/
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
this->cpu->setIntReg(_destRegIdx[idx], val);
|
||||
this->cpu->setIntReg(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
|
||||
int width)
|
||||
{
|
||||
this->cpu->setFloatReg(_destRegIdx[idx], val, width);
|
||||
this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
|
||||
}
|
||||
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
this->cpu->setFloatReg(_destRegIdx[idx], val);
|
||||
this->cpu->setFloatReg(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val, int width)
|
||||
{
|
||||
this->cpu->setFloatRegBits(_destRegIdx[idx], val, width);
|
||||
this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val)
|
||||
{
|
||||
this->cpu->setFloatRegBits(_destRegIdx[idx], val);
|
||||
this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th destination
|
||||
* register.
|
||||
*/
|
||||
PhysRegIndex renamedDestRegIdx(int idx) const
|
||||
{
|
||||
return _destRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th source register. */
|
||||
PhysRegIndex renamedSrcRegIdx(int idx) const
|
||||
{
|
||||
return _srcRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the previous physical register
|
||||
* that remapped to the same logical register index.
|
||||
*/
|
||||
PhysRegIndex prevDestRegIdx(int idx) const
|
||||
{
|
||||
return _prevDestRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Renames a destination register to a physical register. Also records
|
||||
* the previous physical register that the logical register mapped to.
|
||||
*/
|
||||
void renameDestReg(int idx,
|
||||
PhysRegIndex renamed_dest,
|
||||
PhysRegIndex previous_rename)
|
||||
{
|
||||
_destRegIdx[idx] = renamed_dest;
|
||||
_prevDestRegIdx[idx] = previous_rename;
|
||||
}
|
||||
|
||||
/** Renames a source logical register to the physical register which
|
||||
* has/will produce that logical register's result.
|
||||
* @todo: add in whether or not the source register is ready.
|
||||
*/
|
||||
void renameSrcReg(int idx, PhysRegIndex renamed_src)
|
||||
{
|
||||
_srcRegIdx[idx] = renamed_src;
|
||||
}
|
||||
|
||||
public:
|
||||
/** Calculates EA part of a memory instruction. Currently unused,
|
||||
* though it may be useful in the future if we want to split
|
||||
|
|
|
@ -53,11 +53,11 @@ AlphaDynInst<Impl>::initVars()
|
|||
// as the normal register entries. It will allow the IQ to work
|
||||
// without any modifications.
|
||||
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
|
||||
_destRegIdx[i] = this->staticInst->destRegIdx(i);
|
||||
this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
|
||||
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
|
||||
this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
|
||||
this->_readySrcRegIdx[i] = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,12 +36,6 @@ class AlphaTC : public O3ThreadContext<Impl>
|
|||
{
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
/** Returns a pointer to the ITB. */
|
||||
virtual AlphaISA::ITB *getITBPtr() { return this->cpu->itb; }
|
||||
|
||||
/** Returns a pointer to the DTB. */
|
||||
virtual AlphaISA::DTB *getDTBPtr() { return this->cpu->dtb; }
|
||||
|
||||
/** Returns pointer to the quiesce event. */
|
||||
virtual EndQuiesceEvent *getQuiesceEvent()
|
||||
{
|
||||
|
|
|
@ -233,15 +233,6 @@ BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
|
|||
}
|
||||
}
|
||||
|
||||
if (pred_taken) {
|
||||
// Set the PC and the instruction's predicted target.
|
||||
PC = target;
|
||||
inst->setPredTarg(target);
|
||||
} else {
|
||||
PC = PC + sizeof(MachInst);
|
||||
inst->setPredTarg(PC);
|
||||
}
|
||||
|
||||
predHist[tid].push_front(predict_record);
|
||||
|
||||
DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());
|
||||
|
|
|
@ -87,9 +87,10 @@ struct DefaultIEWDefaultCommit {
|
|||
bool squash[Impl::MaxThreads];
|
||||
bool branchMispredict[Impl::MaxThreads];
|
||||
bool branchTaken[Impl::MaxThreads];
|
||||
bool condDelaySlotBranch[Impl::MaxThreads];
|
||||
bool squashDelaySlot[Impl::MaxThreads];
|
||||
uint64_t mispredPC[Impl::MaxThreads];
|
||||
uint64_t nextPC[Impl::MaxThreads];
|
||||
uint64_t nextNPC[Impl::MaxThreads];
|
||||
InstSeqNum squashedSeqNum[Impl::MaxThreads];
|
||||
|
||||
bool includeSquashInst[Impl::MaxThreads];
|
||||
|
@ -121,6 +122,7 @@ struct TimeBufStruct {
|
|||
bool branchTaken;
|
||||
uint64_t mispredPC;
|
||||
uint64_t nextPC;
|
||||
uint64_t nextNPC;
|
||||
|
||||
unsigned branchCount;
|
||||
};
|
||||
|
@ -160,6 +162,7 @@ struct TimeBufStruct {
|
|||
bool branchTaken;
|
||||
uint64_t mispredPC;
|
||||
uint64_t nextPC;
|
||||
uint64_t nextNPC;
|
||||
|
||||
// Represents the instruction that has either been retired or
|
||||
// squashed. Similar to having a single bus that broadcasts the
|
||||
|
|
|
@ -514,6 +514,7 @@ DefaultCommit<Impl>::squashAll(unsigned tid)
|
|||
toIEW->commitInfo[tid].branchMispredict = false;
|
||||
|
||||
toIEW->commitInfo[tid].nextPC = PC[tid];
|
||||
toIEW->commitInfo[tid].nextNPC = nextPC[tid];
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -728,28 +729,11 @@ DefaultCommit<Impl>::commit()
|
|||
InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
InstSeqNum bdelay_done_seq_num;
|
||||
bool squash_bdelay_slot;
|
||||
InstSeqNum bdelay_done_seq_num = squashed_inst;
|
||||
bool squash_bdelay_slot = fromIEW->squashDelaySlot[tid];
|
||||
|
||||
if (fromIEW->branchMispredict[tid]) {
|
||||
if (fromIEW->branchTaken[tid] &&
|
||||
fromIEW->condDelaySlotBranch[tid]) {
|
||||
DPRINTF(Commit, "[tid:%i]: Cond. delay slot branch"
|
||||
"mispredicted as taken. Squashing after previous "
|
||||
"inst, [sn:%i]\n",
|
||||
tid, squashed_inst);
|
||||
bdelay_done_seq_num = squashed_inst;
|
||||
squash_bdelay_slot = true;
|
||||
} else {
|
||||
DPRINTF(Commit, "[tid:%i]: Branch Mispredict. Squashing "
|
||||
"after delay slot [sn:%i]\n", tid, squashed_inst+1);
|
||||
bdelay_done_seq_num = squashed_inst + 1;
|
||||
squash_bdelay_slot = false;
|
||||
}
|
||||
} else {
|
||||
bdelay_done_seq_num = squashed_inst;
|
||||
squash_bdelay_slot = true;
|
||||
}
|
||||
if (!squash_bdelay_slot)
|
||||
bdelay_done_seq_num++;
|
||||
#endif
|
||||
|
||||
if (fromIEW->includeSquashInst[tid] == true) {
|
||||
|
@ -787,6 +771,7 @@ DefaultCommit<Impl>::commit()
|
|||
fromIEW->branchTaken[tid];
|
||||
|
||||
toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
|
||||
toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];
|
||||
|
||||
toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
|
||||
|
||||
|
@ -1117,7 +1102,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
|
|||
|
||||
// Update the commit rename map
|
||||
for (int i = 0; i < head_inst->numDestRegs(); i++) {
|
||||
renameMap[tid]->setEntry(head_inst->destRegIdx(i),
|
||||
renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i),
|
||||
head_inst->renamedDestRegIdx(i));
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,10 @@ FullO3CPU<Impl>::DeallocateContextEvent::description()
|
|||
template <class Impl>
|
||||
FullO3CPU<Impl>::FullO3CPU(Params *params)
|
||||
: BaseO3CPU(params),
|
||||
#if FULL_SYSTEM
|
||||
itb(params->itb),
|
||||
dtb(params->dtb),
|
||||
#endif
|
||||
tickEvent(this),
|
||||
removeInstsThisCycle(false),
|
||||
fetch(params),
|
||||
|
@ -696,7 +700,7 @@ FullO3CPU<Impl>::removeThread(unsigned tid)
|
|||
|
||||
// Squash Throughout Pipeline
|
||||
InstSeqNum squash_seq_num = commit.rob->readHeadInst(tid)->seqNum;
|
||||
fetch.squash(0, squash_seq_num, true, tid);
|
||||
fetch.squash(0, sizeof(TheISA::MachInst), squash_seq_num, true, tid);
|
||||
decode.squash(tid);
|
||||
rename.squash(squash_seq_num, tid);
|
||||
iew.squash(tid);
|
||||
|
|
|
@ -91,9 +91,6 @@ template <class Impl>
|
|||
class FullO3CPU : public BaseO3CPU
|
||||
{
|
||||
public:
|
||||
typedef TheISA::FloatReg FloatReg;
|
||||
typedef TheISA::FloatRegBits FloatRegBits;
|
||||
|
||||
// Typedefs from the Impl here.
|
||||
typedef typename Impl::CPUPol CPUPolicy;
|
||||
typedef typename Impl::Params Params;
|
||||
|
@ -114,6 +111,11 @@ class FullO3CPU : public BaseO3CPU
|
|||
SwitchedOut
|
||||
};
|
||||
|
||||
#if FULL_SYSTEM
|
||||
TheISA::ITB * itb;
|
||||
TheISA::DTB * dtb;
|
||||
#endif
|
||||
|
||||
/** Overall CPU status. */
|
||||
Status _status;
|
||||
|
||||
|
@ -382,23 +384,23 @@ class FullO3CPU : public BaseO3CPU
|
|||
/** Register accessors. Index refers to the physical register index. */
|
||||
uint64_t readIntReg(int reg_idx);
|
||||
|
||||
FloatReg readFloatReg(int reg_idx);
|
||||
TheISA::FloatReg readFloatReg(int reg_idx);
|
||||
|
||||
FloatReg readFloatReg(int reg_idx, int width);
|
||||
TheISA::FloatReg readFloatReg(int reg_idx, int width);
|
||||
|
||||
FloatRegBits readFloatRegBits(int reg_idx);
|
||||
TheISA::FloatRegBits readFloatRegBits(int reg_idx);
|
||||
|
||||
FloatRegBits readFloatRegBits(int reg_idx, int width);
|
||||
TheISA::FloatRegBits readFloatRegBits(int reg_idx, int width);
|
||||
|
||||
void setIntReg(int reg_idx, uint64_t val);
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val);
|
||||
void setFloatReg(int reg_idx, TheISA::FloatReg val);
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val, int width);
|
||||
void setFloatReg(int reg_idx, TheISA::FloatReg val, int width);
|
||||
|
||||
void setFloatRegBits(int reg_idx, FloatRegBits val);
|
||||
void setFloatRegBits(int reg_idx, TheISA::FloatRegBits val);
|
||||
|
||||
void setFloatRegBits(int reg_idx, FloatRegBits val, int width);
|
||||
void setFloatRegBits(int reg_idx, TheISA::FloatRegBits val, int width);
|
||||
|
||||
uint64_t readArchIntReg(int reg_idx, unsigned tid);
|
||||
|
||||
|
|
|
@ -741,7 +741,7 @@ DefaultDecode<Impl>::decodeInsts(unsigned tid)
|
|||
|
||||
// Ensure that if it was predicted as a branch, it really is a
|
||||
// branch.
|
||||
if (inst->predTaken() && !inst->isControl()) {
|
||||
if (inst->readPredTaken() && !inst->isControl()) {
|
||||
DPRINTF(Decode, "PredPC : %#x != NextPC: %#x\n",inst->predPC,
|
||||
inst->nextPC + 4);
|
||||
|
||||
|
@ -760,26 +760,29 @@ DefaultDecode<Impl>::decodeInsts(unsigned tid)
|
|||
if (inst->isDirectCtrl() && inst->isUncondCtrl()) {
|
||||
++decodeBranchResolved;
|
||||
|
||||
if (inst->branchTarget() != inst->readPredTarg()) {
|
||||
if (inst->branchTarget() != inst->readPredPC()) {
|
||||
++decodeBranchMispred;
|
||||
|
||||
// Might want to set some sort of boolean and just do
|
||||
// a check at the end
|
||||
#if !ISA_HAS_DELAY_SLOT
|
||||
squash(inst, inst->threadNumber);
|
||||
inst->setPredTarg(inst->branchTarget());
|
||||
Addr target = inst->branchTarget();
|
||||
inst->setPredTarg(target, target + sizeof(TheISA::MachInst));
|
||||
break;
|
||||
#else
|
||||
// If mispredicted as taken, then ignore delay slot
|
||||
// instruction... else keep delay slot and squash
|
||||
// after it is sent to rename
|
||||
if (inst->predTaken() && inst->isCondDelaySlot()) {
|
||||
if (inst->readPredTaken() && inst->isCondDelaySlot()) {
|
||||
DPRINTF(Decode, "[tid:%i]: Conditional delay slot inst."
|
||||
"[sn:%i] PC %#x mispredicted as taken.\n", tid,
|
||||
inst->seqNum, inst->PC);
|
||||
bdelayDoneSeqNum[tid] = inst->seqNum;
|
||||
squash(inst, inst->threadNumber);
|
||||
inst->setPredTarg(inst->branchTarget());
|
||||
Addr target = inst->branchTarget();
|
||||
inst->setPredTarg(target,
|
||||
target + sizeof(TheISA::MachInst));
|
||||
break;
|
||||
} else {
|
||||
DPRINTF(Decode, "[tid:%i]: Misprediction detected at "
|
||||
|
@ -798,7 +801,9 @@ DefaultDecode<Impl>::decodeInsts(unsigned tid)
|
|||
if (squashAfterDelaySlot[tid]) {
|
||||
assert(!inst->isSquashed());
|
||||
squash(squashInst[tid], squashInst[tid]->threadNumber);
|
||||
squashInst[tid]->setPredTarg(squashInst[tid]->branchTarget());
|
||||
Addr target = squashInst[tid]->branchTarget();
|
||||
squashInst[tid]->setPredTarg(target,
|
||||
target + sizeof(TheISA::MachInst));
|
||||
assert(!inst->isSquashed());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -239,13 +239,13 @@ class DefaultFetch
|
|||
bool fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid);
|
||||
|
||||
/** Squashes a specific thread and resets the PC. */
|
||||
inline void doSquash(const Addr &new_PC, unsigned tid);
|
||||
inline void doSquash(const Addr &new_PC, const Addr &new_NPC, unsigned tid);
|
||||
|
||||
/** Squashes a specific thread and resets the PC. Also tells the CPU to
|
||||
* remove any instructions between fetch and decode that should be sqaushed.
|
||||
*/
|
||||
void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num,
|
||||
unsigned tid);
|
||||
void squashFromDecode(const Addr &new_PC, const Addr &new_NPC,
|
||||
const InstSeqNum &seq_num, unsigned tid);
|
||||
|
||||
/** Checks if a thread is stalled. */
|
||||
bool checkStall(unsigned tid) const;
|
||||
|
@ -259,7 +259,8 @@ class DefaultFetch
|
|||
* remove any instructions that are not in the ROB. The source of this
|
||||
* squash should be the commit stage.
|
||||
*/
|
||||
void squash(const Addr &new_PC, const InstSeqNum &seq_num,
|
||||
void squash(const Addr &new_PC, const Addr &new_NPC,
|
||||
const InstSeqNum &seq_num,
|
||||
bool squash_delay_slot, unsigned tid);
|
||||
|
||||
/** Ticks the fetch stage, processing all inputs signals and fetching
|
||||
|
|
|
@ -319,9 +319,7 @@ DefaultFetch<Impl>::initStage()
|
|||
for (int tid = 0; tid < numThreads; tid++) {
|
||||
PC[tid] = cpu->readPC(tid);
|
||||
nextPC[tid] = cpu->readNextPC(tid);
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
nextNPC[tid] = cpu->readNextNPC(tid);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Size of cache block.
|
||||
|
@ -504,14 +502,14 @@ DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
|
|||
|
||||
if (!inst->isControl()) {
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
Addr cur_PC = next_PC;
|
||||
next_PC = cur_PC + instSize; //next_NPC;
|
||||
next_NPC = cur_PC + (2 * instSize);//next_NPC + instSize;
|
||||
inst->setPredTarg(next_NPC);
|
||||
next_PC = next_NPC;
|
||||
next_NPC = next_NPC + instSize;
|
||||
inst->setPredTarg(next_PC, next_NPC);
|
||||
#else
|
||||
next_PC = next_PC + instSize;
|
||||
inst->setPredTarg(next_PC);
|
||||
inst->setPredTarg(next_PC, next_PC + sizeof(TheISA::MachInst));
|
||||
#endif
|
||||
inst->setPredTaken(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -521,36 +519,29 @@ DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
|
|||
predict_taken = branchPred.predict(inst, pred_PC, tid);
|
||||
|
||||
if (predict_taken) {
|
||||
DPRINTF(Fetch, "[tid:%i]: Branch predicted to be true.\n", tid);
|
||||
DPRINTF(Fetch, "[tid:%i]: Branch predicted to be taken.\n", tid);
|
||||
} else {
|
||||
DPRINTF(Fetch, "[tid:%i]: Branch predicted to be false.\n", tid);
|
||||
DPRINTF(Fetch, "[tid:%i]: Branch predicted to be not taken.\n", tid);
|
||||
}
|
||||
|
||||
if (predict_taken) {
|
||||
next_PC = next_NPC;
|
||||
if (predict_taken) {
|
||||
next_NPC = pred_PC;
|
||||
|
||||
// Update delay slot info
|
||||
++delaySlotInfo[tid].numInsts;
|
||||
delaySlotInfo[tid].targetAddr = pred_PC;
|
||||
DPRINTF(Fetch, "[tid:%i]: %i delay slot inst(s) to process.\n", tid,
|
||||
delaySlotInfo[tid].numInsts);
|
||||
} else { // !predict_taken
|
||||
if (inst->isCondDelaySlot()) {
|
||||
next_PC = pred_PC;
|
||||
// The delay slot is skipped here if there is on
|
||||
// prediction
|
||||
} else {
|
||||
next_PC = next_NPC;
|
||||
// No need to declare a delay slot here since
|
||||
// there is no for the pred. target to jump
|
||||
}
|
||||
|
||||
next_NPC = next_NPC + instSize;
|
||||
}
|
||||
#else
|
||||
predict_taken = branchPred.predict(inst, next_PC, tid);
|
||||
#endif
|
||||
DPRINTF(Fetch, "[tid:%i]: Branch predicted to go to %#x and then %#x.\n",
|
||||
tid, next_PC, next_NPC);
|
||||
inst->setPredTarg(next_PC, next_NPC);
|
||||
inst->setPredTaken(predict_taken);
|
||||
|
||||
++fetchedBranches;
|
||||
|
||||
|
@ -671,14 +662,15 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
|
|||
|
||||
template <class Impl>
|
||||
inline void
|
||||
DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
|
||||
DefaultFetch<Impl>::doSquash(const Addr &new_PC,
|
||||
const Addr &new_NPC, unsigned tid)
|
||||
{
|
||||
DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n",
|
||||
tid, new_PC);
|
||||
DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x, NPC to: %#x.\n",
|
||||
tid, new_PC, new_NPC);
|
||||
|
||||
PC[tid] = new_PC;
|
||||
nextPC[tid] = new_PC + instSize;
|
||||
nextNPC[tid] = new_PC + (2 * instSize);
|
||||
nextPC[tid] = new_NPC;
|
||||
nextNPC[tid] = new_NPC + instSize;
|
||||
|
||||
// Clear the icache miss if it's outstanding.
|
||||
if (fetchStatus[tid] == IcacheWaitResponse) {
|
||||
|
@ -704,13 +696,13 @@ DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
|
|||
|
||||
template<class Impl>
|
||||
void
|
||||
DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC,
|
||||
DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, const Addr &new_NPC,
|
||||
const InstSeqNum &seq_num,
|
||||
unsigned tid)
|
||||
{
|
||||
DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
|
||||
|
||||
doSquash(new_PC, tid);
|
||||
doSquash(new_PC, new_NPC, tid);
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (seq_num <= delaySlotInfo[tid].branchSeqNum) {
|
||||
|
@ -793,12 +785,13 @@ DefaultFetch<Impl>::updateFetchStatus()
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultFetch<Impl>::squash(const Addr &new_PC, const InstSeqNum &seq_num,
|
||||
DefaultFetch<Impl>::squash(const Addr &new_PC, const Addr &new_NPC,
|
||||
const InstSeqNum &seq_num,
|
||||
bool squash_delay_slot, unsigned tid)
|
||||
{
|
||||
DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
|
||||
|
||||
doSquash(new_PC, tid);
|
||||
doSquash(new_PC, new_NPC, tid);
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (seq_num <= delaySlotInfo[tid].branchSeqNum) {
|
||||
|
@ -928,6 +921,7 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
|
|||
#endif
|
||||
// In any case, squash.
|
||||
squash(fromCommit->commitInfo[tid].nextPC,
|
||||
fromCommit->commitInfo[tid].nextNPC,
|
||||
doneSeqNum,
|
||||
fromCommit->commitInfo[tid].squashDelaySlot,
|
||||
tid);
|
||||
|
@ -985,6 +979,7 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
|
|||
#endif
|
||||
// Squash unless we're already squashing
|
||||
squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
|
||||
fromDecode->decodeInfo[tid].nextNPC,
|
||||
doneSeqNum,
|
||||
tid);
|
||||
|
||||
|
@ -1041,6 +1036,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
// The current PC.
|
||||
Addr &fetch_PC = PC[tid];
|
||||
|
||||
Addr &fetch_NPC = nextPC[tid];
|
||||
|
||||
// Fault code for memory access.
|
||||
Fault fault = NoFault;
|
||||
|
||||
|
@ -1097,7 +1094,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
}
|
||||
|
||||
Addr next_PC = fetch_PC;
|
||||
Addr next_NPC = next_PC + instSize;
|
||||
Addr next_NPC = fetch_NPC;
|
||||
|
||||
InstSeqNum inst_seq;
|
||||
MachInst inst;
|
||||
ExtMachInst ext_inst;
|
||||
|
@ -1116,15 +1114,17 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
// ended this fetch block.
|
||||
bool predicted_branch = false;
|
||||
|
||||
// Need to keep track of whether or not a delay slot
|
||||
// instruction has been fetched
|
||||
|
||||
for (;
|
||||
offset < cacheBlkSize &&
|
||||
numInst < fetchWidth &&
|
||||
(!predicted_branch || delaySlotInfo[tid].numInsts > 0);
|
||||
!predicted_branch;
|
||||
++numInst) {
|
||||
|
||||
// If we're branching after this instruction, quite fetching
|
||||
// from the same block then.
|
||||
predicted_branch =
|
||||
(fetch_PC + sizeof(TheISA::MachInst) != fetch_NPC);
|
||||
|
||||
// Get a sequence number.
|
||||
inst_seq = cpu->getAndIncrementInstSeq();
|
||||
|
||||
|
@ -1144,8 +1144,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
#endif
|
||||
|
||||
// Create a new DynInst from the instruction fetched.
|
||||
DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
|
||||
next_PC,
|
||||
DynInstPtr instruction = new DynInst(ext_inst,
|
||||
fetch_PC, fetch_NPC,
|
||||
next_PC, next_NPC,
|
||||
inst_seq, cpu);
|
||||
instruction->setTid(tid);
|
||||
|
||||
|
@ -1157,6 +1158,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
"[sn:%lli]\n",
|
||||
tid, instruction->readPC(), inst_seq);
|
||||
|
||||
DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);
|
||||
|
||||
DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
|
||||
tid, instruction->staticInst->disassemble(fetch_PC));
|
||||
|
||||
|
@ -1165,8 +1168,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
instruction->staticInst,
|
||||
instruction->readPC());
|
||||
|
||||
predicted_branch = lookupAndUpdateNextPC(instruction, next_PC,
|
||||
next_NPC);
|
||||
lookupAndUpdateNextPC(instruction, next_PC, next_NPC);
|
||||
|
||||
// Add instruction to the CPU's list of instructions.
|
||||
instruction->setInstListIt(cpu->addInst(instruction));
|
||||
|
@ -1182,6 +1184,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
|
||||
// Move to the next instruction, unless we have a branch.
|
||||
fetch_PC = next_PC;
|
||||
fetch_NPC = next_NPC;
|
||||
|
||||
if (instruction->isQuiesce()) {
|
||||
DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",
|
||||
|
@ -1193,29 +1196,6 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
}
|
||||
|
||||
offset += instSize;
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
if (predicted_branch) {
|
||||
delaySlotInfo[tid].branchSeqNum = inst_seq;
|
||||
|
||||
DPRINTF(Fetch, "[tid:%i]: Delay slot branch set to [sn:%i]\n",
|
||||
tid, inst_seq);
|
||||
continue;
|
||||
} else if (delaySlotInfo[tid].numInsts > 0) {
|
||||
--delaySlotInfo[tid].numInsts;
|
||||
|
||||
// It's OK to set PC to target of branch
|
||||
if (delaySlotInfo[tid].numInsts == 0) {
|
||||
delaySlotInfo[tid].targetReady = true;
|
||||
|
||||
// Break the looping condition
|
||||
predicted_branch = true;
|
||||
}
|
||||
|
||||
DPRINTF(Fetch, "[tid:%i]: %i delay slot inst(s) left to"
|
||||
" process.\n", tid, delaySlotInfo[tid].numInsts);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (offset >= cacheBlkSize) {
|
||||
|
@ -1224,7 +1204,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
} else if (numInst >= fetchWidth) {
|
||||
DPRINTF(Fetch, "[tid:%i]: Done fetching, reached fetch bandwidth "
|
||||
"for this cycle.\n", tid);
|
||||
} else if (predicted_branch && delaySlotInfo[tid].numInsts <= 0) {
|
||||
} else if (predicted_branch) {
|
||||
DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
|
||||
"instruction encountered.\n", tid);
|
||||
}
|
||||
|
@ -1241,9 +1221,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
if (delaySlotInfo[tid].targetReady &&
|
||||
delaySlotInfo[tid].numInsts == 0) {
|
||||
// Set PC to target
|
||||
PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC
|
||||
nextPC[tid] = next_PC + instSize; //next_NPC
|
||||
nextNPC[tid] = next_PC + (2 * instSize);
|
||||
PC[tid] = next_PC;
|
||||
nextPC[tid] = next_NPC;
|
||||
nextNPC[tid] = next_NPC + instSize;
|
||||
|
||||
delaySlotInfo[tid].targetReady = false;
|
||||
} else {
|
||||
|
|
|
@ -481,18 +481,29 @@ DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, unsigned tid)
|
|||
toCommit->branchMispredict[tid] = true;
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
bool branch_taken = inst->readNextNPC() !=
|
||||
(inst->readNextPC() + sizeof(TheISA::MachInst));
|
||||
int instSize = sizeof(TheISA::MachInst);
|
||||
bool branch_taken =
|
||||
!(inst->readNextPC() + instSize == inst->readNextNPC() &&
|
||||
(inst->readNextPC() == inst->readPC() + instSize ||
|
||||
inst->readNextPC() == inst->readPC() + 2 * instSize));
|
||||
DPRINTF(Sparc, "Branch taken = %s [sn:%i]\n",
|
||||
branch_taken ? "true": "false", inst->seqNum);
|
||||
|
||||
toCommit->branchTaken[tid] = branch_taken;
|
||||
|
||||
toCommit->condDelaySlotBranch[tid] = inst->isCondDelaySlot();
|
||||
|
||||
if (inst->isCondDelaySlot() && branch_taken) {
|
||||
bool squashDelaySlot = true;
|
||||
// (inst->readNextPC() != inst->readPC() + sizeof(TheISA::MachInst));
|
||||
DPRINTF(Sparc, "Squash delay slot = %s [sn:%i]\n",
|
||||
squashDelaySlot ? "true": "false", inst->seqNum);
|
||||
toCommit->squashDelaySlot[tid] = squashDelaySlot;
|
||||
//If we're squashing the delay slot, we need to pick back up at NextPC.
|
||||
//Otherwise, NextPC isn't being squashed, so we should pick back up at
|
||||
//NextNPC.
|
||||
if (squashDelaySlot) {
|
||||
toCommit->nextPC[tid] = inst->readNextPC();
|
||||
} else {
|
||||
toCommit->nextNPC[tid] = inst->readNextNPC();
|
||||
} else
|
||||
toCommit->nextPC[tid] = inst->readNextNPC();
|
||||
}
|
||||
#else
|
||||
toCommit->branchTaken[tid] = inst->readNextPC() !=
|
||||
(inst->readPC() + sizeof(TheISA::MachInst));
|
||||
|
@ -514,6 +525,9 @@ DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, unsigned tid)
|
|||
toCommit->squash[tid] = true;
|
||||
toCommit->squashedSeqNum[tid] = inst->seqNum;
|
||||
toCommit->nextPC[tid] = inst->readNextPC();
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
toCommit->nextNPC[tid] = inst->readNextNPC();
|
||||
#endif
|
||||
toCommit->branchMispredict[tid] = false;
|
||||
|
||||
toCommit->includeSquashInst[tid] = false;
|
||||
|
@ -531,6 +545,9 @@ DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, unsigned tid)
|
|||
toCommit->squash[tid] = true;
|
||||
toCommit->squashedSeqNum[tid] = inst->seqNum;
|
||||
toCommit->nextPC[tid] = inst->readPC();
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
toCommit->nextNPC[tid] = inst->readNextNPC();
|
||||
#endif
|
||||
toCommit->branchMispredict[tid] = false;
|
||||
|
||||
// Must include the broadcasted SN in the squash.
|
||||
|
@ -1338,6 +1355,7 @@ DefaultIEW<Impl>::executeInsts()
|
|||
fetchRedirect[tid] = true;
|
||||
|
||||
DPRINTF(IEW, "Execute: Branch mispredict detected.\n");
|
||||
DPRINTF(IEW, "Predicted target was %#x.\n", inst->predPC);
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x.\n",
|
||||
inst->nextNPC);
|
||||
|
@ -1348,7 +1366,7 @@ DefaultIEW<Impl>::executeInsts()
|
|||
// If incorrect, then signal the ROB that it must be squashed.
|
||||
squashDueToBranch(inst, tid);
|
||||
|
||||
if (inst->predTaken()) {
|
||||
if (inst->readPredTaken()) {
|
||||
predictedTakenIncorrect++;
|
||||
} else {
|
||||
predictedNotTakenIncorrect++;
|
||||
|
|
|
@ -561,6 +561,12 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
|||
// Cast this to type T?
|
||||
data = storeQueue[store_idx].data >> shift_amt;
|
||||
|
||||
// When the data comes from the store queue entry, it's in host
|
||||
// order. When it gets sent to the load, it needs to be in guest
|
||||
// order so when the load converts it again, it ends up back
|
||||
// in host order like the inst expects.
|
||||
data = TheISA::htog(data);
|
||||
|
||||
assert(!load_inst->memData);
|
||||
load_inst->memData = new uint8_t[64];
|
||||
|
||||
|
|
|
@ -597,7 +597,20 @@ LSQUnit<Impl>::writebackStores()
|
|||
|
||||
assert(!inst->memData);
|
||||
inst->memData = new uint8_t[64];
|
||||
memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data,
|
||||
|
||||
TheISA::IntReg convertedData =
|
||||
TheISA::htog(storeQueue[storeWBIdx].data);
|
||||
|
||||
//FIXME This is a hack to get SPARC working. It, along with endianness
|
||||
//in the memory system in general, need to be straightened out more
|
||||
//formally. The problem is that the data's endianness is swapped when
|
||||
//it's in the 64 bit data field in the store queue. The data that you
|
||||
//want won't start at the beginning of the field anymore unless it was
|
||||
//a 64 bit access.
|
||||
memcpy(inst->memData,
|
||||
(uint8_t *)&convertedData +
|
||||
(TheISA::ByteOrderDiffers ?
|
||||
(sizeof(TheISA::IntReg) - req->getSize()) : 0),
|
||||
req->getSize());
|
||||
|
||||
PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
|
||||
|
@ -612,7 +625,7 @@ LSQUnit<Impl>::writebackStores()
|
|||
DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
|
||||
"to Addr:%#x, data:%#x [sn:%lli]\n",
|
||||
storeWBIdx, inst->readPC(),
|
||||
req->getPaddr(), *(inst->memData),
|
||||
req->getPaddr(), (int)*(inst->memData),
|
||||
inst->seqNum);
|
||||
|
||||
// @todo: Remove this SC hack once the memory system handles it.
|
||||
|
|
|
@ -220,16 +220,6 @@ template <class Impl>
|
|||
void
|
||||
MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
|
||||
{
|
||||
// check for error condition.
|
||||
if (return_value.successful()) {
|
||||
// no error
|
||||
this->setArchIntReg(TheISA::SyscallSuccessReg, 0, tid);
|
||||
this->setArchIntReg(TheISA::ReturnValueReg, return_value.value(), tid);
|
||||
} else {
|
||||
// got an error, return details
|
||||
this->setArchIntReg(TheISA::SyscallSuccessReg,
|
||||
(TheISA::IntReg) -1, tid);
|
||||
this->setArchIntReg(TheISA::ReturnValueReg, -return_value.value(), tid);
|
||||
}
|
||||
TheISA::setSyscallReturn(return_value, this->tcBase(tid));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -54,10 +54,6 @@ class MipsDynInst : public BaseDynInst<Impl>
|
|||
/** Typedef for the CPU. */
|
||||
typedef typename Impl::O3CPU O3CPU;
|
||||
|
||||
/** Binary machine instruction type. */
|
||||
typedef TheISA::MachInst MachInst;
|
||||
/** Extended machine instruction type. */
|
||||
typedef TheISA::ExtMachInst ExtMachInst;
|
||||
/** Logical register index type. */
|
||||
typedef TheISA::RegIndex RegIndex;
|
||||
/** Integer register index type. */
|
||||
|
@ -127,22 +123,6 @@ class MipsDynInst : public BaseDynInst<Impl>
|
|||
/** Calls a syscall. */
|
||||
void syscall(int64_t callnum);
|
||||
|
||||
private:
|
||||
/** Physical register index of the destination registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _destRegIdx[MaxInstDestRegs];
|
||||
|
||||
/** Physical register index of the source registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _srcRegIdx[MaxInstSrcRegs];
|
||||
|
||||
/** Physical register index of the previous producers of the
|
||||
* architected destinations.
|
||||
*/
|
||||
PhysRegIndex _prevDestRegIdx[MaxInstDestRegs];
|
||||
|
||||
public:
|
||||
|
||||
// The register accessor methods provide the index of the
|
||||
|
@ -158,28 +138,28 @@ class MipsDynInst : public BaseDynInst<Impl>
|
|||
|
||||
uint64_t readIntRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readIntReg(_srcRegIdx[idx]);
|
||||
return this->cpu->readIntReg(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
|
||||
{
|
||||
return this->cpu->readFloatReg(_srcRegIdx[idx], width);
|
||||
return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatReg(_srcRegIdx[idx]);
|
||||
return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
int width)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(_srcRegIdx[idx], width);
|
||||
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(_srcRegIdx[idx]);
|
||||
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
/** @todo: Make results into arrays so they can handle multiple dest
|
||||
|
@ -187,79 +167,37 @@ class MipsDynInst : public BaseDynInst<Impl>
|
|||
*/
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
this->cpu->setIntReg(_destRegIdx[idx], val);
|
||||
this->cpu->setIntReg(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
|
||||
int width)
|
||||
{
|
||||
this->cpu->setFloatReg(_destRegIdx[idx], val, width);
|
||||
this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
|
||||
}
|
||||
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
this->cpu->setFloatReg(_destRegIdx[idx], val);
|
||||
this->cpu->setFloatReg(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val, int width)
|
||||
{
|
||||
this->cpu->setFloatRegBits(_destRegIdx[idx], val, width);
|
||||
this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val)
|
||||
{
|
||||
this->cpu->setFloatRegBits(_destRegIdx[idx], val);
|
||||
this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th destination
|
||||
* register.
|
||||
*/
|
||||
PhysRegIndex renamedDestRegIdx(int idx) const
|
||||
{
|
||||
return _destRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th source register. */
|
||||
PhysRegIndex renamedSrcRegIdx(int idx) const
|
||||
{
|
||||
return _srcRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the previous physical register
|
||||
* that remapped to the same logical register index.
|
||||
*/
|
||||
PhysRegIndex prevDestRegIdx(int idx) const
|
||||
{
|
||||
return _prevDestRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Renames a destination register to a physical register. Also records
|
||||
* the previous physical register that the logical register mapped to.
|
||||
*/
|
||||
void renameDestReg(int idx,
|
||||
PhysRegIndex renamed_dest,
|
||||
PhysRegIndex previous_rename)
|
||||
{
|
||||
_destRegIdx[idx] = renamed_dest;
|
||||
_prevDestRegIdx[idx] = previous_rename;
|
||||
}
|
||||
|
||||
/** Renames a source logical register to the physical register which
|
||||
* has/will produce that logical register's result.
|
||||
* @todo: add in whether or not the source register is ready.
|
||||
*/
|
||||
void renameSrcReg(int idx, PhysRegIndex renamed_src)
|
||||
{
|
||||
_srcRegIdx[idx] = renamed_src;
|
||||
}
|
||||
|
||||
public:
|
||||
/** Calculates EA part of a memory instruction. Currently unused,
|
||||
* though it may be useful in the future if we want to split
|
||||
|
|
|
@ -53,11 +53,11 @@ MipsDynInst<Impl>::initVars()
|
|||
// as the normal register entries. It will allow the IQ to work
|
||||
// without any modifications.
|
||||
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
|
||||
_destRegIdx[i] = this->staticInst->destRegIdx(i);
|
||||
this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
|
||||
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
|
||||
this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
|
||||
this->_readySrcRegIdx[i] = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -411,6 +411,14 @@ class DefaultRename
|
|||
/** Whether or not rename needs to block this cycle. */
|
||||
bool blockThisCycle;
|
||||
|
||||
/** Whether or not rename needs to resume a serialize instruction
|
||||
* after squashing. */
|
||||
bool resumeSerialize;
|
||||
|
||||
/** Whether or not rename needs to resume clearing out the skidbuffer
|
||||
* after squashing. */
|
||||
bool resumeUnblocking;
|
||||
|
||||
/** The number of threads active in rename. */
|
||||
unsigned numThreads;
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include <list>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/regfile.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "cpu/o3/rename.hh"
|
||||
|
||||
|
@ -41,6 +43,8 @@ DefaultRename<Impl>::DefaultRename(Params *params)
|
|||
commitToRenameDelay(params->commitToRenameDelay),
|
||||
renameWidth(params->renameWidth),
|
||||
commitWidth(params->commitWidth),
|
||||
resumeSerialize(false),
|
||||
resumeUnblocking(false),
|
||||
numThreads(params->numberOfThreads),
|
||||
maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs)
|
||||
{
|
||||
|
@ -332,13 +336,23 @@ DefaultRename<Impl>::squash(const InstSeqNum &squash_seq_num, unsigned tid)
|
|||
// If it still needs to block, the blocking should happen the next
|
||||
// cycle and there should be space to hold everything due to the squash.
|
||||
if (renameStatus[tid] == Blocked ||
|
||||
renameStatus[tid] == Unblocking ||
|
||||
renameStatus[tid] == SerializeStall) {
|
||||
renameStatus[tid] == Unblocking) {
|
||||
toDecode->renameUnblock[tid] = 1;
|
||||
|
||||
resumeSerialize = false;
|
||||
serializeInst[tid] = NULL;
|
||||
} else if (renameStatus[tid] == SerializeStall) {
|
||||
if (serializeInst[tid]->seqNum <= squash_seq_num) {
|
||||
DPRINTF(Rename, "Rename will resume serializing after squash\n");
|
||||
resumeSerialize = true;
|
||||
assert(serializeInst[tid]);
|
||||
} else {
|
||||
resumeSerialize = false;
|
||||
toDecode->renameUnblock[tid] = 1;
|
||||
|
||||
serializeInst[tid] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the status to Squashing.
|
||||
renameStatus[tid] = Squashing;
|
||||
|
@ -392,6 +406,9 @@ DefaultRename<Impl>::squash(const InstSeqNum &squash_seq_num, unsigned tid)
|
|||
}
|
||||
slist_it++;
|
||||
}
|
||||
resumeUnblocking = (skidBuffer[tid].size() != 0);
|
||||
DPRINTF(Rename, "Resume unblocking set to %s\n",
|
||||
resumeUnblocking ? "true" : "false");
|
||||
#else
|
||||
skidBuffer[tid].clear();
|
||||
#endif
|
||||
|
@ -475,6 +492,20 @@ DefaultRename<Impl>::rename(bool &status_change, unsigned tid)
|
|||
++renameSquashCycles;
|
||||
} else if (renameStatus[tid] == SerializeStall) {
|
||||
++renameSerializeStallCycles;
|
||||
// If we are currently in SerializeStall and resumeSerialize
|
||||
// was set, then that means that we are resuming serializing
|
||||
// this cycle. Tell the previous stages to block.
|
||||
if (resumeSerialize) {
|
||||
resumeSerialize = false;
|
||||
block(tid);
|
||||
toDecode->renameUnblock[tid] = false;
|
||||
}
|
||||
} else if (renameStatus[tid] == Unblocking) {
|
||||
if (resumeUnblocking) {
|
||||
block(tid);
|
||||
resumeUnblocking = false;
|
||||
toDecode->renameUnblock[tid] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (renameStatus[tid] == Running ||
|
||||
|
@ -740,8 +771,18 @@ DefaultRename<Impl>::skidInsert(unsigned tid)
|
|||
}
|
||||
|
||||
if (skidBuffer[tid].size() > skidBufferMax)
|
||||
{
|
||||
typename InstQueue::iterator it;
|
||||
warn("Skidbuffer contents:\n");
|
||||
for(it = skidBuffer[tid].begin(); it != skidBuffer[tid].end(); it++)
|
||||
{
|
||||
warn("[tid:%u]: %s [sn:%i].\n", tid,
|
||||
(*it)->staticInst->disassemble(inst->readPC()),
|
||||
(*it)->seqNum);
|
||||
}
|
||||
panic("Skidbuffer Exceeded Max Size");
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
|
@ -827,7 +868,10 @@ DefaultRename<Impl>::block(unsigned tid)
|
|||
// Only signal backwards to block if the previous stages do not think
|
||||
// rename is already blocked.
|
||||
if (renameStatus[tid] != Blocked) {
|
||||
if (renameStatus[tid] != Unblocking) {
|
||||
// If resumeUnblocking is set, we unblocked during the squash,
|
||||
// but now we're have unblocking status. We need to tell earlier
|
||||
// stages to block.
|
||||
if (resumeUnblocking || renameStatus[tid] != Unblocking) {
|
||||
toDecode->renameBlock[tid] = true;
|
||||
toDecode->renameUnblock[tid] = false;
|
||||
wroteToTimeBuffer = true;
|
||||
|
@ -960,13 +1004,19 @@ DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid)
|
|||
// Will need to mark dependencies though.
|
||||
for (int src_idx = 0; src_idx < num_src_regs; src_idx++) {
|
||||
RegIndex src_reg = inst->srcRegIdx(src_idx);
|
||||
RegIndex flat_src_reg = src_reg;
|
||||
if (src_reg < TheISA::FP_Base_DepTag) {
|
||||
flat_src_reg = TheISA::flattenIntIndex(inst->tcBase(), src_reg);
|
||||
DPRINTF(Rename, "Flattening index %d to %d.\n", (int)src_reg, (int)flat_src_reg);
|
||||
}
|
||||
inst->flattenSrcReg(src_idx, flat_src_reg);
|
||||
|
||||
// Look up the source registers to get the phys. register they've
|
||||
// been renamed to, and set the sources to those registers.
|
||||
PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg);
|
||||
PhysRegIndex renamed_reg = renameMap[tid]->lookup(flat_src_reg);
|
||||
|
||||
DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got "
|
||||
"physical reg %i.\n", tid, (int)src_reg,
|
||||
"physical reg %i.\n", tid, (int)flat_src_reg,
|
||||
(int)renamed_reg);
|
||||
|
||||
inst->renameSrcReg(src_idx, renamed_reg);
|
||||
|
@ -993,20 +1043,27 @@ DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid)
|
|||
// Rename the destination registers.
|
||||
for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) {
|
||||
RegIndex dest_reg = inst->destRegIdx(dest_idx);
|
||||
RegIndex flat_dest_reg = dest_reg;
|
||||
if (dest_reg < TheISA::FP_Base_DepTag) {
|
||||
flat_dest_reg = TheISA::flattenIntIndex(inst->tcBase(), dest_reg);
|
||||
DPRINTF(Rename, "Flattening index %d to %d.\n", (int)dest_reg, (int)flat_dest_reg);
|
||||
}
|
||||
|
||||
inst->flattenDestReg(dest_idx, flat_dest_reg);
|
||||
|
||||
// Get the physical register that the destination will be
|
||||
// renamed to.
|
||||
rename_result = renameMap[tid]->rename(dest_reg);
|
||||
rename_result = renameMap[tid]->rename(flat_dest_reg);
|
||||
|
||||
//Mark Scoreboard entry as not ready
|
||||
scoreboard->unsetReg(rename_result.first);
|
||||
|
||||
DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical "
|
||||
"reg %i.\n", tid, (int)dest_reg,
|
||||
"reg %i.\n", tid, (int)flat_dest_reg,
|
||||
(int)rename_result.first);
|
||||
|
||||
// Record the rename information so that a history can be kept.
|
||||
RenameHistory hb_entry(inst->seqNum, dest_reg,
|
||||
RenameHistory hb_entry(inst->seqNum, flat_dest_reg,
|
||||
rename_result.first,
|
||||
rename_result.second);
|
||||
|
||||
|
@ -1230,13 +1287,25 @@ DefaultRename<Impl>::checkSignalsAndUpdate(unsigned tid)
|
|||
if (renameStatus[tid] == Squashing) {
|
||||
// Switch status to running if rename isn't being told to block or
|
||||
// squash this cycle.
|
||||
if (resumeSerialize) {
|
||||
DPRINTF(Rename, "[tid:%u]: Done squashing, switching to serialize.\n",
|
||||
tid);
|
||||
|
||||
renameStatus[tid] = SerializeStall;
|
||||
return true;
|
||||
} else if (resumeUnblocking) {
|
||||
DPRINTF(Rename, "[tid:%u]: Done squashing, switching to unblocking.\n",
|
||||
tid);
|
||||
renameStatus[tid] = Unblocking;
|
||||
return true;
|
||||
} else {
|
||||
DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n",
|
||||
tid);
|
||||
|
||||
renameStatus[tid] = Running;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (renameStatus[tid] == SerializeStall) {
|
||||
// Stall ends once the ROB is free.
|
||||
|
|
|
@ -37,12 +37,6 @@
|
|||
#include "cpu/o3/cpu.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
|
||||
namespace TheISA
|
||||
{
|
||||
class ITB;
|
||||
class DTB;
|
||||
}
|
||||
|
||||
class EndQuiesceEvent;
|
||||
namespace Kernel {
|
||||
class Statistics;
|
||||
|
@ -61,14 +55,6 @@ class TranslatingPort;
|
|||
template <class Impl>
|
||||
class SparcO3CPU : public FullO3CPU<Impl>
|
||||
{
|
||||
protected:
|
||||
typedef TheISA::IntReg IntReg;
|
||||
typedef TheISA::FloatReg FloatReg;
|
||||
typedef TheISA::FloatRegBits FloatRegBits;
|
||||
typedef TheISA::MiscReg MiscReg;
|
||||
typedef TheISA::RegFile RegFile;
|
||||
typedef TheISA::MiscRegFile MiscRegFile;
|
||||
|
||||
public:
|
||||
typedef O3ThreadState<Impl> ImplState;
|
||||
typedef O3ThreadState<Impl> Thread;
|
||||
|
@ -77,13 +63,6 @@ class SparcO3CPU : public FullO3CPU<Impl>
|
|||
/** Constructs an AlphaO3CPU with the given parameters. */
|
||||
SparcO3CPU(Params *params);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
/** ITB pointer. */
|
||||
SparcISA::ITB *itb;
|
||||
/** DTB pointer. */
|
||||
SparcISA::DTB *dtb;
|
||||
#endif
|
||||
|
||||
/** Registers statistics. */
|
||||
void regStats();
|
||||
|
||||
|
@ -91,19 +70,19 @@ class SparcO3CPU : public FullO3CPU<Impl>
|
|||
/** Translates instruction requestion. */
|
||||
Fault translateInstReq(RequestPtr &req, Thread *thread)
|
||||
{
|
||||
return itb->translate(req, thread->getTC());
|
||||
return this->itb->translate(req, thread->getTC());
|
||||
}
|
||||
|
||||
/** Translates data read request. */
|
||||
Fault translateDataReadReq(RequestPtr &req, Thread *thread)
|
||||
{
|
||||
return dtb->translate(req, thread->getTC(), false);
|
||||
return this->dtb->translate(req, thread->getTC(), false);
|
||||
}
|
||||
|
||||
/** Translates data write request. */
|
||||
Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
|
||||
{
|
||||
return dtb->translate(req, thread->getTC(), true);
|
||||
return this->dtb->translate(req, thread->getTC(), true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -127,20 +106,21 @@ class SparcO3CPU : public FullO3CPU<Impl>
|
|||
|
||||
#endif
|
||||
/** Reads a miscellaneous register. */
|
||||
MiscReg readMiscReg(int misc_reg, unsigned tid);
|
||||
TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
|
||||
|
||||
/** Reads a misc. register, including any side effects the read
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid);
|
||||
TheISA::MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid);
|
||||
|
||||
/** Sets a miscellaneous register. */
|
||||
void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid);
|
||||
void setMiscReg(int misc_reg, const TheISA::MiscReg &val, unsigned tid);
|
||||
|
||||
/** Sets a misc. register, including any side effects the write
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
void setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid);
|
||||
void setMiscRegWithEffect(int misc_reg, const TheISA::MiscReg &val,
|
||||
unsigned tid);
|
||||
|
||||
/** Initiates a squash of all in-flight instructions for a given
|
||||
* thread. The source of the squash is an external update of
|
||||
|
@ -175,10 +155,10 @@ class SparcO3CPU : public FullO3CPU<Impl>
|
|||
*/
|
||||
void syscall(int64_t callnum, int tid);
|
||||
/** Gets a syscall argument. */
|
||||
IntReg getSyscallArg(int i, int tid);
|
||||
TheISA::IntReg getSyscallArg(int i, int tid);
|
||||
|
||||
/** Used to shift args for indirect syscall. */
|
||||
void setSyscallArg(int i, IntReg val, int tid);
|
||||
void setSyscallArg(int i, TheISA::IntReg val, int tid);
|
||||
|
||||
/** Sets the return value of a syscall. */
|
||||
void setSyscallReturn(SyscallReturn return_value, int tid);
|
||||
|
@ -204,4 +184,4 @@ class SparcO3CPU : public FullO3CPU<Impl>
|
|||
bool lockFlag;
|
||||
};
|
||||
|
||||
#endif // __CPU_O3_ALPHA_CPU_HH__
|
||||
#endif // __CPU_O3_SPARC_CPU_HH__
|
||||
|
|
|
@ -55,8 +55,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU)
|
|||
#if FULL_SYSTEM
|
||||
SimObjectParam<System *> system;
|
||||
Param<int> cpu_id;
|
||||
SimObjectParam<AlphaISA::ITB *> itb;
|
||||
SimObjectParam<AlphaISA::DTB *> dtb;
|
||||
SimObjectParam<SparcISA::ITB *> itb;
|
||||
SimObjectParam<SparcISA::DTB *> dtb;
|
||||
Param<Tick> profile;
|
||||
|
||||
Param<bool> do_quiesce;
|
||||
|
|
|
@ -55,12 +55,7 @@
|
|||
#endif
|
||||
|
||||
template <class Impl>
|
||||
SparcO3CPU<Impl>::SparcO3CPU(Params *params)
|
||||
#if FULL_SYSTEM
|
||||
: FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb)
|
||||
#else
|
||||
: FullO3CPU<Impl>(params)
|
||||
#endif
|
||||
SparcO3CPU<Impl>::SparcO3CPU(Params *params) : FullO3CPU<Impl>(params)
|
||||
{
|
||||
DPRINTF(O3CPU, "Creating SparcO3CPU object.\n");
|
||||
|
||||
|
@ -172,15 +167,16 @@ SparcO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid)
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
SparcO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
|
||||
SparcO3CPU<Impl>::setMiscReg(int misc_reg,
|
||||
const SparcISA::MiscReg &val, unsigned tid)
|
||||
{
|
||||
this->regFile.setMiscReg(misc_reg, val, tid);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
SparcO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val,
|
||||
unsigned tid)
|
||||
SparcO3CPU<Impl>::setMiscRegWithEffect(int misc_reg,
|
||||
const SparcISA::MiscReg &val, unsigned tid)
|
||||
{
|
||||
this->regFile.setMiscRegWithEffect(misc_reg, val, tid);
|
||||
}
|
||||
|
@ -285,35 +281,24 @@ template <class Impl>
|
|||
TheISA::IntReg
|
||||
SparcO3CPU<Impl>::getSyscallArg(int i, int tid)
|
||||
{
|
||||
return this->readArchIntReg(SparcISA::ArgumentReg0 + i, tid);
|
||||
TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid),
|
||||
SparcISA::ArgumentReg0 + i);
|
||||
return this->readArchIntReg(idx, tid);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
SparcO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
|
||||
SparcO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid)
|
||||
{
|
||||
this->setArchIntReg(SparcISA::ArgumentReg0 + i, val, tid);
|
||||
TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid),
|
||||
SparcISA::ArgumentReg0 + i);
|
||||
this->setArchIntReg(idx, val, tid);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
|
||||
{
|
||||
// check for error condition. SPARC syscall convention is to
|
||||
// indicate success/failure in reg the carry bit of the ccr
|
||||
// and put the return value itself in the standard return value reg ().
|
||||
if (return_value.successful()) {
|
||||
// no error, clear XCC.C
|
||||
this->setMiscReg(SparcISA::MISCREG_CCR,
|
||||
this->readMiscReg(SparcISA::MISCREG_CCR, tid) & 0xEE, tid);
|
||||
this->setArchIntReg(SparcISA::ReturnValueReg,
|
||||
return_value.value(), tid);
|
||||
} else {
|
||||
// got an error, set XCC.C
|
||||
this->setMiscReg(SparcISA::MISCREG_CCR,
|
||||
this->readMiscReg(SparcISA::MISCREG_CCR, tid) | 0x11, tid);
|
||||
this->setArchIntReg(SparcISA::ReturnValueReg,
|
||||
return_value.value(), tid);
|
||||
}
|
||||
TheISA::setSyscallReturn(return_value, this->tcBase(tid));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define __CPU_O3_SPARC_DYN_INST_HH__
|
||||
|
||||
#include "arch/sparc/isa_traits.hh"
|
||||
#include "arch/sparc/types.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "cpu/o3/sparc/cpu.hh"
|
||||
|
@ -55,8 +56,8 @@ class SparcDynInst : public BaseDynInst<Impl>
|
|||
|
||||
public:
|
||||
/** BaseDynInst constructor given a binary instruction. */
|
||||
SparcDynInst(TheISA::ExtMachInst inst, Addr PC,
|
||||
Addr Pred_PC, InstSeqNum seq_num, O3CPU *cpu);
|
||||
SparcDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC,
|
||||
Addr Pred_PC, Addr Pred_NPC, InstSeqNum seq_num, O3CPU *cpu);
|
||||
|
||||
/** BaseDynInst constructor given a static inst pointer. */
|
||||
SparcDynInst(StaticInstPtr &_staticInst);
|
||||
|
@ -105,6 +106,45 @@ class SparcDynInst : public BaseDynInst<Impl>
|
|||
this->threadNumber);
|
||||
}
|
||||
|
||||
/** Reads a miscellaneous register. */
|
||||
TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readMiscReg(
|
||||
si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
|
||||
this->threadNumber);
|
||||
}
|
||||
|
||||
/** Reads a misc. register, including any side-effects the read
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
TheISA::MiscReg readMiscRegOperandWithEffect(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readMiscRegWithEffect(
|
||||
si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
|
||||
this->threadNumber);
|
||||
}
|
||||
|
||||
/** Sets a misc. register. */
|
||||
void setMiscRegOperand(const StaticInst * si,
|
||||
int idx, const TheISA::MiscReg &val)
|
||||
{
|
||||
this->instResult.integer = val;
|
||||
return this->cpu->setMiscReg(
|
||||
si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
|
||||
val, this->threadNumber);
|
||||
}
|
||||
|
||||
/** Sets a misc. register, including any side-effects the write
|
||||
* might have as defined by the architecture.
|
||||
*/
|
||||
void setMiscRegOperandWithEffect(
|
||||
const StaticInst *si, int idx, const TheISA::MiscReg &val)
|
||||
{
|
||||
return this->cpu->setMiscRegWithEffect(
|
||||
si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
|
||||
val, this->threadNumber);
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
/** Calls hardware return from error interrupt. */
|
||||
Fault hwrei();
|
||||
|
@ -116,22 +156,6 @@ class SparcDynInst : public BaseDynInst<Impl>
|
|||
void syscall(int64_t callnum);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/** Physical register index of the destination registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _destRegIdx[TheISA::MaxInstDestRegs];
|
||||
|
||||
/** Physical register index of the source registers of this
|
||||
* instruction.
|
||||
*/
|
||||
PhysRegIndex _srcRegIdx[TheISA::MaxInstSrcRegs];
|
||||
|
||||
/** Physical register index of the previous producers of the
|
||||
* architected destinations.
|
||||
*/
|
||||
PhysRegIndex _prevDestRegIdx[TheISA::MaxInstDestRegs];
|
||||
|
||||
public:
|
||||
|
||||
// The register accessor methods provide the index of the
|
||||
|
@ -145,108 +169,70 @@ class SparcDynInst : public BaseDynInst<Impl>
|
|||
// storage (which is pretty hard to imagine they would have reason
|
||||
// to do).
|
||||
|
||||
uint64_t readIntReg(const StaticInst *si, int idx)
|
||||
uint64_t readIntRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readIntReg(_srcRegIdx[idx]);
|
||||
uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]);
|
||||
DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val);
|
||||
return this->cpu->readIntReg(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
TheISA::FloatReg readFloatReg(const StaticInst *si, int idx, int width)
|
||||
{
|
||||
return this->cpu->readFloatReg(_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
TheISA::FloatReg readFloatReg(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatReg(_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
TheISA::FloatRegBits readFloatRegBits(const StaticInst *si,
|
||||
TheISA::FloatReg readFloatRegOperand(const StaticInst *si,
|
||||
int idx, int width)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(_srcRegIdx[idx], width);
|
||||
return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
TheISA::FloatRegBits readFloatRegBits(const StaticInst *si, int idx)
|
||||
TheISA::FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(_srcRegIdx[idx]);
|
||||
return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si,
|
||||
int idx, int width)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
|
||||
}
|
||||
|
||||
TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
|
||||
}
|
||||
|
||||
/** @todo: Make results into arrays so they can handle multiple dest
|
||||
* registers.
|
||||
*/
|
||||
void setIntReg(const StaticInst *si, int idx, uint64_t val)
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
this->cpu->setIntReg(_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setIntReg(si, idx, val);
|
||||
DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val);
|
||||
this->cpu->setIntReg(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatReg(const StaticInst *si, int idx,
|
||||
void setFloatRegOperand(const StaticInst *si, int idx,
|
||||
TheISA::FloatReg val, int width)
|
||||
{
|
||||
this->cpu->setFloatReg(_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatReg(si, idx, val, width);
|
||||
this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
|
||||
}
|
||||
|
||||
void setFloatReg(const StaticInst *si, int idx, TheISA::FloatReg val)
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, TheISA::FloatReg val)
|
||||
{
|
||||
this->cpu->setFloatReg(_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatReg(si, idx, val);
|
||||
this->cpu->setFloatReg(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegBits(const StaticInst *si, int idx,
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
TheISA::FloatRegBits val, int width)
|
||||
{
|
||||
this->cpu->setFloatRegBits(_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegBits(si, idx, val);
|
||||
this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
|
||||
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegBits(const StaticInst *si,
|
||||
void setFloatRegOperandBits(const StaticInst *si,
|
||||
int idx, TheISA::FloatRegBits val)
|
||||
{
|
||||
this->cpu->setFloatRegBits(_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegBits(si, idx, val);
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th destination
|
||||
* register.
|
||||
*/
|
||||
PhysRegIndex renamedDestRegIdx(int idx) const
|
||||
{
|
||||
return _destRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the i'th source register. */
|
||||
PhysRegIndex renamedSrcRegIdx(int idx) const
|
||||
{
|
||||
return _srcRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Returns the physical register index of the previous physical register
|
||||
* that remapped to the same logical register index.
|
||||
*/
|
||||
PhysRegIndex prevDestRegIdx(int idx) const
|
||||
{
|
||||
return _prevDestRegIdx[idx];
|
||||
}
|
||||
|
||||
/** Renames a destination register to a physical register. Also records
|
||||
* the previous physical register that the logical register mapped to.
|
||||
*/
|
||||
void renameDestReg(int idx,
|
||||
PhysRegIndex renamed_dest,
|
||||
PhysRegIndex previous_rename)
|
||||
{
|
||||
_destRegIdx[idx] = renamed_dest;
|
||||
_prevDestRegIdx[idx] = previous_rename;
|
||||
}
|
||||
|
||||
/** Renames a source logical register to the physical register which
|
||||
* has/will produce that logical register's result.
|
||||
* @todo: add in whether or not the source register is ready.
|
||||
*/
|
||||
void renameSrcReg(int idx, PhysRegIndex renamed_src)
|
||||
{
|
||||
_srcRegIdx[idx] = renamed_src;
|
||||
this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
|
||||
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -31,9 +31,10 @@
|
|||
#include "cpu/o3/sparc/dyn_inst.hh"
|
||||
|
||||
template <class Impl>
|
||||
SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst, Addr PC,
|
||||
Addr Pred_PC, InstSeqNum seq_num, O3CPU *cpu)
|
||||
: BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu)
|
||||
SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst,
|
||||
Addr PC, Addr NPC, Addr Pred_PC, Addr Pred_NPC,
|
||||
InstSeqNum seq_num, O3CPU *cpu)
|
||||
: BaseDynInst<Impl>(inst, PC, NPC, Pred_PC, Pred_NPC, seq_num, cpu)
|
||||
{
|
||||
initVars();
|
||||
}
|
||||
|
@ -53,11 +54,11 @@ SparcDynInst<Impl>::initVars()
|
|||
// as the normal register entries. It will allow the IQ to work
|
||||
// without any modifications.
|
||||
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
|
||||
_destRegIdx[i] = this->staticInst->destRegIdx(i);
|
||||
this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
|
||||
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
|
||||
this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
|
||||
this->_readySrcRegIdx[i] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +127,8 @@ template <class Impl>
|
|||
bool
|
||||
SparcDynInst<Impl>::simPalCheck(int palFunc)
|
||||
{
|
||||
return this->cpu->simPalCheck(palFunc, this->threadNumber);
|
||||
panic("simPalCheck called, but there's no PAL in SPARC!\n");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
template <class Impl>
|
||||
|
|
|
@ -36,12 +36,6 @@ class SparcTC : public O3ThreadContext<Impl>
|
|||
{
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
/** Returns a pointer to the ITB. */
|
||||
virtual SparcISA::ITB *getITBPtr() { return this->cpu->itb; }
|
||||
|
||||
/** Returns a pointer to the DTB. */
|
||||
virtual SparcISA::DTB *getDTBPtr() { return this->cpu->dtb; }
|
||||
|
||||
/** Returns pointer to the quiesce event. */
|
||||
virtual EndQuiesceEvent *getQuiesceEvent()
|
||||
{
|
||||
|
@ -62,7 +56,7 @@ class SparcTC : public O3ThreadContext<Impl>
|
|||
virtual void changeRegFileContext(TheISA::RegContextParam param,
|
||||
TheISA::RegContextVal val)
|
||||
{
|
||||
panic("This doesn't make sense!\n");
|
||||
//XXX Ignore this for now. This -really- needs to get fixed.
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,6 +66,14 @@ class O3ThreadContext : public ThreadContext
|
|||
/** Pointer to the thread state that this TC corrseponds to. */
|
||||
O3ThreadState<Impl> *thread;
|
||||
|
||||
#if FULL_SYSTEM
|
||||
/** Returns a pointer to the ITB. */
|
||||
TheISA::ITB *getITBPtr() { return cpu->itb; }
|
||||
|
||||
/** Returns a pointer to the DTB. */
|
||||
TheISA::DTB *getDTBPtr() { return cpu->dtb; }
|
||||
#endif
|
||||
|
||||
/** Returns a pointer to this CPU. */
|
||||
virtual BaseCPU *getCpuPtr() { return cpu; }
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* Korey Sewell
|
||||
*/
|
||||
|
||||
#include "arch/regfile.hh"
|
||||
#include "cpu/o3/thread_context.hh"
|
||||
#include "cpu/quiesce_event.hh"
|
||||
|
||||
|
@ -305,6 +306,7 @@ template <class Impl>
|
|||
uint64_t
|
||||
O3ThreadContext<Impl>::readIntReg(int reg_idx)
|
||||
{
|
||||
reg_idx = TheISA::flattenIntIndex(this, reg_idx);
|
||||
return cpu->readArchIntReg(reg_idx, thread->readTid());
|
||||
}
|
||||
|
||||
|
@ -349,6 +351,7 @@ template <class Impl>
|
|||
void
|
||||
O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
|
||||
{
|
||||
reg_idx = TheISA::flattenIntIndex(this, reg_idx);
|
||||
cpu->setArchIntReg(reg_idx, val, thread->readTid());
|
||||
|
||||
// Squash if we're not already in a state update mode.
|
||||
|
|
|
@ -303,6 +303,31 @@ class BaseSimpleCPU : public BaseCPU
|
|||
return thread->setMiscRegWithEffect(misc_reg, val);
|
||||
}
|
||||
|
||||
MiscReg readMiscRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->readMiscReg(reg_idx);
|
||||
}
|
||||
|
||||
MiscReg readMiscRegOperandWithEffect(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->readMiscRegWithEffect(reg_idx);
|
||||
}
|
||||
|
||||
void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->setMiscReg(reg_idx, val);
|
||||
}
|
||||
|
||||
void setMiscRegOperandWithEffect(
|
||||
const StaticInst *si, int idx, const MiscReg &val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->setMiscRegWithEffect(reg_idx, val);
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Fault hwrei() { return thread->hwrei(); }
|
||||
void ev5_trap(Fault fault) { fault->invoke(tc); }
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#define __CPU_SIMPLE_THREAD_HH__
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/regfile.hh"
|
||||
#include "arch/syscallreturn.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/thread_state.hh"
|
||||
|
@ -250,7 +252,7 @@ class SimpleThread : public ThreadState
|
|||
//
|
||||
uint64_t readIntReg(int reg_idx)
|
||||
{
|
||||
return regs.readIntReg(reg_idx);
|
||||
return regs.readIntReg(TheISA::flattenIntIndex(getTC(), reg_idx));
|
||||
}
|
||||
|
||||
FloatReg readFloatReg(int reg_idx, int width)
|
||||
|
@ -275,7 +277,7 @@ class SimpleThread : public ThreadState
|
|||
|
||||
void setIntReg(int reg_idx, uint64_t val)
|
||||
{
|
||||
regs.setIntReg(reg_idx, val);
|
||||
regs.setIntReg(TheISA::flattenIntIndex(getTC(), reg_idx), val);
|
||||
}
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val, int width)
|
||||
|
@ -376,18 +378,20 @@ class SimpleThread : public ThreadState
|
|||
#if !FULL_SYSTEM
|
||||
TheISA::IntReg getSyscallArg(int i)
|
||||
{
|
||||
return regs.readIntReg(TheISA::ArgumentReg0 + i);
|
||||
return regs.readIntReg(TheISA::flattenIntIndex(getTC(),
|
||||
TheISA::ArgumentReg0 + i));
|
||||
}
|
||||
|
||||
// used to shift args for indirect syscall
|
||||
void setSyscallArg(int i, TheISA::IntReg val)
|
||||
{
|
||||
regs.setIntReg(TheISA::ArgumentReg0 + i, val);
|
||||
regs.setIntReg(TheISA::flattenIntIndex(getTC(),
|
||||
TheISA::ArgumentReg0 + i), val);
|
||||
}
|
||||
|
||||
void setSyscallReturn(SyscallReturn return_value)
|
||||
{
|
||||
TheISA::setSyscallReturn(return_value, ®s);
|
||||
TheISA::setSyscallReturn(return_value, getTC());
|
||||
}
|
||||
|
||||
void syscall(int64_t callnum)
|
||||
|
|
|
@ -32,13 +32,13 @@
|
|||
#define __CPU_THREAD_CONTEXT_HH__
|
||||
|
||||
#include "arch/regfile.hh"
|
||||
#include "arch/syscallreturn.hh"
|
||||
#include "arch/types.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/faults.hh"
|
||||
#include "sim/host.hh"
|
||||
#include "sim/serialize.hh"
|
||||
#include "sim/syscallreturn.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
|
||||
// @todo: Figure out a more architecture independent way to obtain the ITB and
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include <libkern/OSByteOrder.h>
|
||||
#endif
|
||||
|
||||
enum ByteOrder {BigEndianByteOrder, LittleEndianByteOrder};
|
||||
|
||||
//These functions actually perform the swapping for parameters
|
||||
//of various bit lengths
|
||||
static inline uint64_t
|
||||
|
@ -131,11 +133,13 @@ template <typename T> static inline T letobe(T value) {return swap_byte(value);}
|
|||
//For conversions not involving the guest system, we can define the functions
|
||||
//conditionally based on the BYTE_ORDER macro and outside of the namespaces
|
||||
#if defined(_BIG_ENDIAN) || BYTE_ORDER == BIG_ENDIAN
|
||||
const ByteOrder HostByteOrder = BigEndianByteOrder;
|
||||
template <typename T> static inline T htole(T value) {return swap_byte(value);}
|
||||
template <typename T> static inline T letoh(T value) {return swap_byte(value);}
|
||||
template <typename T> static inline T htobe(T value) {return value;}
|
||||
template <typename T> static inline T betoh(T value) {return value;}
|
||||
#elif defined(_LITTLE_ENDIAN) || BYTE_ORDER == LITTLE_ENDIAN
|
||||
const ByteOrder HostByteOrder = LittleEndianByteOrder;
|
||||
template <typename T> static inline T htole(T value) {return value;}
|
||||
template <typename T> static inline T letoh(T value) {return value;}
|
||||
template <typename T> static inline T htobe(T value) {return swap_byte(value);}
|
||||
|
@ -146,6 +150,7 @@ template <typename T> static inline T betoh(T value) {return swap_byte(value);}
|
|||
|
||||
namespace BigEndianGuest
|
||||
{
|
||||
const bool ByteOrderDiffers = (HostByteOrder != BigEndianByteOrder);
|
||||
template <typename T>
|
||||
static inline T gtole(T value) {return betole(value);}
|
||||
template <typename T>
|
||||
|
@ -162,6 +167,7 @@ namespace BigEndianGuest
|
|||
|
||||
namespace LittleEndianGuest
|
||||
{
|
||||
const bool ByteOrderDiffers = (HostByteOrder != LittleEndianByteOrder);
|
||||
template <typename T>
|
||||
static inline T gtole(T value) {return value;}
|
||||
template <typename T>
|
||||
|
|
70
src/sim/syscallreturn.hh
Normal file
70
src/sim/syscallreturn.hh
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2005 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: Gabe Black
|
||||
*/
|
||||
|
||||
#ifndef __SIM_SYSCALLRETURN_HH__
|
||||
#define __SIM_SYSCALLRETURN_HH__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
class SyscallReturn
|
||||
{
|
||||
public:
|
||||
template <class T>
|
||||
SyscallReturn(T v, bool s)
|
||||
{
|
||||
retval = (uint64_t)v;
|
||||
success = s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SyscallReturn(T v)
|
||||
{
|
||||
success = (v >= 0);
|
||||
retval = (uint64_t)v;
|
||||
}
|
||||
|
||||
~SyscallReturn() {}
|
||||
|
||||
SyscallReturn& operator=(const SyscallReturn& s)
|
||||
{
|
||||
retval = s.retval;
|
||||
success = s.success;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool successful() { return success; }
|
||||
uint64_t value() { return retval; }
|
||||
|
||||
private:
|
||||
uint64_t retval;
|
||||
bool success;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue