Skip to content

Commit 649deb1

Browse files
committed
ast_code_generator is updated: Redundant parans are removed from generated source codes. A new test for it is added.
1 parent a9ece0c commit 649deb1

File tree

3 files changed

+168
-34
lines changed

3 files changed

+168
-34
lines changed

pyverilog/ast_code_generator/codegen.py

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from pyverilog.vparser.ast import *
1919
from pyverilog.utils.op2mark import op2mark
20+
from pyverilog.utils.op2mark import op2order
2021

2122
DEFAULT_TEMPLATE_DIR = os.path.dirname(os.path.abspath(__file__)) + '/template/'
2223

@@ -55,6 +56,11 @@ def escape(s):
5556
return s + ' '
5657
return s
5758

59+
def del_paren(s):
60+
if s.startswith('(') and s.endswith(')'):
61+
return s[1:-1]
62+
return s
63+
5864
class ASTCodeGenerator(ConvertVisitor):
5965
def __init__(self, indentsize=2):
6066
self.env = Environment(loader=FileSystemLoader(DEFAULT_TEMPLATE_DIR))
@@ -127,8 +133,8 @@ def visit_Width(self, node):
127133
filename = getfilename(node)
128134
template = self.env.get_template(filename)
129135
template_dict = {
130-
'msb' : self.visit(node.msb),
131-
'lsb' : self.visit(node.lsb),
136+
'msb' : del_paren(self.visit(node.msb)),
137+
'lsb' : del_paren(self.visit(node.lsb)),
132138
}
133139
rslt = template.render(template_dict)
134140
return rslt
@@ -137,8 +143,8 @@ def visit_Length(self, node):
137143
filename = getfilename(node)
138144
template = self.env.get_template(filename)
139145
template_dict = {
140-
'msb' : self.visit(node.msb),
141-
'lsb' : self.visit(node.lsb),
146+
'msb' : del_paren(self.visit(node.msb)),
147+
'lsb' : del_paren(self.visit(node.lsb)),
142148
}
143149
rslt = template.render(template_dict)
144150
return rslt
@@ -342,7 +348,7 @@ def visit_Ioport(self, node):
342348
def visit_Parameter(self, node):
343349
filename = getfilename(node)
344350
template = self.env.get_template(filename)
345-
value = self.visit(node.value)
351+
value = del_paren(self.visit(node.value))
346352
template_dict = {
347353
'name' : escape(node.name),
348354
'width' : '' if node.width is None or (value.startswith('"') and value.endswith('"')) else self.visit(node.width),
@@ -355,7 +361,7 @@ def visit_Parameter(self, node):
355361
def visit_Localparam(self, node):
356362
filename = getfilename(node)
357363
template = self.env.get_template(filename)
358-
value = self.visit(node.value)
364+
value = del_paren(self.visit(node.value))
359365
template_dict = {
360366
'name' : escape(node.name),
361367
'width' : '' if node.width is None or (value.startswith('"') and value.endswith('"')) else self.visit(node.width),
@@ -377,7 +383,7 @@ def visit_Decl(self, node):
377383
def visit_Concat(self, node):
378384
filename = getfilename(node)
379385
template = self.env.get_template(filename)
380-
items = [ self.visit(item) for item in node.list ]
386+
items = [ del_paren(self.visit(item)) for item in node.list ]
381387
template_dict = {
382388
'items' : items,
383389
'len_items' : len(items),
@@ -388,7 +394,7 @@ def visit_Concat(self, node):
388394
def visit_LConcat(self, node):
389395
filename = getfilename(node)
390396
template = self.env.get_template(filename)
391-
items = [ self.visit(item) for item in node.list ]
397+
items = [ del_paren(self.visit(item)) for item in node.list ]
392398
template_dict = {
393399
'items' : items,
394400
'len_items' : len(items),
@@ -400,8 +406,8 @@ def visit_Repeat(self, node):
400406
filename = getfilename(node)
401407
template = self.env.get_template(filename)
402408
template_dict = {
403-
'value' : self.visit(node.value),
404-
'times' : self.visit(node.times),
409+
'value' : del_paren(self.visit(node.value)),
410+
'times' : del_paren(self.visit(node.times)),
405411
}
406412
rslt = template.render(template_dict)
407413
return rslt
@@ -411,8 +417,8 @@ def visit_Partselect(self, node):
411417
template = self.env.get_template(filename)
412418
template_dict = {
413419
'var' : self.visit(node.var),
414-
'msb' : self.visit(node.msb),
415-
'lsb' : self.visit(node.lsb),
420+
'msb' : del_paren(self.visit(node.msb)),
421+
'lsb' : del_paren(self.visit(node.lsb)),
416422
}
417423
rslt = template.render(template_dict)
418424
return rslt
@@ -422,7 +428,7 @@ def visit_Pointer(self, node):
422428
template = self.env.get_template(filename)
423429
template_dict = {
424430
'var' : self.visit(node.var),
425-
'ptr' : self.visit(node.ptr),
431+
'ptr' : del_paren(self.visit(node.ptr)),
426432
}
427433
rslt = template.render(template_dict)
428434
return rslt
@@ -431,7 +437,7 @@ def visit_Lvalue(self, node):
431437
filename = getfilename(node)
432438
template = self.env.get_template(filename)
433439
template_dict = {
434-
'var' : self.visit(node.var),
440+
'var' : del_paren(self.visit(node.var)),
435441
}
436442
rslt = template.render(template_dict)
437443
return rslt
@@ -440,17 +446,30 @@ def visit_Rvalue(self, node):
440446
filename = getfilename(node)
441447
template = self.env.get_template(filename)
442448
template_dict = {
443-
'var' : self.visit(node.var),
449+
'var' : del_paren(self.visit(node.var)),
444450
}
445451
rslt = template.render(template_dict)
446452
return rslt
447453

448454
def visit_Operator(self, node):
449455
filename = getfilename(node)
450456
template = self.env.get_template(filename)
451-
template_dict = {
452-
'left' : self.visit(node.left),
453-
'right' : self.visit(node.right),
457+
order = op2order(node.__class__.__name__)
458+
lorder = op2order(node.left.__class__.__name__)
459+
rorder = op2order(node.right.__class__.__name__)
460+
left = self.visit(node.left)
461+
right = self.visit(node.right)
462+
if ( isinstance(node.left, (Identifier, Value)) or
463+
((not isinstance(node.left, (Sll, Srl, Sra))) and
464+
(lorder is not None and lorder <= order)) ):
465+
left = del_paren(left)
466+
if ( isinstance(node.right, (Identifier, Value)) or
467+
((not isinstance(node.right, (Sll, Srl, Sra))) and
468+
(rorder is not None and order > rorder)) ):
469+
right = del_paren(right)
470+
template_dict = {
471+
'left' : left,
472+
'right' : right,
454473
'op' : op2mark(node.__class__.__name__),
455474
}
456475
rslt = template.render(template_dict)
@@ -459,8 +478,11 @@ def visit_Operator(self, node):
459478
def visit_UnaryOperator(self, node):
460479
filename = getfilename(node)
461480
template = self.env.get_template(filename)
481+
right = self.visit(node.right)
482+
if isinstance(node.right, (Identifier, Value)):
483+
right = del_paren(right)
462484
template_dict = {
463-
'right' : self.visit(node.right),
485+
'right' : right,
464486
'op' : op2mark(node.__class__.__name__),
465487
}
466488
rslt = template.render(template_dict)
@@ -569,9 +591,9 @@ def visit_Cond(self, node):
569591
filename = getfilename(node)
570592
template = self.env.get_template(filename)
571593
template_dict = {
572-
'cond' : self.visit(node.cond),
573-
'true_value' : self.visit(node.true_value),
574-
'false_value' : self.visit(node.false_value),
594+
'cond' : del_paren(self.visit(node.cond)),
595+
'true_value' : del_paren(self.visit(node.true_value)),
596+
'false_value' : del_paren(self.visit(node.false_value)),
575597
}
576598
rslt = template.render(template_dict)
577599
return rslt
@@ -659,7 +681,7 @@ def visit_IfStatement(self, node):
659681
true_statement = '' if node.true_statement is None else self.visit(node.true_statement)
660682
false_statement = '' if node.false_statement is None else self.visit(node.false_statement)
661683
template_dict = {
662-
'cond' : self.visit(node.cond),
684+
'cond' : del_paren(self.visit(node.cond)),
663685
'true_statement' : true_statement,
664686
'false_statement' : false_statement,
665687
}
@@ -671,7 +693,7 @@ def visit_ForStatement(self, node):
671693
template = self.env.get_template(filename)
672694
template_dict = {
673695
'pre' : '' if node.pre is None else self.visit(node.pre),
674-
'cond' : '' if node.cond is None else self.visit(node.cond),
696+
'cond' : '' if node.cond is None else del_paren(self.visit(node.cond)),
675697
'post' : '' if node.post is None else self.visit(node.post).replace(';', ''),
676698
'statement' : '' if node.statement is None else self.visit(node.statement),
677699
}
@@ -682,7 +704,7 @@ def visit_WhileStatement(self, node):
682704
filename = getfilename(node)
683705
template = self.env.get_template(filename)
684706
template_dict = {
685-
'cond' : '' if node.cond is None else self.visit(node.cond),
707+
'cond' : '' if node.cond is None else del_paren(self.visit(node.cond)),
686708
'statement' : '' if node.statement is None else self.visit(node.statement),
687709
}
688710
rslt = template.render(template_dict)
@@ -692,7 +714,7 @@ def visit_CaseStatement(self, node):
692714
filename = getfilename(node)
693715
template = self.env.get_template(filename)
694716
template_dict = {
695-
'comp' : self.visit(node.comp),
717+
'comp' : del_paren(self.visit(node.comp)),
696718
'caselist' : [ self.indent(self.visit(case)) for case in node.caselist ],
697719
}
698720
rslt = template.render(template_dict)
@@ -702,7 +724,7 @@ def visit_CasexStatement(self, node):
702724
filename = getfilename(node)
703725
template = self.env.get_template(filename)
704726
template_dict = {
705-
'comp' : self.visit(node.comp),
727+
'comp' : del_paren(self.visit(node.comp)),
706728
'caselist' : [ self.indent(self.visit(case)) for case in node.caselist ],
707729
}
708730
rslt = template.render(template_dict)
@@ -711,7 +733,7 @@ def visit_CasexStatement(self, node):
711733
def visit_Case(self, node):
712734
filename = getfilename(node)
713735
template = self.env.get_template(filename)
714-
condlist = [ 'default' ] if node.cond is None else [ self.visit(c) for c in node.cond ]
736+
condlist = [ 'default' ] if node.cond is None else [ del_paren(self.visit(c)) for c in node.cond ]
715737
cond = []
716738
for c in condlist:
717739
cond.append(c)
@@ -746,7 +768,7 @@ def visit_EventStatement(self, node):
746768
filename = getfilename(node)
747769
template = self.env.get_template(filename)
748770
template_dict = {
749-
'senslist': self.visit(node.senslist),
771+
'senslist': del_paren(self.visit(node.senslist)),
750772
}
751773
rslt = template.render(template_dict)
752774
return rslt
@@ -755,7 +777,7 @@ def visit_WaitStatement(self, node):
755777
filename = getfilename(node)
756778
template = self.env.get_template(filename)
757779
template_dict = {
758-
'cond': self.visit(node.cond),
780+
'cond': del_paren(self.visit(node.cond)),
759781
'statement' : self.visit(node.statement) if node.statement else '',
760782
}
761783
rslt = template.render(template_dict)
@@ -813,7 +835,7 @@ def visit_ParamArg(self, node):
813835
template = self.env.get_template(filename)
814836
template_dict = {
815837
'paramname' : '' if node.paramname is None else escape(node.paramname),
816-
'argname' : '' if node.argname is None else self.visit(node.argname),
838+
'argname' : '' if node.argname is None else del_paren(self.visit(node.argname)),
817839
}
818840
rslt = template.render(template_dict)
819841
return rslt
@@ -823,7 +845,7 @@ def visit_PortArg(self, node):
823845
template = self.env.get_template(filename)
824846
template_dict = {
825847
'portname' : '' if node.portname is None else escape(node.portname),
826-
'argname' : '' if node.argname is None else self.visit(node.argname),
848+
'argname' : '' if node.argname is None else del_paren(self.visit(node.argname)),
827849
}
828850
rslt = template.render(template_dict)
829851
return rslt

pyverilog/utils/op2mark.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# License: Apache 2.0
88
#-------------------------------------------------------------------------------
99

10-
operator_dict = {
10+
operator_mark = {
1111
'Uminus':'-', 'Ulnot':'!', 'Unot':'~', 'Uand':'&', 'Unand':'~&',
1212
'Uor':'|', 'Unor':'~|', 'Uxor':'^', 'Uxnor':'~^',
1313
'Power':'**', 'Times':'*', 'Divide':'/', 'Mod':'%',
@@ -20,4 +20,26 @@
2020
}
2121

2222
def op2mark(op):
23-
return operator_dict[op]
23+
if op not in operator_mark:
24+
return None
25+
return operator_mark[op]
26+
27+
operator_order = {
28+
'Uminus':0, 'Ulnot':0, 'Unot':0, 'Uand':0, 'Unand':0,
29+
'Uor':0, 'Unor':0, 'Uxor':0, 'Uxnor':0,
30+
'Power':1,
31+
'Times':2, 'Divide':2, 'Mod':2,
32+
'Plus':3, 'Minus':3,
33+
'Sll':4, 'Srl':4, 'Sra':4,
34+
'LessThan':5, 'GreaterThan':5, 'LessEq':5, 'GreaterEq':5,
35+
'Eq':6, 'NotEq':6, 'Eql':6, 'NotEql':6,
36+
'And':7, 'Xor':7, 'Xnor':7,
37+
'Or':8,
38+
'Land':9,
39+
'Lor':10
40+
}
41+
42+
def op2order(op):
43+
if op not in operator_order:
44+
return None
45+
return operator_order[op]
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import os
2+
import sys
3+
4+
import pyverilog.vparser.ast as vast
5+
from pyverilog.ast_code_generator.codegen import ASTCodeGenerator
6+
7+
expected = """\
8+
9+
module top #
10+
(
11+
parameter DATAWID = 32
12+
)
13+
(
14+
input CLK,
15+
input RST,
16+
output [7:0] led
17+
);
18+
19+
reg [DATAWID - 1:0] count;
20+
assign led = count[DATAWID - 1:DATAWID - 8];
21+
22+
always @(posedge CLK) begin
23+
if(RST) begin
24+
count <= 0;
25+
end else begin
26+
count <= (count + 1) * 2 + 1;
27+
end
28+
end
29+
30+
31+
endmodule
32+
"""
33+
34+
def test():
35+
datawid = vast.Parameter( 'DATAWID', vast.Rvalue(vast.IntConst('32')) )
36+
params = vast.Paramlist( [datawid] )
37+
clk = vast.Ioport( vast.Input('CLK') )
38+
rst = vast.Ioport( vast.Input('RST') )
39+
width = vast.Width( vast.IntConst('7'), vast.IntConst('0') )
40+
led = vast.Ioport( vast.Output('led', width=width) )
41+
ports = vast.Portlist( [clk, rst, led] )
42+
43+
width = vast.Width( vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('1')), vast.IntConst('0') )
44+
count = vast.Reg('count', width=width)
45+
46+
assign = vast.Assign(
47+
vast.Lvalue(vast.Identifier('led')),
48+
vast.Rvalue(
49+
vast.Partselect(
50+
vast.Identifier('count'), # count
51+
vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('1')), # [DATAWID-1:
52+
vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('8'))))) # :DATAWID-8]
53+
54+
sens = vast.Sens(vast.Identifier('CLK'), type='posedge')
55+
senslist = vast.SensList([ sens ])
56+
57+
assign_count_true = vast.NonblockingSubstitution(
58+
vast.Lvalue(vast.Identifier('count')),
59+
vast.Rvalue(vast.IntConst('0')))
60+
if0_true = vast.Block([ assign_count_true ])
61+
62+
# (count + 1) * 2
63+
count_plus_1 = vast.Plus(vast.Identifier('count'), vast.IntConst('1'))
64+
cp1_times_2 = vast.Times(count_plus_1, vast.IntConst('2'))
65+
cp1t2_plus_1 = vast.Plus(cp1_times_2, vast.IntConst('1'))
66+
assign_count_false = vast.NonblockingSubstitution(
67+
vast.Lvalue(vast.Identifier('count')),
68+
vast.Rvalue(cp1t2_plus_1))
69+
if0_false = vast.Block([ assign_count_false ])
70+
71+
if0 = vast.IfStatement(vast.Identifier('RST'), if0_true, if0_false)
72+
statement = vast.Block([ if0 ])
73+
74+
always = vast.Always(senslist, statement)
75+
76+
items = []
77+
items.append(count)
78+
items.append(assign)
79+
items.append(always)
80+
81+
ast = vast.ModuleDef("top", params, ports, items)
82+
83+
codegen = ASTCodeGenerator()
84+
rslt = codegen.visit(ast)
85+
print(rslt)
86+
87+
assert(expected == rslt)
88+
89+
if __name__ == '__main__':
90+
test()

0 commit comments

Comments
 (0)