// -*- mode:c++ -*-

// Copyright (c) 2009 The University of Edinburgh
// Copyright (c) 2021 IBM Corporation
// 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.

////////////////////////////////////////////////////////////////////
//
// Control transfer instructions
//
// From the Power ISA Book I v3.0B, page 35, the following rules should
// be obeyed by programmers:
//
// - Use branch instructions where LK == 1 only as subroutine calls.
// - Pair each subroutine call with a bclr instruction with BH == 00
//   and LK == 0 that returns from the subroutine.
// - Do not use bclr with LK == 1 as a subroutine call.
//
// Therefore, all versions that update the link register (LR) are flagged
// as calls, except bclr with LK == 1 (i.e. bclrl). The latter should not
// be tagged as a return either.

let {{

# Simple code to update link register (LR).
updateLrCode = 'LR = CIA + 4;'

}};


// Instructions that unconditionally branch either to an address relative
// to the current PC or an absolute address.
def format BranchOp(code, code_aa1, inst_flags = []) {{
    inst_flags += ('IsUncondControl', 'IsDirectControl')

    # Setup the 4 code versions and add code to update LR if necessary
    code_lk1 = code + updateLrCode
    code_aa1_lk1 = code_aa1 + updateLrCode

    # Generate the classes
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'BranchOp', code, inst_flags,
                 CheckAaLkDecode, BasicConstructor)
    (header_output_aa1, decoder_output_aa1, _, exec_output_aa1) = \
        GenAluOp(name, Name + 'AaSet', 'BranchOp', code_aa1, inst_flags,
                 CheckAaLkDecode, BasicConstructor)
    (header_output_lk1, decoder_output_lk1, _, exec_output_lk1) = \
        GenAluOp(name, Name + 'LkSet', 'BranchOp', code_lk1, inst_flags,
                 CheckAaLkDecode, BasicConstructor)
    (header_output_aa1_lk1, decoder_output_aa1_lk1, _, exec_output_aa1_lk1) = \
        GenAluOp(name, Name + 'AaSetLkSet', 'BranchOp', code_aa1_lk1,
                 inst_flags, CheckAaLkDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += \
        header_output_aa1 + header_output_lk1 + header_output_aa1_lk1
    decoder_output += \
        decoder_output_aa1 + decoder_output_lk1 + decoder_output_aa1_lk1
    exec_output += \
        exec_output_aa1 + exec_output_lk1 + exec_output_aa1_lk1
}};


let {{

# Check the condition register (CR) allows the branch to be taken.
def GetCondCode(br_code):
    cond_code =  'Msr msr = MSR;\n'
    cond_code += 'if (condOk(CR)) {\n'
    cond_code += '    ' + br_code + '\n'
    cond_code += '}\n'
    cond_code += 'NIA = msr.sf ? NIA : NIA & UINT32_MAX;\n'
    return cond_code

# Check the condition register (CR) and count register (CTR) allow the
# branch to be taken. Also, in certain situations, decrement the count
# register too. This takes place in ctrOk within BranchCondOp classes.
def GetCtrCondCode(br_code):
    cond_code =  'uint64_t ctr = CTR;\n'
    cond_code += 'Msr msr = MSR;\n'
    cond_code += 'if (ctrOk(ctr) && condOk(CR)) {\n'
    cond_code += '    ' + br_code + '\n'
    cond_code += '}\n'
    cond_code += 'NIA = msr.sf ? NIA : NIA & UINT32_MAX;\n'
    cond_code += 'CTR = ctr;\n'
    return cond_code

}};


// Instructions that conditionally branch either to an address relative
// to the current PC or an absolute address depending on the value of the
// condition register (CR) and count register (CTR).
def format BranchDispCondOp(code, code_aa1, inst_flags = []) {{
    inst_flags += ('IsCondControl', 'IsDirectControl')

    # Setup the 4 code versions and add code to update LR if necessary
    code = GetCtrCondCode(code)
    code_aa1 = GetCtrCondCode(code_aa1)
    code_lk1 = code + updateLrCode
    code_aa1_lk1 = code_aa1 + updateLrCode
    inst_flags_lk1 = inst_flags + [ 'IsCall' ]

    # Generate the classes
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'BranchDispCondOp', code, inst_flags,
                 CheckAaLkDecode, BasicConstructor)
    (header_output_aa1, decoder_output_aa1, _, exec_output_aa1) = \
        GenAluOp(name, Name + 'AaSet', 'BranchDispCondOp', code_aa1,
                 inst_flags, CheckAaLkDecode, BasicConstructor)
    (header_output_lk1, decoder_output_lk1, _, exec_output_lk1) = \
        GenAluOp(name, Name + 'LkSet', 'BranchDispCondOp', code_lk1,
                 inst_flags_lk1, CheckAaLkDecode, BasicConstructor)
    (header_output_aa1_lk1, decoder_output_aa1_lk1, _, exec_output_aa1_lk1) = \
        GenAluOp(name, Name + 'AaSetLkSet', 'BranchDispCondOp', code_aa1_lk1,
                 inst_flags_lk1, CheckAaLkDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += \
        header_output_aa1 + header_output_lk1 + header_output_aa1_lk1
    decoder_output += \
        decoder_output_aa1 + decoder_output_lk1 + decoder_output_aa1_lk1
    exec_output += \
        exec_output_aa1 + exec_output_lk1 + exec_output_aa1_lk1
}};


// Instructions that conditionally branch to an address in a register
// depending on the value of the condition register (CR) and count
// register (CTR).
def format BranchRegCondOp(code, checkCTR = 0, inst_flags = []) {{
    inst_flags += ('IsCondControl', 'IsIndirectControl')

    # Setup the 2 code versions and add code to update LR if necessary
    if checkCTR:
        code = GetCtrCondCode(code)
        decode_template = CheckLkDecode
    else:
        code = GetCondCode(code)
        decode_template = CheckBoLkDecode
    code_lk1 = code + updateLrCode
    inst_flags_lk1 = inst_flags + [ 'IsCall' ]

    # When LK is set, this cannot be used to return to the callee
    if 'IsReturn' in inst_flags:
        inst_flags_lk1.remove('IsReturn')

    # Generate the classes
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'BranchRegCondOp', code, inst_flags,
                 decode_template, BasicConstructor)
    (header_output_lk1, decoder_output_lk1, _, exec_output_lk1) = \
        GenAluOp(name, Name + 'LkSet', 'BranchRegCondOp', code_lk1,
                 inst_flags_lk1, decode_template, BasicConstructor)

    # Finally, add to the other outputs
    header_output += header_output_lk1
    decoder_output += decoder_output_lk1
    exec_output += exec_output_lk1
}};
