gem5/arch/mips/isa/formats/branch.isa
Korey Sewell 38ce95db3b Support for All Jump Instructions ...
Redo format for Branches and Jumps ( Must update NNPC not NPC )

Now all branches and jumps look like they auto-generate correctly from isa_parser.py!!!

arch/mips/isa/decoder.isa:
    Support for All Jump Instructions ..
arch/mips/isa/formats/branch.isa:
    Redo format for Branches and Jumps ( Must update NNPC not NPC )
arch/mips/isa/formats/util.isa:
    define clear_exe_inst_hazards for later use

--HG--
extra : convert_revision : 63618ed12ee6ed94c47d29619cc1cab2cbaf5cda
2006-02-20 01:49:16 -05:00

318 lines
8.3 KiB
C++

// -*- mode:c++ -*-
////////////////////////////////////////////////////////////////////
//
// Control transfer instructions
//
output header {{
/**
* Base class for instructions whose disassembly is not purely a
* function of the machine instruction (i.e., it depends on the
* PC). This class overrides the disassemble() method to check
* the PC and symbol table values before re-using a cached
* disassembly string. This is necessary for branches and jumps,
* where the disassembly string includes the target address (which
* may depend on the PC and/or symbol table).
*/
class PCDependentDisassembly : public MipsStaticInst
{
protected:
/// Cached program counter from last disassembly
mutable Addr cachedPC;
/// Cached symbol table pointer from last disassembly
mutable const SymbolTable *cachedSymtab;
/// Constructor
PCDependentDisassembly(const char *mnem, MachInst _machInst,
OpClass __opClass)
: MipsStaticInst(mnem, _machInst, __opClass),
cachedPC(0), cachedSymtab(0)
{
}
const std::string &
disassemble(Addr pc, const SymbolTable *symtab) const;
};
/**
* Base class for branches (PC-relative control transfers),
* conditional or unconditional.
*/
class Branch : public PCDependentDisassembly
{
protected:
/// target address (signed) Displacement .
int32_t disp;
/// Constructor.
Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
: PCDependentDisassembly(mnem, _machInst, __opClass),
disp(OFFSET << 2)
{
}
Addr branchTarget(Addr branchPC) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
/**
* Base class for branch likely branches (PC-relative control transfers),
*/
class BranchLikely : public PCDependentDisassembly
{
protected:
/// target address (signed) Displacement .
int32_t disp;
/// Constructor.
Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
: PCDependentDisassembly(mnem, _machInst, __opClass),
disp(OFFSET << 2)
{
}
Addr branchTarget(Addr branchPC) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
/**
* Base class for jumps (register-indirect control transfers). In
* the Mips ISA, these are always unconditional.
*/
class Jump : public PCDependentDisassembly
{
protected:
/// Displacement to target address (signed).
int32_t disp;
public:
/// Constructor
Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
: PCDependentDisassembly(mnem, _machInst, __opClass),
disp(OFFSET)
{
}
Addr branchTarget(ExecContext *xc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
}};
output decoder {{
Addr
Branch::branchTarget(Addr branchPC) const
{
return branchPC + 4 + disp;
}
Addr
BranchLikely::branchTarget(Addr branchPC) const
{
return branchPC + 4 + disp;
}
Addr
Jump::branchTarget(ExecContext *xc) const
{
Addr NPC = xc->readPC() + 4;
uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
return (Rb & ~3) | (NPC & 1);
}
const std::string &
PCDependentDisassembly::disassemble(Addr pc,
const SymbolTable *symtab) const
{
if (!cachedDisassembly ||
pc != cachedPC || symtab != cachedSymtab)
{
if (cachedDisassembly)
delete cachedDisassembly;
cachedDisassembly =
new std::string(generateDisassembly(pc, symtab));
cachedPC = pc;
cachedSymtab = symtab;
}
return *cachedDisassembly;
}
std::string
Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
ccprintf(ss, "%-10s ", mnemonic);
// There's only one register arg (RA), but it could be
// either a source (the condition for conditional
// branches) or a destination (the link reg for
// unconditional branches)
if (_numSrcRegs > 0) {
printReg(ss, _srcRegIdx[0]);
ss << ",";
}
else if (_numDestRegs > 0) {
printReg(ss, _destRegIdx[0]);
ss << ",";
}
#ifdef SS_COMPATIBLE_DISASSEMBLY
if (_numSrcRegs == 0 && _numDestRegs == 0) {
printReg(ss, 31);
ss << ",";
}
#endif
Addr target = pc + 4 + disp;
std::string str;
if (symtab && symtab->findSymbol(target, str))
ss << str;
else
ccprintf(ss, "0x%x", target);
return ss.str();
}
std::string
BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
ccprintf(ss, "%-10s ", mnemonic);
// There's only one register arg (RA), but it could be
// either a source (the condition for conditional
// branches) or a destination (the link reg for
// unconditional branches)
if (_numSrcRegs > 0) {
printReg(ss, _srcRegIdx[0]);
ss << ",";
}
else if (_numDestRegs > 0) {
printReg(ss, _destRegIdx[0]);
ss << ",";
}
#ifdef SS_COMPATIBLE_DISASSEMBLY
if (_numSrcRegs == 0 && _numDestRegs == 0) {
printReg(ss, 31);
ss << ",";
}
#endif
Addr target = pc + 4 + disp;
std::string str;
if (symtab && symtab->findSymbol(target, str))
ss << str;
else
ccprintf(ss, "0x%x", target);
return ss.str();
}
std::string
Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
ccprintf(ss, "%-10s ", mnemonic);
#ifdef SS_COMPATIBLE_DISASSEMBLY
if (_numDestRegs == 0) {
printReg(ss, 31);
ss << ",";
}
#endif
if (_numDestRegs > 0) {
printReg(ss, _destRegIdx[0]);
ss << ",";
}
ccprintf(ss, "(r%d)", RB);
return ss.str();
}
}};
def format Branch(code,*flags) {{
#Add Link Code if Link instruction
strlen = len(name)
if name[strlen-2:] == 'al':
code += 'R31 = NNPC;\n'
#Condition code
code = 'bool cond;\n' + code
code += 'if (cond) {\n'
#code += '//NPC=NPC: just placeholder to force parser to writeback NPC\n'
#code += ' NPC = NPC; \n'
code += ' NNPC = NPC + disp;\n'
code += '} \n'
iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
('IsDirectControl', 'IsCondControl'))
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = BasicExecute.subst(iop)
}};
def format BranchLikely(code,*flags) {{
#Add Link Code if Link instruction
strlen = len(name)
if name[strlen-3:] == 'all':
code += 'R31 = NNPC;\n'
#Condition code
code = 'bool cond;\n' + code
code += 'if (cond) {'
#code += '//NPC=NPC: just placeholder to force parser to writeback NPC\n'
#code += 'NPC = NPC; \n'
code += 'NNPC = NPC + disp;\n'
code += '} \n'
iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
('IsDirectControl', 'IsCondControl','IsCondDelaySlot'))
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = BasicExecute.subst(iop)
}};
def format Jump(code,*flags) {{
#Add Link Code if Link instruction
strlen = len(name)
if strlen >= 3 and name[2:3] == 'al':
code = 'R31 = NNPC;\n' + code
iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\
('IsIndirectControl', 'IsUncondControl'))
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = BasicExecute.subst(iop)
}};