diff --git a/pyverilog/ast_code_generator/codegen.py b/pyverilog/ast_code_generator/codegen.py index 9b87569..ea6c5e9 100644 --- a/pyverilog/ast_code_generator/codegen.py +++ b/pyverilog/ast_code_generator/codegen.py @@ -899,6 +899,7 @@ def visit_Function(self, node): 'name': escape(node.name), 'retwidth': self.visit(node.retwidth), 'statement': statement, + 'automatic': 'automatic' if node.automatic else '' } rslt = template.render(template_dict) return rslt diff --git a/pyverilog/ast_code_generator/template/function.txt b/pyverilog/ast_code_generator/template/function.txt index 0186fd8..80791e2 100644 --- a/pyverilog/ast_code_generator/template/function.txt +++ b/pyverilog/ast_code_generator/template/function.txt @@ -1,5 +1,5 @@ -function {{ retwidth }} {{ name }}; +function {{automatic}} {{ retwidth }} {{ name }}; {%- for s in statement %} {{ s }} {%- endfor %} diff --git a/pyverilog/vparser/ast.py b/pyverilog/vparser/ast.py index df288ed..9ed826c 100644 --- a/pyverilog/vparser/ast.py +++ b/pyverilog/vparser/ast.py @@ -1074,11 +1074,12 @@ def children(self): class Function(Node): attr_names = ('name',) - def __init__(self, name, retwidth, statement, lineno=0): + def __init__(self, name, retwidth, statement, automatic=False, lineno=0): self.lineno = lineno self.name = name self.retwidth = retwidth self.statement = statement + self.automatic = automatic def children(self): nodelist = [] diff --git a/pyverilog/vparser/lexer.py b/pyverilog/vparser/lexer.py index 8fe6628..e26c0ff 100644 --- a/pyverilog/vparser/lexer.py +++ b/pyverilog/vparser/lexer.py @@ -52,7 +52,7 @@ def token(self): keywords = ( 'MODULE', 'ENDMODULE', 'BEGIN', 'END', 'GENERATE', 'ENDGENERATE', 'GENVAR', - 'FUNCTION', 'ENDFUNCTION', 'TASK', 'ENDTASK', + 'FUNCTION', 'ENDFUNCTION', 'AUTOMATIC', 'TASK', 'ENDTASK', 'INPUT', 'INOUT', 'OUTPUT', 'TRI', 'REG', 'LOGIC', 'WIRE', 'INTEGER', 'REAL', 'SIGNED', 'PARAMETER', 'LOCALPARAM', 'SUPPLY0', 'SUPPLY1', 'ASSIGN', 'ALWAYS', 'ALWAYS_FF', 'ALWAYS_COMB', 'ALWAYS_LATCH', 'SENS_OR', 'POSEDGE', 'NEGEDGE', 'INITIAL', diff --git a/pyverilog/vparser/parser.py b/pyverilog/vparser/parser.py index 0de0264..9ab45ab 100644 --- a/pyverilog/vparser/parser.py +++ b/pyverilog/vparser/parser.py @@ -2092,6 +2092,11 @@ def p_function(self, p): p.set_lineno(0, p.lineno(1)) p[0].end_lineno = p.lineno(6) + def p_function_automatic(self, p): + 'function : FUNCTION AUTOMATIC width ID SEMICOLON function_statement ENDFUNCTION' + p[0] = Function(p[4], p[3], p[6], automatic=True, lineno=p.lineno(1)) + p.set_lineno(0, p.lineno(1)) + def p_function_nowidth(self, p): 'function : FUNCTION ID SEMICOLON function_statement ENDFUNCTION' p[0] = Function(p[2], @@ -2102,6 +2107,15 @@ def p_function_nowidth(self, p): p.set_lineno(0, p.lineno(1)) p[0].end_lineno = p.lineno(5) + def p_function_automatic_nowidth(self, p): + 'function : FUNCTION AUTOMATIC ID SEMICOLON function_statement ENDFUNCTION' + p[0] = Function(p[3], + Width(IntConst('0', lineno=p.lineno(1)), + IntConst('0', lineno=p.lineno(1)), + lineno=p.lineno(1)), + p[5], automatic=True, 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' p[0] = Function(p[3], @@ -2112,6 +2126,15 @@ def p_function_integer(self, p): p.set_lineno(0, p.lineno(1)) p[0].end_lineno = p.lineno(6) + def p_function_integer_automatic(self, p): + 'function : FUNCTION AUTOMATIC INTEGER ID SEMICOLON function_statement ENDFUNCTION' + p[0] = Function(p[4], + Width(IntConst('31', lineno=p.lineno(1)), + IntConst('0', lineno=p.lineno(1)), + lineno=p.lineno(1)), + p[6], automatic=True, lineno=p.lineno(1)) + p.set_lineno(0, p.lineno(1)) + def p_function_statement(self, p): 'function_statement : funcvardecls function_calc' p[0] = p[1] + (p[2],) diff --git a/tests/ast_code_generator_test/test_read_write_automatic_function.py b/tests/ast_code_generator_test/test_read_write_automatic_function.py new file mode 100644 index 0000000..d2660ae --- /dev/null +++ b/tests/ast_code_generator_test/test_read_write_automatic_function.py @@ -0,0 +1,71 @@ +from __future__ import absolute_import +from __future__ import print_function +import os +import sys +from pyverilog.vparser.parser import VerilogCodeParser +from pyverilog.ast_code_generator.codegen import ASTCodeGenerator + +try: + from StringIO import StringIO +except: + from io import StringIO + +codedir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/verilogcode/' + +expected = """\ + + +module TOP +( + CLK, + RST_X +); + + input CLK; + input RST_X; + reg [3:0] cnt; + + function automatic [3:0] inc; + input [3:0] in; + begin + if(&inc) begin + inc = 0; + end else begin + inc = in + 1; + end + 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 + +""" + +def test(): + filelist = [codedir + 'automatic_function.v'] + output = 'preprocess.out' + include = None + define = None + + parser = VerilogCodeParser(filelist, + preprocess_include=include, + preprocess_define=define) + ast = parser.parse() + directives = parser.get_directives() + + codegen = ASTCodeGenerator() + rslt = codegen.visit(ast) + print(rslt) + assert(expected == rslt) + +if __name__ == '__main__': + test() diff --git a/tests/parser_test/test_automatic_function.py b/tests/parser_test/test_automatic_function.py new file mode 100644 index 0000000..4380b60 --- /dev/null +++ b/tests/parser_test/test_automatic_function.py @@ -0,0 +1,108 @@ +from __future__ import absolute_import +from __future__ import print_function +import os +import sys +from pyverilog.vparser.parser import VerilogCodeParser + +try: + from StringIO import StringIO +except: + from io import StringIO + +codedir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/verilogcode/' + +expected = """\ +Source: (at 1) + Description: (at 1) + ModuleDef: TOP (from 1 to 25) + Paramlist: (at 0) + Portlist: (at 1) + Port: CLK, None (at 1) + Port: RST_X, None (at 1) + Decl: (at 2) + Input: CLK, False (at 2) + Decl: (at 3) + Input: RST_X, False (at 3) + Decl: (at 4) + Reg: cnt, False (at 4) + Width: (at 4) + IntConst: 3 (at 4) + IntConst: 0 (at 4) + Function: inc (at 6) + Width: (at 6) + IntConst: 3 (at 6) + IntConst: 0 (at 6) + Decl: (at 7) + Input: in, False (at 7) + Width: (at 7) + IntConst: 3 (at 7) + IntConst: 0 (at 7) + Block: None (from 8 to 14) + IfStatement: (from 9 to 13) + Uand: (at 9) + Identifier: inc (at 9) + Block: None (from 9 to 11) + BlockingSubstitution: (from 10 to 10) + Lvalue: (at 10) + Identifier: inc (at 10) + Rvalue: (at 10) + IntConst: 0 (at 10) + Block: None (from 11 to 13) + BlockingSubstitution: (from 12 to 12) + Lvalue: (at 12) + Identifier: inc (at 12) + Rvalue: (at 12) + Plus: (at 12) + Identifier: in (at 12) + IntConst: 1 (at 12) + Always: (from 17 to 23) + SensList: (at 17) + Sens: posedge (at 17) + Identifier: CLK (at 17) + Sens: negedge (at 17) + Identifier: RST_X (at 17) + Block: None (from 17 to 23) + IfStatement: (from 18 to 22) + Ulnot: (at 18) + Identifier: RST_X (at 18) + Block: None (from 18 to 20) + NonblockingSubstitution: (from 19 to 19) + Lvalue: (at 19) + Identifier: cnt (at 19) + Rvalue: (at 19) + IntConst: 0 (at 19) + Block: None (from 20 to 22) + NonblockingSubstitution: (from 21 to 21) + Lvalue: (at 21) + Identifier: cnt (at 21) + Rvalue: (at 21) + FunctionCall: (at 21) + Identifier: inc (at 21) + Identifier: cnt (at 21) +""" + +def test(): + filelist = [codedir + 'automatic_function.v'] + output = 'preprocess.out' + include = None + define = None + + parser = VerilogCodeParser(filelist, + preprocess_include=include, + preprocess_define=define) + ast = parser.parse() + directives = parser.get_directives() + + output = StringIO() + ast.show(buf=output) + + for lineno, directive in directives: + output.write('Line %d : %s' % (lineno, directive)) + + rslt = output.getvalue() + + print(rslt) + assert(expected == rslt) + +if __name__ == '__main__': + test() diff --git a/verilogcode/automatic_function.v b/verilogcode/automatic_function.v new file mode 100644 index 0000000..5da640c --- /dev/null +++ b/verilogcode/automatic_function.v @@ -0,0 +1,25 @@ +module TOP(CLK, RST_X); + input CLK; + input RST_X; + reg [3:0] cnt; + + function automatic [3:0] inc; + input [3:0] in; + begin + if(&inc) begin + inc = 0; + end else begin + inc = in + 1; + end + 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