convert numbers to python format
[sv2nmigen.git] / absyn.py
index c59f8b6dc559fc6c04f626ccf80702c9da8615ba..386e5d3f23bfe1ddd981d38cc1d7079a865e2fd2 100644 (file)
--- a/absyn.py
+++ b/absyn.py
@@ -1,5 +1,277 @@
+from lib2to3.pytree import Node, Leaf
+from lib2to3.pgen2 import token
+from lib2to3.pygram import python_symbols as syms
+
+preamble = """# this file has been generated by sv2nmigen
+
+from nmigen import Signal, Module, Const, Cat, Elaboratable
+
+
+
+"""
+
+
+def port_decl_do_not_use(comment, dt, name):
+    if dt is None or dt.dims is None:
+        width = ''  # width: 1
+    else:
+        width = dt.dims
+        # XXX TODO, better checking, should be using data structure... *sigh*
+        width = width[1:-1]  # strip brackets
+        width = width.split(':')
+        assert width[0] == '0'
+        width = width[1]
+    return 'self.%s = Signal(%s) # %s' % (name, width, comment)
+
+
+indent_debug = 0
+
+
+class PortDecl:
+    def __init__(self, comment, dt, name):
+        self.comment = comment
+        self.dt = dt
+        self.name = name
+
+    def initNode(self):
+        return port_decl_do_not_use(self.comment, self.dt, self.name)
+
+
+class Assignment:
+    def __init__(self, left, op, right):
+        self.left = left
+        self.op = op
+        self.right = right
+
+    def debugInfo(self):
+        return "Assignment:"+str(self.left) + " "+str(self.op)+" "+str(self.right)
+
+
+class CondStatement:
+    def __init__(self, cond, ifpart, elsepart):
+        self.cond = cond
+        self.ifpart = ifpart
+        self.elsepart = elsepart
+
+
+def makeBlock(x):
+    if(type(x) == Assignment):
+        return [x]
+    elif(type(x) == CondStatement):
+        return [x]
+    else:
+        return x.statements
+
+
 class Absyn:
-    def __init__(self):
-        self.outputfile = open("output.py","w")
-    def printpy(self,p):
+    def __init__(self, outputfn):
+        self.outputfn = outputfn
+        self.outputfile = None
+        self.assign = []
+        self.ports = []
+        self.wires = []
+        self.comb = []
+        self.sync = []
+
+    def open(self):
+        if(self.outputfile is None):
+            self.outputfile = open(self.outputfn, "w")
+            self.outputfile.write(preamble)
+
+    def printpy(self, p):
+        self.open()
         self.outputfile.write(str(p)+"\n")
