From 2b9c75f8e372f6886e073743d1df11bcd1c58281 Mon Sep 17 00:00:00 2001 From: Udi Finkelstein Date: Fri, 9 Mar 2018 10:35:33 +0200 Subject: [PATCH 1/3] This PR should be the base for discussion, do not merge it yet! It correctly detects reg/wire mix and incorrect use on blocking,nonblocking assignments within blocks and assign statements. What it DOES'T do: Detect registers connected to output ports of instances. Where it FAILS: memorty nonblocking assignments causes spurious (I assume??) errors on yosys-generated "_ADDR", "_DATA", "EN" signals. You can test it with tests/simple/reg_wire_error.v (look inside for the comments to enable/disable specific lines) --- frontends/ast/ast.cc | 7 +++++- frontends/ast/ast.h | 2 +- frontends/ast/simplify.cc | 10 ++++++++ frontends/verilog/verilog_lexer.l | 2 +- frontends/verilog/verilog_parser.y | 6 ++++- tests/simple/reg_wire_error.v | 40 ++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 tests/simple/reg_wire_error.v diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 037a9f3ee..25267775a 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -191,6 +191,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch is_input = false; is_output = false; is_reg = false; + is_logic = false; is_signed = false; is_string = false; range_valid = false; @@ -285,7 +286,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const fprintf(f, " input"); if (is_output) fprintf(f, " output"); - if (is_reg) + if (is_logic) + fprintf(f, " logic"); + if (is_reg) // this is an AST dump, not Verilog - if we see "logic reg" that's fine. fprintf(f, " reg"); if (is_signed) fprintf(f, " signed"); @@ -652,6 +655,8 @@ bool AstNode::operator==(const AstNode &other) const return false; if (is_output != other.is_output) return false; + if (is_logic != other.is_logic) + return false; if (is_reg != other.is_reg) return false; if (is_signed != other.is_signed) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index d1e2c78d1..9b7124934 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -168,7 +168,7 @@ namespace AST // node content - most of it is unused in most node types std::string str; std::vector bits; - bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped; + bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped; int port_id, range_left, range_right; uint32_t integer; double realvalue; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index a16fdfeeb..c9c5e5263 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -327,6 +327,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (node->type == AST_WIRE) { if (this_wire_scope.count(node->str) > 0) { AstNode *first_node = this_wire_scope[node->str]; + if (first_node->is_input && node->is_reg) + goto wires_are_incompatible; if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0) goto wires_are_compatible; if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) { @@ -361,6 +363,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, first_node->is_output = true; if (node->is_reg) first_node->is_reg = true; + if (node->is_logic) + first_node->is_logic = true; if (node->is_signed) first_node->is_signed = true; for (auto &it : node->attributes) { @@ -440,6 +444,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children[1]->detectSignWidth(width_hint, sign_hint); width_hint = max(width_hint, backup_width_hint); child_0_is_self_determined = true; + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic) + children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) + log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); + if (type == AST_ASSIGN && children[0]->id2ast->is_reg) + log_error("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); break; case AST_PARAMETER: diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index d6d00c371..8aa123e1e 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -189,7 +189,7 @@ YOSYS_NAMESPACE_END "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } -"logic" { SV_KEYWORD(TOK_REG); } +"logic" { SV_KEYWORD(TOK_LOGIC); } "bit" { SV_KEYWORD(TOK_REG); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index ba2fc036e..722febf13 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -105,7 +105,7 @@ static void free_attr(std::map *al) %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP -%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG +%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC @@ -394,6 +394,9 @@ wire_type_token: TOK_REG { astbuf3->is_reg = true; } | + TOK_LOGIC { + astbuf3->is_logic = true; + } | TOK_INTEGER { astbuf3->is_reg = true; astbuf3->range_left = 31; @@ -827,6 +830,7 @@ wire_name: node->port_id = current_function_or_task_port_id++; } ast_stack.back()->children.push_back(node); + delete $1; }; diff --git a/tests/simple/reg_wire_error.v b/tests/simple/reg_wire_error.v new file mode 100644 index 000000000..ab461b95a --- /dev/null +++ b/tests/simple/reg_wire_error.v @@ -0,0 +1,40 @@ +module sub_mod(input i_in, output o_out); +assign o_out = i_in; +endmodule + +module test(i_clk, i_reg, o_reg, o_wire); +input i_clk; +input i_reg; +output o_reg; +output o_wire; + +// Enable this to see how it doesn't fail on yosys although it should +//reg o_wire; +// Enable this instead of the above to see how logic can be mapped to a wire +logic o_wire; +// Enable this to see how it doesn't fail on yosys although it should +//reg i_reg; +// Disable this to see how it doesn't fail on yosys although it should +reg o_reg; + +logic l_reg; + +// Enable this to tst if logic-turne-reg will catch assignments even if done before it turned into a reg +//assign l_reg = !o_reg; +initial o_reg = 1'b0; +always @(posedge i_clk) +begin + o_reg <= !o_reg; + l_reg <= !o_reg; +end + +assign o_wire = !o_reg; +// Uncomment this to see how a logic already turned intoa reg can be freely assigned on yosys +//assign l_reg = !o_reg; + +sub_mod sm_inst ( + .i_in(1'b1), + .o_out(o_reg) +); +endmodule + From 80d9d15f1c4b73ee73172b06fd2c8c55703aea54 Mon Sep 17 00:00:00 2001 From: Udi Finkelstein Date: Tue, 5 Jun 2018 12:15:59 +0300 Subject: [PATCH 2/3] reg_wire_error test needs the -sv flag so it is run via a script so it had to be moved out of the tests/simple dir that only runs Verilog files --- tests/{simple/reg_wire_error.v => various/reg_wire_error.sv} | 0 tests/various/reg_wire_error.ys | 1 + 2 files changed, 1 insertion(+) rename tests/{simple/reg_wire_error.v => various/reg_wire_error.sv} (100%) create mode 100644 tests/various/reg_wire_error.ys diff --git a/tests/simple/reg_wire_error.v b/tests/various/reg_wire_error.sv similarity index 100% rename from tests/simple/reg_wire_error.v rename to tests/various/reg_wire_error.sv diff --git a/tests/various/reg_wire_error.ys b/tests/various/reg_wire_error.ys new file mode 100644 index 000000000..b9d03155d --- /dev/null +++ b/tests/various/reg_wire_error.ys @@ -0,0 +1 @@ +read_verilog -sv reg_wire_error.sv From 73d426bc879087ca522ca595a8ba921b647fae27 Mon Sep 17 00:00:00 2001 From: Udi Finkelstein Date: Tue, 5 Jun 2018 17:44:24 +0300 Subject: [PATCH 3/3] Modified errors into warnings No longer false warnings for memories and assertions --- frontends/ast/ast.cc | 1 + frontends/ast/ast.h | 2 +- frontends/ast/simplify.cc | 44 ++++++++++++++++++++++++++---- frontends/verilog/verilog_parser.y | 1 + tests/various/reg_wire_error.sv | 42 +++++++++++++++++++++++++--- 5 files changed, 79 insertions(+), 11 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 25267775a..b8f25e53e 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -194,6 +194,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch is_logic = false; is_signed = false; is_string = false; + was_checked = false; range_valid = false; range_swapped = false; port_id = 0; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 9b7124934..8a640b1cc 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -168,7 +168,7 @@ namespace AST // node content - most of it is unused in most node types std::string str; std::vector bits; - bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped; + bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked; int port_id, range_left, range_right; uint32_t integer; double realvalue; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c9c5e5263..a9608369c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -444,12 +444,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children[1]->detectSignWidth(width_hint, sign_hint); width_hint = max(width_hint, backup_width_hint); child_0_is_self_determined = true; - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic) - children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) - log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); - if (type == AST_ASSIGN && children[0]->id2ast->is_reg) - log_error("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); + // test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier + if (children[0]->id2ast && !children[0]->was_checked) { + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic) + children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) + log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); + if (type == AST_ASSIGN && children[0]->id2ast->is_reg) + log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); + children[0]->was_checked = true; + } break; case AST_PARAMETER: @@ -959,6 +963,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); assign->children[0]->str = wire_id; + assign->children[0]->was_checked = true; if (current_block) { @@ -1425,16 +1430,19 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire_check = new AstNode(AST_WIRE); wire_check->str = id_check; + wire_check->was_checked = true; current_ast_mod->children.push_back(wire_check); current_scope[wire_check->str] = wire_check; while (wire_check->simplify(true, false, false, 1, -1, false, false)) { } AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; + wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); if (current_always_clocked) { current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))))); current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en; + current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; } current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } @@ -1444,9 +1452,11 @@ skip_dynamic_range_lvalue_expansion:; AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); assign_check->children[0]->str = id_check; + assign_check->children[0]->was_checked = true; AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; AstNode *default_signals = new AstNode(AST_BLOCK); default_signals->children.push_back(assign_check); @@ -1455,6 +1465,7 @@ skip_dynamic_range_lvalue_expansion:; assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); assign_check->children[0]->str = id_check; + assign_check->children[0]->was_checked = true; if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); @@ -1463,6 +1474,7 @@ skip_dynamic_range_lvalue_expansion:; assign_en->children[1]->str = "\\$initstate"; } assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; newNode = new AstNode(AST_BLOCK); newNode->children.push_back(assign_check); @@ -1571,12 +1583,14 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; + wire_addr->was_checked = true; current_ast_mod->children.push_back(wire_addr); current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; + wire_data->was_checked = true; wire_data->is_signed = mem_signed; current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; @@ -1586,6 +1600,7 @@ skip_dynamic_range_lvalue_expansion:; if (current_always->type != AST_INITIAL) { wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_en->str = id_en; + wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } @@ -1601,14 +1616,17 @@ skip_dynamic_range_lvalue_expansion:; AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; AstNode *assign_en = nullptr; if (current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } AstNode *default_signals = new AstNode(AST_BLOCK); @@ -1620,6 +1638,7 @@ skip_dynamic_range_lvalue_expansion:; assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; if (children[0]->children.size() == 2) { @@ -1634,12 +1653,14 @@ skip_dynamic_range_lvalue_expansion:; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; if (current_always->type != AST_INITIAL) { for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } } else @@ -1661,6 +1682,7 @@ skip_dynamic_range_lvalue_expansion:; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; if (current_always->type != AST_INITIAL) { for (int i = 0; i < mem_width; i++) @@ -1668,6 +1690,7 @@ skip_dynamic_range_lvalue_expansion:; assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } delete left_at_zero_ast; @@ -1679,10 +1702,12 @@ skip_dynamic_range_lvalue_expansion:; { assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; if (current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } } @@ -3018,6 +3043,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; + wire_addr->was_checked = true; wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); mod->children.push_back(wire_addr); while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } @@ -3025,6 +3051,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; + wire_data->was_checked = true; wire_data->is_signed = mem_signed; wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); mod->children.push_back(wire_data); @@ -3093,6 +3120,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; + wire_addr->was_checked = true; if (block) wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); mod->children.push_back(wire_addr); @@ -3101,6 +3129,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; + wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); @@ -3109,6 +3138,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); case_node->children[0]->str = id_addr; @@ -3119,6 +3149,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); assign_reg->children[0]->str = id_data; + assign_reg->children[0]->was_checked = true; assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); @@ -3131,6 +3162,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK)); AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); assign_reg->children[0]->str = id_data; + assign_reg->children[0]->was_checked = true; cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 722febf13..dfdeabbdb 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -548,6 +548,7 @@ task_func_decl: AstNode *outreg = new AstNode(AST_WIRE); outreg->str = *$6; outreg->is_signed = $4; + outreg->is_reg = true; if ($5 != NULL) { outreg->children.push_back($5); outreg->is_signed = $4 || $5->is_signed; diff --git a/tests/various/reg_wire_error.sv b/tests/various/reg_wire_error.sv index ab461b95a..fe5ff3abd 100644 --- a/tests/various/reg_wire_error.sv +++ b/tests/various/reg_wire_error.sv @@ -2,11 +2,13 @@ module sub_mod(input i_in, output o_out); assign o_out = i_in; endmodule -module test(i_clk, i_reg, o_reg, o_wire); +module test(i_clk, i, i_reg, o_reg, o_wire, o_mr, o_mw, o_ml); input i_clk; +input i; input i_reg; output o_reg; output o_wire; +output o_mr, o_mw, o_ml; // Enable this to see how it doesn't fail on yosys although it should //reg o_wire; @@ -15,12 +17,12 @@ logic o_wire; // Enable this to see how it doesn't fail on yosys although it should //reg i_reg; // Disable this to see how it doesn't fail on yosys although it should -reg o_reg; +//reg o_reg; logic l_reg; // Enable this to tst if logic-turne-reg will catch assignments even if done before it turned into a reg -//assign l_reg = !o_reg; +assign l_reg = !o_reg; initial o_reg = 1'b0; always @(posedge i_clk) begin @@ -30,11 +32,43 @@ end assign o_wire = !o_reg; // Uncomment this to see how a logic already turned intoa reg can be freely assigned on yosys -//assign l_reg = !o_reg; +assign l_reg = !o_reg; sub_mod sm_inst ( .i_in(1'b1), .o_out(o_reg) ); + +wire mw1[0:1]; +wire mw2[0:1]; +wire mw3[0:1]; +reg mr1[0:1]; +reg mr2[0:1]; +reg mr3[0:1]; +logic ml1[0:1]; +logic ml2[0:1]; +logic ml3[0:1]; + +assign o_mw = mw1[i]; +assign o_mr = mr1[i]; +assign o_ml = ml1[i]; + +assign mw1[1] = 1'b1; +//assign mr1[1] = 1'b1; +assign ml1[1] = 1'b1; +always @(posedge i_clk) +begin + mr2[0] = 1'b0; + mw2[0] = 1'b0; + ml2[0] = 1'b0; +end + +always @(posedge i_clk) +begin + mr3[0] <= 1'b0; + mw3[0] <= 1'b0; + ml3[0] <= 1'b0; +end + endmodule