diff --git a/src/lexer.l b/src/lexer.l index bff25f7db..8d39418d5 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -681,6 +681,10 @@ BEFORE ?i:before "while" { return tWHILE; } "repeat" { return tREPEAT; } "do" { return tDO; } +"task" { return tTASK; } +"endtask" { return tENDTASK; } +"function" { return tFUNCTION; } +"endfunction" { return tENDFUNCTION; } {SYSTASK} { yylval.str = xstrdup(yytext); return tSYSTASK; } {VLOG_ID} { yylval.str = xstrdup(yytext); return tID; } diff --git a/src/scan.c b/src/scan.c index 090fee577..c9095d5ec 100644 --- a/src/scan.c +++ b/src/scan.c @@ -248,7 +248,8 @@ const char *token_str(token_t tok) "shortint", "longint", "int", "integer", "time", "typedef", "logic", "enum", "tagged", "abort", "sync_abort", "async_abort", "before", "before!", "before_", "before!_", "|->", "|=>", "next", "inf", - "repeat", "do", "endpoint", "<<", ">>", "<<<", ">>>", + "repeat", "do", "endpoint", "<<", ">>", "<<<", ">>>", "task", + "endtask", "endfunction", }; if (tok >= 200 && tok - 200 < ARRAY_LEN(token_strs)) diff --git a/src/scan.h b/src/scan.h index 00b9125e0..96d479d6c 100644 --- a/src/scan.h +++ b/src/scan.h @@ -411,5 +411,8 @@ bool is_scanned_as_psl(void); #define tSHIFTRL 511 #define tSHIFTLA 512 #define tSHIFTRA 513 +#define tTASK 514 +#define tENDTASK 515 +#define tENDFUNCTION 516 #endif // _SCAN_H diff --git a/src/vlog/vlog-node.c b/src/vlog/vlog-node.c index f22e929ff..7c07ed36f 100644 --- a/src/vlog/vlog-node.c +++ b/src/vlog/vlog-node.c @@ -153,6 +153,12 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { // V_DO_WHILE (I_VALUE | I_STMTS), + + // V_TASK_DECL + (I_IDENT | I_STMTS | I_DECLS), + + // V_FUNC_DECL + (I_IDENT | I_STMTS | I_DECLS | I_TYPE), }; static const char *kind_text_map[V_LAST_NODE_KIND] = { @@ -166,7 +172,8 @@ static const char *kind_text_map[V_LAST_NODE_KIND] = { "V_SPECIFY", "V_PRIMITIVE", "V_UDP_TABLE", "V_UDP_ENTRY", "V_DATA_TYPE", "V_TYPE_DECL", "V_ENUM_DECL", "V_ENUM_NAME", "V_UNION_DECL", "V_STRUCT_DECL", "V_EVENT_CONTROL", "V_EMPTY", - "V_REPEAT", "V_WHILE", "V_DO_WHILE", + "V_REPEAT", "V_WHILE", "V_DO_WHILE", "V_TASK_DECL", + "V_FUNC_DECL", }; static const change_allowed_t change_allowed[] = { diff --git a/src/vlog/vlog-node.h b/src/vlog/vlog-node.h index 64c78943e..e7e999f25 100644 --- a/src/vlog/vlog-node.h +++ b/src/vlog/vlog-node.h @@ -87,6 +87,8 @@ typedef enum { V_REPEAT, V_WHILE, V_DO_WHILE, + V_TASK_DECL, + V_FUNC_DECL, V_LAST_NODE_KIND } vlog_kind_t; diff --git a/src/vlog/vlog-parse.c b/src/vlog/vlog-parse.c index 756f25fd7..88d322ae0 100644 --- a/src/vlog/vlog-parse.c +++ b/src/vlog/vlog-parse.c @@ -870,7 +870,7 @@ static vlog_node_t p_data_type_or_implicit(void) BEGIN("data type or implicit"); - if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT)) + if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tLOGIC)) return p_data_type(); else return p_implicit_data_type(); @@ -2002,6 +2002,171 @@ static void p_data_declaration(vlog_node_t mod) } } +static v_port_kind_t p_port_direction(void) +{ + // input | output | inout | ref + + BEGIN("port direction"); + + switch (one_of(tINPUT, tOUTPUT, tINOUT)) { + case tINPUT: return V_PORT_INPUT; + case tOUTPUT: return V_PORT_OUTPUT; + case tINOUT: return V_PORT_INOUT; + default: return V_PORT_INPUT; + } +} + +static v_port_kind_t p_tf_port_direction(void) +{ + // port_direction | const ref + + BEGIN("task or function port direction"); + + return p_port_direction(); +} + +static vlog_node_t p_tf_port_item(void) +{ + // { attribute_instance } [ tf_port_direction ] [ var ] + // data_type_or_implicit [ port_identifier { variable_dimension } + // [ = expression ] ] + + BEGIN("task or function port item"); + + vlog_node_t v = vlog_new(V_PORT_DECL); + + if (scan(tINPUT, tOUTPUT)) + vlog_set_subkind(v, p_tf_port_direction()); + else + vlog_set_subkind(v, V_PORT_INPUT); + + vlog_set_type(v, p_data_type_or_implicit()); + + if (peek() == tID) { + vlog_set_ident(v, p_identifier()); + + if (optional(tEQ)) + vlog_set_value(v, p_expression()); + } + + vlog_set_loc(v, CURRENT_LOC); + return v; +} + +static void p_tf_port_list(vlog_node_t tf) +{ + // tf_port_item { , tf_port_item } + + BEGIN("task or function port list"); + + do { + p_tf_port_item(); + } while (optional(tCOMMA)); +} + +static void p_task_body_declaration(vlog_node_t task) +{ + // [ interface_identifier . | class_scope ] task_identifier ; + // { tf_item_declaration } { statement_or_null } + // endtask [ : task_identifier ] + // | [ interface_identifier . | class_scope ] task_identifier + // ( [ tf_port_list ] ) ; { block_item_declaration } + // { statement_or_null } endtask [ : task_identifier ] + + BEGIN("task body declaration"); + + ident_t id = p_identifier(); + vlog_set_ident(task, id); + + if (optional(tLPAREN)) { + p_tf_port_list(task); + consume(tRPAREN); + } + + consume(tSEMI); + + while (not_at_token(tENDTASK)) { + vlog_node_t s = p_statement_or_null(); + if (s != NULL) + vlog_add_stmt(task, s); + } + + consume(tENDTASK); +} + +static vlog_node_t p_task_declaration(void) +{ + // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration + + BEGIN("task declaration"); + + vlog_node_t v = vlog_new(V_TASK_DECL); + + consume(tTASK); + + p_task_body_declaration(v); + + vlog_set_loc(v, CURRENT_LOC); + return v; +} + +static vlog_node_t p_function_data_type_or_implicit(void) +{ + // data_type_or_void | implicit_data_type + + BEGIN("function data type or implicit"); + + return p_implicit_data_type(); +} + +static void p_function_body_declaration(vlog_node_t func) +{ + // function_data_type_or_implicit [ interface_identifier . | class_scope ] + // function_identifier ; { tf_item_declaration } + // { function_statement_or_null } endfunction [ : function_identifier ] + // | function_data_type_or_implicit [ interface_identifier . | class_scope ] + // function_identifier ( [ tf_port_list ] ) ; { block_item_declaration } + // { function_statement_or_null } endfunction [ : function_identifier ] + + BEGIN("function body declaration"); + + vlog_set_type(func, p_function_data_type_or_implicit()); + + ident_t id = p_identifier(); + vlog_set_ident(func, id); + + if (optional(tLPAREN)) { + p_tf_port_list(func); + consume(tRPAREN); + } + + consume(tSEMI); + + while (not_at_token(tENDFUNCTION)) { + vlog_node_t s = p_statement_or_null(); + if (s != NULL) + vlog_add_stmt(func, s); + } + + consume(tENDFUNCTION); +} + +static vlog_node_t p_function_declaration(void) +{ + // function [ lifetime ] function_body_declaration + + BEGIN("function declaration"); + + vlog_node_t v = vlog_new(V_FUNC_DECL); + + consume(tFUNCTION); + + p_function_body_declaration(v); + + vlog_set_loc(v, CURRENT_LOC); + return v; +} + static void p_package_or_generate_item_declaration(vlog_node_t mod) { // net_declaration | data_declaration | task_declaration @@ -2027,9 +2192,15 @@ static void p_package_or_generate_item_declaration(vlog_node_t mod) case tSVINT: p_data_declaration(mod); break; + case tTASK: + vlog_add_decl(mod, p_task_declaration()); + break; + case tFUNCTION: + vlog_add_decl(mod, p_function_declaration()); + break; default: one_of(tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION, tTYPEDEF, - tENUM, tSVINT); + tENUM, tSVINT, tTASK, tFUNCTION); drop_tokens_until(tSEMI); break; } @@ -2073,6 +2244,8 @@ static void p_module_common_item(vlog_node_t mod) case tTYPEDEF: case tENUM: case tSVINT: + case tTASK: + case tFUNCTION: p_module_or_generate_item_declaration(mod); break; case tASSIGN: @@ -2080,7 +2253,7 @@ static void p_module_common_item(vlog_node_t mod) break; default: one_of(tALWAYS, tINITIAL, tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, - tUNION, tTYPEDEF, tENUM, tSVINT, tASSIGN); + tUNION, tTYPEDEF, tENUM, tSVINT, tTASK, tFUNCTION, tASSIGN); drop_tokens_until(tSEMI); } } @@ -2541,6 +2714,8 @@ static void p_module_or_generate_item(vlog_node_t mod) case tTYPEDEF: case tENUM: case tSVINT: + case tTASK: + case tFUNCTION: p_module_common_item(mod); break; case tPULLDOWN: @@ -2560,8 +2735,8 @@ static void p_module_or_generate_item(vlog_node_t mod) break; default: one_of(tALWAYS, tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION, tASSIGN, - tINITIAL, tTYPEDEF, tENUM, tSVINT, tPULLDOWN, tPULLUP, tID, tAND, - tNAND, tOR, tNOR, tXOR, tXNOR, tNOT, tBUF); + tINITIAL, tTYPEDEF, tENUM, tSVINT, tTASK, tFUNCTION, tPULLDOWN, + tPULLUP, tID, tAND, tNAND, tOR, tNOR, tXOR, tXNOR, tNOT, tBUF); drop_tokens_until(tSEMI); } } @@ -2599,6 +2774,8 @@ static void p_non_port_module_item(vlog_node_t mod) case tTYPEDEF: case tENUM: case tSVINT: + case tTASK: + case tFUNCTION: p_module_or_generate_item(mod); break; case tSPECIFY: @@ -2608,7 +2785,7 @@ static void p_non_port_module_item(vlog_node_t mod) one_of(tALWAYS, tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION, tASSIGN, tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR, tXNOR, tNOT, tBUF, tTYPEDEF, tENUM, tSVINT, - tSPECIFY); + tTASK, tFUNCTION, tSPECIFY); drop_tokens_until(tSEMI); } } diff --git a/test/test_vlog.c b/test/test_vlog.c index 821cfcffc..738cb2a70 100644 --- a/test/test_vlog.c +++ b/test/test_vlog.c @@ -171,7 +171,7 @@ START_TEST(test_parse1) fail_unless(vlog_kind(m) == V_MODULE); fail_unless(vlog_stmts(m) == 11); fail_unless(vlog_ports(m) == 0); - fail_unless(vlog_decls(m) == 6); + fail_unless(vlog_decls(m) == 9); vlog_node_t x = vlog_decl(m, 0); fail_unless(vlog_kind(x) == V_NET_DECL); diff --git a/test/vlog/parse1.v b/test/vlog/parse1.v index bb33f68c5..0a44d2b85 100644 --- a/test/vlog/parse1.v +++ b/test/vlog/parse1.v @@ -35,4 +35,13 @@ module parse1; end int r1 = 5; wire w1 = 0; + task task1; + @(x) y = 2; + endtask // task1 + task task2(input int x, output logic y); + y = !x; + endtask // task2 + function sum(input int a, b); + sum = a + b; + endfunction // sum endmodule // parse1