ecd3846516ddf89e773c7b3bdb20754cf52e5e8b
[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
47 class Absyn:
48 def __init__(self, outputfn):
49 self.outputfn = outputfn
50 self.outputfile = None
51 self.assign = []
52 self.ports = []
53 self.wires = []
54
55 def open(self):
56 if(self.outputfile is None):
57 self.outputfile = open(self.outputfn, "w")
58 self.outputfile.write(preamble)
59
60 def printpy(self, p):
61 self.open()
62 self.outputfile.write(str(p)+"\n")
63
64 def assign(self, p):
65 p = list(p)
66 if(p[1] == "assign"):
67 self.printpy(p[4])
68
69 def assign3(self, left, op, right):
70 return Assignment(left, op, right)
71
72 def indent(self, count):
73 if(indent_debug):
74 return Leaf(token.INDENT, '>>> '*count)
75 else:
76 return Leaf(token.INDENT, ' '*4*count)
77
78 def dedent(self, count):
79 return Leaf(token.DEDENT, '')
80
81 def nl(self):
82 return Leaf(token.NEWLINE, '\n')
83
84 def port_decl(self, comment, dt, name):
85 port = PortDecl(comment, dt, name)
86 self.ports += [port]
87 return port
88
89 def isPort(self, name):
90 for p in self.ports:
91 if(str(p.name) == str(name)):
92 return True
93 return False
94
95 def initFunc(self, ports, params):
96 params = [Leaf(token.LPAR, '('), Leaf(
97 token.NAME, "self")] + [Leaf(token.RPAR, ')')]
98 # TODO handle sv params
99 fn = [Leaf(token.NAME, 'def'),
100 Leaf(token.NAME, '__init__', prefix=' '),
101 Node(syms.parameters, params),
102 Leaf(token.COLON, ':'),
103 self.nl()
104 ]
105 fndef = Node(syms.funcdef, fn)
106 stmts = Node(syms.stmt, [fndef])
107 for port in ports:
108 stmts.children.append(self.indent(2))
109 stmts.children.append(port.initNode())
110 stmts.children.append(self.nl())
111 return stmts
112
113 def elaborateFunc(self):
114 params = [Leaf(token.LPAR, '('), Leaf(
115 token.NAME, "self, platform=None"), Leaf(token.RPAR, ')')]
116 fn = [Leaf(token.NAME, 'def'),
117 Leaf(token.NAME, 'elaborate', prefix=' '),
118 Node(syms.parameters, params),
119 Leaf(token.COLON, ':'),
120 self.nl()
121 ]
122 fndef = Node(syms.funcdef, fn)
123 stmts = Node(syms.stmt, [fndef])
124 stmts.children.append(self.indent(2))
125 stmts.children.append(Leaf(token.STRING, "m = Module()"))
126 stmts.children.append(self.nl())
127
128 for w in self.wires:
129 wirename = w[0]
130 hasdims = (len(w) >= 4)
131 stmts.children.append(self.indent(2))
132 stmts.children.append(Leaf(token.STRING, wirename))
133 stmts.children.append(Leaf(token.STRING, " = Signal("))
134 if(hasdims):
135 stmts.children.append(Leaf(token.STRING, str(w[3])))
136 stmts.children.append(Leaf(token.STRING, ")"))
137 stmts.children.append(self.nl())
138
139 for a in self.assign:
140 stmts.children.append(self.indent(2))
141 # m.d.sync += self.left.eq(right)
142 stmts.children.append(Leaf(token.STRING, "m.d.comb += "))
143 if(self.isPort(a.left)):
144 stmts.children.append(Leaf(token.STRING, "self."))
145 stmts.children.append(Leaf(token.STRING, a.left))
146 stmts.children.append(Leaf(token.STRING, ".eq("))
147 if(self.isPort(a.right)):
148 stmts.children.append(Leaf(token.STRING, "self."))
149 stmts.children.append(Leaf(token.STRING, a.right))
150 stmts.children.append(Leaf(token.STRING, ")"))
151 stmts.children.append(self.nl())
152
153 stmts.children.append(self.indent(2))
154 stmts.children.append(Leaf(token.STRING, "return m"))
155 stmts.children.append(self.nl())
156 return stmts
157
158 def module_1(self, p):
159 params = p[7]
160 ports = p[8]
161 clsname = [Leaf(token.NAME, 'class'),
162 Leaf(token.NAME, p[4], prefix=' '),
163 Leaf(token.LPAR, '('),
164 Leaf(token.NAME, 'Elaboratable'),
165 Leaf(token.LPAR, ')'),
166 Leaf(token.COLON, ':'),
167 self.nl(),
168 ]
169
170 suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
171 self.indent(1),
172 self.initFunc(ports, params),
173 self.indent(1),
174 self.elaborateFunc()
175
176 ])
177 clsdecl = Node(syms.classdef, clsname + [suite])
178 clsdecl = Node(syms.compound_stmt, [clsdecl])
179
180 self.printpy(str(clsdecl))
181 return clsdecl
182
183 def module_item_2(self, signaltype, dims, mlist):
184 if(signaltype == "wire"):
185 for m in mlist:
186 if(dims):
187 self.wires.append(m+dims)
188 else:
189 self.wires.append(m)
190
191 def appendComments(self, data):
192 self.open()
193 self.outputfile.write(data)
194 #lines = data.split("\n")
195 # for line in lines:
196 # self.printpy("#"+line)
197
198 # combinatorical assign
199 def cont_assign_1(self, p):
200 self.assign += [Assignment(p[1], p[2], p[3])]
201
202 def always_comb(self, p3, p1):
203 print("always_comb")
204 slist = p3[6]
205 for s in slist.statements:
206 self.assign += [s]