blob: 3e4531fb57eca48ae1af8fe7b3e2446c2a122a5f [file] [log] [blame]
// -*- 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.
////////////////////////////////////////////////////////////////////
//
// Integer ALU instructions
//
let {{
readXERCode = '[[maybe_unused]] Xer xer = XER;'
setXERCode = 'XER = xer;'
computeCR0Code = '''
{
Cr cr = CR;
Msr msr = MSR;
cr.cr0 = msr.sf ?
makeCRFieldSigned((int64_t)%(result)s, 0, xer.so) :
makeCRFieldSigned((int32_t)%(result)s, 0, xer.so);
CR = cr;
}
'''
computeCACode = '''
{
Msr msr = MSR;
if (findCarry(32, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ca = 1;
xer.ca32 = 1;
} else {
xer.ca = 0;
xer.ca32 = 0;
}
if (msr.sf) {
if (findCarry(64, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ca = 1;
} else {
xer.ca = 0;
}
}
}
'''
computeOVCode = '''
{
Msr msr = MSR;
if (findOverflow(32, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ov = 1;
xer.ov32 = 1;
} else {
xer.ov = 0;
xer.ov32 = 0;
}
if (msr.sf) {
if (findOverflow(64, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ov = 1;
} else {
xer.ov = 0;
}
}
if (xer.ov) {
xer.so = 1;
}
}
'''
setCACode = '''
if (setCA) {
xer.ca = 1;
xer.ca32 = 1;
} else {
xer.ca = 0;
xer.ca32 = 0;
}
'''
setOVCode = '''
if (setOV) {
xer.ov = 1;
xer.ov32 = 1;
xer.so = 1;
} else {
xer.ov = 0;
xer.ov32 = 0;
}
'''
}};
// A basic integer instruction.
def format IntOp(code, inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer instructions with immediate (signed or unsigned).
def format IntImmOp(code, inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer instructions with immediate that perform arithmetic.
// These instructions all write to Rt and use an altered form of the
// value in source register Ra, hence the use of src to hold the actual
// value. The control flags include the use of code to compute the
// carry bit or the CR0 code.
def format IntImmArithOp(code, computeCA = 0, computeCR0 = 0,
inst_flags = []) {{
# Set up the dictionary
dict = {'result':'Rt', 'inputa':'src', 'inputb':'si'}
# Deal with computing CR0 and carry
if computeCA or computeCR0:
code += readXERCode
if computeCA:
code += computeCACode % dict + setXERCode
if computeCR0:
code += computeCR0Code % dict
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmArithOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer instructions with immediate that perform arithmetic but use
// the value 0 when Ra == 0. We generate two versions of each instruction
// corresponding to these two different scenarios. The correct version is
// determined at decode (see the CheckRaDecode template).
def format IntImmArithCheckRaOp(code, code_ra0, inst_flags = []) {{
# First the version where Ra is non-zero
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmArithOp', code, inst_flags,
CheckRaDecode, BasicConstructor)
# Now another version where Ra == 0
(header_output_ra0, decoder_output_ra0, _, exec_output_ra0) = \
GenAluOp(name, Name + 'RaZero', 'IntImmArithOp', code_ra0, inst_flags,
CheckRaDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_ra0
decoder_output += decoder_output_ra0
exec_output += exec_output_ra0
}};
// Integer instructions with immediate that perform logic operations.
// All instructions write to Ra and use Rs as a source register. Some
// also compute the CR0 code too.
def format IntImmLogicOp(code, computeCR0 = 0, inst_flags = []) {{
# Set up the dictionary and deal with computing CR0
dict = {'result':'Ra'}
# Code when Rc is set
if computeCR0:
code += readXERCode + computeCR0Code % dict
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmLogicOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer instructions with displacement that perform arithmetic.
// There are no control flags to set.
def format IntDispArithOp(code, inst_flags = []) {{
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntDispArithOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer compare instructions.
def format IntCompOp(code, inst_flags = []) {{
# Add code to setup variables
code = '[[maybe_unused]] uint32_t cr = 0;\n' + code
code += 'CR = insertCRField(CR, bf, cr);\n'
# Add code to access XER
code = readXERCode + code
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntCompOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer immediate compare instructions.
def format IntImmCompOp(code, inst_flags = []) {{
# Add code to setup variables
code = '[[maybe_unused]] uint32_t cr = 0;\n' + code
code += 'CR = insertCRField(CR, bf, cr);\n'
# Add code to access XER
code = readXERCode + code
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmCompOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer immediate compare logical instructions.
def format IntImmCompLogicOp(code, inst_flags = []) {{
# Add code to setup variables
code = '[[maybe_unused]] uint32_t cr = 0;\n' + code
code += 'CR = insertCRField(CR, bf, cr);\n'
# Add code to access XER
code = readXERCode + code
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmCompLogicOp', code, inst_flags,
BasicDecode, BasicConstructor)
}};
// Integer instructions that perform logic operations. The result is
// always written into Ra. Some instructions have 2 versions depending on
// whether the Rc bit is set to compute the CR0 code. This is determined
// at decode as before.
def format IntLogicOp(code, computeCR0 = 0, inst_flags = []) {{
dict = {'result':'Ra'}
# Deal with computing CR0
if computeCR0:
# Setup the 2 code versions and add code to access XER if necessary
code_rc1 = code + readXERCode + computeCR0Code % dict
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntLogicOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntLogicOp', code_rc1, inst_flags,
CheckRcDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
else:
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntLogicOp', code, inst_flags,
BasicDecode, BasicConstructor)
}};
// Integer instructions that perform shift operations. All of these
// instructions write to Ra and use Rs as a source register. The shift
// value is obtained from an register or an instruction field. If it
// from a register, Rb is also used as a source register. In certain
// situations, the carry bits have to be set and this is dealt with
// using the 'setCA' boolean in decoder.isa. We need two versions for
// each instruction to deal with the Rc bit.
def format IntShiftOp(code, computeCA = 0, inst_flags = []) {{
dict = {'result':'Ra'}
# Add code to setup variables and access XER if necessary
code = '[[maybe_unused]] bool setCA = false;\n' + code
# Code when Rc is set
code_rc1 = readXERCode + code + computeCR0Code % dict
# Add code for calculating the carry, if needed
if computeCA:
code = readXERCode + code + setCACode + setXERCode
code_rc1 += setCACode + setXERCode
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntShiftOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntShiftOp', code_rc1, inst_flags,
CheckRcDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
// Instructions in this format are all reduced to the form Rt = src1 + src2,
// therefore we just give src1 and src2 definitions. In working out the
// template we first put in the definitions of the variables and then
// the code for the addition. We also deal with computing the carry flag
// if required.
//
// We generate 4 versions of each instruction. This correspond to the
// different combinations of having the OE bit set or unset (which controls
// whether the overflow flag is computed) and the Rc bit set or unset too
// (which controls whether the CR0 code is computed).
def format IntSumOp(src1, src2, ca = {{ 0 }}, computeCA = 0,
inst_flags = []) {{
# The result is always in Rt, but the source values vary
dict = {'result':'Rt', 'inputa':'src1', 'inputb':'src2'}
# Add code to set up variables and do the sum
code = 'uint64_t src1 = ' + src1 + ';\n'
code += 'uint64_t src2 = ' + src2 + ';\n'
code += 'uint64_t ca = ' + ca + ';\n'
code += 'Rt = src1 + src2 + ca;\n'
# Add code for calculating the carry, if needed
if computeCA:
code += computeCACode % dict + setXERCode
# Setup the 4 code versions and add code to access XER if necessary
code_rc1 = readXERCode + code
code_oe1 = readXERCode + code + computeOVCode % dict + setXERCode
code_rc1_oe1 = readXERCode + code + computeOVCode % dict + setXERCode
if (computeCA or ca == 'xer.ca'):
code = readXERCode + code
code_rc1 += computeCR0Code % dict
code_rc1_oe1 += computeCR0Code % dict
# Generate the classes
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntArithOp', code, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntArithOp', code_rc1, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_oe1, decoder_output_oe1, _, exec_output_oe1) = \
GenAluOp(name, Name + 'OeSet', 'IntArithOp', code_oe1, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_rc1_oe1, decoder_output_rc1_oe1, _, exec_output_rc1_oe1) = \
GenAluOp(name, Name + 'RcSetOeSet', 'IntArithOp', code_rc1_oe1,
inst_flags, CheckRcOeDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += \
header_output_rc1 + header_output_oe1 + header_output_rc1_oe1
decoder_output += \
decoder_output_rc1 + decoder_output_oe1 + decoder_output_rc1_oe1
exec_output += \
exec_output_rc1 + exec_output_oe1 + exec_output_rc1_oe1
}};
// Instructions that use source registers Ra and Rb, with the result
// placed into Rt but do not check for carry, overflow or the Rc bit.
def format IntArithOp(code, inst_flags = []) {{
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntArithOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Instructions that use source registers Ra and Rb, with the result
// placed into Rt. Basically multiply and divide instructions. The
// carry bit is never set, but overflow can be calculated. In certain
// situations, the overflow bits have to be set and this is dealt with
// using the 'setOV' boolean in decoder.isa.
//
// In case overflow is to be calculated, we generate four versions of
// each instruction to deal with different combinations of having the
// OE bit set or unset and the Rc bit set or unset too. Otherwise, we
// generate two versions of each instruction to deal with the Rc bit.
def format IntArithCheckRcOp(code, computeOV = 0, inst_flags = []) {{
# The result is always in Rt, but the source values vary
dict = {'result':'Rt', 'inputa':'src1', 'inputb':'src2'}
# Deal with setting the overflow flag
if computeOV:
# Setup the 4 code versions and add code to access XER if necessary
code = '[[maybe_unused]] bool setOV = false;\n' + code
code_rc1 = readXERCode + code + computeCR0Code % dict
code_oe1 = readXERCode + code + setOVCode + setXERCode
code_rc1_oe1 = readXERCode + code + setOVCode + setXERCode
code_rc1_oe1 += computeCR0Code % dict
# Generate the classes
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntArithOp', code, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntArithOp', code_rc1, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_oe1, decoder_output_oe1, _, exec_output_oe1) = \
GenAluOp(name, Name + 'OeSet', 'IntArithOp', code_oe1, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_rc1_oe1, decoder_output_rc1_oe1, _,
exec_output_rc1_oe1) = \
GenAluOp(name, Name + 'RcSetOeSet', 'IntArithOp', code_rc1_oe1,
inst_flags, CheckRcOeDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += \
header_output_rc1 + header_output_oe1 + header_output_rc1_oe1
decoder_output += \
decoder_output_rc1 + decoder_output_oe1 + decoder_output_rc1_oe1
exec_output += \
exec_output_rc1 + exec_output_oe1 + exec_output_rc1_oe1
else:
# Setup the 2 code versions and add code to access XER if necessary
code_rc1 = readXERCode + code + computeCR0Code % dict
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntArithOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntArithOp', code_rc1, inst_flags,
CheckRcDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
// Integer instructions that also perform shift operations. Everything
// is same as above except if the shift value is not obtained from a
// register, two immediates need to be concatenated to get the final
// shift value.
def format IntConcatShiftOp(code, computeCA = 0, inst_flags = []) {{
dict = {'result':'Ra'}
# Add code to setup variables and access XER if necessary
code = '[[maybe_unused]] bool setCA = false;\n' + code
# Code when Rc is set
code_rc1 = readXERCode + code + computeCR0Code % dict
# Add code for calculating the carry, if needed
if computeCA:
code = readXERCode + code + setCACode + setXERCode
code_rc1 += setCACode + setXERCode
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntConcatShiftOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntConcatShiftOp', code_rc1,
inst_flags, CheckRcDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
// Integer instructions with or without immediate that perform rotate
// operations. All instructions write to Ra and use Rs as a source
// register. If immediate is not used, Rb is also used as a source
// register. We need two versions for each instruction to deal with
// the Rc bit.
def format IntRotateOp(code, inst_flags = []) {{
# The result is always in Ra
dict = {'result':'Ra'}
# Code when Rc is set
code_rc1 = readXERCode + code + computeCR0Code % dict
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntRotateOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntRotateOp', code_rc1, inst_flags,
CheckRcDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
// Everything is same as above except that the immediates may need to be
// concatenated to get the final values for the mask bounds or the shift
// value. We need two versions for each instruction to deal with the Rc
// bit.
def format IntConcatRotateOp(code, inst_flags = []) {{
# The result is always in Ra
dict = {'result':'Ra'}
# Code when Rc is set
code_rc1 = readXERCode + code + computeCR0Code % dict
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntConcatRotateOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntConcatRotateOp', code_rc1,
inst_flags, CheckRcDecode, BasicConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
def format IntTrapOp(src1, src2, inst_flags = []) {{
# Add code to set up variables and check for a trap
code = 'int64_t src1 = ' + src1 + ';\n'
code += 'int64_t src2 = ' + src2 + ';\n'
code += 'if (checkTrap(src1, src2)) {\n'
code += ' return std::make_shared<TrapFault>();\n'
code += '}\n'
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntTrapOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
def format IntImmTrapOp(src, inst_flags = []) {{
# Add code to set up variables and check for a trap
code = 'int64_t src = ' + src + ';\n'
code += 'if (checkTrap(src, si)) {\n'
code += ' return std::make_shared<TrapFault>();\n'
code += '}\n'
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmTrapOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};