ARM: Implement branch instructions external to the decoder.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 2 Jun 2010 17:58:02 +0000 (12:58 -0500)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 2 Jun 2010 17:58:02 +0000 (12:58 -0500)
src/arch/arm/isa/decoder/arm.isa
src/arch/arm/isa/insts/branch.isa [new file with mode: 0644]
src/arch/arm/isa/insts/insts.isa
src/arch/arm/isa/operands.isa

index 8a5ba3e436f9b9c34193db9b6129bf97a0df1100..717bd18577b2a62d7f229600d0b81110177f40a1 100644 (file)
@@ -129,7 +129,7 @@ format DataOp {
                     }
                 }
                 0x1: decode OPCODE {
-                    0x9: BranchExchange::bx({{ }});
+                    0x9: BranchExchange::oldbx({{ }});
                     0xb: PredOp::clz({{
                         Rd = ((Rm == 0) ? 32 : (31 - findMsbSet(Rm)));
                     }});
@@ -138,7 +138,7 @@ format DataOp {
                     0x9: WarnUnimpl::bxj();
                 }
                 0x3: decode OPCODE {
-                    0x9: BranchExchange::blx({{ }}, Link);
+                    0x9: BranchExchange::oldblx({{ }}, Link);
                 }
                 0x5: decode OPCODE {
                     0x8: WarnUnimpl::qadd();
@@ -265,8 +265,8 @@ format DataOp {
     0x4: ArmMacroMem::armMacroMem();
     0x5: decode OPCODE_24 {
         // Branch (and Link) Instructions
-        0: Branch::b({{ }});
-        1: Branch::bl({{ }}, Link);
+        0: Branch::oldb({{ }});
+        1: Branch::oldbl({{ }}, Link);
     }
     0x6: decode CPNUM {
         0xb: decode LOADOP {
diff --git a/src/arch/arm/isa/insts/branch.isa b/src/arch/arm/isa/insts/branch.isa
new file mode 100644 (file)
index 0000000..71a9805
--- /dev/null
@@ -0,0 +1,175 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2010 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 = '''
+        Addr PC = readPC(xc);
+        NPC = ((PC + imm) & mask(32)) | (PC & ~mask(32));
+        '''
+        if (link):
+            bCode += '''
+                Addr tBit = PC & (ULL(1) << PcTBitShift);
+                if (!tBit)
+                    LR = PC - 4;
+                else
+                    LR = PC | 1;
+            '''
+
+        bIop = InstObjParams(mnem, mnem.capitalize(), "BranchImmCond",
+                             {"code": bCode,
+                              "predicate_test": predicateTest})
+        header_output += BranchImmCondDeclare.subst(bIop)
+        decoder_output += BranchImmCondConstructor.subst(bIop)
+        exec_output += PredOpExecute.subst(bIop)
+
+    # BX, BLX
+    blxCode = '''
+    Addr PC = readPC(xc);
+    Addr tBit = PC & (ULL(1) << PcTBitShift);
+    // Other than the assert below, jBit isn't used.
+#if !defined(NDEBUG)
+    Addr jBit = PC & (ULL(1) << PcJBitShift);
+#endif
+    // X isn't permitted in ThumbEE mode. We shouldn't be in jazzelle mode?
+    assert(!jBit);
+    bool arm = !tBit;
+    arm = arm; // In case it's not used otherwise.
+    Addr tempPc = ((%(newPC)s) & mask(32)) | (PC & ~mask(32));
+    %(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()
+        if imm and link: #blx with imm
+            branchStr = "FNPC = tempPc ^ (ULL(1) << PcTBitShift);"
+        else:
+            branchStr = "IWNPC = tempPc ^ (ULL(1) << PcTBitShift);"
+
+        if imm:
+            Name += "Imm"
+            # Since we're switching ISAs, the target ISA will be the opposite
+            # of the current ISA. !arm is whether the target is ARM.
+            newPC = '(!arm ? (roundDown(PC, 4) + imm) : (PC + imm))'
+            base = "BranchImm"
+            declare = BranchImmDeclare
+            constructor = BranchImmConstructor
+        else:
+            Name += "Reg"
+            newPC = '(PC & PcModeMask) | Op1'
+            base = "BranchRegCond"
+            declare = BranchRegCondDeclare
+            constructor = BranchRegCondConstructor
+        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 (arm)
+                    LR = PC - 4;
+                else
+                    LR = PC  | 1;
+            '''
+        elif link:
+            linkStr = '''
+                if (arm)
+                    LR = PC - 4;
+                else
+                    LR = (PC - 2) | 1;
+            '''
+        else:
+            linkStr = ""
+        code = blxCode % {"link": linkStr,
+                          "newPC": newPC,
+                          "branch": branchStr}
+        blxIop = InstObjParams(mnem, Name, base,
+                               {"code": code,
+                                "predicate_test": predicateTest})
+        header_output += declare.subst(blxIop)
+        decoder_output += constructor.subst(blxIop)
+        exec_output += PredOpExecute.subst(blxIop)
+
+    #Ignore BXJ for now
+
+    #CBNZ, CBZ. These are always unconditional as far as predicates
+    for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")):
+        code = '''
+        Addr PC = readPC(xc);
+        NPC = ((PC + imm) & mask(32)) | (PC & ~mask(32));
+        '''
+        predTest = "Op1 %(test)s 0" % {"test": test}
+        iop = InstObjParams(mnem, mnem.capitalize(), "BranchImmReg",
+                            {"code": code, "predicate_test": predTest})
+        header_output += BranchImmRegDeclare.subst(iop)
+        decoder_output += BranchImmRegConstructor.subst(iop)
+        exec_output += PredOpExecute.subst(iop)
+
+    #TBB, TBH
+    for isTbh in (0, 1):
+        if isTbh:
+            eaCode = "EA = Op1 + Op2 * 2"
+            accCode = "NPC = readPC(xc) + 2 * (Mem.uh);"
+            mnem = "tbh"
+        else:
+            eaCode = "EA = Op1 + Op2"
+            accCode = "NPC = readPC(xc) + 2 * (Mem.ub);"
+            mnem = "tbb"
+        eaCode = "unsigned memAccessFlags = 0;\n" + eaCode
+        iop = InstObjParams(mnem, mnem.capitalize(), "BranchRegReg",
+                            {'ea_code': eaCode,
+                             'memacc_code': accCode,
+                             'predicate_test': predicateTest})
+        header_output += BranchTableDeclare.subst(iop)
+        decoder_output += BranchRegRegConstructor.subst(iop)
+        exec_output += LoadExecute.subst(iop) + \
+                       LoadInitiateAcc.subst(iop) + \
+                       LoadCompleteAcc.subst(iop)
+}};
index 4168d39b5d8748b105e4685ba18ab72ca3e6a873..a7a96a51c304ec0c1d9a4cfe6d44a4449d413840 100644 (file)
@@ -54,3 +54,6 @@
 
 //Data processing instructions
 ##include "data.isa"
+
+//Branches
+##include "branch.isa"
index 3f331832c7f4a56c690ed01c3db21f0688ade3ba..ab4d95d47681c939e3a4efac3d3607c320c95dbc 100644 (file)
@@ -68,6 +68,7 @@ let {{
     readNPC = 'xc->readNextPC() & ~PcModeMask'
     writeNPC = 'setNextPC(xc, %(final_val)s)'
     writeIWNPC = 'setIWNextPC(xc, %(final_val)s)'
+    forceNPC = 'xc->setNextPC(%(final_val)s)'
 }};
 
 def operands {{
@@ -125,6 +126,8 @@ def operands {{
     'Fpexc': ('ControlReg', 'uw', 'MISCREG_FPEXC', None, 45),
     'NPC': ('NPC', 'ud', None, (None, None, 'IsControl'), 51,
             readNPC, writeNPC),
+    'FNPC': ('NPC', 'ud', None, (None, None, 'IsControl'), 51,
+             readNPC, forceNPC),
     'IWNPC': ('NPC', 'ud', None, (None, None, 'IsControl'), 51,
               readNPC, writeIWNPC),
 }};