Skip to content

Commit 07d26aa

Browse files
committed
from_verilog.py supports a Verilog code with generate statements
1 parent 5d05fff commit 07d26aa

File tree

6 files changed

+298
-16
lines changed

6 files changed

+298
-16
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
TARGET=led.py
2+
TEST=test_led.py
3+
ARGS=
4+
5+
PYTHON=python3
6+
#PYTHON=python
7+
#OPT=-m pdb
8+
#OPT=-m cProfile -s time
9+
#OPT=-m cProfile -o profile.rslt
10+
11+
.PHONY: all
12+
all: test
13+
14+
.PHONY: run
15+
run:
16+
$(PYTHON) $(OPT) $(TARGET) $(ARGS)
17+
18+
.PHONY: test
19+
test:
20+
$(PYTHON) -m pytest -vv $(TEST)
21+
22+
.PHONY: check
23+
check:
24+
$(PYTHON) $(OPT) $(TARGET) $(ARGS) > tmp.v
25+
iverilog -tnull -Wall tmp.v
26+
rm -f tmp.v
27+
28+
.PHONY: clean
29+
clean:
30+
rm -rf *.pyc __pycache__ parsetab.py *.out
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import sys
2+
import os
3+
import collections
4+
5+
from veriloggen import *
6+
7+
def mkLed():
8+
modules = read_verilog_module('led.v')
9+
m = modules['blinkled']
10+
return m
11+
12+
def mkTop():
13+
m = Module('top')
14+
width = m.Parameter('WIDTH', 8)
15+
clk = m.Input('CLK')
16+
rst = m.Input('RST')
17+
led = m.Output('LED', width)
18+
19+
params = ( width, )
20+
ports = ( clk, rst, led )
21+
22+
led = mkLed()
23+
m.Instance(led, 'inst_blinkled', params, ports)
24+
25+
return m
26+
27+
if __name__ == '__main__':
28+
top_module = mkTop()
29+
top_code = top_module.to_verilog()
30+
print(top_code)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module blinkled #
2+
(
3+
parameter WIDTH = 8,
4+
parameter NUM_INST = 4
5+
)
6+
(
7+
input CLK,
8+
input RST,
9+
output reg [WIDTH-1:0] LED
10+
);
11+
12+
reg [32-1:0] count;
13+
14+
always @(posedge CLK) begin
15+
if(RST) begin
16+
count <= 0;
17+
end else begin
18+
if(count == 1023) begin
19+
count <= 0;
20+
end else begin
21+
count <= count + 1;
22+
end
23+
end
24+
end
25+
26+
genvar i;
27+
generate for(i=0; i<NUM_INST; i=i+1) begin: gen_for
28+
reg [32-1:0] gen_count;
29+
if(i == 0) begin: gen_if_true
30+
always @(posedge CLK) begin
31+
gen_count <= count;
32+
end
33+
end else begin: gen_if_false
34+
reg [32-1:0] gen_if_count;
35+
always @(posedge CLK) begin
36+
gen_count <= gen_for[i-1].gen_count;
37+
gen_if_count <= gen_count;
38+
end
39+
end
40+
end endgenerate
41+
42+
always @(posedge CLK) begin
43+
if(RST) begin
44+
LED <= 0;
45+
end else begin
46+
if(gen_for[NUM_INST-1].gen_if_false.gen_if_count == 1023) begin
47+
LED <= LED + 1;
48+
end
49+
end
50+
end
51+
endmodule
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import led
2+
3+
expected_verilog = """
4+
module top #
5+
(
6+
parameter WIDTH = 8
7+
)
8+
(
9+
input CLK,
10+
input RST,
11+
output [WIDTH-1:0] LED
12+
);
13+
blinkled #
14+
(
15+
WIDTH
16+
)
17+
inst_blinkled
18+
(
19+
CLK,
20+
RST,
21+
LED
22+
);
23+
endmodule
24+
25+
module blinkled #
26+
(
27+
parameter WIDTH = 8,
28+
parameter NUM_INST = 4
29+
)
30+
(
31+
input CLK,
32+
input RST,
33+
output reg [(WIDTH-1)+1-1:0] LED
34+
);
35+
36+
reg [(32-1)+1-1:0] count;
37+
38+
always @(posedge CLK) begin
39+
if(RST) begin
40+
count <= 0;
41+
end else begin
42+
if(count == 1023) begin
43+
count <= 0;
44+
end else begin
45+
count <= count + 1;
46+
end
47+
end
48+
end
49+
50+
genvar i;
51+
generate for(i=0; i<NUM_INST; i=i+1) begin: gen_for
52+
reg [(32-1)+1-1:0] gen_count;
53+
if(i == 0) begin: gen_if_true
54+
always @(posedge CLK) begin
55+
gen_count <= count;
56+
end
57+
end else begin: gen_if_false
58+
reg [(32-1)+1-1:0] gen_if_count;
59+
always @(posedge CLK) begin
60+
gen_count <= gen_for[i-1].gen_count;
61+
gen_if_count <= gen_count;
62+
end
63+
end
64+
end endgenerate
65+
66+
always @(posedge CLK) begin
67+
if(RST) begin
68+
LED <= 0;
69+
end else begin
70+
if(gen_for[NUM_INST-1].gen_if_false.gen_if_count == 1023) begin
71+
LED <= LED + 1;
72+
end
73+
end
74+
end
75+
endmodule
76+
"""
77+
78+
def test_led():
79+
top_module = led.mkTop()
80+
top_code = top_module.to_verilog()
81+
82+
from pyverilog.vparser.parser import VerilogParser
83+
from pyverilog.ast_code_generator.codegen import ASTCodeGenerator
84+
parser = VerilogParser()
85+
expected_ast = parser.parse(expected_verilog)
86+
codegen = ASTCodeGenerator()
87+
expected_code = codegen.visit(expected_ast)
88+
89+
assert(top_code == expected_code)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../veriloggen

