blob: 50badce53142d059ae63492d4704767ae180054a [file] [log] [blame]
// -*- mode:c++ -*-
// Copyright (c) 2009 The University of Edinburgh
// 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
//
// Instruction class constructor template when Rc is set.
def template IntRcConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst) :
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
%(set_reg_idx_arr)s;
%(constructor)s;
rcSet = true;
}
}};
// Instruction class constructor template when OE is set.
def template IntOeConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst) :
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
%(set_reg_idx_arr)s;
%(constructor)s;
oeSet = true;
}
}};
// Instruction class constructor template when both Rc and OE are set.
def template IntRcOeConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst) :
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
%(set_reg_idx_arr)s;
%(constructor)s;
rcSet = true;
oeSet = true;
}
}};
let {{
readXERCode = 'Xer xer = XER;'
setXERCode = 'XER = xer;'
computeCR0Code = '''
Cr cr = CR;
cr.cr0 = makeCRField((int32_t)%(result)s, (int32_t)0, xer.so);
CR = cr;
'''
computeCACode = '''
if (findCarry(32, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ca = 1;
} else {
xer.ca = 0;
}
'''
computeOVCode = '''
if (findOverflow(32, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ov = 1;
xer.so = 1;
} else {
xer.ov = 0;
}
'''
computeDivOVCode = '''
if (divSetOV) {
xer.ov = 1;
xer.so = 1;
} else {
if (findOverflow(32, %(result)s, %(inputa)s, %(inputb)s)) {
xer.ov = 1;
xer.so = 1;
} else {
xer.ov = 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, ctrl_flags = [], inst_flags = []) {{
# Set up the dictionary and deal with control flags
dict = {'result':'Rt', 'inputa':'src', 'inputb':'imm'}
if ctrl_flags:
code += readXERCode
for val in ctrl_flags:
if val == 'computeCA':
code += computeCACode % dict + setXERCode
elif val == 'computeCR0':
code += computeCR0Code % dict
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmOp', 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, 'IntImmOp', code, inst_flags,
CheckRaDecode, BasicConstructor)
# Now another version where Ra == 0
(header_output_ra0, decoder_output_ra0, _, exec_output_ra0) = \
GenAluOp(name, Name + 'RaZero', 'IntImmOp', 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'}
if computeCR0:
code += readXERCode + computeCR0Code % dict
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode,
BasicConstructor)
}};
// Integer instructions that perform logic operations. The result is
// always written into Ra. All 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, inst_flags = []) {{
dict = {'result':'Ra'}
# Code when Rc is set
code_rc1 = code + readXERCode + computeCR0Code % dict
# Generate the first class
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntOp', code_rc1, inst_flags,
CheckRcDecode, IntRcConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
// Integer instructions with a shift amount. As above, except inheriting
// from the IntShiftOp class.
def format IntShiftOp(code, inst_flags = []) {{
dict = {'result':'Ra'}
# Code when Rc is set
code_rc1 = code + readXERCode + computeCR0Code % dict
# 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, IntRcConstructor)
# 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 = 'uint32_t src1 = ' + src1 + ';\n'
code += 'uint32_t src2 = ' + src2 + ';\n'
code += 'uint32_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, 'IntOp', code, inst_flags,
CheckRcOeDecode, BasicConstructor)
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntOp', code_rc1, inst_flags,
CheckRcOeDecode, IntRcConstructor)
(header_output_oe1, decoder_output_oe1, _, exec_output_oe1) = \
GenAluOp(name, Name + 'OeSet', 'IntOp', code_oe1, inst_flags,
CheckRcOeDecode, IntOeConstructor)
(header_output_rc1_oe1, decoder_output_rc1_oe1, _, exec_output_rc1_oe1) = \
GenAluOp(name, Name + 'RcSetOeSet', 'IntOp', code_rc1_oe1,
inst_flags, CheckRcOeDecode, IntRcOeConstructor)
# 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. Basically multiply and divide instructions. The
// carry bit is never set, but overflow can be calculated. Division
// explicitly sets the overflow bit in certain situations and this is
// dealt with using the 'divSetOV' boolean in decoder.isa. We generate
// two versions of each instruction to deal with the Rc bit.
def format IntArithOp(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:
code = 'bool divSetOV = false;\n' + code
code += computeDivOVCode % dict + setXERCode
# Setup the 2 code versions and add code to access XER if necessary
code_rc1 = readXERCode + code + computeCR0Code % dict
if computeOV:
code = readXERCode + code
# Generate the classes
(header_output, decoder_output, decode_block, exec_output) = \
GenAluOp(name, Name, 'IntOp', code, inst_flags,
CheckRcDecode, BasicConstructor)
# Generate the second class
(header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
GenAluOp(name, Name + 'RcSet', 'IntOp', code_rc1, inst_flags,
CheckRcDecode, IntRcConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};
// A special format for rotate instructions which use certain fields
// from the instruction's binary encoding. 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'}
# Setup the code for 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, IntRcConstructor)
# Finally, add to the other outputs
header_output += header_output_rc1
decoder_output += decoder_output_rc1
exec_output += exec_output_rc1
}};