mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
Merge pull request #513 from udif/pr_reg_wire_error
Add error checking for reg/wire/logic misuse - PR now passes 'make test' (plus a new test)
This commit is contained in:
commit
3d27c1cc80
|
@ -191,8 +191,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
|
||||||
is_input = false;
|
is_input = false;
|
||||||
is_output = false;
|
is_output = false;
|
||||||
is_reg = false;
|
is_reg = false;
|
||||||
|
is_logic = false;
|
||||||
is_signed = false;
|
is_signed = false;
|
||||||
is_string = false;
|
is_string = false;
|
||||||
|
was_checked = false;
|
||||||
range_valid = false;
|
range_valid = false;
|
||||||
range_swapped = false;
|
range_swapped = false;
|
||||||
port_id = 0;
|
port_id = 0;
|
||||||
|
@ -285,7 +287,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
|
||||||
fprintf(f, " input");
|
fprintf(f, " input");
|
||||||
if (is_output)
|
if (is_output)
|
||||||
fprintf(f, " 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");
|
fprintf(f, " reg");
|
||||||
if (is_signed)
|
if (is_signed)
|
||||||
fprintf(f, " signed");
|
fprintf(f, " signed");
|
||||||
|
@ -652,6 +656,8 @@ bool AstNode::operator==(const AstNode &other) const
|
||||||
return false;
|
return false;
|
||||||
if (is_output != other.is_output)
|
if (is_output != other.is_output)
|
||||||
return false;
|
return false;
|
||||||
|
if (is_logic != other.is_logic)
|
||||||
|
return false;
|
||||||
if (is_reg != other.is_reg)
|
if (is_reg != other.is_reg)
|
||||||
return false;
|
return false;
|
||||||
if (is_signed != other.is_signed)
|
if (is_signed != other.is_signed)
|
||||||
|
|
|
@ -168,7 +168,7 @@ namespace AST
|
||||||
// node content - most of it is unused in most node types
|
// node content - most of it is unused in most node types
|
||||||
std::string str;
|
std::string str;
|
||||||
std::vector<RTLIL::State> bits;
|
std::vector<RTLIL::State> 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, was_checked;
|
||||||
int port_id, range_left, range_right;
|
int port_id, range_left, range_right;
|
||||||
uint32_t integer;
|
uint32_t integer;
|
||||||
double realvalue;
|
double realvalue;
|
||||||
|
|
|
@ -327,6 +327,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
if (node->type == AST_WIRE) {
|
if (node->type == AST_WIRE) {
|
||||||
if (this_wire_scope.count(node->str) > 0) {
|
if (this_wire_scope.count(node->str) > 0) {
|
||||||
AstNode *first_node = this_wire_scope[node->str];
|
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)
|
if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0)
|
||||||
goto wires_are_compatible;
|
goto wires_are_compatible;
|
||||||
if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
|
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;
|
first_node->is_output = true;
|
||||||
if (node->is_reg)
|
if (node->is_reg)
|
||||||
first_node->is_reg = true;
|
first_node->is_reg = true;
|
||||||
|
if (node->is_logic)
|
||||||
|
first_node->is_logic = true;
|
||||||
if (node->is_signed)
|
if (node->is_signed)
|
||||||
first_node->is_signed = true;
|
first_node->is_signed = true;
|
||||||
for (auto &it : node->attributes) {
|
for (auto &it : node->attributes) {
|
||||||
|
@ -440,6 +444,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
children[1]->detectSignWidth(width_hint, sign_hint);
|
children[1]->detectSignWidth(width_hint, sign_hint);
|
||||||
width_hint = max(width_hint, backup_width_hint);
|
width_hint = max(width_hint, backup_width_hint);
|
||||||
child_0_is_self_determined = true;
|
child_0_is_self_determined = true;
|
||||||
|
// 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;
|
break;
|
||||||
|
|
||||||
case AST_PARAMETER:
|
case AST_PARAMETER:
|
||||||
|
@ -949,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);
|
AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data);
|
||||||
assign->children[0]->str = wire_id;
|
assign->children[0]->str = wire_id;
|
||||||
|
assign->children[0]->was_checked = true;
|
||||||
|
|
||||||
if (current_block)
|
if (current_block)
|
||||||
{
|
{
|
||||||
|
@ -1414,16 +1429,19 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
|
|
||||||
AstNode *wire_check = new AstNode(AST_WIRE);
|
AstNode *wire_check = new AstNode(AST_WIRE);
|
||||||
wire_check->str = id_check;
|
wire_check->str = id_check;
|
||||||
|
wire_check->was_checked = true;
|
||||||
current_ast_mod->children.push_back(wire_check);
|
current_ast_mod->children.push_back(wire_check);
|
||||||
current_scope[wire_check->str] = wire_check;
|
current_scope[wire_check->str] = wire_check;
|
||||||
while (wire_check->simplify(true, false, false, 1, -1, false, false)) { }
|
while (wire_check->simplify(true, false, false, 1, -1, false, false)) { }
|
||||||
|
|
||||||
AstNode *wire_en = new AstNode(AST_WIRE);
|
AstNode *wire_en = new AstNode(AST_WIRE);
|
||||||
wire_en->str = id_en;
|
wire_en->str = id_en;
|
||||||
|
wire_en->was_checked = true;
|
||||||
current_ast_mod->children.push_back(wire_en);
|
current_ast_mod->children.push_back(wire_en);
|
||||||
if (current_always_clocked) {
|
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.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]->str = id_en;
|
||||||
|
current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true;
|
||||||
}
|
}
|
||||||
current_scope[wire_en->str] = wire_en;
|
current_scope[wire_en->str] = wire_en;
|
||||||
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
||||||
|
@ -1433,9 +1451,11 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
|
|
||||||
AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false));
|
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]->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));
|
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]->str = id_en;
|
||||||
|
assign_en->children[0]->was_checked = true;
|
||||||
|
|
||||||
AstNode *default_signals = new AstNode(AST_BLOCK);
|
AstNode *default_signals = new AstNode(AST_BLOCK);
|
||||||
default_signals->children.push_back(assign_check);
|
default_signals->children.push_back(assign_check);
|
||||||
|
@ -1444,6 +1464,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 = 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]->str = id_check;
|
||||||
|
assign_check->children[0]->was_checked = true;
|
||||||
|
|
||||||
if (current_always == nullptr || current_always->type != AST_INITIAL) {
|
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));
|
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
|
||||||
|
@ -1452,6 +1473,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
assign_en->children[1]->str = "\\$initstate";
|
assign_en->children[1]->str = "\\$initstate";
|
||||||
}
|
}
|
||||||
assign_en->children[0]->str = id_en;
|
assign_en->children[0]->str = id_en;
|
||||||
|
assign_en->children[0]->was_checked = true;
|
||||||
|
|
||||||
newNode = new AstNode(AST_BLOCK);
|
newNode = new AstNode(AST_BLOCK);
|
||||||
newNode->children.push_back(assign_check);
|
newNode->children.push_back(assign_check);
|
||||||
|
@ -1560,12 +1582,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)));
|
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->str = id_addr;
|
||||||
|
wire_addr->was_checked = true;
|
||||||
current_ast_mod->children.push_back(wire_addr);
|
current_ast_mod->children.push_back(wire_addr);
|
||||||
current_scope[wire_addr->str] = wire_addr;
|
current_scope[wire_addr->str] = wire_addr;
|
||||||
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
|
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)));
|
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->str = id_data;
|
||||||
|
wire_data->was_checked = true;
|
||||||
wire_data->is_signed = mem_signed;
|
wire_data->is_signed = mem_signed;
|
||||||
current_ast_mod->children.push_back(wire_data);
|
current_ast_mod->children.push_back(wire_data);
|
||||||
current_scope[wire_data->str] = wire_data;
|
current_scope[wire_data->str] = wire_data;
|
||||||
|
@ -1575,6 +1599,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
if (current_always->type != AST_INITIAL) {
|
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 = 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->str = id_en;
|
||||||
|
wire_en->was_checked = true;
|
||||||
current_ast_mod->children.push_back(wire_en);
|
current_ast_mod->children.push_back(wire_en);
|
||||||
current_scope[wire_en->str] = wire_en;
|
current_scope[wire_en->str] = wire_en;
|
||||||
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
||||||
|
@ -1590,14 +1615,17 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
|
|
||||||
AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false));
|
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]->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));
|
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]->str = id_data;
|
||||||
|
assign_data->children[0]->was_checked = true;
|
||||||
|
|
||||||
AstNode *assign_en = nullptr;
|
AstNode *assign_en = nullptr;
|
||||||
if (current_always->type != AST_INITIAL) {
|
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 = 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]->str = id_en;
|
||||||
|
assign_en->children[0]->was_checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *default_signals = new AstNode(AST_BLOCK);
|
AstNode *default_signals = new AstNode(AST_BLOCK);
|
||||||
|
@ -1609,6 +1637,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 = 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]->str = id_addr;
|
||||||
|
assign_addr->children[0]->was_checked = true;
|
||||||
|
|
||||||
if (children[0]->children.size() == 2)
|
if (children[0]->children.size() == 2)
|
||||||
{
|
{
|
||||||
|
@ -1623,12 +1652,14 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
||||||
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
|
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
|
||||||
assign_data->children[0]->str = id_data;
|
assign_data->children[0]->str = id_data;
|
||||||
|
assign_data->children[0]->was_checked = true;
|
||||||
|
|
||||||
if (current_always->type != AST_INITIAL) {
|
if (current_always->type != AST_INITIAL) {
|
||||||
for (int i = 0; i < mem_width; i++)
|
for (int i = 0; i < mem_width; i++)
|
||||||
set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
|
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 = 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]->str = id_en;
|
||||||
|
assign_en->children[0]->was_checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1650,6 +1681,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
||||||
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
|
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
|
||||||
assign_data->children[0]->str = id_data;
|
assign_data->children[0]->str = id_data;
|
||||||
|
assign_data->children[0]->was_checked = true;
|
||||||
|
|
||||||
if (current_always->type != AST_INITIAL) {
|
if (current_always->type != AST_INITIAL) {
|
||||||
for (int i = 0; i < mem_width; i++)
|
for (int i = 0; i < mem_width; i++)
|
||||||
|
@ -1657,6 +1689,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
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()));
|
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]->str = id_en;
|
||||||
|
assign_en->children[0]->was_checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete left_at_zero_ast;
|
delete left_at_zero_ast;
|
||||||
|
@ -1668,10 +1701,12 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
{
|
{
|
||||||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
|
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]->str = id_data;
|
||||||
|
assign_data->children[0]->was_checked = true;
|
||||||
|
|
||||||
if (current_always->type != AST_INITIAL) {
|
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 = 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]->str = id_en;
|
||||||
|
assign_en->children[0]->was_checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3007,6 +3042,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &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)));
|
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->str = id_addr;
|
||||||
wire_addr->is_reg = true;
|
wire_addr->is_reg = true;
|
||||||
|
wire_addr->was_checked = true;
|
||||||
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
mod->children.push_back(wire_addr);
|
mod->children.push_back(wire_addr);
|
||||||
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
|
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
|
||||||
|
@ -3014,6 +3050,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &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)));
|
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->str = id_data;
|
||||||
wire_data->is_reg = true;
|
wire_data->is_reg = true;
|
||||||
|
wire_data->was_checked = true;
|
||||||
wire_data->is_signed = mem_signed;
|
wire_data->is_signed = mem_signed;
|
||||||
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
mod->children.push_back(wire_data);
|
mod->children.push_back(wire_data);
|
||||||
|
@ -3082,6 +3119,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &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)));
|
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->str = id_addr;
|
||||||
wire_addr->is_reg = true;
|
wire_addr->is_reg = true;
|
||||||
|
wire_addr->was_checked = true;
|
||||||
if (block)
|
if (block)
|
||||||
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
mod->children.push_back(wire_addr);
|
mod->children.push_back(wire_addr);
|
||||||
|
@ -3090,6 +3128,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &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)));
|
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->str = id_data;
|
||||||
wire_data->is_reg = true;
|
wire_data->is_reg = true;
|
||||||
|
wire_data->was_checked = true;
|
||||||
wire_data->is_signed = mem_signed;
|
wire_data->is_signed = mem_signed;
|
||||||
if (block)
|
if (block)
|
||||||
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
|
@ -3098,6 +3137,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
|
||||||
|
|
||||||
AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
|
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]->str = id_addr;
|
||||||
|
assign_addr->children[0]->was_checked = true;
|
||||||
|
|
||||||
AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
|
AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
|
||||||
case_node->children[0]->str = id_addr;
|
case_node->children[0]->str = id_addr;
|
||||||
|
@ -3108,6 +3148,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
|
||||||
AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK));
|
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));
|
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]->str = id_data;
|
||||||
|
assign_reg->children[0]->was_checked = true;
|
||||||
assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i);
|
assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i);
|
||||||
cond_node->children[1]->children.push_back(assign_reg);
|
cond_node->children[1]->children.push_back(assign_reg);
|
||||||
case_node->children.push_back(cond_node);
|
case_node->children.push_back(cond_node);
|
||||||
|
@ -3120,6 +3161,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
|
||||||
AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK));
|
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));
|
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]->str = id_data;
|
||||||
|
assign_reg->children[0]->was_checked = true;
|
||||||
cond_node->children[1]->children.push_back(assign_reg);
|
cond_node->children[1]->children.push_back(assign_reg);
|
||||||
case_node->children.push_back(cond_node);
|
case_node->children.push_back(cond_node);
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ YOSYS_NAMESPACE_END
|
||||||
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||||
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
||||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
|
"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); }
|
"bit" { SV_KEYWORD(TOK_REG); }
|
||||||
|
|
||||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||||
|
|
|
@ -105,7 +105,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
%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_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_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
|
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
|
||||||
|
@ -397,6 +397,9 @@ wire_type_token:
|
||||||
TOK_REG {
|
TOK_REG {
|
||||||
astbuf3->is_reg = true;
|
astbuf3->is_reg = true;
|
||||||
} |
|
} |
|
||||||
|
TOK_LOGIC {
|
||||||
|
astbuf3->is_logic = true;
|
||||||
|
} |
|
||||||
TOK_INTEGER {
|
TOK_INTEGER {
|
||||||
astbuf3->is_reg = true;
|
astbuf3->is_reg = true;
|
||||||
astbuf3->range_left = 31;
|
astbuf3->range_left = 31;
|
||||||
|
@ -548,6 +551,7 @@ task_func_decl:
|
||||||
AstNode *outreg = new AstNode(AST_WIRE);
|
AstNode *outreg = new AstNode(AST_WIRE);
|
||||||
outreg->str = *$6;
|
outreg->str = *$6;
|
||||||
outreg->is_signed = $4;
|
outreg->is_signed = $4;
|
||||||
|
outreg->is_reg = true;
|
||||||
if ($5 != NULL) {
|
if ($5 != NULL) {
|
||||||
outreg->children.push_back($5);
|
outreg->children.push_back($5);
|
||||||
outreg->is_signed = $4 || $5->is_signed;
|
outreg->is_signed = $4 || $5->is_signed;
|
||||||
|
@ -1027,6 +1031,7 @@ wire_name:
|
||||||
node->port_id = current_function_or_task_port_id++;
|
node->port_id = current_function_or_task_port_id++;
|
||||||
}
|
}
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
|
|
||||||
delete $1;
|
delete $1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
74
tests/various/reg_wire_error.sv
Normal file
74
tests/various/reg_wire_error.sv
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
module sub_mod(input i_in, output o_out);
|
||||||
|
assign o_out = i_in;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
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;
|
||||||
|
// 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)
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
1
tests/various/reg_wire_error.ys
Normal file
1
tests/various/reg_wire_error.ys
Normal file
|
@ -0,0 +1 @@
|
||||||
|
read_verilog -sv reg_wire_error.sv
|
Loading…
Reference in a new issue