veriloggen/from_verilog.py

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,15 @@ def to_tuple(s):
6363
class VerilogReadVisitor(object):
6464
def __init__(self):
6565
self.m = None
66+
self.module_stack = []
6667

68+
def push_module(self, m):
69+
self.module_stack.append(self.m)
70+
self.m = m
71+
72+
def pop_module(self):
73+
self.m = self.module_stack.pop()
74+
6775
def add_object(self, obj):
6876
if isinstance(self.m, module.Module):
6977
self.m.add_object(obj)
@@ -80,9 +88,11 @@ def visit(self, node):
8088

8189
def visit_ModuleDef(self, node):
8290
# create new Verilog module
83-
self.m = module.Module(node.name)
91+
m = module.Module(node.name)
92+
self.push_module(m)
8493
self.generic_visit(node)
85-
return self.m
94+
self.pop_module()
95+
return m
8696

8797
def visit_Paramlist(self, node):
8898
params = []
@@ -120,7 +130,9 @@ def visit_Length(self, node):
120130

121131
def visit_Identifier(self, node):
122132
if node.scope is not None:
123-
raise ValueError("Identifier with scope label is not currently supported.")
133+
labels = self.visit(node.scope)
134+
labels.append(node.name)
135+
return vtypes.Scope(*labels)
124136
if not isinstance(self.m, module.Module):
125137
return vtypes.AnyType(node.name)
126138
return self.m.find_identifier(node.name)
@@ -491,6 +503,8 @@ def visit_NonblockingSubstitution(self, node):
491503
return vtypes.Subst(left, right, blk=False, ldelay=ldelay, rdelay=rdelay)
492504

