convert numbers to python format
[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
14 def port_decl_do_not_use(comment, dt, name):
15 if dt is None or dt.dims is None:
16 width = '' # width: 1
17 else:
18 width = dt.dims
19 # XXX TODO, better checking, should be using data structure... *sigh*
20 width = width[1:-1] # strip brackets
21 width = width.split(':')
22 assert width[0] == '0'
23 width = width[1]
24 return 'self.%s = Signal(%s) # %s' % (name, width, comment)
25
26
27 indent_debug = 0
28
29
30 class PortDecl:
31 def __init__(self, comment, dt, name):
32 self.comment = comment
33 self.dt = dt
34 self.name = name
35
36 def initNode(self):
37 return port_decl_do_not_use(self.comment, self.dt, self.name)
38
39
40 class Assignment:
41 def __init__(self, left, op, right):
42 self.left = left
43 self.op = op
44 self.right = right
45
46 def debugInfo(self):
47 return "Assignment:"+str(self.left) + " "+str(self.op)+" "+str(self.right)
48
49
50 class CondStatement:
51 def __init__(self, cond, ifpart, elsepart):
52 self.cond = cond
53 self.ifpart = ifpart
54 self.elsepart = elsepart
55
56
57 def makeBlock(x):
58 if(type(x) == Assignment):
59 return [x]
60 elif(type(x) == CondStatement):
61 return [x]
62 else:
63 return x.statements
64
65
66 class Absyn:
67 def __init__(self, outputfn):
68 self.outputfn = outputfn
69 self.outputfile = None
70 self.assign = []
71 self.ports = []
72 self.wires = []
73 self.comb = []
74 self.sync = []
75
76 def open(self):
77 if(self.outputfile is None):
78 self.outputfile = open(self.outputfn, "w")
79 self.outputfile.write(preamble)
80
81 def printpy(self, p):
82 self.open()
83 self.outputfile.write(str(p)+"\n")
84
85 def assign(self, p):
86 p = list(p)
87 if(p[1] == "assign"):
88 self.printpy(p[4])
89
90 def assign3(self, left, op, right):
91 return Assignment(left, op, right)
92
93 def cond_statement3(self, cond, ifpart, elsepart):
94 return CondStatement(cond, ifpart, elsepart)
95
96 def indent(self, count):
97 if(indent_debug):
98 return Leaf(token.INDENT, '>>> '*count)
99 else:
100 return Leaf(token.INDENT, ' '*4*count)
101
102 def dedent(self, count):
103 return Leaf(token.DEDENT, '')
104
105 def nl(self):
106 return Leaf(token.NEWLINE, '\n')
107
108 def port_decl(self, comment, dt, name):
109 port = PortDecl(comment, dt, name)
110 self.ports += [port]
111 return port
112
113 def isPort(self, name):
114 for p in self.ports:
115 if(str(p.name) == str(name)):
116 return True
117 return False
118
119 def initFunc(self, ports, params):
120 params = [Leaf(token.LPAR, '('), Leaf(
121 token.NAME, "self")] + [Leaf(token.RPAR, ')')]
122 # TODO handle sv params
123 fn = [Leaf(token.NAME, 'def'),
124 Leaf(token.NAME, '__init__', prefix=' '),
125 Node(syms.parameters, params),
126 Leaf(token.COLON, ':'),
127 self.nl()
128 ]
129 fndef = Node(syms.funcdef, fn)
130 stmts = Node(syms.stmt, [fndef])
131 for port in ports:
132 stmts.children.append(self.indent(2))
133 stmts.children.append(port.initNode())
134 stmts.children.append(self.nl())
135 return stmts
136
137 def do_assign(self, a, stmts, indent):
138 stmts.children.append(self.indent(indent))
139 stmts.children.append(Leaf(token.STRING, "m.d."))
140 stmts.children.append(Leaf(token.STRING, self.blocktype))
141 stmts.children.append(Leaf(token.STRING, " += "))
142 if(self.isPort(a.left)):
143 stmts.children.append(Leaf(token.STRING, "self."))
144 stmts.children.append(Leaf(token.STRING, a.left))
145 stmts.children.append(Leaf(token.STRING, ".eq("))
146 if(self.isPort(a.right)):
147 stmts.children.append(Leaf(token.STRING, "self."))
148 stmts.children.append(Leaf(token.STRING, a.right))
149 stmts.children.append(Leaf(token.STRING, ")"))
150 stmts.children.append(self.nl())
151
152 def do_ifblock(self, c, stmts, indent):
153 stmts.children.append(self.indent(indent))
154 stmts.children.append(Leaf(token.STRING, "with m.If("))
155 if(self.isPort(c.cond)):
156 stmts.children.append(Leaf(token.STRING, "self."))
157 stmts.children.append(Leaf(token.STRING, c.cond))
158 stmts.children.append(Leaf(token.STRING, "):"))
159 stmts.children.append(self.nl())
160
161 for c1 in makeBlock(c.ifpart):
162 if(type(c1) == Assignment):
163 self.do_assign(c1, stmts, indent+1)
164 else:
165 self.do_ifblock(c1, stmts, indent+1)
166
167 if(c.elsepart):
168 stmts.children.append(self.indent(indent))
169 stmts.children.append(Leaf(token.STRING, "with m.Else():"))
170 stmts.children.append(self.nl())
171
172 for c1 in makeBlock(c.elsepart):
173 if(type(c1) == Assignment):
174 self.do_assign(c1, stmts, indent+1)
175 else:
176 self.do_ifblock(c1, stmts, indent+1)
177
178 def elaborateFunc(self):
179 params = [Leaf(token.LPAR, '('), Leaf(
180 token.NAME, "self, platform=None"), Leaf(token.RPAR, ')')]
181 fn = [Leaf(token.NAME, 'def'),
182 Leaf(token.NAME, 'elaborate', prefix=' '),
183 Node(syms.parameters, params),
184 Leaf(token.COLON, ':'),
185 self.nl()
186 ]
187 fndef = Node(syms.funcdef, fn)
188 stmts = Node(syms.stmt, [fndef])
189 stmts.children.append(self.indent(2))
190 stmts.children.append(Leaf(token.STRING, "m = Module()"))
191 stmts.children.append(self.nl())
192
193 for w in self.wires:
194 wirename = w[0]
195 hasdims = (len(w) >= 4)
196 stmts.children.append(self.indent(2))
197 stmts.children.append(Leaf(token.STRING, wirename))
198 stmts.children.append(Leaf(token.STRING, " = Signal("))
199 if(hasdims):
200 stmts.children.append(Leaf(token.STRING, str(w[3])))
201 stmts.children.append(Leaf(token.STRING, ")"))
202 stmts.children.append(self.nl())
203
204 self.blocktype = "comb"
205 for a in self.assign:
206 self.do_assign(a, stmts, 2)
207
208 for c in self.comb:
209 if(type(c) == Assignment):
210 self.do_assign(c, stmts, 2)
211 else:
212 self.do_ifblock(c, stmts, 2)
213
214 self.blocktype = "sync"
215 for c in self.sync:
216 if(type(c) == Assignment):
217 self.do_assign(c, stmts, 2)
218 else:
219 self.do_ifblock(c, stmts, 2)
220
221 stmts.children.append(self.indent(2))
222 stmts.children.append(Leaf(token.STRING, "return m"))
223 stmts.children.append(self.nl())
224 return stmts
225
226 def module_1(self, p):
227 params = p[7]
228 ports = p[8]
229 clsname = [Leaf(token.NAME, 'class'),
230 Leaf(token.NAME, p[4], prefix=' '),
231 Leaf(token.LPAR, '('),
232 Leaf(token.NAME, 'Elaboratable'),
233 Leaf(token.LPAR, ')'),
234 Leaf(token.COLON, ':'),
235 self.nl(),
236 ]
237
238 suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
239 self.indent(1),
240 self.initFunc(ports, params),
241 self.indent(1),
242 self.elaborateFunc()
243
244 ])
245 clsdecl = Node(syms.classdef, clsname + [suite])
246 clsdecl = Node(syms.compound_stmt, [clsdecl])
247
248 self.printpy(str(clsdecl))
249 return clsdecl
250
251 def module_item_2(self, signaltype, dims, mlist):
252 if(signaltype == "wire"):
253 for m in mlist:
254 if(dims):
255 self.wires.append(m+dims)
256 else:
257 self.wires.append(m)
258
259 def appendComments(self, data):
260 self.open()
261 self.outputfile.write(data)
262 #lines = data.split("\n")
263 # for line in lines:
264 # self.printpy("#"+line)
265
266 # combinatorical assign
267 def cont_assign_1(self, p):
268 self.assign += [Assignment(p[1], p[2], p[3])]
269
270 # cond assigmments and other nested blocks
271 def always_comb(self, p3, p1):
272 slist = p3[6]
273 self.comb += slist.statements
274
275 def always_ff(self, p3, p1):
276 slist = p3[1]
277 self.sync += slist.statements