Skip to content

[wip] Add support for functions declarations with port list #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions pyverilog/dataflow/bindvisitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,6 @@ def _createAlwaysinfo(self, node, scope):
return (clock_name, clock_edge, clock_bit, reset_name, reset_edge, reset_bit, senslist)

def visit_IfStatement(self, node):
if self.frames.isFunctiondef() and not self.frames.isFunctioncall():
return
if self.frames.isTaskdef() and not self.frames.isTaskcall():
return

Expand Down Expand Up @@ -361,8 +359,6 @@ def _if_false(self, node, label):
return label

def visit_CaseStatement(self, node):
if self.frames.isFunctiondef() and not self.frames.isFunctioncall():
return
if self.frames.isTaskdef() and not self.frames.isTaskcall():
return
start_frame = self.frames.getCurrent()
Expand Down Expand Up @@ -427,8 +423,6 @@ def _case(self, comp, caselist, myframes):
self._case(comp, caselist[1:], myframes)

def visit_ForStatement(self, node):
if self.frames.isFunctiondef() and not self.frames.isFunctioncall():
return
if self.frames.isTaskdef() and not self.frames.isTaskcall():
return

Expand Down Expand Up @@ -480,8 +474,6 @@ def visit_ForStatement(self, node):
#loop += 1

def visit_WhileStatement(self, node):
if self.frames.isFunctiondef() and not self.frames.isFunctioncall():
return
if self.frames.isTaskdef() and not self.frames.isTaskcall():
return
label = self.labels.get(self.frames.getLabelKey('while'))
Expand Down Expand Up @@ -847,8 +839,6 @@ def makeConstantTerm(self, name, node, scope):
return Term(name, termtypes, msb, lsb)

def addTerm(self, node, rscope=None):
if self.frames.isFunctiondef() and not self.frames.isFunctioncall():
return
if self.frames.isTaskdef() and not self.frames.isTaskcall():
return
scope = self.frames.getCurrent() if rscope is None else rscope
Expand Down Expand Up @@ -880,8 +870,6 @@ def addTerm(self, node, rscope=None):
self.setConstantTerm(name, term)

def addBind(self, left, right, alwaysinfo=None, bindtype=None):
if self.frames.isFunctiondef() and not self.frames.isFunctioncall():
return
if self.frames.isTaskdef() and not self.frames.isTaskcall():
return
lscope = self.frames.getCurrent()
Expand Down
7 changes: 7 additions & 0 deletions pyverilog/dataflow/signalvisitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ def visit_Function(self, node):
self.generic_visit(node)
self.frames.unsetFunctionDef()

def visit_Portlist(self, node):
if not self.frames.isFunctiondef():
# Assume this is a module port list definition, which will be taken are of
# by the ModuleVisitor class
return
self.frames.addFunctionPorts(node.ports)

def visit_Task(self, node):
self.frames.addTask(node)
self.frames.setTaskDef()
Expand Down
8 changes: 7 additions & 1 deletion pyverilog/dataflow/visit.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def addPort(self, port):
def addPorts(self, ports):
for p in ports:
if isinstance(p, Ioport):
self.ioports.append(p.first.name)
self.ioports.append(p.first)
else:
self.ioports.append(p.name)

Expand Down Expand Up @@ -450,6 +450,9 @@ def addTask(self, node):
def addFunctionPort(self, node):
self.functions.addPort(node)

def addFunctionPorts(self, portlist):
self.functions.addPorts(portlist)

def addTaskPort(self, node):
self.tasks.addPort(node)

Expand Down Expand Up @@ -685,6 +688,9 @@ def addGenvar(self, var):
def addFunction(self, var):
self.dict[self.current].addFunction(var)

def addFunctionPorts(self, ports):
self.dict[self.current].addFunctionPorts(ports)

def addTask(self, var):
self.dict[self.current].addTask(var)

Expand Down
5 changes: 4 additions & 1 deletion pyverilog/vparser/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1071,16 +1071,19 @@ def children(self):
class Function(Node):
attr_names = ('name',)

def __init__(self, name, retwidth, statement, lineno=0):
def __init__(self, name, retwidth, portlist, statement, lineno=0):
self.lineno = lineno
self.name = name
self.portlist = portlist
self.retwidth = retwidth
self.statement = statement

def children(self):
nodelist = []
if self.retwidth:
nodelist.append(self.retwidth)
if self.portlist:
nodelist.append(self.portlist)
if self.statement:
nodelist.extend(self.statement)
return tuple(nodelist)
Expand Down
14 changes: 10 additions & 4 deletions pyverilog/vparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2060,25 +2060,27 @@ def p_sysarg(self, p):

# --------------------------------------------------------------------------
def p_function(self, p):
'function : FUNCTION width ID SEMICOLON function_statement ENDFUNCTION'
p[0] = Function(p[3], p[2], p[5], lineno=p.lineno(1))
'function : FUNCTION width ID portlist function_statement ENDFUNCTION'
p[0] = Function(p[3], p[2], p[4], p[5], lineno=p.lineno(1))
p.set_lineno(0, p.lineno(1))

def p_function_nowidth(self, p):
'function : FUNCTION ID SEMICOLON function_statement ENDFUNCTION'
'function : FUNCTION ID portlist function_statement ENDFUNCTION'
p[0] = Function(p[2],
Width(IntConst('0', lineno=p.lineno(1)),
IntConst('0', lineno=p.lineno(1)),
lineno=p.lineno(1)),
p[3],
p[4], lineno=p.lineno(1))
p.set_lineno(0, p.lineno(1))

