From e093a1117e38793e0c32b0c29fd6e8e70fb0c0ed Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 25 Feb 2024 16:18:56 +0000 Subject: [PATCH] Refactor parsing of Verilog port declarations --- src/vlog/Makemodule.am | 3 +- src/vlog/vlog-dump.c | 1 - src/vlog/vlog-lower.c | 40 +++++++----- src/vlog/vlog-node.c | 2 +- src/vlog/vlog-node.h | 3 +- src/vlog/vlog-parse.y | 145 ++++++++++++++++++++++++++--------------- src/vlog/vlog-sem.c | 52 ++++++++------- src/vlog/vlog-simp.c | 18 +++++ src/vlog/vlog-trans.c | 35 +++++++--- src/vlog/vlog-util.c | 34 ++++++++++ src/vlog/vlog-util.h | 25 +++++++ test/test_dump.c | 3 +- test/test_vlog.c | 16 +++-- test/vlog/ports.v | 26 ++++++++ 14 files changed, 289 insertions(+), 114 deletions(-) create mode 100644 src/vlog/vlog-util.c create mode 100644 src/vlog/vlog-util.h diff --git a/src/vlog/Makemodule.am b/src/vlog/Makemodule.am index 6218f0dc..059bf2d3 100644 --- a/src/vlog/Makemodule.am +++ b/src/vlog/Makemodule.am @@ -7,7 +7,8 @@ lib_libnvc_a_SOURCES += \ src/vlog/vlog-number.h \ src/vlog/vlog-number.c \ src/vlog/vlog-trans.c \ - src/vlog/vlog-simp.c + src/vlog/vlog-simp.c \ + src/vlog/vlog-util.c if ENABLE_VERILOG lib_libnvc_a_SOURCES += \ diff --git a/src/vlog/vlog-dump.c b/src/vlog/vlog-dump.c index d1d04264..e59fb7c2 100644 --- a/src/vlog/vlog-dump.c +++ b/src/vlog/vlog-dump.c @@ -64,7 +64,6 @@ static void vlog_dump_port_decl(vlog_node_t v, int indent) case V_PORT_INPUT: print_syntax("#input"); break; case V_PORT_INOUT: print_syntax("#inout"); break; case V_PORT_OUTPUT: print_syntax("#output"); break; - case V_PORT_OUTPUT_REG: print_syntax("#output #reg"); break; } print_syntax(" %s;\n", istr(vlog_ident(v))); diff --git a/src/vlog/vlog-lower.c b/src/vlog/vlog-lower.c index 49d81b04..18ccce8e 100644 --- a/src/vlog/vlog-lower.c +++ b/src/vlog/vlog-lower.c @@ -17,6 +17,7 @@ #include "util.h" #include "diag.h" +#include "hash.h" #include "lib.h" #include "lower.h" #include "tree.h" @@ -25,6 +26,7 @@ #include "vlog/vlog-node.h" #include "vlog/vlog-number.h" #include "vlog/vlog-phase.h" +#include "vlog/vlog-util.h" #include #include @@ -70,20 +72,6 @@ static vcode_reg_t vlog_debug_locus(vlog_node_t v) } #endif -static bool vlog_is_net(vlog_node_t v) -{ - switch (vlog_kind(v)) { - case V_NET_DECL: - return true; - case V_PORT_DECL: - return vlog_subkind(v) != V_PORT_OUTPUT_REG; - case V_REF: - return vlog_is_net(vlog_ref(v)); - default: - return false; - } -} - static vcode_reg_t vlog_helper_package(void) { return emit_link_package(ident_new("NVC.VERILOG")); @@ -236,6 +224,8 @@ static vcode_reg_t vlog_lower_lvalue(lower_unit_t *lu, vlog_node_t v) case V_REF: { vlog_node_t decl = vlog_ref(v); + if (vlog_kind(decl) == V_PORT_DECL) + decl = vlog_ref(decl); int hops; vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops); @@ -307,6 +297,8 @@ static vcode_reg_t vlog_lower_rvalue(lower_unit_t *lu, vlog_node_t v) case V_REF: { vlog_node_t decl = vlog_ref(v); + if (vlog_kind(decl) == V_PORT_DECL) + decl = vlog_ref(decl); int hops; vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops); @@ -888,14 +880,30 @@ vcode_unit_t vlog_lower(unit_registry_t *ur, vlog_node_t mod) vcode_type_t vlogicsignal = vtype_signal(vlogic); vcode_type_t vnetsignal = vtype_signal(vnetvalue); + const int nports = vlog_ports(mod); + for (int i = 0; i < nports; i++) { + vlog_node_t ref = vlog_port(mod, i); + assert(vlog_kind(ref) == V_REF); + + vlog_node_t port = vlog_ref(ref); + assert(vlog_kind(port) == V_PORT_DECL); + + vcode_type_t vtype = vlog_is_net(port) ? vnetsignal : vlogicsignal; + vcode_var_t var = emit_var(vtype, vtype, vlog_ident(port), VAR_SIGNAL); + + lower_put_vcode_obj(port, var, lu); + lower_put_vcode_obj(vlog_ref(port), var, lu); + } + const int ndecls = vlog_decls(mod); - for (int i = 0; i < ndecls; i++) { + for (int i = 0, hops; i < ndecls; i++) { vlog_node_t d = vlog_decl(mod, i); switch (vlog_kind(d)) { case V_PORT_DECL: + break; // Translated above case V_NET_DECL: case V_VAR_DECL: - { + if (lower_search_vcode_obj(d, lu, &hops) == VCODE_INVALID_VAR) { vcode_type_t vtype = vlog_is_net(d) ? vnetsignal : vlogicsignal; vcode_var_t var = emit_var(vtype, vtype, vlog_ident(d), VAR_SIGNAL); lower_put_vcode_obj(d, var, lu); diff --git a/src/vlog/vlog-node.c b/src/vlog/vlog-node.c index c92674f8..a8e49734 100644 --- a/src/vlog/vlog-node.c +++ b/src/vlog/vlog-node.c @@ -30,7 +30,7 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { (I_IDENT | I_PORTS | I_STMTS | I_DECLS | I_IDENT2), // V_PORT_DECL - (I_IDENT | I_SUBKIND | I_IDENT2 | I_RANGES), + (I_IDENT | I_SUBKIND | I_IDENT2 | I_REF), // V_REF (I_IDENT | I_REF), diff --git a/src/vlog/vlog-node.h b/src/vlog/vlog-node.h index 9c17545a..86d84b6c 100644 --- a/src/vlog/vlog-node.h +++ b/src/vlog/vlog-node.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2022 Nick Gasson +// Copyright (C) 2022-2024 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -29,7 +29,6 @@ typedef enum { typedef enum { V_PORT_INPUT, V_PORT_OUTPUT, - V_PORT_OUTPUT_REG, V_PORT_INOUT, } v_port_kind_t; diff --git a/src/vlog/vlog-parse.y b/src/vlog/vlog-parse.y index 34d6bfe7..0d44db8e 100644 --- a/src/vlog/vlog-parse.y +++ b/src/vlog/vlog-parse.y @@ -60,6 +60,7 @@ static void node_list_free(node_list_t *l); static void set_timescale(const char *unit_value, const char *unit_name, const char *prec_value, const char *prec_name, const loc_t *loc); +static void clone_port(node_list_t **list, vlog_node_t p); #define YYLLOC_DEFAULT(Current, Rhs, N) { \ if (N) { \ @@ -80,19 +81,28 @@ static vlog_node_t root; static void add_port(vlog_node_t module, vlog_node_t port) { - if (vlog_kind(port) == V_PORT_DECL) { - // Verilog-2001 style port declaration - vlog_node_t ref = vlog_new(V_REF); - vlog_set_loc(ref, vlog_loc(port)); - vlog_set_ident(ref, vlog_ident(port)); - vlog_set_ref(ref, port); - - vlog_add_port(module, ref); - vlog_add_decl(module, port); - } - else { - assert(vlog_kind(port) == V_REF); + switch (vlog_kind(port)) { + case V_PORT_DECL: + { + // Verilog-2001 style port declaration + vlog_node_t ref = vlog_new(V_REF); + vlog_set_loc(ref, vlog_loc(port)); + vlog_set_ident(ref, vlog_ident(port)); + vlog_set_ref(ref, port); + + vlog_add_port(module, ref); + vlog_add_decl(module, port); + } + break; + case V_REF: vlog_add_port(module, port); + break; + case V_NET_DECL: + case V_VAR_DECL: + vlog_add_decl(module, port); + break; + default: + fatal_trace("unexpected %s in port list", vlog_kind_str(vlog_kind(port))); } } @@ -123,12 +133,12 @@ static vlog_node_t make_strength(vlog_strength_t value, const loc_t *loc) %type procedural_timing_control_statement %type lvalue event_control event_expression %type nonblocking_assignment delay_or_event_control -%type port_declaration port_reference blocking_assignment +%type port_reference blocking_assignment %type port initial_construct net_assignment %type seq_block system_task_enable string number %type decimal_number conditional_statement variable_type %type delay_control delay_value strength0 strength1 -%type pull_gate_instance +%type pull_gate_instance port_identifier %type identifier hierarchical_identifier %type module_item_list module_port_list_opt module_item %type list_of_port_declarations module_item_list_opt @@ -139,6 +149,7 @@ static vlog_node_t make_strength(vlog_strength_t value, const loc_t *loc) %type list_of_net_assignments reg_declaration %type list_of_variable_identifiers list_of_statements_opt %type gate_instantiation pulldown_strength pullup_strength +%type port_declaration port_declaration_head %type external_identifier %type net_type @@ -251,59 +262,68 @@ port_reference: identifier } ; -list_of_port_declarations: - list_of_port_declarations ',' external_identifier +port_identifier: + external_identifier { - vlog_node_t p = vlog_new(V_PORT_DECL); - vlog_set_loc(p, &@3); - vlog_set_ident(p, $3.left); - vlog_set_ident2(p, $3.right); - vlog_set_subkind(p, vlog_subkind($1->tail->value)); + $$ = vlog_new(V_PORT_DECL); + vlog_set_loc($$, &@1); + vlog_set_ident($$, $1.left); + vlog_set_ident2($$, $1.right); + } + ; +list_of_port_declarations: + list_of_port_declarations ',' port_declaration_head + { $$ = $1; - node_list_append(&$$, p); + node_list_concat(&$$, $3); } - | list_of_port_declarations ',' port_declaration + | list_of_port_declarations ',' port_identifier { $$ = $1; - node_list_append(&$$, $3); + clone_port(&$$, $3); } - | port_declaration { $$ = node_list_single($1); } + | port_declaration_head { $$ = $1; } ; -port_declaration: - tINPUT external_identifier +port_declaration_head: + tINPUT port_identifier { - $$ = vlog_new(V_PORT_DECL); - vlog_set_loc($$, &@$); - vlog_set_ident($$, $2.left); - vlog_set_ident2($$, $2.right); - vlog_set_subkind($$, V_PORT_INPUT); + vlog_set_subkind($2, V_PORT_INPUT); + $$ = node_list_single($2); } - | tOUTPUT external_identifier + | tOUTPUT port_identifier { - $$ = vlog_new(V_PORT_DECL); - vlog_set_loc($$, &@$); - vlog_set_ident($$, $2.left); - vlog_set_ident2($$, $2.right); - vlog_set_subkind($$, V_PORT_OUTPUT); + vlog_set_subkind($2, V_PORT_OUTPUT); + $$ = node_list_single($2); } - | tINOUT external_identifier + | tINOUT port_identifier { - $$ = vlog_new(V_PORT_DECL); - vlog_set_loc($$, &@$); - vlog_set_ident($$, $2.left); - vlog_set_ident2($$, $2.right); - vlog_set_subkind($$, V_PORT_INOUT); + vlog_set_subkind($2, V_PORT_INOUT); + $$ = node_list_single($2); } - | tOUTPUT tREG external_identifier + | tOUTPUT tREG port_identifier { - $$ = vlog_new(V_PORT_DECL); - vlog_set_loc($$, &@$); - vlog_set_ident($$, $3.left); - vlog_set_ident2($$, $3.right); - vlog_set_subkind($$, V_PORT_OUTPUT_REG); + vlog_set_subkind($3, V_PORT_OUTPUT); + + $$ = NULL; + node_list_append(&$$, $3); + + vlog_node_t reg = vlog_new(V_VAR_DECL); + vlog_set_loc(reg, &@$); + vlog_set_ident(reg, vlog_ident($3)); + + node_list_append(&$$, reg); + } + ; + +port_declaration: + port_declaration_head ',' port_identifier + { + $$ = $1; + clone_port(&$$, $3); } + | port_declaration_head ; module_item_list_opt: @@ -323,10 +343,6 @@ module_item_list: module_item: module_or_generate_item | port_declaration ';' - { - $$ = NULL; - node_list_append(&$$, $1); - } ; module_or_generate_item: @@ -982,6 +998,27 @@ static void set_timescale(const char *unit_value, const char *unit_name, // TODO: do something with parsed scale/precision } +static void clone_port(node_list_t **list, vlog_node_t p) +{ + node_list_t *last = NULL; + for (node_list_t *it = *list; it != NULL; it = it->next) { + if (vlog_kind(it->value) == V_PORT_DECL) + last = it; + } + + vlog_set_subkind(p, vlog_subkind(last->value)); + + node_list_append(list, p); + + if (last->next && vlog_kind(last->next->value) == V_VAR_DECL) { + vlog_node_t reg = vlog_new(V_VAR_DECL); + vlog_set_loc(reg, vlog_loc(p)); + vlog_set_ident(reg, vlog_ident(p)); + + node_list_append(list, reg); + } +} + vlog_node_t vlog_parse(void) { make_new_arena(); diff --git a/src/vlog/vlog-sem.c b/src/vlog/vlog-sem.c index 5d6d4da5..5733d90e 100644 --- a/src/vlog/vlog-sem.c +++ b/src/vlog/vlog-sem.c @@ -17,11 +17,12 @@ #include "util.h" #include "common.h" +#include "diag.h" #include "hash.h" #include "ident.h" -#include "diag.h" #include "vlog/vlog-node.h" #include "vlog/vlog-phase.h" +#include "vlog/vlog-util.h" #include #include @@ -35,26 +36,6 @@ struct _vlog_scope { static vlog_scope_t *top_scope = NULL; -static bool is_net(vlog_node_t v) -{ - switch (vlog_kind(v)) { - case V_REF: - if (vlog_has_ref(v)) { - vlog_node_t decl = vlog_ref(v); - switch (vlog_kind(decl)) { - case V_NET_DECL: return true; - case V_PORT_DECL: return vlog_subkind(decl) != V_PORT_OUTPUT_REG; - default: return false; - } - } - else - return false; - - default: - return false; - } -} - static void name_for_diag(diag_t *d, vlog_node_t v, const char *alt) { switch (vlog_kind(v)) { @@ -141,7 +122,7 @@ static void vlog_check_unary(vlog_node_t op) static void vlog_check_variable_target(vlog_node_t target) { - if (is_net(target)) { + if (vlog_is_net(target)) { diag_t *d = diag_new(DIAG_ERROR, vlog_loc(target)); name_for_diag(d, target, "target"); diag_printf(d, " cannot be assigned in a procedural block"); @@ -179,7 +160,7 @@ static void vlog_check_assign(vlog_node_t stmt) vlog_node_t value = vlog_value(stmt); vlog_check(value); - if (!is_net(target)) { + if (!vlog_is_net(target)) { diag_t *d = diag_new(DIAG_ERROR, vlog_loc(target)); name_for_diag(d, target, "target"); diag_printf(d, " cannot be driven by continuous assignment"); @@ -268,17 +249,38 @@ static void vlog_check_if(vlog_node_t stmt) static void vlog_check_port_decl(vlog_node_t port) { + ident_t id = vlog_ident(port); + vlog_node_t exist = hash_get(top_scope->symbols, id); + if (exist != NULL) { + const vlog_kind_t kind = vlog_kind(exist); + if (kind == V_VAR_DECL || kind == V_NET_DECL) { + vlog_set_ref(port, exist); + hash_put(top_scope->symbols, id, port); + return; + } + } + vlog_insert_decl(port); } static void vlog_check_net_decl(vlog_node_t net) { - vlog_insert_decl(net); + vlog_node_t exist = hash_get(top_scope->symbols, vlog_ident(net)); + if (exist != NULL && vlog_kind(exist) == V_PORT_DECL + && !vlog_has_ref(exist)) + vlog_set_ref(exist, net); + else + vlog_insert_decl(net); } static void vlog_check_var_decl(vlog_node_t var) { - vlog_insert_decl(var); + vlog_node_t exist = hash_get(top_scope->symbols, vlog_ident(var)); + if (exist != NULL && vlog_kind(exist) == V_PORT_DECL + && !vlog_has_ref(exist)) + vlog_set_ref(exist, var); + else + vlog_insert_decl(var); } static void vlog_check_module(vlog_node_t module) diff --git a/src/vlog/vlog-simp.c b/src/vlog/vlog-simp.c index 48854d82..2ddb40a5 100644 --- a/src/vlog/vlog-simp.c +++ b/src/vlog/vlog-simp.c @@ -62,11 +62,29 @@ static vlog_node_t simp_net_decl(vlog_node_t decl, vlog_node_t mod) return decl; } +static vlog_node_t simp_port_decl(vlog_node_t decl, vlog_node_t mod) +{ + if (vlog_has_ref(decl)) + return decl; + + vlog_node_t wire = vlog_new(V_NET_DECL); + vlog_set_subkind(wire, V_NET_WIRE); + vlog_set_loc(wire, vlog_loc(decl)); + vlog_set_ident(wire, vlog_ident(decl)); + + vlog_set_ref(decl, wire); + vlog_add_decl(mod, wire); + + return decl; +} + static vlog_node_t vlog_simp_cb(vlog_node_t v, void *context) { switch (vlog_kind(v)) { case V_NET_DECL: return simp_net_decl(v, context); + case V_PORT_DECL: + return simp_port_decl(v, context); default: return v; } diff --git a/src/vlog/vlog-trans.c b/src/vlog/vlog-trans.c index 3b48e506..a6b132e0 100644 --- a/src/vlog/vlog-trans.c +++ b/src/vlog/vlog-trans.c @@ -17,12 +17,14 @@ #include "util.h" #include "common.h" +#include "hash.h" #include "tree.h" #include "type.h" #include "vlog/vlog-defs.h" #include "vlog/vlog-node.h" #include "vlog/vlog-number.h" #include "vlog/vlog-phase.h" +#include "vlog/vlog-util.h" #include @@ -107,7 +109,6 @@ static void trans_port_decl(vlog_node_t decl, tree_t out) static const port_mode_t map[] = { [V_PORT_INPUT] = PORT_IN, [V_PORT_OUTPUT] = PORT_OUT, - [V_PORT_OUTPUT_REG] = PORT_OUT, [V_PORT_INOUT] = PORT_INOUT, }; @@ -118,10 +119,11 @@ static void trans_port_decl(vlog_node_t decl, tree_t out) tree_set_subkind(t, map[kind]); tree_set_class(t, C_SIGNAL); - if (kind == V_PORT_OUTPUT_REG) - tree_set_type(t, trans_var_type(decl)); + vlog_node_t net = vlog_ref(decl); + if (vlog_is_net(net)) + tree_set_type(t, trans_net_type(net)); else - tree_set_type(t, trans_net_type(decl)); + tree_set_type(t, trans_var_type(net)); tree_add_port(out, t); } @@ -157,18 +159,33 @@ static void trans_net_decl(vlog_node_t decl, tree_t out) void vlog_trans(vlog_node_t mod, tree_t out) { + hset_t *ports = hset_new(16); + const int nports = vlog_ports(mod); + for (int i = 0; i < nports; i++) { + vlog_node_t ref = vlog_port(mod, i); + assert(vlog_kind(ref) == V_REF); + + vlog_node_t port = vlog_ref(ref); + assert(vlog_kind(port) == V_PORT_DECL); + trans_port_decl(port, out); + + // Do not translate the associated var/net declaration twice + hset_insert(ports, vlog_ref(port)); + } + const int ndecls = vlog_decls(mod); for (int i = 0; i < ndecls; i++) { vlog_node_t d = vlog_decl(mod, i); switch (vlog_kind(d)) { case V_PORT_DECL: - trans_port_decl(d, out); - break; + break; // Translated above case V_VAR_DECL: - trans_var_decl(d, out); + if (!hset_contains(ports, d)) + trans_var_decl(d, out); break; case V_NET_DECL: - trans_net_decl(d, out); + if (!hset_contains(ports, d)) + trans_net_decl(d, out); break; default: CANNOT_HANDLE(d); @@ -186,4 +203,6 @@ void vlog_trans(vlog_node_t mod, tree_t out) tree_add_stmt(out, w); } + + hset_free(ports); } diff --git a/src/vlog/vlog-util.c b/src/vlog/vlog-util.c new file mode 100644 index 00000000..08657510 --- /dev/null +++ b/src/vlog/vlog-util.c @@ -0,0 +1,34 @@ +// +// Copyright (C) 2024 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "util.h" +#include "vlog/vlog-node.h" +#include "vlog/vlog-util.h" + +bool vlog_is_net(vlog_node_t v) +{ + switch (vlog_kind(v)) { + case V_REF: + return vlog_has_ref(v) ? vlog_is_net(vlog_ref(v)) : false; + case V_PORT_DECL: + return vlog_has_ref(v) ? vlog_is_net(vlog_ref(v)) : true; + case V_NET_DECL: + return true; + default: + return false; + } +} diff --git a/src/vlog/vlog-util.h b/src/vlog/vlog-util.h new file mode 100644 index 00000000..77b2fc18 --- /dev/null +++ b/src/vlog/vlog-util.h @@ -0,0 +1,25 @@ +// +// Copyright (C) 2024 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef _VLOG_UTIL_H +#define _VLOG_UTIL_H + +#include "prim.h" + +bool vlog_is_net(vlog_node_t v); + +#endif // _VLOG_UTIL_H diff --git a/test/test_dump.c b/test/test_dump.c index f167f1a4..971ba22a 100644 --- a/test/test_dump.c +++ b/test/test_dump.c @@ -462,7 +462,8 @@ START_TEST(test_vlog1) " input d;\n" " input clk;\n" " input rstb;\n" - " output reg q;\n" + " output q;\n" + " reg q;\n" " always @(posedge clk) q <= d;\n" "endmodule // dff\n\n"); tb_rewind(tb); diff --git a/test/test_vlog.c b/test/test_vlog.c index e9e7ed05..66b55b31 100644 --- a/test/test_vlog.c +++ b/test/test_vlog.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2022 Nick Gasson +// Copyright (C) 2022-2024 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ START_TEST(test_dff) fail_unless(vlog_kind(m) == V_MODULE); fail_unless(vlog_stmts(m) == 1); fail_unless(vlog_ports(m) == 4); - fail_unless(vlog_decls(m) == 4); + fail_unless(vlog_decls(m) == 5); vlog_node_t p0 = vlog_port(m, 0); fail_unless(vlog_kind(p0) == V_REF); @@ -64,10 +64,14 @@ START_TEST(test_dff) vlog_node_t d3 = vlog_decl(m, 3); fail_unless(vlog_kind(d3) == V_PORT_DECL); - fail_unless(vlog_subkind(d3) == V_PORT_OUTPUT_REG); + fail_unless(vlog_subkind(d3) == V_PORT_OUTPUT); fail_unless(vlog_ident(d3) == ident_new("q")); fail_unless(vlog_ident2(d3) == ident_new("Q")); + vlog_node_t d4 = vlog_decl(m, 4); + fail_unless(vlog_kind(d4) == V_VAR_DECL); + fail_unless(vlog_ident(d4) == ident_new("q")); + vlog_node_t a = vlog_stmt(m, 0); fail_unless(vlog_kind(a) == V_ALWAYS); fail_unless(vlog_stmts(a) == 1); @@ -129,14 +133,16 @@ START_TEST(test_ports) { const error_t expect[] = { { 4, "duplicate declaration of y" }, - { 1, "no visible declaration for z" }, + { 19, "duplicate declaration of x" }, + { 22, "duplicate declaration of y" }, + { 31, "'o3' cannot be assigned in a procedural block" }, { -1, NULL } }; expect_errors(expect); input_from_file(TESTDIR "/vlog/ports.v"); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 5; i++) { vlog_node_t m = vlog_parse(); fail_if(m == NULL); fail_unless(vlog_kind(m) == V_MODULE); diff --git a/test/vlog/ports.v b/test/vlog/ports.v index 8e75e759..c3c6b313 100644 --- a/test/vlog/ports.v +++ b/test/vlog/ports.v @@ -2,6 +2,8 @@ module ports1 (x, y, z, y); // Error input x; output reg y; output y; // Error + output z; + reg z; // OK endmodule module ports2 (x, y, z); @@ -10,3 +12,27 @@ module ports2 (x, y, z); output reg y; inout z; // OK endmodule // ports2 + +module ports3 (x, y, z); + reg x; + output x; + output x; // Error + input y; + reg y; + reg y; // Error + input z; + wire z; +endmodule // ports3 + +module ports4 (input i0, i1, output reg o1, o2, output o3); + initial begin + o1 = 1; + o2 = 0; + o3 = 1; // Error + end +endmodule // ports4 + +module ports5 (x, y, z); + input x, y; // OK + output reg z; +endmodule // ports5 -- 2.39.2