blob: 435b4fdff29ad8e9a2a81cadc0ebc47b0609a13d [file] [log] [blame]
/* Copyright (c) 2007-2008 The Florida State University
* Copyright (c) 2009 The University of Edinburgh
* 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.
*/
#ifndef __ARCH_POWER_INSTS_BRANCH_HH__
#define __ARCH_POWER_INSTS_BRANCH_HH__
#include "arch/power/insts/static_inst.hh"
namespace PowerISA
{
/**
* 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 PowerStaticInst
{
protected:
/// Cached program counter from last disassembly
mutable Addr cachedPC;
/// Cached symbol table pointer from last disassembly
mutable const Loader::SymbolTable *cachedSymtab;
/// Constructor
PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
OpClass __opClass)
: PowerStaticInst(mnem, _machInst, __opClass),
cachedPC(0), cachedSymtab(0)
{
}
const std::string &
disassemble(Addr pc, const Loader::SymbolTable *symtab) const;
};
/**
* Base class for unconditional, PC-relative branches.
*/
class BranchPCRel : public PCDependentDisassembly
{
protected:
/// Displacement
uint32_t disp;
/// Constructor.
BranchPCRel(const char *mnem, MachInst _machInst, OpClass __opClass)
: PCDependentDisassembly(mnem, _machInst, __opClass),
disp(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;
/// Explicitly import the otherwise hidden branchTarget
using StaticInst::branchTarget;
std::string generateDisassembly(
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
{
protected:
/// Fields needed for conditions
uint32_t bo;
uint32_t bi;
/// Constructor.
BranchCond(const char *mnem, MachInst _machInst, OpClass __opClass)
: PCDependentDisassembly(mnem, _machInst, __opClass),
bo(machInst.bo),
bi(machInst.bi)
{
}
inline bool
ctrOk(uint32_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);
}
}
return ctr_ok;
}
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));
}
return cond_ok;
}
};
/**
* Base class for conditional, PC-relative branches.
*/
class BranchPCRelCond : public BranchCond
{
protected:
/// Displacement
uint32_t disp;
/// Constructor.
BranchPCRelCond(const char *mnem, MachInst _machInst, OpClass __opClass)
: BranchCond(mnem, _machInst, __opClass),
disp(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;
/// Explicitly import the otherwise hidden branchTarget
using StaticInst::branchTarget;
std::string generateDisassembly(
Addr pc, const Loader::SymbolTable *symtab) const override;
};
/**
* Base class for conditional, non PC-relative branches.
*/
class BranchNonPCRelCond : public BranchCond
{
protected:
/// Target address
uint32_t targetAddr;
/// 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)
{
}
PowerISA::PCState branchTarget(ThreadContext *tc) const override;
/// Explicitly import the otherwise hidden branchTarget
using StaticInst::branchTarget;
std::string generateDisassembly(
Addr pc, const Loader::SymbolTable *symtab) const override;
};
} // namespace PowerISA
#endif //__ARCH_POWER_INSTS_BRANCH_HH__