16691Stjones1@inf.ed.ac.uk// -*- mode:c++ -*-
26691Stjones1@inf.ed.ac.uk
36691Stjones1@inf.ed.ac.uk// Copyright (c) 2009 The University of Edinburgh
46691Stjones1@inf.ed.ac.uk// All rights reserved.
56691Stjones1@inf.ed.ac.uk//
66691Stjones1@inf.ed.ac.uk// Redistribution and use in source and binary forms, with or without
76691Stjones1@inf.ed.ac.uk// modification, are permitted provided that the following conditions are
86691Stjones1@inf.ed.ac.uk// met: redistributions of source code must retain the above copyright
96691Stjones1@inf.ed.ac.uk// notice, this list of conditions and the following disclaimer;
106691Stjones1@inf.ed.ac.uk// redistributions in binary form must reproduce the above copyright
116691Stjones1@inf.ed.ac.uk// notice, this list of conditions and the following disclaimer in the
126691Stjones1@inf.ed.ac.uk// documentation and/or other materials provided with the distribution;
136691Stjones1@inf.ed.ac.uk// neither the name of the copyright holders nor the names of its
146691Stjones1@inf.ed.ac.uk// contributors may be used to endorse or promote products derived from
156691Stjones1@inf.ed.ac.uk// this software without specific prior written permission.
166691Stjones1@inf.ed.ac.uk//
176691Stjones1@inf.ed.ac.uk// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186691Stjones1@inf.ed.ac.uk// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196691Stjones1@inf.ed.ac.uk// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206691Stjones1@inf.ed.ac.uk// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216691Stjones1@inf.ed.ac.uk// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226691Stjones1@inf.ed.ac.uk// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236691Stjones1@inf.ed.ac.uk// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246691Stjones1@inf.ed.ac.uk// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256691Stjones1@inf.ed.ac.uk// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266691Stjones1@inf.ed.ac.uk// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276691Stjones1@inf.ed.ac.uk// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286691Stjones1@inf.ed.ac.uk//
296691Stjones1@inf.ed.ac.uk// Authors: Timothy M. Jones
306691Stjones1@inf.ed.ac.uk
316691Stjones1@inf.ed.ac.uk////////////////////////////////////////////////////////////////////
326691Stjones1@inf.ed.ac.uk//
336691Stjones1@inf.ed.ac.uk// Control transfer instructions
346691Stjones1@inf.ed.ac.uk//
356691Stjones1@inf.ed.ac.uk// From the Power ISA Book I v2.06, page 33, the following rules should
366691Stjones1@inf.ed.ac.uk// be obeyed by programmers:
376691Stjones1@inf.ed.ac.uk//
386691Stjones1@inf.ed.ac.uk// - Use branch instructions where LK == 1 only as subroutine calls.
396691Stjones1@inf.ed.ac.uk// - Pair each subroutine call with a bclr instruction with BH == 00
406691Stjones1@inf.ed.ac.uk//   that returns from the subroutine.
416691Stjones1@inf.ed.ac.uk// - Do not use bclrl as a subroutine call.
426691Stjones1@inf.ed.ac.uk//
436691Stjones1@inf.ed.ac.uk// Therefore, I've flagged all versions that update the link register (LR)
446691Stjones1@inf.ed.ac.uk// as calls, except bclrl (BranchLrCtrCond format) which is flagged as
456691Stjones1@inf.ed.ac.uk// a return.
466691Stjones1@inf.ed.ac.uk
476691Stjones1@inf.ed.ac.uk
486691Stjones1@inf.ed.ac.uklet {{
496691Stjones1@inf.ed.ac.uk
506691Stjones1@inf.ed.ac.uk# Simple code to update link register (LR).
5113801Ssandipan@linux.ibm.comupdateLrCode = 'LR = CIA + 4;'
526691Stjones1@inf.ed.ac.uk
536691Stjones1@inf.ed.ac.uk}};
546691Stjones1@inf.ed.ac.uk
556691Stjones1@inf.ed.ac.uk// Instructions that unconditionally branch relative to the current PC.
566691Stjones1@inf.ed.ac.ukdef format BranchPCRel(br_code, inst_flags = []) {{
576691Stjones1@inf.ed.ac.uk    inst_flags += ('IsUncondControl', 'IsDirectControl')
586691Stjones1@inf.ed.ac.uk    basic_code = br_code
596691Stjones1@inf.ed.ac.uk
606691Stjones1@inf.ed.ac.uk    # The version that does not update LR
616691Stjones1@inf.ed.ac.uk    (header_output, decoder_output, decode_block, exec_output) = \
626691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name, 'BranchPCRel', basic_code, inst_flags,
636691Stjones1@inf.ed.ac.uk                 CheckLkDecode, BasicConstructor)
646691Stjones1@inf.ed.ac.uk
656691Stjones1@inf.ed.ac.uk    # The version that does the update
666691Stjones1@inf.ed.ac.uk    update_code = basic_code + updateLrCode
676691Stjones1@inf.ed.ac.uk    update_flags = inst_flags + [ 'IsCall' ]
686691Stjones1@inf.ed.ac.uk    (header_output_up, decoder_output_up, _, exec_output_up) = \
696691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name + 'UpdateLr', 'BranchPCRel', update_code,
706691Stjones1@inf.ed.ac.uk                 update_flags, CheckLkDecode, BasicConstructor)
716691Stjones1@inf.ed.ac.uk
726691Stjones1@inf.ed.ac.uk    # Add the outputs together
736691Stjones1@inf.ed.ac.uk    header_output += header_output_up
746691Stjones1@inf.ed.ac.uk    decoder_output += decoder_output_up
756691Stjones1@inf.ed.ac.uk    exec_output += exec_output_up
766691Stjones1@inf.ed.ac.uk}};
776691Stjones1@inf.ed.ac.uk
786691Stjones1@inf.ed.ac.uk// Instructions that unconditionally branch to a specific address.
796691Stjones1@inf.ed.ac.ukdef format BranchNonPCRel(br_code, inst_flags = []) {{
806691Stjones1@inf.ed.ac.uk    inst_flags += ('IsUncondControl', 'IsDirectControl')
816691Stjones1@inf.ed.ac.uk    basic_code = br_code
826691Stjones1@inf.ed.ac.uk
836691Stjones1@inf.ed.ac.uk    # The version that does not update LR
846691Stjones1@inf.ed.ac.uk    (header_output, decoder_output, decode_block, exec_output) = \
856691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name, 'BranchNonPCRel', basic_code, inst_flags,
866691Stjones1@inf.ed.ac.uk                 CheckLkDecode, BasicConstructor)
876691Stjones1@inf.ed.ac.uk
886691Stjones1@inf.ed.ac.uk    # The version that does the update
896691Stjones1@inf.ed.ac.uk    update_code = basic_code + updateLrCode
906691Stjones1@inf.ed.ac.uk    update_flags = inst_flags + [ 'IsCall' ]
916691Stjones1@inf.ed.ac.uk    (header_output_up, decoder_output_up, _, exec_output_up) = \
926691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name + 'UpdateLr', 'BranchNonPCRel', update_code,
936691Stjones1@inf.ed.ac.uk                 update_flags, CheckLkDecode, BasicConstructor)
946691Stjones1@inf.ed.ac.uk
956691Stjones1@inf.ed.ac.uk    # Add the outputs together
966691Stjones1@inf.ed.ac.uk    header_output += header_output_up
976691Stjones1@inf.ed.ac.uk    decoder_output += decoder_output_up
986691Stjones1@inf.ed.ac.uk    exec_output += exec_output_up
996691Stjones1@inf.ed.ac.uk}};
1006691Stjones1@inf.ed.ac.uk
1016691Stjones1@inf.ed.ac.uklet {{
1026691Stjones1@inf.ed.ac.uk
1036691Stjones1@inf.ed.ac.uk# Check the condition register (CR) allows the branch to be taken.
1046691Stjones1@inf.ed.ac.ukdef GetCondCode(br_code):
1056691Stjones1@inf.ed.ac.uk    cond_code =  'if(condOk(CR)) {\n'
1066691Stjones1@inf.ed.ac.uk    cond_code += '    ' + br_code + '\n'
1076691Stjones1@inf.ed.ac.uk    cond_code += '} else {\n'
10813801Ssandipan@linux.ibm.com    cond_code += '    NIA = NIA;\n'
1096691Stjones1@inf.ed.ac.uk    cond_code += '}\n'
1106691Stjones1@inf.ed.ac.uk    return cond_code
1116691Stjones1@inf.ed.ac.uk
1126691Stjones1@inf.ed.ac.uk# Check the condition register (CR) and count register (CTR) allow the
1136691Stjones1@inf.ed.ac.uk# branch to be taken. Also, in certain situations, decrement the count
1146691Stjones1@inf.ed.ac.uk# register too. This takes place in ctrOk within BranchCond classes.
1156691Stjones1@inf.ed.ac.ukdef GetCtrCondCode(br_code):
1166691Stjones1@inf.ed.ac.uk    cond_code =  'uint32_t ctr = CTR;\n'
1176691Stjones1@inf.ed.ac.uk    cond_code += 'bool ctr_ok = ctrOk(ctr);\n'
1186691Stjones1@inf.ed.ac.uk    cond_code += 'bool cond_ok = condOk(CR);\n'
1196691Stjones1@inf.ed.ac.uk    cond_code += 'if(ctr_ok && cond_ok) {\n'
1206691Stjones1@inf.ed.ac.uk    cond_code += '    ' + br_code + '\n'
1216691Stjones1@inf.ed.ac.uk    cond_code += '} else {\n'
12213801Ssandipan@linux.ibm.com    cond_code += '    NIA = NIA;\n'
1236691Stjones1@inf.ed.ac.uk    cond_code += '}\n'
1246691Stjones1@inf.ed.ac.uk    cond_code += 'CTR = ctr;\n'
1256691Stjones1@inf.ed.ac.uk    return cond_code
1266691Stjones1@inf.ed.ac.uk
1276691Stjones1@inf.ed.ac.uk}};
1286691Stjones1@inf.ed.ac.uk
1296691Stjones1@inf.ed.ac.uk// Instructions that conditionally branch relative to the current PC based on
1306691Stjones1@inf.ed.ac.uk// the condition register (CR) and count register (CTR).
1316691Stjones1@inf.ed.ac.ukdef format BranchPCRelCondCtr(br_code, inst_flags = []) {{
1326691Stjones1@inf.ed.ac.uk    inst_flags += ('IsCondControl', 'IsDirectControl')
1336691Stjones1@inf.ed.ac.uk    basic_code = GetCtrCondCode(br_code)
1346691Stjones1@inf.ed.ac.uk
1356691Stjones1@inf.ed.ac.uk    # The version that does not update LR
1366691Stjones1@inf.ed.ac.uk    (header_output, decoder_output, decode_block, exec_output) = \
1376691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name, 'BranchPCRelCond', basic_code, inst_flags,
1386691Stjones1@inf.ed.ac.uk                 CheckLkDecode, BasicConstructor)
1396691Stjones1@inf.ed.ac.uk
1406691Stjones1@inf.ed.ac.uk    # The version that does the update
1416691Stjones1@inf.ed.ac.uk    update_code = basic_code + updateLrCode
1426691Stjones1@inf.ed.ac.uk    update_flags = inst_flags + [ 'IsCall' ]
1436691Stjones1@inf.ed.ac.uk    (header_output_up, decoder_output_up, _, exec_output_up) = \
1446691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name + 'UpdateLr', 'BranchPCRelCond', update_code,
1456691Stjones1@inf.ed.ac.uk                 update_flags, CheckLkDecode, BasicConstructor)
1466691Stjones1@inf.ed.ac.uk
1476691Stjones1@inf.ed.ac.uk    # Add the outputs together
1486691Stjones1@inf.ed.ac.uk    header_output += header_output_up
1496691Stjones1@inf.ed.ac.uk    decoder_output += decoder_output_up
1506691Stjones1@inf.ed.ac.uk    exec_output += exec_output_up
1516691Stjones1@inf.ed.ac.uk}};
1526691Stjones1@inf.ed.ac.uk
1536691Stjones1@inf.ed.ac.uk// Instructions that conditionally branch to a specific address based on the
1546691Stjones1@inf.ed.ac.uk// condition register (CR) and count register (CTR).
1556691Stjones1@inf.ed.ac.ukdef format BranchNonPCRelCondCtr(br_code, inst_flags = []) {{
1566691Stjones1@inf.ed.ac.uk    inst_flags += ('IsCondControl', 'IsDirectControl')
1576691Stjones1@inf.ed.ac.uk    basic_code = GetCtrCondCode(br_code)
1586691Stjones1@inf.ed.ac.uk
1596691Stjones1@inf.ed.ac.uk    # The version that does not update LR
1606691Stjones1@inf.ed.ac.uk    (header_output, decoder_output, decode_block, exec_output) = \
1616691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name, 'BranchNonPCRelCond', basic_code, inst_flags,
1626691Stjones1@inf.ed.ac.uk                 CheckLkDecode, BasicConstructor)
1636691Stjones1@inf.ed.ac.uk
1646691Stjones1@inf.ed.ac.uk    # The version that does the update
1656691Stjones1@inf.ed.ac.uk    update_code = basic_code + updateLrCode
1666691Stjones1@inf.ed.ac.uk    update_flags = inst_flags + [ 'IsCall' ]
1676691Stjones1@inf.ed.ac.uk    (header_output_up, decoder_output_up, _, exec_output_up) = \
1686691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name + 'UpdateLr', 'BranchNonPCRelCond', update_code,
1696691Stjones1@inf.ed.ac.uk                 update_flags, CheckLkDecode, BasicConstructor)
1706691Stjones1@inf.ed.ac.uk
1716691Stjones1@inf.ed.ac.uk    # Add the outputs together
1726691Stjones1@inf.ed.ac.uk    header_output += header_output_up
1736691Stjones1@inf.ed.ac.uk    decoder_output += decoder_output_up
1746691Stjones1@inf.ed.ac.uk    exec_output += exec_output_up
1756691Stjones1@inf.ed.ac.uk}};
1766691Stjones1@inf.ed.ac.uk
1776691Stjones1@inf.ed.ac.uk// Instructions that conditionally branch to the address in the link register
1786691Stjones1@inf.ed.ac.uk// (LR) based on the condition register (CR) and count register (CTR).
1796691Stjones1@inf.ed.ac.ukdef format BranchLrCondCtr(br_code, inst_flags = []) {{
1806691Stjones1@inf.ed.ac.uk    inst_flags += ('IsCondControl', 'IsIndirectControl', 'IsReturn')
1816691Stjones1@inf.ed.ac.uk    basic_code = GetCtrCondCode(br_code)
1826691Stjones1@inf.ed.ac.uk
1836691Stjones1@inf.ed.ac.uk    # The version that does not update LR
1846691Stjones1@inf.ed.ac.uk    (header_output, decoder_output, decode_block, exec_output) = \
1856691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name, 'BranchRegCond', basic_code, inst_flags,
1866691Stjones1@inf.ed.ac.uk                 CheckLkDecode, BasicConstructor)
1876691Stjones1@inf.ed.ac.uk
1886691Stjones1@inf.ed.ac.uk    # The version that does the update
1896691Stjones1@inf.ed.ac.uk    update_code = basic_code + updateLrCode
1906691Stjones1@inf.ed.ac.uk    (header_output_up, decoder_output_up, _, exec_output_up) = \
1916691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name + 'UpdateLr', 'BranchRegCond', update_code,
1926691Stjones1@inf.ed.ac.uk                 inst_flags, CheckLkDecode, BasicConstructor)
1936691Stjones1@inf.ed.ac.uk
1946691Stjones1@inf.ed.ac.uk    # Add the outputs together
1956691Stjones1@inf.ed.ac.uk    header_output += header_output_up
1966691Stjones1@inf.ed.ac.uk    decoder_output += decoder_output_up
1976691Stjones1@inf.ed.ac.uk    exec_output += exec_output_up
1986691Stjones1@inf.ed.ac.uk}};
1996691Stjones1@inf.ed.ac.uk
2006691Stjones1@inf.ed.ac.uk// Instructions that conditionally branch to the address in the count register
2016691Stjones1@inf.ed.ac.uk// (CTR) based on the condition register (CR).
2026691Stjones1@inf.ed.ac.ukdef format BranchCtrCond(br_code, inst_flags = []) {{
2036691Stjones1@inf.ed.ac.uk    inst_flags += ('IsCondControl', 'IsIndirectControl')
2046691Stjones1@inf.ed.ac.uk    basic_code = GetCondCode(br_code)
2056691Stjones1@inf.ed.ac.uk
2066691Stjones1@inf.ed.ac.uk    # The version that does not update LR
2076691Stjones1@inf.ed.ac.uk    (header_output, decoder_output, decode_block, exec_output) = \
2086691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name, 'BranchRegCond', basic_code, inst_flags,
2096691Stjones1@inf.ed.ac.uk                 CheckLkDecode, BasicConstructor)
2106691Stjones1@inf.ed.ac.uk
2116691Stjones1@inf.ed.ac.uk    # The version that does the update
2126691Stjones1@inf.ed.ac.uk    update_code = basic_code + updateLrCode
2136691Stjones1@inf.ed.ac.uk    update_flags = inst_flags + [ 'IsCall' ]
2146691Stjones1@inf.ed.ac.uk    (header_output_up, decoder_output_up, _, exec_output_up) = \
2156691Stjones1@inf.ed.ac.uk        GenAluOp(name, Name + 'UpdateLr', 'BranchRegCond', update_code,
2166691Stjones1@inf.ed.ac.uk                 update_flags, CheckLkDecode, BasicConstructor)
2176691Stjones1@inf.ed.ac.uk
2186691Stjones1@inf.ed.ac.uk    # Add the outputs together
2196691Stjones1@inf.ed.ac.uk    header_output += header_output_up
2206691Stjones1@inf.ed.ac.uk    decoder_output += decoder_output_up
2216691Stjones1@inf.ed.ac.uk    exec_output += exec_output_up
2226691Stjones1@inf.ed.ac.uk}};
223