blob: 086abacb7069d6a98f3f5b6c6bd1082f98ff1b2b [file] [log] [blame]
// -*- mode:c++ -*-
// Copyright (c) 2010-2012, 2014 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// 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
let {{
header_output = ""
decoder_output = ""
exec_output = ""
# B, BL
for (mnem, link) in (("b", False), ("bl", True)):
bCode = '''
NPC = (uint32_t)(PC + imm);
'''
br_tgt_code = '''pcs.instNPC((uint32_t)(branchPC.instPC() + imm));'''
instFlags = ["IsDirectControl"]
if (link):
bCode += '''
if (Thumb)
LR = PC | 1;
else
LR = PC - 4;
'''
instFlags += ["IsCall"]
bIop = InstObjParams(mnem, mnem.capitalize(), "BranchImmCond",
{"code": bCode, "predicate_test": predicateTest,
"brTgtCode" : br_tgt_code}, instFlags)
header_output += BranchImmCondDeclare.subst(bIop)
decoder_output += BranchImmCondConstructor.subst(bIop) + \
BranchTarget.subst(bIop)
exec_output += PredOpExecute.subst(bIop)
# BX, BLX
blxCode = '''
%(link)s
// Switch modes
%(branch)s
'''
blxList = (("blx", True, True),
("blx", False, True),
("bx", False, False))
for (mnem, imm, link) in blxList:
Name = mnem.capitalize()
isRasPop = 0
if imm:
Name += "Imm"
# Since we're switching ISAs, the target ISA will be the opposite
# of the current ISA. Thumb is whether the target is ARM.
newPC = '(uint32_t)(Thumb ? (roundDown(PC, 4) + imm) : (PC + imm))'
br_tgt_code = '''
pcs.instNPC((uint32_t)(branchPC.thumb() ? (roundDown(branchPC.instPC(),4) + imm) :
(branchPC.instPC() + imm)));
'''
base = "BranchImmCond"
declare = BranchImmCondDeclare
constructor = BranchImmCondConstructor
instFlags = ["IsDirectControl"]
else:
Name += "Reg"
newPC = 'Op1'
br_tgt_code = ''
base = "BranchRegCond"
declare = BranchRegCondDeclare
constructor = BranchRegCondConstructor
instFlags = ["IsIndirectControl"]
if link and imm:
linkStr = '''
// The immediate version of the blx thumb instruction
// is 32 bits wide, but "next pc" doesn't reflect that
// so we don't want to substract 2 from it at this point
if (Thumb)
LR = PC | 1;
else
LR = PC - 4;
'''
instFlags += ["IsCall"]
elif link:
linkStr = '''
if (Thumb)
LR = (PC - 2) | 1;
else
LR = PC - 4;
'''
instFlags += ["IsCall"]
else:
linkStr = ""
isRasPop = "op1 == INTREG_LR"
if imm and link: #blx with imm
branchStr = '''
NextThumb = !Thumb;
NPC = %(newPC)s;
'''
br_tgt_code = '''pcs.nextThumb(!branchPC.thumb());\n''' + \
br_tgt_code
else:
branchStr = "IWNPC = %(newPC)s;"
branchStr = branchStr % { "newPC" : newPC }
code = blxCode % {"link": linkStr,
"newPC": newPC,
"branch": branchStr}
blxIop = InstObjParams(mnem, Name, base,
{"code": code, "brTgtCode" : br_tgt_code,
"predicate_test": predicateTest,
"is_ras_pop" : isRasPop }, instFlags)
header_output += declare.subst(blxIop)
decoder_output += constructor.subst(blxIop)
exec_output += PredOpExecute.subst(blxIop)
if imm:
decoder_output += BranchTarget.subst(blxIop)
bxjcode = '''
HSTR hstr = Hstr;
CPSR cpsr = Cpsr;
SCR scr = Scr;
if (ArmSystem::haveVirtualization(xc->tcBase()) && hstr.tjdbx &&
!inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) {
fault = std::make_shared<HypervisorTrap>(machInst, op1, EC_TRAPPED_BXJ);
}
IWNPC = Op1;
'''
bxjIop = InstObjParams("bxj", "BxjReg", "BranchRegCond",
{"code": bxjcode,
"predicate_test": predicateTest,
"is_ras_pop": "op1 == INTREG_LR" },
["IsIndirectControl"])
header_output += BranchRegCondDeclare.subst(bxjIop)
decoder_output += BranchRegCondConstructor.subst(bxjIop)
exec_output += PredOpExecute.subst(bxjIop)
#CBNZ, CBZ. These are always unconditional as far as predicates
for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")):
code = 'NPC = (uint32_t)(PC + imm);\n'
br_tgt_code = '''pcs.instNPC((uint32_t)(branchPC.instPC() + imm));'''
predTest = "Op1 %(test)s 0" % {"test": test}
iop = InstObjParams(mnem, mnem.capitalize(), "BranchImmReg",
{"code": code, "predicate_test": predTest,
"brTgtCode" : br_tgt_code},
["IsDirectControl"])
header_output += BranchImmRegDeclare.subst(iop)
decoder_output += BranchImmRegConstructor.subst(iop) + \
BranchTarget.subst(iop)
exec_output += PredOpExecute.subst(iop)
#TBB, TBH
for isTbh in (0, 1):
if isTbh:
eaCode = '''
unsigned memAccessFlags = ArmISA::TLB::AllowUnaligned |
ArmISA::TLB::AlignHalfWord |
ArmISA::TLB::MustBeOne;
EA = Op1 + Op2 * 2
'''
accCode = 'NPC = PC + 2 * (Mem_uh);\n'
mnem = "tbh"
else:
eaCode = '''
unsigned memAccessFlags = ArmISA::TLB::AllowUnaligned |
ArmISA::TLB::AlignByte |
ArmISA::TLB::MustBeOne;
EA = Op1 + Op2
'''
accCode = 'NPC = PC + 2 * (Mem_ub)'
mnem = "tbb"
iop = InstObjParams(mnem, mnem.capitalize(), "BranchRegReg",
{'ea_code': eaCode,
'memacc_code': accCode,
'predicate_test': predicateTest},
["IsIndirectControl"])
header_output += BranchTableDeclare.subst(iop)
decoder_output += BranchRegRegConstructor.subst(iop)
exec_output += LoadExecute.subst(iop) + \
LoadInitiateAcc.subst(iop) + \
LoadCompleteAcc.subst(iop)
}};