1// -*- mode:c++ -*-
2
3// Copyright (c) 2010-2012, 2014 ARM Limited
4// All rights reserved
5//
6// The license below extends only to copyright in the software and shall
7// not be construed as granting a license to any other intellectual
8// property including but not limited to intellectual property relating
9// to a hardware implementation of the functionality of the software
10// licensed hereunder.  You may use the software subject to the license
11// terms below provided that you ensure that this notice is replicated
12// unmodified and in its entirety in all distributions of the software,
13// modified or unmodified, in source code or in binary form.
14//
15// Redistribution and use in source and binary forms, with or without
16// modification, are permitted provided that the following conditions are
17// met: redistributions of source code must retain the above copyright
18// notice, this list of conditions and the following disclaimer;
19// redistributions in binary form must reproduce the above copyright
20// notice, this list of conditions and the following disclaimer in the
21// documentation and/or other materials provided with the distribution;
22// neither the name of the copyright holders nor the names of its
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Authors: Gabe Black
39
40let {{
41
42    header_output = ""
43    decoder_output = ""
44    exec_output = ""
45
46    # B, BL
47    for (mnem, link) in (("b", False), ("bl", True)):
48        bCode = '''
49        NPC = (uint32_t)(PC + imm);
50        '''
51        br_tgt_code = '''pcs.instNPC((uint32_t)(branchPC.instPC() + imm));'''
52        instFlags = ["IsDirectControl"]
53        if (link):
54            bCode += '''
55                if (Thumb)
56                    LR = PC | 1;
57                else
58                    LR = PC - 4;
59            '''
60            instFlags += ["IsCall"]
61
62
63        bIop = InstObjParams(mnem, mnem.capitalize(), "BranchImmCond",
64                             {"code": bCode, "predicate_test": predicateTest,
65                             "brTgtCode" : br_tgt_code}, instFlags)
66        header_output += BranchImmCondDeclare.subst(bIop)
67        decoder_output += BranchImmCondConstructor.subst(bIop) + \
68                       BranchTarget.subst(bIop)
69        exec_output += PredOpExecute.subst(bIop)
70
71    # BX, BLX
72    blxCode = '''
73    %(link)s
74    // Switch modes
75    %(branch)s
76    '''
77
78    blxList = (("blx", True, True),
79               ("blx", False, True),
80               ("bx", False, False))
81
82    for (mnem, imm, link) in blxList:
83        Name = mnem.capitalize()
84        isRasPop = 0
85        if imm:
86            Name += "Imm"
87            # Since we're switching ISAs, the target ISA will be the opposite
88            # of the current ISA. Thumb is whether the target is ARM.
89            newPC = '(uint32_t)(Thumb ? (roundDown(PC, 4) + imm) : (PC + imm))'
90            br_tgt_code = '''
91            pcs.instNPC((uint32_t)(branchPC.thumb() ? (roundDown(branchPC.instPC(),4) + imm) :
92                                (branchPC.instPC() + imm)));
93            '''
94            base = "BranchImmCond"
95            declare = BranchImmCondDeclare
96            constructor = BranchImmCondConstructor
97            instFlags = ["IsDirectControl"]
98        else:
99            Name += "Reg"
100            newPC = 'Op1'
101            br_tgt_code = ''
102            base = "BranchRegCond"
103            declare = BranchRegCondDeclare
104            constructor = BranchRegCondConstructor
105            instFlags = ["IsIndirectControl"]
106        if link and imm:
107            linkStr = '''
108                // The immediate version of the blx thumb instruction
109                // is 32 bits wide, but "next pc" doesn't reflect that
110                // so we don't want to substract 2 from it at this point
111                if (Thumb)
112                    LR = PC  | 1;
113                else
114                    LR = PC - 4;
115            '''
116            instFlags += ["IsCall"]
117        elif link:
118            linkStr = '''
119                if (Thumb)
120                    LR = (PC - 2) | 1;
121                else
122                    LR = PC - 4;
123            '''
124            instFlags += ["IsCall"]
125        else:
126            linkStr = ""
127            isRasPop = "op1 == INTREG_LR"
128
129        if imm and link: #blx with imm
130            branchStr = '''
131                NextThumb = !Thumb;
132                NPC = %(newPC)s;
133            '''
134            br_tgt_code = '''pcs.nextThumb(!branchPC.thumb());\n''' + \
135                          br_tgt_code
136        else:
137            branchStr = "IWNPC = %(newPC)s;"
138        branchStr = branchStr % { "newPC" : newPC }
139
140        code = blxCode % {"link": linkStr,
141                          "newPC": newPC,
142                          "branch": branchStr}
143        blxIop = InstObjParams(mnem, Name, base,
144                               {"code": code, "brTgtCode" : br_tgt_code,
145                                "predicate_test": predicateTest,
146                                "is_ras_pop" : isRasPop }, instFlags)
147        header_output += declare.subst(blxIop)
148        decoder_output += constructor.subst(blxIop)
149        exec_output += PredOpExecute.subst(blxIop)
150        if imm:
151            decoder_output += BranchTarget.subst(blxIop)
152
153    bxjcode = '''
154    HSTR hstr = Hstr;
155    CPSR cpsr = Cpsr;
156    SCR  scr  = Scr;
157
158    if (ArmSystem::haveVirtualization(xc->tcBase()) && hstr.tjdbx &&
159        !inSecureState(scr, cpsr) && (cpsr.mode != MODE_HYP)) {
160        fault = std::make_shared<HypervisorTrap>(machInst, op1, EC_TRAPPED_BXJ);
161    }
162    IWNPC = Op1;
163    '''
164
165    bxjIop = InstObjParams("bxj", "BxjReg", "BranchRegCond",
166                           {"code": bxjcode,
167                            "predicate_test": predicateTest,
168                            "is_ras_pop": "op1 == INTREG_LR" },
169                           ["IsIndirectControl"])
170    header_output += BranchRegCondDeclare.subst(bxjIop)
171    decoder_output += BranchRegCondConstructor.subst(bxjIop)
172    exec_output += PredOpExecute.subst(bxjIop)
173
174    #CBNZ, CBZ. These are always unconditional as far as predicates
175    for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")):
176        code = 'NPC = (uint32_t)(PC + imm);\n'
177        br_tgt_code = '''pcs.instNPC((uint32_t)(branchPC.instPC() + imm));'''
178        predTest = "Op1 %(test)s 0" % {"test": test}
179        iop = InstObjParams(mnem, mnem.capitalize(), "BranchImmReg",
180                            {"code": code, "predicate_test": predTest,
181                            "brTgtCode" : br_tgt_code},
182                            ["IsDirectControl"])
183        header_output += BranchImmRegDeclare.subst(iop)
184        decoder_output += BranchImmRegConstructor.subst(iop) + \
185                          BranchTarget.subst(iop)
186        exec_output += PredOpExecute.subst(iop)
187
188    #TBB, TBH
189    for isTbh in (0, 1):
190        if isTbh:
191            eaCode = '''
192            unsigned memAccessFlags = ArmISA::TLB::AllowUnaligned |
193                                      ArmISA::TLB::AlignHalfWord |
194                                      ArmISA::TLB::MustBeOne;
195            EA = Op1 + Op2 * 2
196            '''
197            accCode = 'NPC = PC + 2 * (Mem_uh);\n'
198            mnem = "tbh"
199        else:
200            eaCode = '''
201            unsigned memAccessFlags = ArmISA::TLB::AllowUnaligned |
202                                      ArmISA::TLB::AlignByte |
203                                      ArmISA::TLB::MustBeOne;
204            EA = Op1 + Op2
205            '''
206            accCode = 'NPC = PC + 2 * (Mem_ub)'
207            mnem = "tbb"
208        iop = InstObjParams(mnem, mnem.capitalize(), "BranchRegReg",
209                            {'ea_code': eaCode,
210                             'memacc_code': accCode,
211                             'predicate_test': predicateTest},
212                             ["IsIndirectControl"])
213        header_output += BranchTableDeclare.subst(iop)
214        decoder_output += BranchRegRegConstructor.subst(iop)
215        exec_output += LoadExecute.subst(iop) + \
216                       LoadInitiateAcc.subst(iop) + \
217                       LoadCompleteAcc.subst(iop)
218}};
219