+
+    def assign(self, p):
+        p = list(p)
+        if(p[1] == "assign"):
+            self.printpy(p[4])
+
+    def assign3(self, left, op, right):
+        return Assignment(left, op, right)
+
+    def cond_statement3(self, cond, ifpart, elsepart):
+        return CondStatement(cond, ifpart, elsepart)
+
+    def indent(self, count):
+        if(indent_debug):
+            return Leaf(token.INDENT, '>>> '*count)
+        else:
+            return Leaf(token.INDENT, ' '*4*count)
+
+    def dedent(self, count):
+        return Leaf(token.DEDENT, '')
+
+    def nl(self):
+        return Leaf(token.NEWLINE, '\n')
+
+    def port_decl(self, comment, dt, name):
+        port = PortDecl(comment, dt, name)
+        self.ports += [port]
+        return port
+
+    def isPort(self, name):
+        for p in self.ports:
+            if(str(p.name) == str(name)):
+                return True
+        return False
+
+    def initFunc(self, ports, params):
+        params = [Leaf(token.LPAR, '('), Leaf(
+            token.NAME, "self")] + [Leaf(token.RPAR, ')')]
+        # TODO handle sv params
+        fn = [Leaf(token.NAME, 'def'),
+              Leaf(token.NAME, '__init__', prefix=' '),
+              Node(syms.parameters, params),
+              Leaf(token.COLON, ':'),
+              self.nl()
+              ]
+        fndef = Node(syms.funcdef, fn)
+        stmts = Node(syms.stmt, [fndef])
+        for port in ports:
+            stmts.children.append(self.indent(2))
+            stmts.children.append(port.initNode())
+            stmts.children.append(self.nl())
+        return stmts
+
+    def do_assign(self, a, stmts, indent):
+        stmts.children.append(self.indent(indent))
+        stmts.children.append(Leaf(token.STRING, "m.d."))
+        stmts.children.append(Leaf(token.STRING, self.blocktype))
+        stmts.children.append(Leaf(token.STRING, " += "))
+        if(self.isPort(a.left)):
+            stmts.children.append(Leaf(token.STRING, "self."))
+        stmts.children.append(Leaf(token.STRING, a.left))
+        stmts.children.append(Leaf(token.STRING, ".eq("))
+        if(self.isPort(a.right)):
+            stmts.children.append(Leaf(token.STRING, "self."))
+        stmts.children.append(Leaf(token.STRING, a.right))
+        stmts.children.append(Leaf(token.STRING, ")"))
+        stmts.children.append(self.nl())
+
+    def do_ifblock(self, c, stmts, indent):
+        stmts.children.append(self.indent(indent))
+        stmts.children.append(Leaf(token.STRING, "with m.If("))
+        if(self.isPort(c.cond)):
+            stmts.children.append(Leaf(token.STRING, "self."))
+        stmts.children.append(Leaf(token.STRING, c.cond))
+        stmts.children.append(Leaf(token.STRING, "):"))
+        stmts.children.append(self.nl())
+
+        for c1 in makeBlock(c.ifpart):
+            if(type(c1) == Assignment):
+                self.do_assign(c1, stmts, indent+1)
+            else:
+                self.do_ifblock(c1, stmts, indent+1)
+
+        if(c.elsepart):
+            stmts.children.append(self.indent(indent))
+            stmts.children.append(Leaf(token.STRING, "with m.Else():"))
+            stmts.children.append(self.nl())
+
+            for c1 in makeBlock(c.elsepart):
+                if(type(c1) == Assignment):
+                    self.do_assign(c1, stmts, indent+1)
+                else:
+                    self.do_ifblock(c1, stmts, indent+1)
+
+    def elaborateFunc(self):
+        params = [Leaf(token.LPAR, '('), Leaf(
+            token.NAME, "self, platform=None"), Leaf(token.RPAR, ')')]
+        fn = [Leaf(token.NAME, 'def'),
+              Leaf(token.NAME, 'elaborate', prefix=' '),
+              Node(syms.parameters, params),
+              Leaf(token.COLON, ':'),
+              self.nl()
+              ]
+        fndef = Node(syms.funcdef, fn)
+        stmts = Node(syms.stmt, [fndef])
+        stmts.children.append(self.indent(2))
+        stmts.children.append(Leaf(token.STRING, "m = Module()"))
+        stmts.children.append(self.nl())
+
+        for w in self.wires:
+            wirename = w[0]
+            hasdims = (len(w) >= 4)
+            stmts.children.append(self.indent(2))
+            stmts.children.append(Leaf(token.STRING, wirename))
+            stmts.children.append(Leaf(token.STRING, " = Signal("))
+            if(hasdims):
+                stmts.children.append(Leaf(token.STRING, str(w[3])))
+            stmts.children.append(Leaf(token.STRING, ")"))
+            stmts.children.append(self.nl())
+
+        self.blocktype = "comb"
+        for a in self.assign:
+            self.do_assign(a, stmts, 2)
+
+        for c in self.comb:
+            if(type(c) == Assignment):
+                self.do_assign(c, stmts, 2)
+            else:
+                self.do_ifblock(c, stmts, 2)
+
+        self.blocktype = "sync"
+        for c in self.sync:
+            if(type(c) == Assignment):
+                self.do_assign(c, stmts, 2)
+            else:
+                self.do_ifblock(c, stmts, 2)
+
+        stmts.children.append(self.indent(2))
+        stmts.children.append(Leaf(token.STRING, "return m"))
+        stmts.children.append(self.nl())
+        return stmts
+
+    def module_1(self, p):
+        params = p[7]
+        ports = p[8]
+        clsname = [Leaf(token.NAME, 'class'),
+                   Leaf(token.NAME, p[4], prefix=' '),
+                   Leaf(token.LPAR, '('),
+                   Leaf(token.NAME, 'Elaboratable'),
+                   Leaf(token.LPAR, ')'),
+                   Leaf(token.COLON, ':'),
+                   self.nl(),
+                   ]
+
+        suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
+                                  self.indent(1),
+                                  self.initFunc(ports, params),
+                                  self.indent(1),
+                                  self.elaborateFunc()
+
+                                  ])
+        clsdecl = Node(syms.classdef, clsname + [suite])
+        clsdecl = Node(syms.compound_stmt, [clsdecl])
+
+        self.printpy(str(clsdecl))
+        return clsdecl
+
+    def module_item_2(self, signaltype, dims, mlist):
+        if(signaltype == "wire"):
+            for m in mlist:
+                if(dims):
+                    self.wires.append(m+dims)
+                else:
+                    self.wires.append(m)
+
+    def appendComments(self, data):
+        self.open()
+        self.outputfile.write(data)
+        #lines = data.split("\n")
+        # for line in lines:
+        #    self.printpy("#"+line)
+
+    # combinatorical assign
+    def cont_assign_1(self, p):
+        self.assign += [Assignment(p[1], p[2], p[3])]
+
+    # cond assigmments and other nested blocks
+    def always_comb(self, p3, p1):
+        slist = p3[6]
+        self.comb += slist.statements
+
+    def always_ff(self, p3, p1):
+        slist = p3[1]
+        self.sync += slist.statements