| // -*- 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. | |
| // | |
| // Authors: Timothy M. Jones | |
| //////////////////////////////////////////////////////////////////// | |
| // | |
| // 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) | |
| { | |
| %(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) | |
| { | |
| %(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) | |
| { | |
| %(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 | |
| }}; |