arch-power: Refactor branch instructions
This changes the base classes for branch instructions and switches to two high-level classes for unconditional and conditional branches. The conditional branches are further classified based on whether they use an immediate field or a register for determining the target address. Decoding has also been consolidated using formats that can generate code after determining if an instruction branches to an absolute address or a PC-relative address, or if it implicitly sets the return address by looking at the AA and LK bits. Change-Id: I5fa7db7b6693586b4ea3c71e5cad8a60753de29c Signed-off-by: Sandipan Das <sandipan@linux.ibm.com> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/40886 Reviewed-by: Boris Shingarov <shingarov@gmail.com> Maintainer: Gabe Black <gabe.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
committed by
Boris Shingarov
parent
e3d58b6132
commit
07f5053c1b
@@ -49,21 +49,30 @@ PCDependentDisassembly::disassemble(
|
||||
return *cachedDisassembly;
|
||||
}
|
||||
|
||||
|
||||
PowerISA::PCState
|
||||
BranchPCRel::branchTarget(const PowerISA::PCState &pc) const
|
||||
BranchOp::branchTarget(const PowerISA::PCState &pc) const
|
||||
{
|
||||
return (uint32_t)(pc.pc() + disp);
|
||||
if (aa)
|
||||
return li;
|
||||
else
|
||||
return pc.pc() + li;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
BranchPCRel::generateDisassembly(
|
||||
BranchOp::generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
Addr target;
|
||||
|
||||
ccprintf(ss, "%-10s ", mnemonic);
|
||||
|
||||
Addr target = pc + disp;
|
||||
if (aa)
|
||||
target = li;
|
||||
else
|
||||
target = pc + li;
|
||||
|
||||
Loader::SymbolTable::const_iterator it;
|
||||
if (symtab && (it = symtab->find(target)) != symtab->end())
|
||||
@@ -74,46 +83,34 @@ BranchPCRel::generateDisassembly(
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
PowerISA::PCState
|
||||
BranchNonPCRel::branchTarget(const PowerISA::PCState &pc) const
|
||||
BranchDispCondOp::branchTarget(const PowerISA::PCState &pc) const
|
||||
{
|
||||
return targetAddr;
|
||||
if (aa) {
|
||||
return bd;
|
||||
} else {
|
||||
return pc.pc() + bd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
BranchNonPCRel::generateDisassembly(
|
||||
BranchDispCondOp::generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
Addr target;
|
||||
|
||||
ccprintf(ss, "%-10s ", mnemonic);
|
||||
|
||||
Loader::SymbolTable::const_iterator it;
|
||||
if (symtab && (it = symtab->find(targetAddr)) != symtab->end())
|
||||
ss << it->name;
|
||||
// Print BI and BO fields
|
||||
ss << bi << ", " << bo << ", ";
|
||||
|
||||
if (aa)
|
||||
target = bd;
|
||||
else
|
||||
ccprintf(ss, "%#x", targetAddr);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
PowerISA::PCState
|
||||
BranchPCRelCond::branchTarget(const PowerISA::PCState &pc) const
|
||||
{
|
||||
return (uint32_t)(pc.pc() + disp);
|
||||
}
|
||||
|
||||
std::string
|
||||
BranchPCRelCond::generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ccprintf(ss, "%-10s ", mnemonic);
|
||||
|
||||
ss << bo << ", " << bi << ", ";
|
||||
|
||||
Addr target = pc + disp;
|
||||
target = pc + bd;
|
||||
|
||||
Loader::SymbolTable::const_iterator it;
|
||||
if (symtab && (it = symtab->find(target)) != symtab->end())
|
||||
@@ -124,47 +121,25 @@ BranchPCRelCond::generateDisassembly(
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
PowerISA::PCState
|
||||
BranchNonPCRelCond::branchTarget(const PowerISA::PCState &pc) const
|
||||
BranchRegCondOp::branchTarget(ThreadContext *tc) const
|
||||
{
|
||||
return targetAddr;
|
||||
Addr addr = tc->readIntReg(srcRegIdx(_numSrcRegs - 1).index());
|
||||
return addr & -4ULL;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
BranchNonPCRelCond::generateDisassembly(
|
||||
BranchRegCondOp::generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ccprintf(ss, "%-10s ", mnemonic);
|
||||
|
||||
ss << bo << ", " << bi << ", ";
|
||||
|
||||
Loader::SymbolTable::const_iterator it;
|
||||
if (symtab && (it = symtab->find(targetAddr)) != symtab->end())
|
||||
ss << it->name;
|
||||
else
|
||||
ccprintf(ss, "%#x", targetAddr);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
PowerISA::PCState
|
||||
BranchRegCond::branchTarget(ThreadContext *tc) const
|
||||
{
|
||||
uint32_t regVal = tc->readIntReg(srcRegIdx(_numSrcRegs - 1).index());
|
||||
return regVal & 0xfffffffc;
|
||||
}
|
||||
|
||||
std::string
|
||||
BranchRegCond::generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ccprintf(ss, "%-10s ", mnemonic);
|
||||
|
||||
ss << bo << ", " << bi << ", ";
|
||||
// Print the BI and BO fields
|
||||
ss << bi << ", " << bo;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -63,25 +63,25 @@ class PCDependentDisassembly : public PowerStaticInst
|
||||
disassemble(Addr pc, const Loader::SymbolTable *symtab) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base class for unconditional, PC-relative branches.
|
||||
* Base class for unconditional, PC-relative or absolute address branches.
|
||||
*/
|
||||
class BranchPCRel : public PCDependentDisassembly
|
||||
class BranchOp : public PCDependentDisassembly
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Displacement
|
||||
uint32_t disp;
|
||||
bool aa;
|
||||
bool lk;
|
||||
int64_t li;
|
||||
|
||||
/// Constructor.
|
||||
BranchPCRel(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: PCDependentDisassembly(mnem, _machInst, __opClass),
|
||||
disp(machInst.li << 2)
|
||||
/// Constructor
|
||||
BranchOp(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: PCDependentDisassembly(mnem, _machInst, __opClass),
|
||||
aa(machInst.aa),
|
||||
lk(machInst.lk),
|
||||
li(sext<26>(machInst.li << 2))
|
||||
{
|
||||
// If bit 26 is 1 then sign extend
|
||||
if (disp & 0x2000000) {
|
||||
disp |= 0xfc000000;
|
||||
}
|
||||
}
|
||||
|
||||
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const override;
|
||||
@@ -93,104 +93,66 @@ class BranchPCRel : public PCDependentDisassembly
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for unconditional, non PC-relative branches.
|
||||
*/
|
||||
class BranchNonPCRel : public PCDependentDisassembly
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Target address
|
||||
uint32_t targetAddr;
|
||||
|
||||
/// Constructor.
|
||||
BranchNonPCRel(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: PCDependentDisassembly(mnem, _machInst, __opClass),
|
||||
targetAddr(machInst.li << 2)
|
||||
{
|
||||
// If bit 26 is 1 then sign extend
|
||||
if (targetAddr & 0x2000000) {
|
||||
targetAddr |= 0xfc000000;
|
||||
}
|
||||
}
|
||||
|
||||
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const override;
|
||||
|
||||
/// Explicitly import the otherwise hidden branchTarget
|
||||
using StaticInst::branchTarget;
|
||||
|
||||
std::string generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for conditional branches.
|
||||
*/
|
||||
class BranchCond : public PCDependentDisassembly
|
||||
class BranchCondOp : public PCDependentDisassembly
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Fields needed for conditions
|
||||
uint32_t bo;
|
||||
uint32_t bi;
|
||||
bool lk;
|
||||
uint8_t bi;
|
||||
uint8_t bo;
|
||||
|
||||
/// Constructor.
|
||||
BranchCond(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: PCDependentDisassembly(mnem, _machInst, __opClass),
|
||||
bo(machInst.bo),
|
||||
bi(machInst.bi)
|
||||
/// Constructor
|
||||
BranchCondOp(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: PCDependentDisassembly(mnem, _machInst, __opClass),
|
||||
lk(machInst.lk),
|
||||
bi(machInst.bi),
|
||||
bo(machInst.bo)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool
|
||||
ctrOk(uint32_t& ctr) const
|
||||
ctrOk(uint64_t& ctr) const
|
||||
{
|
||||
bool ctr_ok;
|
||||
if (bo & 4) {
|
||||
ctr_ok = true;
|
||||
} else {
|
||||
ctr--;
|
||||
if (ctr != 0) {
|
||||
ctr_ok = ((bo & 2) == 0);
|
||||
} else {
|
||||
ctr_ok = ((bo & 2) != 0);
|
||||
}
|
||||
if (bits(bo, 2)) {
|
||||
return true;
|
||||
}
|
||||
return ctr_ok;
|
||||
|
||||
ctr--;
|
||||
return !((ctr != 0) ^ (bits(bo, 1) == 0));
|
||||
}
|
||||
|
||||
inline bool
|
||||
condOk(uint32_t cr) const
|
||||
{
|
||||
bool cond_ok;
|
||||
if (bo & 16) {
|
||||
cond_ok = true;
|
||||
} else {
|
||||
cond_ok = (((cr >> (31 - bi)) & 1) == ((bo >> 3) & 1));
|
||||
if (bits(bo, 4)) {
|
||||
return true;
|
||||
}
|
||||
return cond_ok;
|
||||
|
||||
return bits(cr >> (31 - bi), 0) == bits(bo >> 3, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base class for conditional, PC-relative branches.
|
||||
* Base class for conditional, PC-relative or absolute address branches.
|
||||
*/
|
||||
class BranchPCRelCond : public BranchCond
|
||||
class BranchDispCondOp : public BranchCondOp
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Displacement
|
||||
uint32_t disp;
|
||||
bool aa;
|
||||
int64_t bd;
|
||||
|
||||
/// Constructor.
|
||||
BranchPCRelCond(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: BranchCond(mnem, _machInst, __opClass),
|
||||
disp(machInst.bd << 2)
|
||||
/// Constructor
|
||||
BranchDispCondOp(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: BranchCondOp(mnem, _machInst, __opClass),
|
||||
aa(machInst.aa),
|
||||
bd(sext<16>(machInst.bd << 2))
|
||||
{
|
||||
// If bit 16 is 1 then sign extend
|
||||
if (disp & 0x8000) {
|
||||
disp |= 0xffff0000;
|
||||
}
|
||||
}
|
||||
|
||||
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const override;
|
||||
@@ -202,46 +164,21 @@ class BranchPCRelCond : public BranchCond
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base class for conditional, non PC-relative branches.
|
||||
* Base class for conditional, register-based branches.
|
||||
*/
|
||||
class BranchNonPCRelCond : public BranchCond
|
||||
class BranchRegCondOp : public BranchCondOp
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Target address
|
||||
uint32_t targetAddr;
|
||||
/// TODO: Branch hints are currently ignored
|
||||
uint8_t bh;
|
||||
|
||||
/// Constructor.
|
||||
BranchNonPCRelCond(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: BranchCond(mnem, _machInst, __opClass),
|
||||
targetAddr(machInst.bd << 2)
|
||||
{
|
||||
// If bit 16 is 1 then sign extend
|
||||
if (targetAddr & 0x8000) {
|
||||
targetAddr |= 0xffff0000;
|
||||
}
|
||||
}
|
||||
|
||||
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const override;
|
||||
|
||||
/// Explicitly import the otherwise hidden branchTarget
|
||||
using StaticInst::branchTarget;
|
||||
|
||||
std::string generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for conditional, register-based branches
|
||||
*/
|
||||
class BranchRegCond : public BranchCond
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Constructor.
|
||||
BranchRegCond(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: BranchCond(mnem, _machInst, __opClass)
|
||||
BranchRegCondOp(const char *mnem, MachInst _machInst, OpClass __opClass)
|
||||
: BranchCondOp(mnem, _machInst, __opClass),
|
||||
bh(machInst.bh)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -77,25 +77,16 @@ decode PO default Unknown::unknown() {
|
||||
{{ Rt = imm << 16; }});
|
||||
}
|
||||
|
||||
16: decode AA {
|
||||
|
||||
// Conditionally branch relative to PC based on CR and CTR.
|
||||
0: BranchPCRelCondCtr::bc({{ NIA = (uint32_t)(CIA + disp); }});
|
||||
|
||||
// Conditionally branch to fixed address based on CR and CTR.
|
||||
1: BranchNonPCRelCondCtr::bca({{ NIA = targetAddr; }});
|
||||
}
|
||||
// Conditionally branch to a PC-relative or absoulute address based
|
||||
// on CR and CTR.
|
||||
16: BranchDispCondOp::bc({{ NIA = CIA + bd; }},
|
||||
{{ NIA = bd; }});
|
||||
|
||||
17: IntOp::sc({{ return std::make_shared<SESyscallFault>(); }});
|
||||
|
||||
18: decode AA {
|
||||
|
||||
// Unconditionally branch relative to PC.
|
||||
0: BranchPCRel::b({{ NIA = (uint32_t)(CIA + disp); }});
|
||||
|
||||
// Unconditionally branch to fixed address.
|
||||
1: BranchNonPCRel::ba({{ NIA = targetAddr; }});
|
||||
}
|
||||
// Unconditionally branch to a PC-relative or absoulute address.
|
||||
18: BranchOp::b({{ NIA = CIA + li; }},
|
||||
{{ NIA = li; }});
|
||||
|
||||
19: decode XL_XO {
|
||||
|
||||
@@ -105,7 +96,7 @@ decode PO default Unknown::unknown() {
|
||||
}});
|
||||
|
||||
// Conditionally branch to address in LR based on CR and CTR.
|
||||
16: BranchLrCondCtr::bclr({{ NIA = LR & 0xfffffffc; }});
|
||||
16: BranchRegCondOp::bclr({{ NIA = LR & -4ULL; }}, true, [ IsReturn ]);
|
||||
|
||||
format CondLogicOp {
|
||||
33: crnor({{
|
||||
@@ -162,7 +153,7 @@ decode PO default Unknown::unknown() {
|
||||
}
|
||||
|
||||
// Conditionally branch to address in CTR based on CR.
|
||||
528: BranchCtrCond::bcctr({{ NIA = CTR & 0xfffffffc; }});
|
||||
528: BranchRegCondOp::bcctr({{ NIA = CTR & -4ULL; }});
|
||||
}
|
||||
|
||||
format IntRotateOp {
|
||||
|
||||
@@ -30,18 +30,17 @@
|
||||
//
|
||||
// Control transfer instructions
|
||||
//
|
||||
// From the Power ISA Book I v2.06, page 33, the following rules should
|
||||
// From the Power ISA Book I v3.0B, page 35, the following rules should
|
||||
// be obeyed by programmers:
|
||||
//
|
||||
// - Use branch instructions where LK == 1 only as subroutine calls.
|
||||
// - Pair each subroutine call with a bclr instruction with BH == 00
|
||||
// that returns from the subroutine.
|
||||
// - Do not use bclrl as a subroutine call.
|
||||
// and LK == 0 that returns from the subroutine.
|
||||
// - Do not use bclr with LK == 1 as a subroutine call.
|
||||
//
|
||||
// Therefore, I've flagged all versions that update the link register (LR)
|
||||
// as calls, except bclrl (BranchLrCtrCond format) which is flagged as
|
||||
// a return.
|
||||
|
||||
// Therefore, all versions that update the link register (LR) are flagged
|
||||
// as calls, except bclr with LK == 1 (i.e. bclrl). The latter should not
|
||||
// be tagged as a return either.
|
||||
|
||||
let {{
|
||||
|
||||
@@ -50,57 +49,45 @@ updateLrCode = 'LR = CIA + 4;'
|
||||
|
||||
}};
|
||||
|
||||
// Instructions that unconditionally branch relative to the current PC.
|
||||
def format BranchPCRel(br_code, inst_flags = []) {{
|
||||
|
||||
// Instructions that unconditionally branch either to an address relative
|
||||
// to the current PC or an absolute address.
|
||||
def format BranchOp(code, code_aa1, inst_flags = []) {{
|
||||
inst_flags += ('IsUncondControl', 'IsDirectControl')
|
||||
basic_code = br_code
|
||||
|
||||
# The version that does not update LR
|
||||
# Setup the 4 code versions and add code to update LR if necessary
|
||||
code_lk1 = code + updateLrCode
|
||||
code_aa1_lk1 = code_aa1 + updateLrCode
|
||||
|
||||
# Generate the classes
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
GenAluOp(name, Name, 'BranchPCRel', basic_code, inst_flags,
|
||||
CheckLkDecode, BasicConstructor)
|
||||
GenAluOp(name, Name, 'BranchOp', code, inst_flags,
|
||||
CheckAaLkDecode, BasicConstructor)
|
||||
(header_output_aa1, decoder_output_aa1, _, exec_output_aa1) = \
|
||||
GenAluOp(name, Name + 'AaSet', 'BranchOp', code_aa1, inst_flags,
|
||||
CheckAaLkDecode, BasicConstructor)
|
||||
(header_output_lk1, decoder_output_lk1, _, exec_output_lk1) = \
|
||||
GenAluOp(name, Name + 'LkSet', 'BranchOp', code_lk1, inst_flags,
|
||||
CheckAaLkDecode, BasicConstructor)
|
||||
(header_output_aa1_lk1, decoder_output_aa1_lk1, _, exec_output_aa1_lk1) = \
|
||||
GenAluOp(name, Name + 'AaSetLkSet', 'BranchOp', code_aa1_lk1,
|
||||
inst_flags, CheckAaLkDecode, BasicConstructor)
|
||||
|
||||
# The version that does the update
|
||||
update_code = basic_code + updateLrCode
|
||||
update_flags = inst_flags + [ 'IsCall' ]
|
||||
(header_output_up, decoder_output_up, _, exec_output_up) = \
|
||||
GenAluOp(name, Name + 'UpdateLr', 'BranchPCRel', update_code,
|
||||
update_flags, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# Add the outputs together
|
||||
header_output += header_output_up
|
||||
decoder_output += decoder_output_up
|
||||
exec_output += exec_output_up
|
||||
# Finally, add to the other outputs
|
||||
header_output += \
|
||||
header_output_aa1 + header_output_lk1 + header_output_aa1_lk1
|
||||
decoder_output += \
|
||||
decoder_output_aa1 + decoder_output_lk1 + decoder_output_aa1_lk1
|
||||
exec_output += \
|
||||
exec_output_aa1 + exec_output_lk1 + exec_output_aa1_lk1
|
||||
}};
|
||||
|
||||
// Instructions that unconditionally branch to a specific address.
|
||||
def format BranchNonPCRel(br_code, inst_flags = []) {{
|
||||
inst_flags += ('IsUncondControl', 'IsDirectControl')
|
||||
basic_code = br_code
|
||||
|
||||
# The version that does not update LR
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
GenAluOp(name, Name, 'BranchNonPCRel', basic_code, inst_flags,
|
||||
CheckLkDecode, BasicConstructor)
|
||||
|
||||
# The version that does the update
|
||||
update_code = basic_code + updateLrCode
|
||||
update_flags = inst_flags + [ 'IsCall' ]
|
||||
(header_output_up, decoder_output_up, _, exec_output_up) = \
|
||||
GenAluOp(name, Name + 'UpdateLr', 'BranchNonPCRel', update_code,
|
||||
update_flags, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# Add the outputs together
|
||||
header_output += header_output_up
|
||||
decoder_output += decoder_output_up
|
||||
exec_output += exec_output_up
|
||||
}};
|
||||
|
||||
let {{
|
||||
|
||||
# Check the condition register (CR) allows the branch to be taken.
|
||||
def GetCondCode(br_code):
|
||||
cond_code = 'if(condOk(CR)) {\n'
|
||||
cond_code = 'if (condOk(CR)) {\n'
|
||||
cond_code += ' ' + br_code + '\n'
|
||||
cond_code += '} else {\n'
|
||||
cond_code += ' NIA = NIA;\n'
|
||||
@@ -109,12 +96,10 @@ def GetCondCode(br_code):
|
||||
|
||||
# Check the condition register (CR) and count register (CTR) allow the
|
||||
# branch to be taken. Also, in certain situations, decrement the count
|
||||
# register too. This takes place in ctrOk within BranchCond classes.
|
||||
# register too. This takes place in ctrOk within BranchCondOp classes.
|
||||
def GetCtrCondCode(br_code):
|
||||
cond_code = 'uint32_t ctr = CTR;\n'
|
||||
cond_code += 'bool ctr_ok = ctrOk(ctr);\n'
|
||||
cond_code += 'bool cond_ok = condOk(CR);\n'
|
||||
cond_code += 'if(ctr_ok && cond_ok) {\n'
|
||||
cond_code = 'uint64_t ctr = CTR;\n'
|
||||
cond_code += 'if (ctrOk(ctr) && condOk(CR)) {\n'
|
||||
cond_code += ' ' + br_code + '\n'
|
||||
cond_code += '} else {\n'
|
||||
cond_code += ' NIA = NIA;\n'
|
||||
@@ -124,97 +109,72 @@ def GetCtrCondCode(br_code):
|
||||
|
||||
}};
|
||||
|
||||
// Instructions that conditionally branch relative to the current PC based on
|
||||
// the condition register (CR) and count register (CTR).
|
||||
def format BranchPCRelCondCtr(br_code, inst_flags = []) {{
|
||||
inst_flags += ('IsCondControl', 'IsDirectControl')
|
||||
basic_code = GetCtrCondCode(br_code)
|
||||
|
||||
# The version that does not update LR
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
GenAluOp(name, Name, 'BranchPCRelCond', basic_code, inst_flags,
|
||||
CheckLkDecode, BasicConstructor)
|
||||
|
||||
# The version that does the update
|
||||
update_code = basic_code + updateLrCode
|
||||
update_flags = inst_flags + [ 'IsCall' ]
|
||||
(header_output_up, decoder_output_up, _, exec_output_up) = \
|
||||
GenAluOp(name, Name + 'UpdateLr', 'BranchPCRelCond', update_code,
|
||||
update_flags, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# Add the outputs together
|
||||
header_output += header_output_up
|
||||
decoder_output += decoder_output_up
|
||||
exec_output += exec_output_up
|
||||
}};
|
||||
|
||||
// Instructions that conditionally branch to a specific address based on the
|
||||
// Instructions that conditionally branch either to an address relative
|
||||
// to the current PC or an absolute address depending on the value of the
|
||||
// condition register (CR) and count register (CTR).
|
||||
def format BranchNonPCRelCondCtr(br_code, inst_flags = []) {{
|
||||
def format BranchDispCondOp(code, code_aa1, inst_flags = []) {{
|
||||
inst_flags += ('IsCondControl', 'IsDirectControl')
|
||||
basic_code = GetCtrCondCode(br_code)
|
||||
|
||||
# The version that does not update LR
|
||||
# Setup the 4 code versions and add code to update LR if necessary
|
||||
code = GetCtrCondCode(code)
|
||||
code_aa1 = GetCtrCondCode(code_aa1)
|
||||
code_lk1 = code + updateLrCode
|
||||
code_aa1_lk1 = code_aa1 + updateLrCode
|
||||
inst_flags_lk1 = inst_flags + [ 'IsCall' ]
|
||||
|
||||
# Generate the classes
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
GenAluOp(name, Name, 'BranchNonPCRelCond', basic_code, inst_flags,
|
||||
CheckLkDecode, BasicConstructor)
|
||||
GenAluOp(name, Name, 'BranchDispCondOp', code, inst_flags,
|
||||
CheckAaLkDecode, BasicConstructor)
|
||||
(header_output_aa1, decoder_output_aa1, _, exec_output_aa1) = \
|
||||
GenAluOp(name, Name + 'AaSet', 'BranchDispCondOp', code_aa1,
|
||||
inst_flags, CheckAaLkDecode, BasicConstructor)
|
||||
(header_output_lk1, decoder_output_lk1, _, exec_output_lk1) = \
|
||||
GenAluOp(name, Name + 'LkSet', 'BranchDispCondOp', code_lk1,
|
||||
inst_flags_lk1, CheckAaLkDecode, BasicConstructor)
|
||||
(header_output_aa1_lk1, decoder_output_aa1_lk1, _, exec_output_aa1_lk1) = \
|
||||
GenAluOp(name, Name + 'AaSetLkSet', 'BranchDispCondOp', code_aa1_lk1,
|
||||
inst_flags_lk1, CheckAaLkDecode, BasicConstructor)
|
||||
|
||||
# The version that does the update
|
||||
update_code = basic_code + updateLrCode
|
||||
update_flags = inst_flags + [ 'IsCall' ]
|
||||
(header_output_up, decoder_output_up, _, exec_output_up) = \
|
||||
GenAluOp(name, Name + 'UpdateLr', 'BranchNonPCRelCond', update_code,
|
||||
update_flags, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# Add the outputs together
|
||||
header_output += header_output_up
|
||||
decoder_output += decoder_output_up
|
||||
exec_output += exec_output_up
|
||||
# Finally, add to the other outputs
|
||||
header_output += \
|
||||
header_output_aa1 + header_output_lk1 + header_output_aa1_lk1
|
||||
decoder_output += \
|
||||
decoder_output_aa1 + decoder_output_lk1 + decoder_output_aa1_lk1
|
||||
exec_output += \
|
||||
exec_output_aa1 + exec_output_lk1 + exec_output_aa1_lk1
|
||||
}};
|
||||
|
||||
// Instructions that conditionally branch to the address in the link register
|
||||
// (LR) based on the condition register (CR) and count register (CTR).
|
||||
def format BranchLrCondCtr(br_code, inst_flags = []) {{
|
||||
inst_flags += ('IsCondControl', 'IsIndirectControl', 'IsReturn')
|
||||
basic_code = GetCtrCondCode(br_code)
|
||||
|
||||
# The version that does not update LR
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
GenAluOp(name, Name, 'BranchRegCond', basic_code, inst_flags,
|
||||
CheckLkDecode, BasicConstructor)
|
||||
|
||||
# The version that does the update
|
||||
update_code = basic_code + updateLrCode
|
||||
(header_output_up, decoder_output_up, _, exec_output_up) = \
|
||||
GenAluOp(name, Name + 'UpdateLr', 'BranchRegCond', update_code,
|
||||
inst_flags, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# Add the outputs together
|
||||
header_output += header_output_up
|
||||
decoder_output += decoder_output_up
|
||||
exec_output += exec_output_up
|
||||
}};
|
||||
|
||||
// Instructions that conditionally branch to the address in the count register
|
||||
// (CTR) based on the condition register (CR).
|
||||
def format BranchCtrCond(br_code, inst_flags = []) {{
|
||||
// Instructions that conditionally branch to an address in a register
|
||||
// depending on the value of the condition register (CR) and count
|
||||
// register (CTR).
|
||||
def format BranchRegCondOp(code, checkCTR = 0, inst_flags = []) {{
|
||||
inst_flags += ('IsCondControl', 'IsIndirectControl')
|
||||
basic_code = GetCondCode(br_code)
|
||||
|
||||
# The version that does not update LR
|
||||
# Setup the 2 code versions and add code to update LR if necessary
|
||||
if checkCTR:
|
||||
code = GetCtrCondCode(code)
|
||||
else:
|
||||
code = GetCondCode(code)
|
||||
code_lk1 = code + updateLrCode
|
||||
inst_flags_lk1 = inst_flags + [ 'IsCall' ]
|
||||
|
||||
# When LK is set, this cannot be used to return to the callee
|
||||
if 'IsReturn' in inst_flags:
|
||||
inst_flags_lk1.remove('IsReturn')
|
||||
|
||||
# Generate the classes
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
GenAluOp(name, Name, 'BranchRegCond', basic_code, inst_flags,
|
||||
GenAluOp(name, Name, 'BranchRegCondOp', code, inst_flags,
|
||||
CheckLkDecode, BasicConstructor)
|
||||
(header_output_lk1, decoder_output_lk1, _, exec_output_lk1) = \
|
||||
GenAluOp(name, Name + 'LkSet', 'BranchRegCondOp', code_lk1,
|
||||
inst_flags_lk1, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# The version that does the update
|
||||
update_code = basic_code + updateLrCode
|
||||
update_flags = inst_flags + [ 'IsCall' ]
|
||||
(header_output_up, decoder_output_up, _, exec_output_up) = \
|
||||
GenAluOp(name, Name + 'UpdateLr', 'BranchRegCond', update_code,
|
||||
update_flags, CheckLkDecode, BasicConstructor)
|
||||
|
||||
# Add the outputs together
|
||||
header_output += header_output_up
|
||||
decoder_output += decoder_output_up
|
||||
exec_output += exec_output_up
|
||||
# Finally, add to the other outputs
|
||||
header_output += header_output_lk1
|
||||
decoder_output += decoder_output_lk1
|
||||
exec_output += exec_output_lk1
|
||||
}};
|
||||
|
||||
@@ -78,11 +78,38 @@ def template CheckLkDecode {{
|
||||
if (LK == 0) {
|
||||
return new %(class_name)s(machInst);
|
||||
} else {
|
||||
return new %(class_name)sUpdateLr(machInst);
|
||||
return new %(class_name)sLkSet(machInst);
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
def template CheckAaDecode {{
|
||||
{
|
||||
if (AA == 0) {
|
||||
return new %(class_name)s(machInst);
|
||||
} else {
|
||||
return new %(class_name)sAaSet(machInst);
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
def template CheckAaLkDecode {{
|
||||
{
|
||||
if (AA == 0) {
|
||||
if (LK == 0) {
|
||||
return new %(class_name)s(machInst);
|
||||
} else {
|
||||
return new %(class_name)sLkSet(machInst);
|
||||
}
|
||||
} else {
|
||||
if (LK == 0) {
|
||||
return new %(class_name)sAaSet(machInst);
|
||||
} else {
|
||||
return new %(class_name)sAaSetLkSet(machInst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
let {{
|
||||
|
||||
|
||||
@@ -55,14 +55,18 @@ BitUnion32(ExtMachInst)
|
||||
|
||||
// Special purpose register identifier
|
||||
Bitfield<20, 11> spr;
|
||||
Bitfield<25, 2> li;
|
||||
Bitfield<1> aa;
|
||||
Bitfield<25, 23> bf;
|
||||
Bitfield<15, 2> bd;
|
||||
Bitfield<25, 21> bo;
|
||||
Bitfield<20, 16> bi;
|
||||
Bitfield<20, 18> bfa;
|
||||
|
||||
// Branch instruction fields
|
||||
Bitfield<1> aa;
|
||||
Bitfield<15, 2> bd;
|
||||
Bitfield<20, 16> bi;
|
||||
Bitfield<12, 11> bh;
|
||||
Bitfield<25, 21> bo;
|
||||
Bitfield<25, 2> li;
|
||||
Bitfield<0> lk;
|
||||
|
||||
// Record bits
|
||||
Bitfield<0> rc31;
|
||||
Bitfield<10> oe;
|
||||
|
||||
Reference in New Issue
Block a user