def p_function_integer(self, p):
'function : FUNCTION INTEGER ID SEMICOLON function_statement ENDFUNCTION'
'function : FUNCTION INTEGER ID portlist function_statement ENDFUNCTION'
p[0] = Function(p[3],
Width(IntConst('31', lineno=p.lineno(1)),
IntConst('0', lineno=p.lineno(1)),
lineno=p.lineno(1)),
p[4],
p[5], lineno=p.lineno(1))
p.set_lineno(0, p.lineno(1))

Expand All @@ -2097,6 +2099,10 @@ def p_funcvardecls_one(self, p):
p[0] = (p[1],)
p.set_lineno(0, p.lineno(1))

def p_funcvardecls_empty(self, p):
'funcvardecls : empty'
p[0] = ()

def p_funcvardecl(self, p):
"""funcvardecl : decl
| integerdecl
Expand Down
62 changes: 62 additions & 0 deletions tests/dataflow_test/test_dat_function_portlist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
from pyverilog.dataflow.dataflow_analyzer import VerilogDataflowAnalyzer
from pyverilog.dataflow.optimizer import VerilogDataflowOptimizer
from pyverilog.controlflow.controlflow_analyzer import VerilogControlflowAnalyzer

codedir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/verilogcode/'

expected = """\
TOP.CLK: TOP_CLK
TOP.RST_X: TOP_RST_X
TOP.cnt: (((!TOP_RST_X))? 'd0 : (((!TOP_RST_X))? TOP_cnt : (((&TOP_al_block0_al_block2_al_functioncall0_inc))? 'd0 : (((!TOP_RST_X))? (TOP_cnt+'d1) : (TOP_cnt+'d1)))))
TOP.md_always0.al_block0.al_if0_ELSE.al_block2.al_functioncall0._rn0_inc: 'd0
TOP.md_always0.al_block0.al_if0_ELSE.al_block2.al_functioncall0._rn1_inc: (((!TOP_RST_X))? (TOP_al_block0_al_block2_al_functioncall0__rn1_inc+'d1) : (TOP_cnt+'d1))
TOP.md_always0.al_block0.al_if0_ELSE.al_block2.al_functioncall0.in: (((!TOP_RST_X))? TOP_al_block0_al_block2_al_functioncall0_in : TOP_cnt)
TOP.md_always0.al_block0.al_if0_ELSE.al_block2.al_functioncall0.inc: (((!TOP_RST_X))? TOP_al_block0_al_block2_al_functioncall0_inc : (((!TOP_RST_X))? (((&TOP_al_block0_al_block2_al_functioncall0_inc))? 'd0 : (((!TOP_RST_X))? (TOP_al_block0_al_block2_al_functioncall0_inc+'d1) : (TOP_cnt+'d1))) : (((&TOP_al_block0_al_block2_al_functioncall0_inc))? (((!TOP_RST_X))? (TOP_al_block0_al_block2_al_functioncall0_inc+'d1) : (TOP_cnt+'d1)) : (((!TOP_RST_X))? (((&(TOP_al_block0_al_block2_al_functioncall0_inc+'d1)))? 'd0 : (((!TOP_RST_X))? (TOP_al_block0_al_block2_al_functioncall0_inc+'d1) : (TOP_cnt+'d1))) : (((&(TOP_cnt+'d1)))? 'd0 : (((!TOP_RST_X))? (TOP_al_block0_al_block2_al_functioncall0_inc+'d1) : (TOP_cnt+'d1)))))))
"""

def test():
filelist = [os.path.join(codedir, 'function_portlist.v')]
topmodule = 'TOP'
noreorder = False
nobind = False
include = None
define = None

analyzer = VerilogDataflowAnalyzer(filelist, topmodule,
noreorder=noreorder,
nobind=nobind,
preprocess_include=include,
preprocess_define=define)
analyzer.generate()

directives = analyzer.get_directives()
instances = analyzer.getInstances()
terms = analyzer.getTerms()
binddict = analyzer.getBinddict()

optimizer = VerilogDataflowOptimizer(terms, binddict)
optimizer.resolveConstant()

c_analyzer = VerilogControlflowAnalyzer(topmodule, terms,
binddict,
resolved_terms=optimizer.getResolvedTerms(),
resolved_binddict=optimizer.getResolvedBinddict(),
constlist=optimizer.getConstlist()
)

output = []
for tk in sorted(c_analyzer.resolved_terms.keys(), key=lambda x:str(x)):
tree = c_analyzer.makeTree(tk)
output.append(str(tk) + ': ' + tree.tocode())

rslt = '\n'.join(output) + '\n'

print(rslt)
assert(expected == rslt)

if __name__ == '__main__':
test()
22 changes: 22 additions & 0 deletions verilogcode/function_portlist.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module TOP(CLK, RST_X);
input CLK;
input RST_X;
reg [3:0] cnt;

function [3:0] inc(input [3:0] in);
if(&inc) begin
inc = 0;
end else begin
inc = in + 1;
end
endfunction

always @(posedge CLK or negedge RST_X) begin
if(!RST_X) begin
cnt <= 0;
end else begin
cnt <= inc(cnt);
end
end

endmodule