413e51301580f81b58f54dd12e3e1b0dc6ebbc2b
[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 class Absyn:
58 def __init__(self, outputfn):
59 self.outputfn = outputfn
60 self.outputfile = None
61 self.assign = []
62 self.ports = []
63 self.wires = []
64 self.comb = []
65
66 def open(self):
67 if(self.outputfile is None):
68 self.outputfile = open(self.outputfn, "w")
69 self.outputfile.write(preamble)
70
71 def printpy(self, p):
72 self.open()
73 self.outputfile.write(str(p)+"\n")
74
75 def assign(self, p):
76 p = list(p)
77 if(p[1] == "assign"):
78 self.printpy(p[4])
79
80 def assign3(self, left, op, right):
81 return Assignment(left, op, right)
82
83 def cond_statement3(self, cond, ifpart, elsepart):
84 return CondStatement(cond, ifpart, elsepart)
85
86 def indent(self, count):
87 if(indent_debug):
88 return Leaf(token.INDENT, '>>> '*count)
89 else:
90 return Leaf(token.INDENT, ' '*4*count)
91
92 def dedent(self, count):
93 return Leaf(token.DEDENT, '')
94
95 def nl(self):
96 return Leaf(token.NEWLINE, '\n')
97
98 def port_decl(self, comment, dt, name):
99 port = PortDecl(comment, dt, name)
100 self.ports += [port]
101 return port
102
103 def isPort(self, name):
104 for p in self.ports:
105 if(str(p.name) == str(name)):
106 return True
107 return False
108
109 def initFunc(self, ports, params):
110 params = [Leaf(token.LPAR, '('), Leaf(
111 token.NAME, "self")] + [Leaf(token.RPAR, ')')]
112 # TODO handle sv params
113 fn = [Leaf(token.NAME, 'def'),
114 Leaf(token.NAME, '__init__', prefix=' '),
115 Node(syms.parameters, params),
116 Leaf(token.COLON, ':'),
117 self.nl()
118 ]
119 fndef = Node(syms.funcdef, fn)
120 stmts = Node(syms.stmt, [fndef])
121 for port in ports:
122 stmts.children.append(self.indent(2))
123 stmts.children.append(port.initNode())
124 stmts.children.append(self.nl())
125 return stmts
126
127 def do_assign(self, a, stmts, indent):
128 stmts.children.append(self.indent(indent))
129 stmts.children.append(Leaf(token.STRING, "m.d.comb += "))
130 if(self.isPort(a.left)):
131 stmts.children.append(Leaf(token.STRING, "self."))
132 stmts.children.append(Leaf(token.STRING, a.left))
133 stmts.children.append(Leaf(token.STRING, ".eq("))
134 if(self.isPort(a.right)):
135 stmts.children.append(Leaf(token.STRING, "self."))
136 stmts.children.append(Leaf(token.STRING, a.right))
137 stmts.children.append(Leaf(token.STRING, ")"))
138 stmts.children.append(self.nl())
139
140 def do_ifblock(self, c, stmts, indent):
141 stmts.children.append(self.indent(indent))
142 stmts.children.append(Leaf(token.STRING, "with m.If("))
143 if(self.isPort(c.cond)):
144 stmts.children.append(Leaf(token.STRING, "self."))
145 stmts.children.append(Leaf(token.STRING, c.cond))
146 stmts.children.append(Leaf(token.STRING, "):"))
147 stmts.children.append(self.nl())
148
149 for c1 in c.ifpart.statements:
150 if(type(c1) == Assignment):
151 self.do_assign(c1, stmts, indent+1)
152 else:
153 self.do_ifblock(c1, stmts, indent+1)
154
155 if(c.elsepart):
156 stmts.children.append(self.indent(indent))
157 stmts.children.append(Leaf(token.STRING, "with m.Else():"))
158 stmts.children.append(self.nl())
159
160 for c1 in c.elsepart.statements:
161 if(type(c1) == Assignment):
162 self.do_assign(c1, stmts, indent+1)
163 else:
164 self.do_ifblock(c1, stmts, indent+1)
165
166 def elaborateFunc(self):
167 params = [Leaf(token.LPAR, '('), Leaf(
168 token.NAME, "self, platform=None"), Leaf(token.RPAR, ')')]
169 fn = [Leaf(token.NAME, 'def'),
170 Leaf(token.NAME, 'elaborate', prefix=' '),
171 Node(syms.parameters, params),
172 Leaf(token.COLON, ':'),
173 self.nl()
174 ]
175 fndef = Node(syms.funcdef, fn)
176 stmts = Node(syms.stmt, [fndef])
177 stmts.children.append(self.indent(2))
178 stmts.children.append(Leaf(token.STRING, "m = Module()"))
179 stmts.children.append(self.nl())
180
181 for w in self.wires:
182 wirename = w[0]
183 hasdims = (len(w) >= 4)
184 stmts.children.append(self.indent(2))
185 stmts.children.append(Leaf(token.STRING, wirename))
186 stmts.children.append(Leaf(token.STRING, " = Signal("))
187 if(hasdims):
188 stmts.children.append(Leaf(token.STRING, str(w[3])))
189 stmts.children.append(Leaf(token.STRING, ")"))
190 stmts.children.append(self.nl())
191
192 # refactor: assignments non cond
193 for a in self.assign:
194 self.do_assign(a, stmts)
195
196 for c in self.comb:
197 print("comb", c)
198 if(type(c) == Assignment):
199 self.do_assign(c, stmts, 2)
200 else:
201 self.do_ifblock(c, stmts, 2)
202
203 stmts.children.append(self.indent(2))
204 stmts.children.append(Leaf(token.STRING, "return m"))
205 stmts.children.append(self.nl())
206 return stmts
207
208 def module_1(self, p):
209 params = p[7]
210 ports = p[8]
211 clsname = [Leaf(token.NAME, 'class'),
212 Leaf(token.NAME, p[4], prefix=' '),
213 Leaf(token.LPAR, '('),
214 Leaf(token.NAME, 'Elaboratable'),
215 Leaf(token.LPAR, ')'),
216 Leaf(token.COLON, ':'),
217 self.nl(),
218 ]
219
220 suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
221 self.indent(1),
222 self.initFunc(ports, params),
223 self.indent(1),
224 self.elaborateFunc()
225
226 ])
227 clsdecl = Node(syms.classdef, clsname + [suite])
228 clsdecl = Node(syms.compound_stmt, [clsdecl])
229
230 self.printpy(str(clsdecl))
231 return clsdecl
232
233 def module_item_2(self, signaltype, dims, mlist):
234 if(signaltype == "wire"):
235 for m in mlist:
236 if(dims):
237 self.wires.append(m+dims)
238 else:
239 self.wires.append(m)
240
241 def appendComments(self, data):
242 self.open()
243 self.outputfile.write(data)
244 #lines = data.split("\n")
245 # for line in lines:
246 # self.printpy("#"+line)
247
248 # combinatorical assign
249 def cont_assign_1(self, p):
250 self.assign += [Assignment(p[1], p[2], p[3])]
251
252 # cond assigmments and other nested blocks
253 def always_comb(self, p3, p1):
254 print("always_comb")
255 slist = p3[6]
256 self.comb += slist.statements