# -*- coding: utf-8 -*- # # AWL simulator - blocks # # Copyright 2012-2018 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # from __future__ import division, absolute_import, print_function, unicode_literals #from awlsim.common.cython_support cimport * #@cy from awlsim.common.compat import * from awlsim.common.refmanager import * from awlsim.common.blockinfo import * from awlsim.common.wordpacker import * from awlsim.common.exceptions import * from awlsim.common.util import * from awlsim.core.blockinterface import * from awlsim.core.labels import * #+cimport from awlsim.core.datatypes import * from awlsim.core.memory import * #+cimport from awlsim.core.operatortypes import * #+cimport from awlsim.core.operators import * #+cimport from awlsim.core.offset import * #+cimport from awlsim.core.lstack import * #+cimport import hashlib __all__ = [ "Block", "CodeBlock", "StaticCodeBlock", "OB", "FB", "FC", ] class Block(object): #+cdef """Base class for blocks (OBs, FCs, FBs, DBs, etc...)""" BLOCKTYPESTR = "Block" IDENT_HASH = hashlib.sha256 def __init__(self, index): self.index = index self.sourceRef = None self.__identHash = None def setSourceRef(self, sourceManagerOrRef, inheritRef=False): if isinstance(sourceManagerOrRef, ObjRef): manager = None ref = sourceManagerOrRef else: manager = sourceManagerOrRef ref = None self.sourceRef = ObjRef.make( name=lambda ref: str(ref.obj), manager=manager, ref=ref, inheritRef=inheritRef, obj=self) self.__identHash = None def destroySourceRef(self): if self.sourceRef: self.sourceRef.destroy() self.sourceRef = None self.__identHash = None def getSource(self): """Get this block's source (AwlSource() object), if any. """ sourceRef = self.sourceRef if sourceRef: manager = sourceRef.manager if manager: return manager.source return None @property def identHash(self): if not self.__identHash: # Calculate the ident hash h = self.IDENT_HASH(self.BLOCKTYPESTR.encode( "utf-8", "strict")) h.update(WordPacker.toBytes(bytearray(2), 16, 0, self.index)) source = self.getSource() if source: h.update(source.identHash) self.__identHash = h.digest() return self.__identHash def getBlockInfo(self): """Get a BlockInfo instance for this block. """ # By default there is no BlockInfo. Override this method. return None def __repr__(self): return "%s %d" % (self.BLOCKTYPESTR, self.index) class CodeBlock(Block): #+cdef """Base class for code blocks (OBs, (S)FCs, (S)FBs)""" BLOCKTYPESTR = "CodeBlock" # Simple and fast tests for checking block identity. # These are partially overridden in the subclasses. _isOB = False _isFC = False _isFB = False _isSystemBlock = False _isLibraryBlock = False def __init__(self, insns, index, interface): self.isOB = self._isOB self.isFC = self._isFC self.isFB = self._isFB self.isSystemBlock = self._isSystemBlock self.isLibraryBlock = self._isLibraryBlock Block.__init__(self, index) self.insns = insns self.nrInsns = len(insns) self.labels = None self.nrLabels = 0 self.interface = interface self.tempAllocation = 0 # The number of allocated TEMP bytes self.resolveLabels() def resolveLabels(self): if self.insns: self.labels = AwlLabel.resolveLabels(self.insns) self.nrLabels = len(self.labels) else: self.labels = None self.nrLabels = 0 def resolveSymbols(self): pass # Account for interface TEMP allocations and # direct TEMP (L, LB, LW, LD) accesses. def accountTempAllocations(self): directAlloc = 0 def accountDirect(currentAlloc, oper): if oper.operType != AwlOperatorTypes.MEM_L: return currentAlloc offset = oper.offset + make_AwlOffset(0, oper.width) return max(offset.roundUp(2).byteOffset, currentAlloc) for insn in self.insns: for oper in insn.ops: directAlloc = accountDirect(directAlloc, oper) for param in insn.params: directAlloc = accountDirect(directAlloc, param.rvalueOp) self.tempAllocation = max(self.interface.tempAllocation, directAlloc) class StaticCodeBlock(CodeBlock): #+cdef """Base class for static code blocks. (system and library blocks).""" BLOCKTYPESTR = "StaticCodeBlock" # Static interface definition. # To be overridden by the subclass. interfaceFields = { BlockInterfaceField.FTYPE_IN : (), BlockInterfaceField.FTYPE_OUT : (), BlockInterfaceField.FTYPE_INOUT : (), BlockInterfaceField.FTYPE_STAT : (), BlockInterfaceField.FTYPE_TEMP : (), } # Set to True by the subclass, if the implementation is incomplete. broken = False def __init__(self, insns, index, interface): CodeBlock.__init__(self, insns, index, interface) # Register the interface. for ftype in (BlockInterfaceField.FTYPE_IN, BlockInterfaceField.FTYPE_OUT, BlockInterfaceField.FTYPE_INOUT, BlockInterfaceField.FTYPE_STAT, BlockInterfaceField.FTYPE_TEMP): try: fields = self.interfaceFields[ftype] except KeyError: continue for field in fields: if ftype == BlockInterfaceField.FTYPE_IN: self.interface.addField_IN(field) elif ftype == BlockInterfaceField.FTYPE_OUT: self.interface.addField_OUT(field) elif ftype == BlockInterfaceField.FTYPE_INOUT: self.interface.addField_INOUT(field) elif ftype == BlockInterfaceField.FTYPE_STAT: self.interface.addField_STAT(field) elif ftype == BlockInterfaceField.FTYPE_TEMP: self.interface.addField_TEMP(field) else: assert(0) class OB(CodeBlock): #+cdef BLOCKTYPESTR = "OB" _isOB = True def __init__(self, insns, index): CodeBlock.__init__(self, insns, index, OBInterface()) self.lstack = LStackAllocator(0) def getBlockInfo(self): """Get a BlockInfo instance for this block. """ return BlockInfo(blockType = BlockInfo.TYPE_OB, blockIndex = self.index, identHash = self.identHash) class FB(CodeBlock): #+cdef BLOCKTYPESTR = "FB" _isFB = True def __init__(self, insns, index): CodeBlock.__init__(self, insns, index, FBInterface()) def getBlockInfo(self): """Get a BlockInfo instance for this block. """ return BlockInfo(blockType = BlockInfo.TYPE_FB, blockIndex = self.index, identHash = self.identHash) class FC(CodeBlock): #+cdef BLOCKTYPESTR = "FC" _isFC = True def __init__(self, insns, index): CodeBlock.__init__(self, insns, index, FCInterface()) def getBlockInfo(self): """Get a BlockInfo instance for this block. """ return BlockInfo(blockType = BlockInfo.TYPE_FC, blockIndex = self.index, identHash = self.identHash)