cleanup, add example output
[sv2nmigen.git] / absyn.py
1 from lib2to3.pytree import Node, Leaf
2 from lib2to3.pgen2 import token
3 from lib2to3.pygram import python_symbols as syms
4
5 preamble = """# this file has been generated by sv2nmigen
6
7 from nmigen import Signal, Module, Const, Cat, Elaboratable
8
9
10
11 """
12
13 def port_decl_do_not_use(comment, dt, name):
14     if dt is None or dt.dims is None:
15         width = '' # width: 1
16     else:
17         width = dt.dims
18         # XXX TODO, better checking, should be using data structure... *sigh*
19         width = width[1:-1] # strip brackets
20         width = width.split(':')
21         assert width[0] == '0'
22         width = width[1]
23     return 'self.%s = Signal(%s) # %s' % (name, width, comment)
24
25 indent_debug = 0
26
27 class PortDecl:
28     def __init__(self,comment,dt,name):
29         self.comment = comment
30         self.dt=dt
31         self.name=name
32     def initNode(self):
33         return port_decl_do_not_use(self.comment,self.dt,self.name)
34
35 class Assignment:
36     def __init__(self,left,op,right):
37         self.left = left
38         self.op = op
39         self.right = right
40
41 class Absyn:
42     def __init__(self,outputfn):
43         self.outputfile = open(outputfn,"w")
44         self.outputfile.write(preamble)
45         self.assign = []
46         self.ports = []
47     def printpy(self,p):
48         self.outputfile.write(str(p)+"\n")
49     def assign(self,p):
50         p = list(p)
51         if(p[1]=="assign"):
52             self.printpy(p[4])
53             # m.d.comb += [l.eq(r)]
54     def indent(self,count):
55         if(indent_debug):
56             return Leaf(token.INDENT, '>>> '*count)
57         else:
58             return Leaf(token.INDENT, ' '*4*count)
59     
60     def dedent(self,count):
61         return Leaf(token.DEDENT, '')
62     def nl(self):
63         return Leaf(token.NEWLINE, '\n')
64         
65     def port_decl(self,comment, dt, name):
66         port = PortDecl(comment,dt,name)
67         self.ports += [port]
68         return port
69
70     def initFunc(self,ports,params):
71         params = [Leaf(token.LPAR, '('),Leaf(token.NAME,"self")] + [Leaf(token.RPAR, ')')]
72         # TODO handle sv params
73         fn = [Leaf(token.NAME, 'def'),
74               Leaf(token.NAME, '__init__', prefix=' '),
75               Node(syms.parameters, params),
76               Leaf(token.COLON, ':'),
77               self.nl()
78         ]
79         fndef = Node(syms.funcdef, fn)
80         stmts = Node(syms.stmt, [fndef])
81         for port in ports:
82             stmts.children.append(self.indent(2))
83             stmts.children.append(port.initNode())
84             stmts.children.append(self.nl())
85         return stmts
86
87     def elaborateFunc(self):
88         params = [Leaf(token.LPAR, '('),Leaf(token.NAME,"self, platform=None"),Leaf(token.RPAR, ')')]
89         fn = [Leaf(token.NAME, 'def'),
90               Leaf(token.NAME, 'elaborate', prefix=' '),
91               Node(syms.parameters, params),
92               Leaf(token.COLON, ':'),
93               self.nl()
94         ]
95         fndef = Node(syms.funcdef, fn)
96         stmts = Node(syms.stmt, [fndef])
97         stmts.children.append(self.indent(2))
98         stmts.children.append(Leaf(token.STRING,"m = Module()"))
99         stmts.children.append(self.nl())
100         
101
102         for a in self.assign:
103             stmts.children.append(self.indent(2))
104             # m.d.sync += self.left.eq(right)
105             stmts.children.append(Leaf(token.STRING,"m.d.comb += self."))
106             stmts.children.append(Leaf(token.STRING,a.left))
107             stmts.children.append(Leaf(token.STRING,".eq(self."))
108             stmts.children.append(Leaf(token.STRING,a.right))
109             stmts.children.append(Leaf(token.STRING,")"))
110             stmts.children.append(self.nl())
111         
112         #for a in self.assign:
113         #    
114             #
115             #ports = a[8]
116         #    
117             
118         stmts.children.append(self.indent(2))                      
119         stmts.children.append(Leaf(token.STRING,"return m"))                      
120         stmts.children.append(self.nl())
121         return stmts
122         
123     def module_1(self,p):
124         params = p[7]
125         ports = p[8]
126         clsname = [Leaf(token.NAME, 'class'),
127                    Leaf(token.NAME, p[4], prefix=' '),
128                    Leaf(token.LPAR,'('),
129                    Leaf(token.NAME, 'Elaboratable'),
130                    Leaf(token.LPAR,')'),
131                    Leaf(token.COLON, ':'),
132                    self.nl(),
133         ]
134
135         suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
136                                   self.indent(1),
137                                   self.initFunc(ports,params),
138                                   self.indent(1),
139                                   self.elaborateFunc()
140                                   
141         ])
142         clsdecl = Node(syms.classdef, clsname + [suite])
143         clsdecl = Node(syms.compound_stmt, [clsdecl])
144         
145         self.printpy(str(clsdecl))
146         print("=====================")
147         print(str(clsdecl))
148         return clsdecl
149
150     def appendComments(self,data):
151         lines = data.split("\n")
152         for line in lines:
153             self.printpy("#"+line)
154
155     # combinatorical assign
156     def cont_assign_1(self,p):
157        # print("#ASSIGN:BROKEN"+str(list(p)))
158        self.assign += [Assignment(p[1],p[2],p[3])]