From: Gabe Black Date: Tue, 29 Sep 2020 07:49:22 +0000 (-0700) Subject: arch: Split the operand types out of the ISA parser. X-Git-Tag: develop-gem5-snapshot~653 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c05192c669adcad900ecf0986f2eb553875ba14e;p=gem5.git arch: Split the operand types out of the ISA parser. These conceptually go together and don't depend on any other parts of the parser. Change-Id: Ia8bff0d0ec210bdeeb080808968faf9528ee03dd Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35278 Reviewed-by: Gabe Black Maintainer: Gabe Black Tested-by: kokoro --- diff --git a/src/arch/isa_parser/isa_parser.py b/src/arch/isa_parser/isa_parser.py index 955d4e276..c147caf62 100755 --- a/src/arch/isa_parser/isa_parser.py +++ b/src/arch/isa_parser/isa_parser.py @@ -46,6 +46,7 @@ import inspect, traceback from types import * from m5.util.grammar import Grammar +from .operand_types import * debug=False @@ -390,737 +391,6 @@ def makeList(arg): else: return [ arg ] -class Operand(object): - '''Base class for operand descriptors. An instance of this class - (or actually a class derived from this one) represents a specific - operand for a code block (e.g, "Rc.sq" as a dest). Intermediate - derived classes encapsulates the traits of a particular operand - type (e.g., "32-bit integer register").''' - - def buildReadCode(self, func = None): - subst_dict = {"name": self.base_name, - "func": func, - "reg_idx": self.reg_spec, - "ctype": self.ctype} - if hasattr(self, 'src_reg_idx'): - subst_dict['op_idx'] = self.src_reg_idx - code = self.read_code % subst_dict - return '%s = %s;\n' % (self.base_name, code) - - def buildWriteCode(self, func = None): - subst_dict = {"name": self.base_name, - "func": func, - "reg_idx": self.reg_spec, - "ctype": self.ctype, - "final_val": self.base_name} - if hasattr(self, 'dest_reg_idx'): - subst_dict['op_idx'] = self.dest_reg_idx - code = self.write_code % subst_dict - return ''' - { - %s final_val = %s; - %s; - if (traceData) { traceData->setData(final_val); } - }''' % (self.dflt_ctype, self.base_name, code) - - def __init__(self, parser, full_name, ext, is_src, is_dest): - self.full_name = full_name - self.ext = ext - self.is_src = is_src - self.is_dest = is_dest - # The 'effective extension' (eff_ext) is either the actual - # extension, if one was explicitly provided, or the default. - if ext: - self.eff_ext = ext - elif hasattr(self, 'dflt_ext'): - self.eff_ext = self.dflt_ext - - if hasattr(self, 'eff_ext'): - self.ctype = parser.operandTypeMap[self.eff_ext] - - # Finalize additional fields (primarily code fields). This step - # is done separately since some of these fields may depend on the - # register index enumeration that hasn't been performed yet at the - # time of __init__(). The register index enumeration is affected - # by predicated register reads/writes. Hence, we forward the flags - # that indicate whether or not predication is in use. - def finalize(self, predRead, predWrite): - self.flags = self.getFlags() - self.constructor = self.makeConstructor(predRead, predWrite) - self.op_decl = self.makeDecl() - - if self.is_src: - self.op_rd = self.makeRead(predRead) - self.op_src_decl = self.makeDecl() - else: - self.op_rd = '' - self.op_src_decl = '' - - if self.is_dest: - self.op_wb = self.makeWrite(predWrite) - self.op_dest_decl = self.makeDecl() - else: - self.op_wb = '' - self.op_dest_decl = '' - - def isMem(self): - return 0 - - def isReg(self): - return 0 - - def isFloatReg(self): - return 0 - - def isIntReg(self): - return 0 - - def isCCReg(self): - return 0 - - def isControlReg(self): - return 0 - - def isVecReg(self): - return 0 - - def isVecElem(self): - return 0 - - def isVecPredReg(self): - return 0 - - def isPCState(self): - return 0 - - def isPCPart(self): - return self.isPCState() and self.reg_spec - - def hasReadPred(self): - return self.read_predicate != None - - def hasWritePred(self): - return self.write_predicate != None - - def getFlags(self): - # note the empty slice '[:]' gives us a copy of self.flags[0] - # instead of a reference to it - my_flags = self.flags[0][:] - if self.is_src: - my_flags += self.flags[1] - if self.is_dest: - my_flags += self.flags[2] - return my_flags - - def makeDecl(self): - # Note that initializations in the declarations are solely - # to avoid 'uninitialized variable' errors from the compiler. - return self.ctype + ' ' + self.base_name + ' = 0;\n'; - - -src_reg_constructor = '\n\t_srcRegIdx[_numSrcRegs++] = RegId(%s, %s);' -dst_reg_constructor = '\n\t_destRegIdx[_numDestRegs++] = RegId(%s, %s);' - - -class IntRegOperand(Operand): - reg_class = 'IntRegClass' - - def isReg(self): - return 1 - - def isIntReg(self): - return 1 - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - if self.is_src: - c_src = src_reg_constructor % (self.reg_class, self.reg_spec) - if self.hasReadPred(): - c_src = '\n\tif (%s) {%s\n\t}' % \ - (self.read_predicate, c_src) - - if self.is_dest: - c_dest = dst_reg_constructor % (self.reg_class, self.reg_spec) - c_dest += '\n\t_numIntDestRegs++;' - if self.hasWritePred(): - c_dest = '\n\tif (%s) {%s\n\t}' % \ - (self.write_predicate, c_dest) - - return c_src + c_dest - - def makeRead(self, predRead): - if (self.ctype == 'float' or self.ctype == 'double'): - error('Attempt to read integer register as FP') - if self.read_code != None: - return self.buildReadCode('readIntRegOperand') - - int_reg_val = '' - if predRead: - int_reg_val = 'xc->readIntRegOperand(this, _sourceIndex++)' - if self.hasReadPred(): - int_reg_val = '(%s) ? %s : 0' % \ - (self.read_predicate, int_reg_val) - else: - int_reg_val = 'xc->readIntRegOperand(this, %d)' % self.src_reg_idx - - return '%s = %s;\n' % (self.base_name, int_reg_val) - - def makeWrite(self, predWrite): - if (self.ctype == 'float' or self.ctype == 'double'): - error('Attempt to write integer register as FP') - if self.write_code != None: - return self.buildWriteCode('setIntRegOperand') - - if predWrite: - wp = 'true' - if self.hasWritePred(): - wp = self.write_predicate - - wcond = 'if (%s)' % (wp) - windex = '_destIndex++' - else: - wcond = '' - windex = '%d' % self.dest_reg_idx - - wb = ''' - %s - { - %s final_val = %s; - xc->setIntRegOperand(this, %s, final_val);\n - if (traceData) { traceData->setData(final_val); } - }''' % (wcond, self.ctype, self.base_name, windex) - - return wb - -class FloatRegOperand(Operand): - reg_class = 'FloatRegClass' - - def isReg(self): - return 1 - - def isFloatReg(self): - return 1 - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - if self.is_src: - c_src = src_reg_constructor % (self.reg_class, self.reg_spec) - - if self.is_dest: - c_dest = dst_reg_constructor % (self.reg_class, self.reg_spec) - c_dest += '\n\t_numFPDestRegs++;' - - return c_src + c_dest - - def makeRead(self, predRead): - if self.read_code != None: - return self.buildReadCode('readFloatRegOperandBits') - - if predRead: - rindex = '_sourceIndex++' - else: - rindex = '%d' % self.src_reg_idx - - code = 'xc->readFloatRegOperandBits(this, %s)' % rindex - if self.ctype == 'float': - code = 'bitsToFloat32(%s)' % code - elif self.ctype == 'double': - code = 'bitsToFloat64(%s)' % code - return '%s = %s;\n' % (self.base_name, code) - - def makeWrite(self, predWrite): - if self.write_code != None: - return self.buildWriteCode('setFloatRegOperandBits') - - if predWrite: - wp = '_destIndex++' - else: - wp = '%d' % self.dest_reg_idx - - val = 'final_val' - if self.ctype == 'float': - val = 'floatToBits32(%s)' % val - elif self.ctype == 'double': - val = 'floatToBits64(%s)' % val - - wp = 'xc->setFloatRegOperandBits(this, %s, %s);' % (wp, val) - - wb = ''' - { - %s final_val = %s; - %s\n - if (traceData) { traceData->setData(final_val); } - }''' % (self.ctype, self.base_name, wp) - return wb - -class VecRegOperand(Operand): - reg_class = 'VecRegClass' - - def __init__(self, parser, full_name, ext, is_src, is_dest): - Operand.__init__(self, parser, full_name, ext, is_src, is_dest) - self.elemExt = None - self.parser = parser - - def isReg(self): - return 1 - - def isVecReg(self): - return 1 - - def makeDeclElem(self, elem_op): - (elem_name, elem_ext) = elem_op - (elem_spec, dflt_elem_ext, zeroing) = self.elems[elem_name] - if elem_ext: - ext = elem_ext - else: - ext = dflt_elem_ext - ctype = self.parser.operandTypeMap[ext] - return '\n\t%s %s = 0;' % (ctype, elem_name) - - def makeDecl(self): - if not self.is_dest and self.is_src: - c_decl = '\t/* Vars for %s*/' % (self.base_name) - if hasattr(self, 'active_elems'): - if self.active_elems: - for elem in self.active_elems: - c_decl += self.makeDeclElem(elem) - return c_decl + '\t/* End vars for %s */\n' % (self.base_name) - else: - return '' - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - numAccessNeeded = 1 - - if self.is_src: - c_src = src_reg_constructor % (self.reg_class, self.reg_spec) - - if self.is_dest: - c_dest = dst_reg_constructor % (self.reg_class, self.reg_spec) - c_dest += '\n\t_numVecDestRegs++;' - - return c_src + c_dest - - # Read destination register to write - def makeReadWElem(self, elem_op): - (elem_name, elem_ext) = elem_op - (elem_spec, dflt_elem_ext, zeroing) = self.elems[elem_name] - if elem_ext: - ext = elem_ext - else: - ext = dflt_elem_ext - ctype = self.parser.operandTypeMap[ext] - c_read = '\t\t%s& %s = %s[%s];\n' % \ - (ctype, elem_name, self.base_name, elem_spec) - return c_read - - def makeReadW(self, predWrite): - func = 'getWritableVecRegOperand' - if self.read_code != None: - return self.buildReadCode(func) - - if predWrite: - rindex = '_destIndex++' - else: - rindex = '%d' % self.dest_reg_idx - - c_readw = '\t\t%s& tmp_d%s = xc->%s(this, %s);\n'\ - % ('TheISA::VecRegContainer', rindex, func, rindex) - if self.elemExt: - c_readw += '\t\tauto %s = tmp_d%s.as<%s>();\n' % (self.base_name, - rindex, self.parser.operandTypeMap[self.elemExt]) - if self.ext: - c_readw += '\t\tauto %s = tmp_d%s.as<%s>();\n' % (self.base_name, - rindex, self.parser.operandTypeMap[self.ext]) - if hasattr(self, 'active_elems'): - if self.active_elems: - for elem in self.active_elems: - c_readw += self.makeReadWElem(elem) - return c_readw - - # Normal source operand read - def makeReadElem(self, elem_op, name): - (elem_name, elem_ext) = elem_op - (elem_spec, dflt_elem_ext, zeroing) = self.elems[elem_name] - - if elem_ext: - ext = elem_ext - else: - ext = dflt_elem_ext - ctype = self.parser.operandTypeMap[ext] - c_read = '\t\t%s = %s[%s];\n' % \ - (elem_name, name, elem_spec) - return c_read - - def makeRead(self, predRead): - func = 'readVecRegOperand' - if self.read_code != None: - return self.buildReadCode(func) - - if predRead: - rindex = '_sourceIndex++' - else: - rindex = '%d' % self.src_reg_idx - - name = self.base_name - if self.is_dest and self.is_src: - name += '_merger' - - c_read = '\t\t%s& tmp_s%s = xc->%s(this, %s);\n' \ - % ('const TheISA::VecRegContainer', rindex, func, rindex) - # If the parser has detected that elements are being access, create - # the appropriate view - if self.elemExt: - c_read += '\t\tauto %s = tmp_s%s.as<%s>();\n' % \ - (name, rindex, self.parser.operandTypeMap[self.elemExt]) - if self.ext: - c_read += '\t\tauto %s = tmp_s%s.as<%s>();\n' % \ - (name, rindex, self.parser.operandTypeMap[self.ext]) - if hasattr(self, 'active_elems'): - if self.active_elems: - for elem in self.active_elems: - c_read += self.makeReadElem(elem, name) - return c_read - - def makeWrite(self, predWrite): - func = 'setVecRegOperand' - if self.write_code != None: - return self.buildWriteCode(func) - - wb = ''' - if (traceData) { - traceData->setData(tmp_d%d); - } - ''' % self.dest_reg_idx - return wb - - def finalize(self, predRead, predWrite): - super(VecRegOperand, self).finalize(predRead, predWrite) - if self.is_dest: - self.op_rd = self.makeReadW(predWrite) + self.op_rd - -class VecElemOperand(Operand): - reg_class = 'VecElemClass' - - def isReg(self): - return 1 - - def isVecElem(self): - return 1 - - def makeDecl(self): - if self.is_dest and not self.is_src: - return '\n\t%s %s;' % (self.ctype, self.base_name) - else: - return '' - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - numAccessNeeded = 1 - - if self.is_src: - c_src = ('\n\t_srcRegIdx[_numSrcRegs++] = RegId(%s, %s, %s);' % - (self.reg_class, self.reg_spec, self.elem_spec)) - - if self.is_dest: - c_dest = ('\n\t_destRegIdx[_numDestRegs++] = RegId(%s, %s, %s);' % - (self.reg_class, self.reg_spec, self.elem_spec)) - c_dest += '\n\t_numVecElemDestRegs++;' - return c_src + c_dest - - def makeRead(self, predRead): - c_read = 'xc->readVecElemOperand(this, %d)' % self.src_reg_idx - - if self.ctype == 'float': - c_read = 'bitsToFloat32(%s)' % c_read - elif self.ctype == 'double': - c_read = 'bitsToFloat64(%s)' % c_read - - return '\n\t%s %s = %s;\n' % (self.ctype, self.base_name, c_read) - - def makeWrite(self, predWrite): - if self.ctype == 'float': - c_write = 'floatToBits32(%s)' % self.base_name - elif self.ctype == 'double': - c_write = 'floatToBits64(%s)' % self.base_name - else: - c_write = self.base_name - - c_write = ('\n\txc->setVecElemOperand(this, %d, %s);' % - (self.dest_reg_idx, c_write)) - - return c_write - -class VecPredRegOperand(Operand): - reg_class = 'VecPredRegClass' - - def __init__(self, parser, full_name, ext, is_src, is_dest): - Operand.__init__(self, parser, full_name, ext, is_src, is_dest) - self.parser = parser - - def isReg(self): - return 1 - - def isVecPredReg(self): - return 1 - - def makeDecl(self): - return '' - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - if self.is_src: - c_src = src_reg_constructor % (self.reg_class, self.reg_spec) - - if self.is_dest: - c_dest = dst_reg_constructor % (self.reg_class, self.reg_spec) - c_dest += '\n\t_numVecPredDestRegs++;' - - return c_src + c_dest - - def makeRead(self, predRead): - func = 'readVecPredRegOperand' - if self.read_code != None: - return self.buildReadCode(func) - - if predRead: - rindex = '_sourceIndex++' - else: - rindex = '%d' % self.src_reg_idx - - c_read = '\t\t%s& tmp_s%s = xc->%s(this, %s);\n' % ( - 'const TheISA::VecPredRegContainer', rindex, func, rindex) - if self.ext: - c_read += '\t\tauto %s = tmp_s%s.as<%s>();\n' % ( - self.base_name, rindex, - self.parser.operandTypeMap[self.ext]) - return c_read - - def makeReadW(self, predWrite): - func = 'getWritableVecPredRegOperand' - if self.read_code != None: - return self.buildReadCode(func) - - if predWrite: - rindex = '_destIndex++' - else: - rindex = '%d' % self.dest_reg_idx - - c_readw = '\t\t%s& tmp_d%s = xc->%s(this, %s);\n' % ( - 'TheISA::VecPredRegContainer', rindex, func, rindex) - if self.ext: - c_readw += '\t\tauto %s = tmp_d%s.as<%s>();\n' % ( - self.base_name, rindex, - self.parser.operandTypeMap[self.ext]) - return c_readw - - def makeWrite(self, predWrite): - func = 'setVecPredRegOperand' - if self.write_code != None: - return self.buildWriteCode(func) - - wb = ''' - if (traceData) { - traceData->setData(tmp_d%d); - } - ''' % self.dest_reg_idx - return wb - - def finalize(self, predRead, predWrite): - super(VecPredRegOperand, self).finalize(predRead, predWrite) - if self.is_dest: - self.op_rd = self.makeReadW(predWrite) + self.op_rd - -class CCRegOperand(Operand): - reg_class = 'CCRegClass' - - def isReg(self): - return 1 - - def isCCReg(self): - return 1 - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - if self.is_src: - c_src = src_reg_constructor % (self.reg_class, self.reg_spec) - if self.hasReadPred(): - c_src = '\n\tif (%s) {%s\n\t}' % \ - (self.read_predicate, c_src) - - if self.is_dest: - c_dest = dst_reg_constructor % (self.reg_class, self.reg_spec) - c_dest += '\n\t_numCCDestRegs++;' - if self.hasWritePred(): - c_dest = '\n\tif (%s) {%s\n\t}' % \ - (self.write_predicate, c_dest) - - return c_src + c_dest - - def makeRead(self, predRead): - if (self.ctype == 'float' or self.ctype == 'double'): - error('Attempt to read condition-code register as FP') - if self.read_code != None: - return self.buildReadCode('readCCRegOperand') - - int_reg_val = '' - if predRead: - int_reg_val = 'xc->readCCRegOperand(this, _sourceIndex++)' - if self.hasReadPred(): - int_reg_val = '(%s) ? %s : 0' % \ - (self.read_predicate, int_reg_val) - else: - int_reg_val = 'xc->readCCRegOperand(this, %d)' % self.src_reg_idx - - return '%s = %s;\n' % (self.base_name, int_reg_val) - - def makeWrite(self, predWrite): - if (self.ctype == 'float' or self.ctype == 'double'): - error('Attempt to write condition-code register as FP') - if self.write_code != None: - return self.buildWriteCode('setCCRegOperand') - - if predWrite: - wp = 'true' - if self.hasWritePred(): - wp = self.write_predicate - - wcond = 'if (%s)' % (wp) - windex = '_destIndex++' - else: - wcond = '' - windex = '%d' % self.dest_reg_idx - - wb = ''' - %s - { - %s final_val = %s; - xc->setCCRegOperand(this, %s, final_val);\n - if (traceData) { traceData->setData(final_val); } - }''' % (wcond, self.ctype, self.base_name, windex) - - return wb - -class ControlRegOperand(Operand): - reg_class = 'MiscRegClass' - - def isReg(self): - return 1 - - def isControlReg(self): - return 1 - - def makeConstructor(self, predRead, predWrite): - c_src = '' - c_dest = '' - - if self.is_src: - c_src = src_reg_constructor % (self.reg_class, self.reg_spec) - - if self.is_dest: - c_dest = dst_reg_constructor % (self.reg_class, self.reg_spec) - - return c_src + c_dest - - def makeRead(self, predRead): - bit_select = 0 - if (self.ctype == 'float' or self.ctype == 'double'): - error('Attempt to read control register as FP') - if self.read_code != None: - return self.buildReadCode('readMiscRegOperand') - - if predRead: - rindex = '_sourceIndex++' - else: - rindex = '%d' % self.src_reg_idx - - return '%s = xc->readMiscRegOperand(this, %s);\n' % \ - (self.base_name, rindex) - - def makeWrite(self, predWrite): - if (self.ctype == 'float' or self.ctype == 'double'): - error('Attempt to write control register as FP') - if self.write_code != None: - return self.buildWriteCode('setMiscRegOperand') - - if predWrite: - windex = '_destIndex++' - else: - windex = '%d' % self.dest_reg_idx - - wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \ - (windex, self.base_name) - wb += 'if (traceData) { traceData->setData(%s); }' % \ - self.base_name - - return wb - -class MemOperand(Operand): - def isMem(self): - return 1 - - def makeConstructor(self, predRead, predWrite): - return '' - - def makeDecl(self): - # Declare memory data variable. - return '%s %s = {};\n' % (self.ctype, self.base_name) - - def makeRead(self, predRead): - if self.read_code != None: - return self.buildReadCode() - return '' - - def makeWrite(self, predWrite): - if self.write_code != None: - return self.buildWriteCode() - return '' - -class PCStateOperand(Operand): - def makeConstructor(self, predRead, predWrite): - return '' - - def makeRead(self, predRead): - if self.reg_spec: - # A component of the PC state. - return '%s = __parserAutoPCState.%s();\n' % \ - (self.base_name, self.reg_spec) - else: - # The whole PC state itself. - return '%s = xc->pcState();\n' % self.base_name - - def makeWrite(self, predWrite): - if self.reg_spec: - # A component of the PC state. - return '__parserAutoPCState.%s(%s);\n' % \ - (self.reg_spec, self.base_name) - else: - # The whole PC state itself. - return 'xc->pcState(%s);\n' % self.base_name - - def makeDecl(self): - ctype = 'TheISA::PCState' - if self.isPCPart(): - ctype = self.ctype - # Note that initializations in the declarations are solely - # to avoid 'uninitialized variable' errors from the compiler. - return '%s %s = 0;\n' % (ctype, self.base_name) - - def isPCState(self): - return 1 - class OperandList(object): '''Find all the operands in the given code block. Returns an operand descriptor list (instance of class OperandList).''' diff --git a/src/arch/isa_parser/operand_types.py b/src/arch/isa_parser/operand_types.py new file mode 100755 index 000000000..cd341d038 --- /dev/null +++ b/src/arch/isa_parser/operand_types.py @@ -0,0 +1,768 @@ +# Copyright (c) 2014, 2016, 2018-2019 ARM Limited +# All rights reserved +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Copyright (c) 2003-2005 The Regents of The University of Michigan +# Copyright (c) 2013,2015 Advanced Micro Devices, Inc. +# 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. + +class Operand(object): + '''Base class for operand descriptors. An instance of this class + (or actually a class derived from this one) represents a specific + operand for a code block (e.g, "Rc.sq" as a dest). Intermediate + derived classes encapsulates the traits of a particular operand + type (e.g., "32-bit integer register").''' + + src_reg_constructor = '\n\t_srcRegIdx[_numSrcRegs++] = RegId(%s, %s);' + dst_reg_constructor = '\n\t_destRegIdx[_numDestRegs++] = RegId(%s, %s);' + + def buildReadCode(self, func = None): + subst_dict = {"name": self.base_name, + "func": func, + "reg_idx": self.reg_spec, + "ctype": self.ctype} + if hasattr(self, 'src_reg_idx'): + subst_dict['op_idx'] = self.src_reg_idx + code = self.read_code % subst_dict + return '%s = %s;\n' % (self.base_name, code) + + def buildWriteCode(self, func = None): + subst_dict = {"name": self.base_name, + "func": func, + "reg_idx": self.reg_spec, + "ctype": self.ctype, + "final_val": self.base_name} + if hasattr(self, 'dest_reg_idx'): + subst_dict['op_idx'] = self.dest_reg_idx + code = self.write_code % subst_dict + return ''' + { + %s final_val = %s; + %s; + if (traceData) { traceData->setData(final_val); } + }''' % (self.dflt_ctype, self.base_name, code) + + def __init__(self, parser, full_name, ext, is_src, is_dest): + self.full_name = full_name + self.ext = ext + self.is_src = is_src + self.is_dest = is_dest + # The 'effective extension' (eff_ext) is either the actual + # extension, if one was explicitly provided, or the default. + if ext: + self.eff_ext = ext + elif hasattr(self, 'dflt_ext'): + self.eff_ext = self.dflt_ext + + if hasattr(self, 'eff_ext'): + self.ctype = parser.operandTypeMap[self.eff_ext] + + # Finalize additional fields (primarily code fields). This step + # is done separately since some of these fields may depend on the + # register index enumeration that hasn't been performed yet at the + # time of __init__(). The register index enumeration is affected + # by predicated register reads/writes. Hence, we forward the flags + # that indicate whether or not predication is in use. + def finalize(self, predRead, predWrite): + self.flags = self.getFlags() + self.constructor = self.makeConstructor(predRead, predWrite) + self.op_decl = self.makeDecl() + + if self.is_src: + self.op_rd = self.makeRead(predRead) + self.op_src_decl = self.makeDecl() + else: + self.op_rd = '' + self.op_src_decl = '' + + if self.is_dest: + self.op_wb = self.makeWrite(predWrite) + self.op_dest_decl = self.makeDecl() + else: + self.op_wb = '' + self.op_dest_decl = '' + + def isMem(self): + return 0 + + def isReg(self): + return 0 + + def isFloatReg(self): + return 0 + + def isIntReg(self): + return 0 + + def isCCReg(self): + return 0 + + def isControlReg(self): + return 0 + + def isVecReg(self): + return 0 + + def isVecElem(self): + return 0 + + def isVecPredReg(self): + return 0 + + def isPCState(self): + return 0 + + def isPCPart(self): + return self.isPCState() and self.reg_spec + + def hasReadPred(self): + return self.read_predicate != None + + def hasWritePred(self): + return self.write_predicate != None + + def getFlags(self): + # note the empty slice '[:]' gives us a copy of self.flags[0] + # instead of a reference to it + my_flags = self.flags[0][:] + if self.is_src: + my_flags += self.flags[1] + if self.is_dest: + my_flags += self.flags[2] + return my_flags + + def makeDecl(self): + # Note that initializations in the declarations are solely + # to avoid 'uninitialized variable' errors from the compiler. + return self.ctype + ' ' + self.base_name + ' = 0;\n'; + + +class IntRegOperand(Operand): + reg_class = 'IntRegClass' + + def isReg(self): + return 1 + + def isIntReg(self): + return 1 + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + if self.is_src: + c_src = self.src_reg_constructor % (self.reg_class, self.reg_spec) + if self.hasReadPred(): + c_src = '\n\tif (%s) {%s\n\t}' % \ + (self.read_predicate, c_src) + + if self.is_dest: + c_dest = self.dst_reg_constructor % (self.reg_class, self.reg_spec) + c_dest += '\n\t_numIntDestRegs++;' + if self.hasWritePred(): + c_dest = '\n\tif (%s) {%s\n\t}' % \ + (self.write_predicate, c_dest) + + return c_src + c_dest + + def makeRead(self, predRead): + if (self.ctype == 'float' or self.ctype == 'double'): + error('Attempt to read integer register as FP') + if self.read_code != None: + return self.buildReadCode('readIntRegOperand') + + int_reg_val = '' + if predRead: + int_reg_val = 'xc->readIntRegOperand(this, _sourceIndex++)' + if self.hasReadPred(): + int_reg_val = '(%s) ? %s : 0' % \ + (self.read_predicate, int_reg_val) + else: + int_reg_val = 'xc->readIntRegOperand(this, %d)' % self.src_reg_idx + + return '%s = %s;\n' % (self.base_name, int_reg_val) + + def makeWrite(self, predWrite): + if (self.ctype == 'float' or self.ctype == 'double'): + error('Attempt to write integer register as FP') + if self.write_code != None: + return self.buildWriteCode('setIntRegOperand') + + if predWrite: + wp = 'true' + if self.hasWritePred(): + wp = self.write_predicate + + wcond = 'if (%s)' % (wp) + windex = '_destIndex++' + else: + wcond = '' + windex = '%d' % self.dest_reg_idx + + wb = ''' + %s + { + %s final_val = %s; + xc->setIntRegOperand(this, %s, final_val);\n + if (traceData) { traceData->setData(final_val); } + }''' % (wcond, self.ctype, self.base_name, windex) + + return wb + +class FloatRegOperand(Operand): + reg_class = 'FloatRegClass' + + def isReg(self): + return 1 + + def isFloatReg(self): + return 1 + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + if self.is_src: + c_src = self.src_reg_constructor % (self.reg_class, self.reg_spec) + + if self.is_dest: + c_dest = self.dst_reg_constructor % (self.reg_class, self.reg_spec) + c_dest += '\n\t_numFPDestRegs++;' + + return c_src + c_dest + + def makeRead(self, predRead): + if self.read_code != None: + return self.buildReadCode('readFloatRegOperandBits') + + if predRead: + rindex = '_sourceIndex++' + else: + rindex = '%d' % self.src_reg_idx + + code = 'xc->readFloatRegOperandBits(this, %s)' % rindex + if self.ctype == 'float': + code = 'bitsToFloat32(%s)' % code + elif self.ctype == 'double': + code = 'bitsToFloat64(%s)' % code + return '%s = %s;\n' % (self.base_name, code) + + def makeWrite(self, predWrite): + if self.write_code != None: + return self.buildWriteCode('setFloatRegOperandBits') + + if predWrite: + wp = '_destIndex++' + else: + wp = '%d' % self.dest_reg_idx + + val = 'final_val' + if self.ctype == 'float': + val = 'floatToBits32(%s)' % val + elif self.ctype == 'double': + val = 'floatToBits64(%s)' % val + + wp = 'xc->setFloatRegOperandBits(this, %s, %s);' % (wp, val) + + wb = ''' + { + %s final_val = %s; + %s\n + if (traceData) { traceData->setData(final_val); } + }''' % (self.ctype, self.base_name, wp) + return wb + +class VecRegOperand(Operand): + reg_class = 'VecRegClass' + + def __init__(self, parser, full_name, ext, is_src, is_dest): + Operand.__init__(self, parser, full_name, ext, is_src, is_dest) + self.elemExt = None + self.parser = parser + + def isReg(self): + return 1 + + def isVecReg(self): + return 1 + + def makeDeclElem(self, elem_op): + (elem_name, elem_ext) = elem_op + (elem_spec, dflt_elem_ext, zeroing) = self.elems[elem_name] + if elem_ext: + ext = elem_ext + else: + ext = dflt_elem_ext + ctype = self.parser.operandTypeMap[ext] + return '\n\t%s %s = 0;' % (ctype, elem_name) + + def makeDecl(self): + if not self.is_dest and self.is_src: + c_decl = '\t/* Vars for %s*/' % (self.base_name) + if hasattr(self, 'active_elems'): + if self.active_elems: + for elem in self.active_elems: + c_decl += self.makeDeclElem(elem) + return c_decl + '\t/* End vars for %s */\n' % (self.base_name) + else: + return '' + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + numAccessNeeded = 1 + + if self.is_src: + c_src = self.src_reg_constructor % (self.reg_class, self.reg_spec) + + if self.is_dest: + c_dest = self.dst_reg_constructor % (self.reg_class, self.reg_spec) + c_dest += '\n\t_numVecDestRegs++;' + + return c_src + c_dest + + # Read destination register to write + def makeReadWElem(self, elem_op): + (elem_name, elem_ext) = elem_op + (elem_spec, dflt_elem_ext, zeroing) = self.elems[elem_name] + if elem_ext: + ext = elem_ext + else: + ext = dflt_elem_ext + ctype = self.parser.operandTypeMap[ext] + c_read = '\t\t%s& %s = %s[%s];\n' % \ + (ctype, elem_name, self.base_name, elem_spec) + return c_read + + def makeReadW(self, predWrite): + func = 'getWritableVecRegOperand' + if self.read_code != None: + return self.buildReadCode(func) + + if predWrite: + rindex = '_destIndex++' + else: + rindex = '%d' % self.dest_reg_idx + + c_readw = '\t\t%s& tmp_d%s = xc->%s(this, %s);\n'\ + % ('TheISA::VecRegContainer', rindex, func, rindex) + if self.elemExt: + c_readw += '\t\tauto %s = tmp_d%s.as<%s>();\n' % (self.base_name, + rindex, self.parser.operandTypeMap[self.elemExt]) + if self.ext: + c_readw += '\t\tauto %s = tmp_d%s.as<%s>();\n' % (self.base_name, + rindex, self.parser.operandTypeMap[self.ext]) + if hasattr(self, 'active_elems'): + if self.active_elems: + for elem in self.active_elems: + c_readw += self.makeReadWElem(elem) + return c_readw + + # Normal source operand read + def makeReadElem(self, elem_op, name): + (elem_name, elem_ext) = elem_op + (elem_spec, dflt_elem_ext, zeroing) = self.elems[elem_name] + + if elem_ext: + ext = elem_ext + else: + ext = dflt_elem_ext + ctype = self.parser.operandTypeMap[ext] + c_read = '\t\t%s = %s[%s];\n' % \ + (elem_name, name, elem_spec) + return c_read + + def makeRead(self, predRead): + func = 'readVecRegOperand' + if self.read_code != None: + return self.buildReadCode(func) + + if predRead: + rindex = '_sourceIndex++' + else: + rindex = '%d' % self.src_reg_idx + + name = self.base_name + if self.is_dest and self.is_src: + name += '_merger' + + c_read = '\t\t%s& tmp_s%s = xc->%s(this, %s);\n' \ + % ('const TheISA::VecRegContainer', rindex, func, rindex) + # If the parser has detected that elements are being access, create + # the appropriate view + if self.elemExt: + c_read += '\t\tauto %s = tmp_s%s.as<%s>();\n' % \ + (name, rindex, self.parser.operandTypeMap[self.elemExt]) + if self.ext: + c_read += '\t\tauto %s = tmp_s%s.as<%s>();\n' % \ + (name, rindex, self.parser.operandTypeMap[self.ext]) + if hasattr(self, 'active_elems'): + if self.active_elems: + for elem in self.active_elems: + c_read += self.makeReadElem(elem, name) + return c_read + + def makeWrite(self, predWrite): + func = 'setVecRegOperand' + if self.write_code != None: + return self.buildWriteCode(func) + + wb = ''' + if (traceData) { + traceData->setData(tmp_d%d); + } + ''' % self.dest_reg_idx + return wb + + def finalize(self, predRead, predWrite): + super(VecRegOperand, self).finalize(predRead, predWrite) + if self.is_dest: + self.op_rd = self.makeReadW(predWrite) + self.op_rd + +class VecElemOperand(Operand): + reg_class = 'VecElemClass' + + def isReg(self): + return 1 + + def isVecElem(self): + return 1 + + def makeDecl(self): + if self.is_dest and not self.is_src: + return '\n\t%s %s;' % (self.ctype, self.base_name) + else: + return '' + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + numAccessNeeded = 1 + + if self.is_src: + c_src = ('\n\t_srcRegIdx[_numSrcRegs++] = RegId(%s, %s, %s);' % + (self.reg_class, self.reg_spec, self.elem_spec)) + + if self.is_dest: + c_dest = ('\n\t_destRegIdx[_numDestRegs++] = RegId(%s, %s, %s);' % + (self.reg_class, self.reg_spec, self.elem_spec)) + c_dest += '\n\t_numVecElemDestRegs++;' + return c_src + c_dest + + def makeRead(self, predRead): + c_read = 'xc->readVecElemOperand(this, %d)' % self.src_reg_idx + + if self.ctype == 'float': + c_read = 'bitsToFloat32(%s)' % c_read + elif self.ctype == 'double': + c_read = 'bitsToFloat64(%s)' % c_read + + return '\n\t%s %s = %s;\n' % (self.ctype, self.base_name, c_read) + + def makeWrite(self, predWrite): + if self.ctype == 'float': + c_write = 'floatToBits32(%s)' % self.base_name + elif self.ctype == 'double': + c_write = 'floatToBits64(%s)' % self.base_name + else: + c_write = self.base_name + + c_write = ('\n\txc->setVecElemOperand(this, %d, %s);' % + (self.dest_reg_idx, c_write)) + + return c_write + +class VecPredRegOperand(Operand): + reg_class = 'VecPredRegClass' + + def __init__(self, parser, full_name, ext, is_src, is_dest): + Operand.__init__(self, parser, full_name, ext, is_src, is_dest) + self.parser = parser + + def isReg(self): + return 1 + + def isVecPredReg(self): + return 1 + + def makeDecl(self): + return '' + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + if self.is_src: + c_src = self.src_reg_constructor % (self.reg_class, self.reg_spec) + + if self.is_dest: + c_dest = self.dst_reg_constructor % (self.reg_class, self.reg_spec) + c_dest += '\n\t_numVecPredDestRegs++;' + + return c_src + c_dest + + def makeRead(self, predRead): + func = 'readVecPredRegOperand' + if self.read_code != None: + return self.buildReadCode(func) + + if predRead: + rindex = '_sourceIndex++' + else: + rindex = '%d' % self.src_reg_idx + + c_read = '\t\t%s& tmp_s%s = xc->%s(this, %s);\n' % ( + 'const TheISA::VecPredRegContainer', rindex, func, rindex) + if self.ext: + c_read += '\t\tauto %s = tmp_s%s.as<%s>();\n' % ( + self.base_name, rindex, + self.parser.operandTypeMap[self.ext]) + return c_read + + def makeReadW(self, predWrite): + func = 'getWritableVecPredRegOperand' + if self.read_code != None: + return self.buildReadCode(func) + + if predWrite: + rindex = '_destIndex++' + else: + rindex = '%d' % self.dest_reg_idx + + c_readw = '\t\t%s& tmp_d%s = xc->%s(this, %s);\n' % ( + 'TheISA::VecPredRegContainer', rindex, func, rindex) + if self.ext: + c_readw += '\t\tauto %s = tmp_d%s.as<%s>();\n' % ( + self.base_name, rindex, + self.parser.operandTypeMap[self.ext]) + return c_readw + + def makeWrite(self, predWrite): + func = 'setVecPredRegOperand' + if self.write_code != None: + return self.buildWriteCode(func) + + wb = ''' + if (traceData) { + traceData->setData(tmp_d%d); + } + ''' % self.dest_reg_idx + return wb + + def finalize(self, predRead, predWrite): + super(VecPredRegOperand, self).finalize(predRead, predWrite) + if self.is_dest: + self.op_rd = self.makeReadW(predWrite) + self.op_rd + +class CCRegOperand(Operand): + reg_class = 'CCRegClass' + + def isReg(self): + return 1 + + def isCCReg(self): + return 1 + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + if self.is_src: + c_src = self.src_reg_constructor % (self.reg_class, self.reg_spec) + if self.hasReadPred(): + c_src = '\n\tif (%s) {%s\n\t}' % \ + (self.read_predicate, c_src) + + if self.is_dest: + c_dest = self.dst_reg_constructor % (self.reg_class, self.reg_spec) + c_dest += '\n\t_numCCDestRegs++;' + if self.hasWritePred(): + c_dest = '\n\tif (%s) {%s\n\t}' % \ + (self.write_predicate, c_dest) + + return c_src + c_dest + + def makeRead(self, predRead): + if (self.ctype == 'float' or self.ctype == 'double'): + error('Attempt to read condition-code register as FP') + if self.read_code != None: + return self.buildReadCode('readCCRegOperand') + + int_reg_val = '' + if predRead: + int_reg_val = 'xc->readCCRegOperand(this, _sourceIndex++)' + if self.hasReadPred(): + int_reg_val = '(%s) ? %s : 0' % \ + (self.read_predicate, int_reg_val) + else: + int_reg_val = 'xc->readCCRegOperand(this, %d)' % self.src_reg_idx + + return '%s = %s;\n' % (self.base_name, int_reg_val) + + def makeWrite(self, predWrite): + if (self.ctype == 'float' or self.ctype == 'double'): + error('Attempt to write condition-code register as FP') + if self.write_code != None: + return self.buildWriteCode('setCCRegOperand') + + if predWrite: + wp = 'true' + if self.hasWritePred(): + wp = self.write_predicate + + wcond = 'if (%s)' % (wp) + windex = '_destIndex++' + else: + wcond = '' + windex = '%d' % self.dest_reg_idx + + wb = ''' + %s + { + %s final_val = %s; + xc->setCCRegOperand(this, %s, final_val);\n + if (traceData) { traceData->setData(final_val); } + }''' % (wcond, self.ctype, self.base_name, windex) + + return wb + +class ControlRegOperand(Operand): + reg_class = 'MiscRegClass' + + def isReg(self): + return 1 + + def isControlReg(self): + return 1 + + def makeConstructor(self, predRead, predWrite): + c_src = '' + c_dest = '' + + if self.is_src: + c_src = self.src_reg_constructor % (self.reg_class, self.reg_spec) + + if self.is_dest: + c_dest = self.dst_reg_constructor % (self.reg_class, self.reg_spec) + + return c_src + c_dest + + def makeRead(self, predRead): + bit_select = 0 + if (self.ctype == 'float' or self.ctype == 'double'): + error('Attempt to read control register as FP') + if self.read_code != None: + return self.buildReadCode('readMiscRegOperand') + + if predRead: + rindex = '_sourceIndex++' + else: + rindex = '%d' % self.src_reg_idx + + return '%s = xc->readMiscRegOperand(this, %s);\n' % \ + (self.base_name, rindex) + + def makeWrite(self, predWrite): + if (self.ctype == 'float' or self.ctype == 'double'): + error('Attempt to write control register as FP') + if self.write_code != None: + return self.buildWriteCode('setMiscRegOperand') + + if predWrite: + windex = '_destIndex++' + else: + windex = '%d' % self.dest_reg_idx + + wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \ + (windex, self.base_name) + wb += 'if (traceData) { traceData->setData(%s); }' % \ + self.base_name + + return wb + +class MemOperand(Operand): + def isMem(self): + return 1 + + def makeConstructor(self, predRead, predWrite): + return '' + + def makeDecl(self): + # Declare memory data variable. + return '%s %s = {};\n' % (self.ctype, self.base_name) + + def makeRead(self, predRead): + if self.read_code != None: + return self.buildReadCode() + return '' + + def makeWrite(self, predWrite): + if self.write_code != None: + return self.buildWriteCode() + return '' + +class PCStateOperand(Operand): + def makeConstructor(self, predRead, predWrite): + return '' + + def makeRead(self, predRead): + if self.reg_spec: + # A component of the PC state. + return '%s = __parserAutoPCState.%s();\n' % \ + (self.base_name, self.reg_spec) + else: + # The whole PC state itself. + return '%s = xc->pcState();\n' % self.base_name + + def makeWrite(self, predWrite): + if self.reg_spec: + # A component of the PC state. + return '__parserAutoPCState.%s(%s);\n' % \ + (self.reg_spec, self.base_name) + else: + # The whole PC state itself. + return 'xc->pcState(%s);\n' % self.base_name + + def makeDecl(self): + ctype = 'TheISA::PCState' + if self.isPCPart(): + ctype = self.ctype + # Note that initializations in the declarations are solely + # to avoid 'uninitialized variable' errors from the compiler. + return '%s %s = 0;\n' % (ctype, self.base_name) + + def isPCState(self): + return 1