aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--frontends/ast/ast.h3
-rw-r--r--frontends/ast/genrtlil.cc11
-rw-r--r--frontends/ast/simplify.cc76
-rw-r--r--passes/cmds/autoname.cc26
-rw-r--r--tests/simple/mem2reg_bounds_tern.v19
-rw-r--r--tests/simple/module_scope_case.v11
-rw-r--r--tests/verilog/mem_bounds.sv27
-rw-r--r--tests/verilog/mem_bounds.ys6
8 files changed, 150 insertions, 29 deletions
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index bb9f42a05..2bda8fa92 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -326,6 +326,9 @@ namespace AST
// helpers for locations
std::string loc_string() const;
+
+ // Helper for looking up identifiers which are prefixed with the current module name
+ std::string try_pop_module_prefix() const;
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 902fbb01b..52e057486 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -767,8 +767,15 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_IDENTIFIER:
id_ast = id2ast;
- if (id_ast == NULL && current_scope.count(str))
- id_ast = current_scope.at(str);
+ if (!id_ast) {
+ if (current_scope.count(str))
+ id_ast = current_scope[str];
+ else {
+ std::string alt = try_pop_module_prefix();
+ if (current_scope.count(alt))
+ id_ast = current_scope[alt];
+ }
+ }
if (!id_ast)
log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", str.c_str());
if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) {
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 38ca5e063..500288de0 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1698,17 +1698,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_IDENTIFIER) {
if (current_scope.count(str) == 0) {
AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
- size_t pos = str.find('.', 1);
- if (str[0] == '\\' && pos != std::string::npos) {
- std::string new_str = "\\" + str.substr(pos + 1);
- if (current_scope.count(new_str)) {
- std::string prefix = str.substr(0, pos);
- auto it = current_scope_ast->attributes.find(ID::hdlname);
- if ((it != current_scope_ast->attributes.end() && it->second->str == prefix)
- || prefix == current_scope_ast->str)
- str = new_str;
- }
- }
+ str = try_pop_module_prefix();
for (auto node : current_scope_ast->children) {
//log("looking at mod scope child %s\n", type2str(node->type).c_str());
switch (node->type) {
@@ -1762,7 +1752,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
// split memory access with bit select to individual statements
- if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue)
+ if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue && stage == 2)
{
if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1)
log_file_error(filename, location.first_line, "Invalid bit-select on memory access!\n");
@@ -4501,11 +4491,48 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (children[0]->children[0]->type == AST_CONSTANT)
{
int id = children[0]->children[0]->integer;
- str = stringf("%s[%d]", str.c_str(), id);
+ int left = id2ast->children[1]->children[0]->integer;
+ int right = id2ast->children[1]->children[1]->integer;
+ bool valid_const_access =
+ (left <= id && id <= right) ||
+ (right <= id && id <= left);
+ if (valid_const_access)
+ {
+ str = stringf("%s[%d]", str.c_str(), id);
+ delete_children();
+ range_valid = false;
+ id2ast = NULL;
+ }
+ else
+ {
+ int width;
+ if (bit_part_sel)
+ {
+ bit_part_sel->dumpAst(nullptr, "? ");
+ if (bit_part_sel->children.size() == 1)
+ width = 0;
+ else
+ width = bit_part_sel->children[0]->integer -
+ bit_part_sel->children[1]->integer;
+ delete bit_part_sel;
+ bit_part_sel = nullptr;
+ }
+ else
+ {
+ width = id2ast->children[0]->children[0]->integer -
+ id2ast->children[0]->children[1]->integer;
+ }
+ width = abs(width) + 1;
- delete_children();
- range_valid = false;
- id2ast = NULL;
+ delete_children();
+
+ std::vector<RTLIL::State> x_bits;
+ for (int i = 0; i < width; i++)
+ x_bits.push_back(RTLIL::State::Sx);
+ AstNode *constant = AstNode::mkconst_bits(x_bits, false);
+ constant->cloneInto(this);
+ delete constant;
+ }
}
else
{
@@ -5087,4 +5114,21 @@ std::pair<AstNode*, AstNode*> AstNode::get_tern_choice()
return {choice, not_choice};
}
+std::string AstNode::try_pop_module_prefix() const
+{
+ AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
+ size_t pos = str.find('.', 1);
+ if (str[0] == '\\' && pos != std::string::npos) {
+ std::string new_str = "\\" + str.substr(pos + 1);
+ if (current_scope.count(new_str)) {
+ std::string prefix = str.substr(0, pos);
+ auto it = current_scope_ast->attributes.find(ID::hdlname);
+ if ((it != current_scope_ast->attributes.end() && it->second->str == prefix)
+ || prefix == current_scope_ast->str)
+ return new_str;
+ }
+ }
+ return str;
+}
+
YOSYS_NAMESPACE_END
diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc
index bd4e4a0ca..6019c6153 100644
--- a/passes/cmds/autoname.cc
+++ b/passes/cmds/autoname.cc
@@ -22,25 +22,20 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-int autoname_worker(Module *module)
+int autoname_worker(Module *module, const dict<Wire*, int>& wire_score)
{
dict<Cell*, pair<int, IdString>> proposed_cell_names;
dict<Wire*, pair<int, IdString>> proposed_wire_names;
- dict<Wire*, int> wire_score;
int best_score = -1;
- for (auto cell : module->selected_cells())
- for (auto &conn : cell->connections())
- for (auto bit : conn.second)
- if (bit.wire != nullptr)
- wire_score[bit.wire]++;
-
for (auto cell : module->selected_cells()) {
if (cell->name[0] == '$') {
for (auto &conn : cell->connections()) {
- string suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first));
+ string suffix;
for (auto bit : conn.second)
if (bit.wire != nullptr && bit.wire->name[0] != '$') {
+ if (suffix.empty())
+ suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first));
IdString new_name(bit.wire->name.str() + suffix);
int score = wire_score.at(bit.wire);
if (cell->output(conn.first)) score = 0;
@@ -54,9 +49,11 @@ int autoname_worker(Module *module)
}
} else {
for (auto &conn : cell->connections()) {
- string suffix = stringf("_%s", log_id(conn.first));
+ string suffix;
for (auto bit : conn.second)
if (bit.wire != nullptr && bit.wire->name[0] == '$' && !bit.wire->port_id) {
+ if (suffix.empty())
+ suffix = stringf("_%s", log_id(conn.first));
IdString new_name(cell->name.str() + suffix);
int score = wire_score.at(bit.wire);
if (cell->output(conn.first)) score = 0;
@@ -118,10 +115,17 @@ struct AutonamePass : public Pass {
for (auto module : design->selected_modules())
{
+ dict<Wire*, int> wire_score;
+ for (auto cell : module->selected_cells())
+ for (auto &conn : cell->connections())
+ for (auto bit : conn.second)
+ if (bit.wire != nullptr)
+ wire_score[bit.wire]++;
+
int count = 0, iter = 0;
while (1) {
iter++;
- int n = autoname_worker(module);
+ int n = autoname_worker(module, wire_score);
if (!n) break;
count += n;
}
diff --git a/tests/simple/mem2reg_bounds_tern.v b/tests/simple/mem2reg_bounds_tern.v
new file mode 100644
index 000000000..89d6dd3e8
--- /dev/null
+++ b/tests/simple/mem2reg_bounds_tern.v
@@ -0,0 +1,19 @@
+module top(
+ input clk,
+ input wire [1:0] sel,
+ input wire [7:0] base,
+ output reg [7:0] line
+);
+ reg [0:7] mem [0:2];
+
+ generate
+ genvar i;
+ for (i = 0; i < 4; i = i + 1) begin : gen
+ always @(posedge clk)
+ mem[i] <= i == 0 ? base : mem[i - 1] + 1;
+ end
+ endgenerate
+
+ always @(posedge clk)
+ line = mem[sel];
+endmodule
diff --git a/tests/simple/module_scope_case.v b/tests/simple/module_scope_case.v
new file mode 100644
index 000000000..1472b6912
--- /dev/null
+++ b/tests/simple/module_scope_case.v
@@ -0,0 +1,11 @@
+module top(
+ input wire x,
+ output reg y
+);
+ always @* begin
+ case (top.x)
+ 1: top.y = 0;
+ 0: top.y = 1;
+ endcase
+ end
+endmodule
diff --git a/tests/verilog/mem_bounds.sv b/tests/verilog/mem_bounds.sv
new file mode 100644
index 000000000..7fb2fb042
--- /dev/null
+++ b/tests/verilog/mem_bounds.sv
@@ -0,0 +1,27 @@
+module top;
+ reg [0:7] mem [0:2];
+
+ initial mem[1] = '1;
+ wire [31:0] a, b, c, d;
+ assign a = mem[1];
+ assign b = mem[-1];
+ assign c = mem[-1][0];
+ assign d = mem[-1][0:1];
+
+ always @* begin
+
+ assert ($countbits(a, '0) == 24);
+ assert ($countbits(a, '1) == 8);
+ assert ($countbits(a, 'x) == 0);
+
+ assert ($countbits(b, '0) == 24);
+ assert ($countbits(b, 'x) == 8);
+
+ assert ($countbits(c, '0) == 31);
+ assert ($countbits(c, 'x) == 1);
+
+ assert ($countbits(d, '0) == 30);
+ assert ($countbits(d, 'x) == 2);
+
+ end
+endmodule
diff --git a/tests/verilog/mem_bounds.ys b/tests/verilog/mem_bounds.ys
new file mode 100644
index 000000000..42623ad09
--- /dev/null
+++ b/tests/verilog/mem_bounds.ys
@@ -0,0 +1,6 @@
+read_verilog -sv -mem2reg mem_bounds.sv
+proc
+flatten
+opt -full
+select -module top
+sat -verify -seq 1 -tempinduct -prove-asserts -show-all -enable_undef