Commit 4de5011d authored by Michael Büsch's avatar Michael Büsch

fupcompiler: Add basic compilation

parent c34ae2e6
......@@ -170,9 +170,15 @@ def run(inputFile):
writeStdout("Parsing code...\n")
generatedAwlSrcs = []
# Get mnemonics type
mnemonics = project.getCpuSpecs().getConfiguredMnemonics()
if opt_mnemonics is not None:
mnemonics = opt_mnemonics
# Parse FUP sources
for fupSrc in project.getFupSources():
generatedAwlSrcs.append(FupCompiler().compile(fupSrc))
generatedAwlSrcs.append(FupCompiler().compile(
fupSource=fupSrc, mnemonics=mnemonics))
# Parse KOP sources
for kopSrc in project.getKopSources():
......@@ -189,9 +195,6 @@ def run(inputFile):
# Parse symbol tables
symTables = []
for symTabSrc in project.getSymTabSources():
mnemonics = project.getCpuSpecs().getConfiguredMnemonics()
if opt_mnemonics is not None:
mnemonics = opt_mnemonics
tab = SymTabParser.parseSource(symTabSrc,
autodetectFormat = True,
mnemonics = mnemonics)
......
......@@ -24,6 +24,7 @@ from awlsim.common.compat import *
from awlsim.common.sources import *
from awlsim.common.xmlfactory import *
from awlsim.common.cpuspecs import *
from awlsim.fupcompiler.fupcompiler_grid import *
from awlsim.fupcompiler.fupcompiler_elem import *
......@@ -66,6 +67,7 @@ class FupCompiler(object):
self.reset()
def reset(self):
self.opTrans = None
self.awlSource = None
self.awlBytesList = []
self.grids = []
......@@ -81,16 +83,31 @@ class FupCompiler(object):
"%s" % str(e))
def __compile(self):
pass#TODO
insns = []
for grid in self.grids:
insns.extend(grid.compile())
#TODO
print("FINAL", insns)
def compile(self, fupSource):
"""Compile a FupSource.
Returns an AwlSource.
"""
def __trycompile(self, fupSource, mnemonics):
self.reset()
self.opTrans = AwlOpTranslator(mnemonics=mnemonics)
self.awlSource = AwlSource(name=fupSource.name,
filepath=fupSource.filepath)
self.__parse(fupSource)
self.__compile()
self.awlSource.sourceBytes = b''.join(self.awlBytesList)
return self.getAwlSource()
def compile(self, fupSource, mnemonics):
"""Compile a FupSource.
mnemonics is either MNEMONICS_EN, MNEMONICS_DE or MNEMONICS_AUTO.
Returns an AwlSource.
"""
if mnemonics == S7CPUSpecs.MNEMONICS_AUTO:
try:
return self.__trycompile(fupSource, S7CPUSpecs.MNEMONICS_EN)
except AwlSimError as e:
pass
return self.__trycompile(fupSource, S7CPUSpecs.MNEMONICS_DE)
return self.__trycompile(fupSource, mnemonics)
# -*- coding: utf-8 -*-
#
# AWL simulator - FUP compiler - Base object
#
# Copyright 2016 Michael Buesch <m@bues.ch>
#
# 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.compat import *
from awlsim.common.util import *
from awlsim.common.exceptions import *
class FupCompilerError(AwlSimError):
"""FUP compiler exception.
"""
def __init__(self, message, fupObj=None):
AwlSimError.__init__(self, message)
self.fupObj = fupObj
class FupCompiler_BaseObj(object):
"""FUP compiler base class.
"""
factory = None
# compileState values
EnumGen.start
NOT_COMPILED = EnumGen.item
COMPILE_RUNNING = EnumGen.item
COMPILE_DONE = EnumGen.item
EnumGen.end
def __init__(self):
self.__compileState = self.NOT_COMPILED
@property
def compileState(self):
return self.__compileState
@compileState.setter
def compileState(self, state):
if state == self.NOT_COMPILED:
raise FupCompilerError(
"Tried to set FBD/FUP object (%s) state to "
"NOT_COMPILED." % (
type(self).__name__), self)
elif state == self.COMPILE_RUNNING:
if self.__compileState == self.COMPILE_RUNNING:
raise FupCompilerError(
"Tried to set FBD/FUP object (%s) state to "
"COMPILE_RUNNING while already being in that state.\n"
"This most likely happened due to some dependency "
"loop in the FBD/FUP diagram." % (
type(self).__name__), self)
if self.__compileState == self.COMPILE_DONE:
raise FupCompilerError(
"Tried to set FBD/FUP object (%s) state to "
"COMPILE_RUNNING while being in state COMPILE_DONE." % (
type(self).__name__), self)
elif state == self.COMPILE_DONE:
if self.__compileState == self.COMPILE_DONE:
raise FupCompilerError(
"Tried to set FBD/FUP object (%s) state to "
"COMPILE_DONE while already being in that state." % (
type(self).__name__), self)
if self.__compileState == self.NOT_COMPILED:
raise FupCompilerError(
"Tried to set FBD/FUP object (%s) state to "
"COMPILE_DONE, but skipping COMPILE_RUNNING state." % (
type(self).__name__), self)
else:
assert(0)
self.__compileState = state
def __eq__(self, other):
return self is other
def __ne__(self, other):
return self is not other
def __hash__(self):
return id(self)
......@@ -24,6 +24,8 @@ from awlsim.common.compat import *
from awlsim.common.xmlfactory import *
from awlsim.fupcompiler.fupcompiler_base import *
class FupCompiler_ConnFactory(XmlFactory):
def parser_open(self):
......@@ -56,10 +58,11 @@ class FupCompiler_ConnFactory(XmlFactory):
return
XmlFactory.parser_endTag(self, tag)
class FupCompiler_Conn(object):
class FupCompiler_Conn(FupCompiler_BaseObj):
factory = FupCompiler_ConnFactory
def __init__(self, elem, pos, dirIn, dirOut, wireId):
FupCompiler_BaseObj.__init__(self)
self.elem = elem # FupCompiler_Elem
self.pos = pos # Position index
self.dirIn = bool(dirIn) # Input
......
......@@ -25,8 +25,13 @@ from awlsim.common.compat import *
from awlsim.common.xmlfactory import *
from awlsim.common.util import *
from awlsim.fupcompiler.fupcompiler_base import *
from awlsim.fupcompiler.fupcompiler_conn import *
#from awlsim.core.instructions.all_insns cimport * #@cy
from awlsim.core.instructions.all_insns import * #@nocy
from awlsim.core.optrans import *
class FupCompiler_ElemFactory(XmlFactory):
def parser_open(self):
......@@ -57,6 +62,8 @@ class FupCompiler_ElemFactory(XmlFactory):
def parser_endTag(self, tag):
if self.inElem:
if tag.name == "element":
if self.elem:
self.grid.addElem(self.elem)
self.inElem = False
self.elem = None
return
......@@ -66,7 +73,7 @@ class FupCompiler_ElemFactory(XmlFactory):
return
XmlFactory.parser_endTag(self, tag)
class FupCompiler_Elem(object):
class FupCompiler_Elem(FupCompiler_BaseObj):
factory = FupCompiler_ElemFactory
EnumGen.start
......@@ -79,7 +86,7 @@ class FupCompiler_Elem(object):
SUBTYPE_OR = EnumGen.item
SUBTYPE_XOR = EnumGen.item
SUBTYPE_LOAD = EnumGen.item
SYBTYPE_ASSIGN = EnumGen.item
SUBTYPE_ASSIGN = EnumGen.item
EnumGen.end
str2type = {
......@@ -92,7 +99,7 @@ class FupCompiler_Elem(object):
"or" : SUBTYPE_OR,
"xor" : SUBTYPE_XOR,
"load" : SUBTYPE_LOAD,
"assign" : SYBTYPE_ASSIGN,
"assign" : SUBTYPE_ASSIGN,
}
@classmethod
......@@ -109,6 +116,7 @@ class FupCompiler_Elem(object):
return cls(grid, x, y, elemType, subType, content)
def __init__(self, grid, x, y, elemType, subType, content):
FupCompiler_BaseObj.__init__(self)
self.grid = grid # FupCompiler_Grid
self.x = x # X coordinate
self.y = y # Y coordinate
......@@ -120,3 +128,25 @@ class FupCompiler_Elem(object):
def addConn(self, conn):
self.connections.add(conn)
return True
def __compile_ASSIGN(self):
insns = []
if len(self.connections) != 1:
raise AwlSimError("FUP ASSIGN: Invalid number of connections")
conn = getany(self.connections)
if not conn.dirIn or conn.dirOut or conn.pos != 0:
raise AwlSimError("FUP ASSIGN: Invalid connection properties")
wire = self.grid.getWire(conn.wireId)
if not wire:
raise AwlSimError("FUP ASSIGN: Wire does not exist")
pass#TODO
opDesc = self.grid.compiler.opTrans.translateFromString(self.content)
insns.append(AwlInsn_ASSIGN(cpu=None, ops=[opDesc.operator]))
print("ASSIGN", insns)
return insns
def compile(self):
if self.elemType == self.TYPE_OPERAND:
if self.subType == self.SUBTYPE_ASSIGN:
return self.__compile_ASSIGN()
assert(0)
......@@ -24,6 +24,7 @@ from awlsim.common.compat import *
from awlsim.common.xmlfactory import *
from awlsim.fupcompiler.fupcompiler_base import *
from awlsim.fupcompiler.fupcompiler_conn import *
from awlsim.fupcompiler.fupcompiler_wire import *
from awlsim.fupcompiler.fupcompiler_elem import *
......@@ -48,10 +49,11 @@ class FupCompiler_GridFactory(XmlFactory):
return
XmlFactory.parser_endTag(self, tag)
class FupCompiler_Grid(object):
class FupCompiler_Grid(FupCompiler_BaseObj):
factory = FupCompiler_GridFactory
def __init__(self, compiler):
FupCompiler_BaseObj.__init__(self)
self.compiler = compiler # FupCompiler
self.wires = {} # FupCompiler_Wire
self.elems = set() # FupCompiler_Elem
......@@ -61,3 +63,43 @@ class FupCompiler_Grid(object):
return False
self.wires[wire.idNum] = wire
return True
def getWire(self, wireId):
try:
if wireId >= 0:
return self.wires[wireId]
except KeyError:
pass
return None
def addElem(self, elem):
self.elems.add(elem)
def compile(self):
"""Compile this FUP grid to AWL.
Returns a list of instructions.
"""
if self.compileState == self.COMPILE_DONE:
return []
self.compileState = self.COMPILE_RUNNING
insns = []
# Sort all elements in ascending order by Y position.
# The Y position in the diagram is the basic evaluation order.
# Also sort by X position as a secondary key.
yShift = max(e.x for e in self.elems).bit_length()
sortedElems = sorted(self.elems,
key=lambda e: (e.y << yShift) + e.x)
# Find all assignment operators and walk the logic chain upwards.
print("COMPILE ELEMS")
for elem in sortedElems:
if elem.elemType == elem.TYPE_OPERAND and\
elem.subType == elem.SUBTYPE_ASSIGN:
insns.extend(elem.compile())
for elem in self.elems:
pass#TODO find dangling elements
self.compileState = self.COMPILE_DONE
return insns
......@@ -24,6 +24,8 @@ from awlsim.common.compat import *
from awlsim.common.xmlfactory import *
from awlsim.fupcompiler.fupcompiler_base import *
class FupCompiler_WireFactory(XmlFactory):
def parser_open(self):
......@@ -52,9 +54,10 @@ class FupCompiler_WireFactory(XmlFactory):
return
XmlFactory.parser_endTag(self, tag)
class FupCompiler_Wire(object):
class FupCompiler_Wire(FupCompiler_BaseObj):
factory = FupCompiler_WireFactory
def __init__(self, grid, idNum):
FupCompiler_BaseObj.__init__(self)
self.grid = grid # FupCompiler_Grid
self.idNum = idNum # Wire ID
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment