# -*- coding: utf-8 -*- # # AWL simulator - FUP compiler - Helper routines # # Copyright 2017-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.fupcompiler.elembool import * from awlsim.core.operators import * #+cimport from awlsim.core.operatortypes import * #+cimport from awlsim.core.instructions.all_insns import * #+cimport __all__ = [ "FupCompiler_Helpers", ] class FupCompiler_Helpers(object): """FUP compiler helper routines. """ @staticmethod def genIntermediateBool(parentElem, elemsA, connNamesA, elemB, connNameB, boolElemClass): """ parentElem: The parent FUP element for exception accounting, etc. elemsA: A list of the left handed elements. connNamesA: A list of the connection names of the left handed elements. elemB: The right handed element. connNameB: The connection name of the right handed element. boolElemClass: The FUP element class used to create the virtual BOOL element. Returns: None This function converts this: left elem elemB __________ __________ | orig conn|-----(optional)--------|connNameB | |(optional)| | | |__________| |__________| to this: elemsA elemB __________ virtual __________ | connNameA|--+ BOOL +--|connNameB | | | | _______ | | | |__________| +----| & |----+ |__________| __________ | >=1 | | connNameA|-------| x | | | | | |__________| +----| | __________ | | | | connNameA|--+ | | | | | | |__________| +----|_______| | | left elem | __________ | | orig conn|--+ |(optional)| |__________| """ if not elemsA or not elemB: return # We have nothing to do. assert(len(elemsA) == len(connNamesA)) assert(issubclass(boolElemClass, FupCompiler_ElemBool)) def makeConn(text, elem, isOut): pos = elem.numOutConnections if isOut else\ elem.numInConnections return FupCompiler_Conn(elem=elem, pos=pos, dirIn=(not isOut), dirOut=isOut, wireId=FupCompiler_Conn.WIREID_NONE, text=text, virtual=True) connB = elemB.getUniqueConnByText(connNameB, searchInputs=True, constructDefault=lambda: makeConn(connNameB, elemB, False)) if len(elemsA) == 1 and not connB.isConnected: # Element B is not connected and we have only one element A. # This is a special case. # We don't need a virtual BOOL. We can just connect B to A. elemA = elemsA[0] connNameA = connNamesA[0] connA = elemA.getUniqueConnByText(connNameA, searchOutputs=True, constructDefault=lambda: makeConn(connNameA, elemA, True)) connB.connectTo(connA) return # If element B is already connected to a wire, keep that wire # for later connection to the virtual BOOL. if connB.isConnected: origWireB = connB.wire origWireB.removeConn(connB) else: origWireB = None # Create a wire that connects the virtual BOOL's output # to the connB input. wireB = parentElem.grid.newWire(virtual=True) wireB.addConn(connB) # Create a virtual BOOL element to connect the elements. virtElemBool = boolElemClass(grid=parentElem.grid, x=parentElem.x, y=parentElem.y, content=None, virtual=True) # Add an output connection to the virtual BOOL # and connect it to wireB. virtElemOut = FupCompiler_Conn(elem=virtElemBool, pos=0, dirIn=False, dirOut=True, wireId=wireB.idNum, text=None, virtual=True) virtElemBool.addConn(virtElemOut) wireB.addConn(virtElemOut) # Connect all output connections of the A elements to the # virtual BOOL. connPos = -1 for connPos, elemA in enumerate(elemsA): connNameA = connNamesA[connPos] connA = elemA.getUniqueConnByText(connNameA, searchOutputs=True, constructDefault=lambda: makeConn(connNameA, elemA, True)) # Get A's wire, or create a new wire, if A is not connected. if connA.isConnected: wireA = connA.wire else: wireA = parentElem.grid.newWire(virtual=True) wireA.addConn(connA) # Create an input connection to the virtual BOOL # and connect A's wire to it. virtElemIn = FupCompiler_Conn(elem=virtElemBool, pos=connPos, dirIn=True, dirOut=False, wireId=wireA.idNum, text=None, virtual=True) virtElemBool.addConn(virtElemIn) wireA.addConn(virtElemIn) # Connect the element that was originally connected to element B # to a virtual BOOL input. if origWireB: virtElemIn = FupCompiler_Conn(elem=virtElemBool, pos=connPos + 1, dirIn=True, dirOut=False, wireId=origWireB.idNum, text=None, virtual=True) virtElemBool.addConn(virtElemIn) origWireB.addConn(virtElemIn) @staticmethod def genSTWOutputOper(parentElem, conn, andWithBIE, operType, bitPos=0): """Generate instructions for a STW based element output. STW operands are ==0, <>0, >0, <0, >=0, <=0, OV, OS, UO conn: The output connection. andWithBIE: If True, then the operation is ANDed to BIE. This is useful, if the EN state is in BIE. operType: The STW operand type to generate. bitPos: The STW bit position to generate. Returns a list of instructions. """ if not conn or not conn.isConnected: return [] insns = [] # Load the flag from STW. offset = make_AwlOffset(0, bitPos) oper = make_AwlOperator(operType, 1, offset, None) insns.append(parentElem.newInsn(AwlInsn_U, ops=[oper])) if andWithBIE: # AND the EN input to the flag, so that the flag # output is 0 in case EN is 0. insns.append(parentElem.newInsn_LOAD_BIE(AwlInsn_U)) # Store the flag to the output. storeToTempConns = set() for otherElem in parentElem.sorted(conn.getConnectedElems(viaIn=True)): if otherElem.isType(FupCompiler_Elem.TYPE_OPERAND, FupCompiler_ElemOper.SUBTYPE_ASSIGN): insns.extend(otherElem.emitStore_VKE()) else: storeToTempConns.add(conn) insns.extend(parentElem._storeToTemp("BOOL", AwlInsn_ASSIGN, storeToTempConns)) return insns