493505
def visit_IfStatement(self, node):
506+
if isinstance(self.m, (module.GenerateFor, module.GenerateIf)):
507+
return self._visit_GenerateIf(node)
494508
condition = self.visit(node.cond)
495509
true_statement = self.visit(node.true_statement)
496510
false_statement = (self.visit(node.false_statement)
@@ -505,6 +519,8 @@ def visit_IfStatement(self, node):
505519
return _if
506520

507521
def visit_ForStatement(self, node):
522+
if isinstance(self.m, (module.GenerateFor, module.GenerateIf)):
523+
return self._visit_GenerateFor(node)
508524
pre = self.visit(node.pre)
509525
condition = self.visit(node.cond)
510526
post = self.visit(node.post)
@@ -543,10 +559,7 @@ def visit_Case(self, node):
543559

544560
def visit_Block(self, node):
545561
statements = [ self.visit(statement) for statement in node.statements ]
546-
if node.scope is None: return statements
547-
block = vtypes.NamedBlock(scope)
548-
block.extends(statements)
549-
return block
562+
return statements
550563

551564
def visit_Initial(self, node):
552565
statement = to_tuple(self.visit(node.statement))
@@ -587,6 +600,7 @@ def visit_Instance(self, node):
587600
if node.array is not None:
588601
raise ValueError("Instance array is not currently supported.")
589602
instance = vtypes.Instance(module, instname, params, ports)
603+
self.add_object(instance)
590604
return instance
591605

592606
def visit_ParamArg(self, node):
@@ -648,16 +662,83 @@ def visit_TaskCall(self, node):
648662
args = tuple([ self.visit(arg) for arg in ndoe.args ])
649663
call = vtypes.TaskCall(name, args)
650664
return call
665+
666+
def _visit_GenerateFor(self, item):
667+
pre = self.visit(item.pre)
668+
cond = self.visit(item.cond)
669+
post = self.visit(item.post)
670+
scope = (item.statement.scope
671+
if isinstance(item.statement, vast.Block)
672+
else None)
673+
_for = module.GenerateFor(pre, cond, post, scope)
674+
ret = _for
675+
self.add_object(_for)
676+
self.push_module(_for)
677+
statement = self.visit(item.statement)
678+
self.pop_module()
679+
return ret
680+
681+
def _visit_GenerateIf(self, item):
682+
cond = self.visit(item.cond)
683+
true_scope = (item.true_statement.scope
684+
if isinstance(item.true_statement, vast.Block)
685+
else None)
686+
false_scope = (item.false_statement.scope
687+
if isinstance(item.false_statement, vast.Block)
688+
else None)
689+
_if_true = module.GenerateIf(cond, true_scope)
690+
ret = _if_true
691+
self.add_object(_if_true)
692+
self.push_module(_if_true)
693+
statement = self.visit(item.true_statement)
694+
self.pop_module()
695+
_if_false = _if_true.Else(false_scope)
696+
self.push_module(_if_false)
697+
statement = self.visit(item.false_statement)
698+
self.pop_module()
699+
return ret
700+
701+
def visit_GenerateStatement(self, node):
702+
ret = []
703+
for item in node.items:
704+
if isinstance(item, vast.ForStatement):
705+
ret.append( self._visit_GenerateFor(item) )
706+
elif isinstance(item, vsat.IfStatement):
707+
ret.append( self._visit_GenerateIf(item) )
708+
else:
709+
raise TypeError("Only generate-for and generate-if statements are supported.")
710+
return ret
711+
712+
def visit_SystemCall(self, node):
713+
cmd = node.syscall
714+
args = tuple([ self.visit(a) for arg in node.args ])
715+
systask = vtypes.SystemTask(cmd, *args)
716+
return systask
717+
718+
def visit_IdentifierScopeLabel(self, node):
719+
if node.loop is None:
720+
return node.name
721+
index = self.visit(node.loop)
722+
return vtypes.ScopeIndex(node.name, index)
723+
724+
def visit_IdentifierScope(self, node):
725+
args = [ self.visit(label) for label in node.labellist ]
726+
return args
651727

652-
def visit_GenerateStatement(self, node): pass
653-
def visit_SystemCall(self, node): pass
654-
def visit_IdentifierScopeLabel(self, node): pass
655-
def visit_IdentifierScope(self, node): pass
656-
def visit_Pragma(self, node): pass
657-
def visit_PragmaEntry(self, node): pass
658-
def visit_Disable(self, node): pass
659-
def visit_ParallelBlock(self, node): pass
660-
def visit_SingleStatement(self, node): pass
728+
def visit_Pragma(self, node):
729+
raise TypeError("Pragma is not currently supported.")
730+
731+
def visit_PragmaEntry(self, node):
732+
raise TypeError("Pragma is not currently supported.")
733+
734+
def visit_Disable(self, node):
735+
raise TypeError("Disable is not currently supported.")
736+
737+
def visit_ParallelBlock(self, node):
738+
raise TypeError("Fork/Join is not currently supported.")
739+
740+
def visit_SingleStatement(self, node):
741+
return self.visit(node.statement)
661742

662743
#-------------------------------------------------------------------------------
663744
def to_ast(*filelist, **opt):

0 commit comments

Comments
 (0)