aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2016-07-08 14:31:06 +0200
committerClifford Wolf <clifford@clifford.at>2016-07-08 14:31:06 +0200
commit9a101dc1f78acb404cc98e0acc4530c238070fd8 (patch)
treed64e52953a422d8c7d0c8b3d5841bdd2a1dea966
parentb782076698b76445b6b1087671687483c6d6c545 (diff)
downloadyosys-9a101dc1f78acb404cc98e0acc4530c238070fd8.tar.gz
yosys-9a101dc1f78acb404cc98e0acc4530c238070fd8.tar.bz2
yosys-9a101dc1f78acb404cc98e0acc4530c238070fd8.zip
Fixed mem assignment in left-hand-side concatenation
-rw-r--r--frontends/ast/simplify.cc44
-rw-r--r--tests/simple/memory.v13
2 files changed, 57 insertions, 0 deletions
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index c09b912c2..25039a4fb 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1418,6 +1418,50 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
+ // assignment with nontrivial member in left-hand concat expression -> split assignment
+ if ((type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_CONCAT && width_hint > 0)
+ {
+ bool found_nontrivial_member = false;
+
+ for (auto child : children[0]->children) {
+ if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY)
+ found_nontrivial_member = true;
+ }
+
+ if (found_nontrivial_member)
+ {
+ newNode = new AstNode(AST_BLOCK);
+
+ AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true)));
+ wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), linenum, autoidx++);
+ current_ast_mod->children.push_back(wire_tmp);
+ current_scope[wire_tmp->str] = wire_tmp;
+ wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
+
+ AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
+ wire_tmp_id->str = wire_tmp->str;
+
+ newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone()));
+
+ int cursor = 0;
+ for (auto child : children[0]->children)
+ {
+ int child_width_hint = -1;
+ bool child_sign_hint = true;
+ child->detectSignWidth(child_width_hint, child_sign_hint);
+
+ AstNode *rhs = wire_tmp_id->clone();
+ rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true)));
+ newNode->children.push_back(new AstNode(type, child->clone(), rhs));
+
+ cursor += child_width_hint;
+ }
+
+ goto apply_newNode;
+ }
+ }
+
// assignment with memory in left-hand side expression -> replace with memory write port
if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER &&
children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 &&
diff --git a/tests/simple/memory.v b/tests/simple/memory.v
index 9fddce26c..61b36e79a 100644
--- a/tests/simple/memory.v
+++ b/tests/simple/memory.v
@@ -264,3 +264,16 @@ module memtest11(clk, wen, waddr, raddr, wdata, rdata);
end
endmodule
+// ----------------------------------------------------------
+
+module memtest12 (
+ input clk,
+ input [1:0] adr,
+ input [1:0] din,
+ output reg [1:0] q
+);
+ reg [1:0] ram [3:0];
+ always@(posedge clk)
+ {ram[adr], q} <= {din, ram[adr]};
+endmodule
+