From 5fc199fb093f1e970a4a456601fde1d4cee00ea3 Mon Sep 17 00:00:00 2001 From: noloerino Date: Mon, 28 Mar 2022 23:10:45 -0700 Subject: [PATCH 1/3] Add support for functions declarations with port list --- pyverilog/dataflow/signalvisitor.py | 7 +++ pyverilog/dataflow/visit.py | 8 ++- pyverilog/vparser/ast.py | 5 +- pyverilog/vparser/parser.py | 14 +++-- .../test_dat_function_portlist.py | 62 +++++++++++++++++++ verilogcode/function_portlist.v | 22 +++++++ 6 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 tests/dataflow_test/test_dat_function_portlist.py create mode 100644 verilogcode/function_portlist.v diff --git a/pyverilog/dataflow/signalvisitor.py b/pyverilog/dataflow/signalvisitor.py index e2d5251..da594aa 100644 --- a/pyverilog/dataflow/signalvisitor.py +++ b/pyverilog/dataflow/signalvisitor.py @@ -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() diff --git a/pyverilog/dataflow/visit.py b/pyverilog/dataflow/visit.py index da67da3..94e4edc 100644 --- a/pyverilog/dataflow/visit.py +++ b/pyverilog/dataflow/visit.py @@ -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) @@ -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) @@ -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) diff --git a/pyverilog/vparser/ast.py b/pyverilog/vparser/ast.py index 492adc9..da217d0 100644 --- a/pyverilog/vparser/ast.py +++ b/pyverilog/vparser/ast.py @@ -1071,9 +1071,10 @@ 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 @@ -1081,6 +1082,8 @@ 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) diff --git a/pyverilog/vparser/parser.py b/pyverilog/vparser/parser.py index 3a82912..02c8026 100644 --- a/pyverilog/vparser/parser.py +++ b/pyverilog/vparser/parser.py @@ -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)) @@ -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 diff --git a/tests/dataflow_test/test_dat_function_portlist.py b/tests/dataflow_test/test_dat_function_portlist.py new file mode 100644 index 0000000..d5c8287 --- /dev/null +++ b/tests/dataflow_test/test_dat_function_portlist.py @@ -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() diff --git a/verilogcode/function_portlist.v b/verilogcode/function_portlist.v new file mode 100644 index 0000000..1b66f50 --- /dev/null +++ b/verilogcode/function_portlist.v @@ -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 From acb437223229dc3a8b5f1b463d7b287272e32302 Mon Sep 17 00:00:00 2001 From: noloerino Date: Tue, 29 Mar 2022 16:42:53 -0700 Subject: [PATCH 2/3] Add term information for regs in functions --- pyverilog/dataflow/bindvisitor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyverilog/dataflow/bindvisitor.py b/pyverilog/dataflow/bindvisitor.py index cb73857..3d0cb0c 100644 --- a/pyverilog/dataflow/bindvisitor.py +++ b/pyverilog/dataflow/bindvisitor.py @@ -847,8 +847,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 From aafc298c5a5c435cb7801654e931016b0f2955d2 Mon Sep 17 00:00:00 2001 From: noloerino Date: Tue, 29 Mar 2022 16:47:18 -0700 Subject: [PATCH 3/3] Add bind information for regs in functions --- pyverilog/dataflow/bindvisitor.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pyverilog/dataflow/bindvisitor.py b/pyverilog/dataflow/bindvisitor.py index 3d0cb0c..ba921e5 100644 --- a/pyverilog/dataflow/bindvisitor.py +++ b/pyverilog/dataflow/bindvisitor.py @@ -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 @@ -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() @@ -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 @@ -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')) @@ -878,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()