do not create output files on error
[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
54 def open(self):
55 if(self.outputfile is None):
56 self.outputfile = open(self.outputfn, "w")
57 self.outputfile.write(preamble)
58
59 def printpy(self, p):
60 self.open()
61 self.outputfile.write(str(p)+"\n")
62
63 def assign(self, p):
64 p = list(p)
65 if(p[1] == "assign"):
66 self.printpy(p[4])
67 # m.d.comb += [l.eq(r)]
68
69 def indent(self, count):
70 if(indent_debug):
71 return Leaf(token.INDENT, '>>> '*count)
72 else:
73 return Leaf(token.INDENT, ' '*4*count)
74
75 def dedent(self, count):
76 return Leaf(token.DEDENT, '')
77
78 def nl(self):
79 return Leaf(token.NEWLINE, '\n')
80
81 def port_decl(self, comment, dt, name):
82 port = PortDecl(comment, dt, name)
83 self.ports += [port]
84 return port
85
86 def initFunc(self, ports, params):
87 params = [Leaf(token.LPAR, '('), Leaf(
88 token.NAME, "self")] + [Leaf(token.RPAR, ')')]
89 # TODO handle sv params
90 fn = [Leaf(token.NAME, 'def'),
91 Leaf(token.NAME, '__init__', prefix=' '),
92 Node(syms.parameters, params),
93 Leaf(token.COLON, ':'),
94 self.nl()
95 ]
96 fndef = Node(syms.funcdef, fn)
97 stmts = Node(syms.stmt, [fndef])
98 for port in ports:
99 stmts.children.append(self.indent(2))
100 stmts.children.append(port.initNode())
101 stmts.children.append(self.nl())
102 return stmts
103
104 def elaborateFunc(self):
105 params = [Leaf(token.LPAR, '('), Leaf(
106 token.NAME, "self, platform=None"), Leaf(token.RPAR, ')')]
107 fn = [Leaf(token.NAME, 'def'),
108 Leaf(token.NAME, 'elaborate', prefix=' '),
109 Node(syms.parameters, params),
110 Leaf(token.COLON, ':'),
111 self.nl()
112 ]
113 fndef = Node(syms.funcdef, fn)
114 stmts = Node(syms.stmt, [fndef])
115 stmts.children.append(self.indent(2))
116 stmts.children.append(Leaf(token.STRING, "m = Module()"))
117 stmts.children.append(self.nl())
118
119 for a in self.assign:
120 stmts.children.append(self.indent(2))
121 # m.d.sync += self.left.eq(right)
122 stmts.children.append(Leaf(token.STRING, "m.d.comb += self."))
123 stmts.children.append(Leaf(token.STRING, a.left))
124 stmts.children.append(Leaf(token.STRING, ".eq(self."))
125 stmts.children.append(Leaf(token.STRING, a.right))
126 stmts.children.append(Leaf(token.STRING, ")"))
127 stmts.children.append(self.nl())
128
129 # for a in self.assign:
130 #
131 #
132 #ports = a[8]
133 #
134
135 stmts.children.append(self.indent(2))
136 stmts.children.append(Leaf(token.STRING, "return m"))
137 stmts.children.append(self.nl())
138 return stmts
139
140 def module_1(self, p):
141 params = p[7]
142 ports = p[8]
143 clsname = [Leaf(token.NAME, 'class'),
144 Leaf(token.NAME, p[4], prefix=' '),
145 Leaf(token.LPAR, '('),
146 Leaf(token.NAME, 'Elaboratable'),
147 Leaf(token.LPAR, ')'),
148 Leaf(token.COLON, ':'),
149 self.nl(),
150 ]
151
152 suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
153 self.indent(1),
154 self.initFunc(ports, params),
155 self.indent(1),
156 self.elaborateFunc()
157
158 ])
159 clsdecl = Node(syms.classdef, clsname + [suite])
160 clsdecl = Node(syms.compound_stmt, [clsdecl])
161
162 self.printpy(str(clsdecl))
163 print("=====================")
164 print(str(clsdecl))
165 return clsdecl
166
167 def appendComments(self, data):
168 self.open()
169 self.outputfile.write(data)
170 #lines = data.split("\n")
171 # for line in lines:
172 # self.printpy("#"+line)
173
174 # combinatorical assign
175 def cont_assign_1(self, p):
176 # print("#ASSIGN:BROKEN"+str(list(p)))
177 self.assign += [Assignment(p[1], p[2], p[3])]