Fixed mem assignment in left-hand-side concatenation
authorClifford Wolf <clifford@clifford.at>
Fri, 8 Jul 2016 12:31:06 +0000 (14:31 +0200)
committerClifford Wolf <clifford@clifford.at>
Fri, 8 Jul 2016 12:31:06 +0000 (14:31 +0200)
frontends/ast/simplify.cc
tests/simple/memory.v

index c09b912c2797caa7339526d62f9348a21e4a4ab8..25039a4fb528a64190935fe3c3a5e32c052a5ffd 100644 (file)
@@ -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 &&
index 9fddce26ca05a9cf1c6117cb1a0247196b96a19a..61b36e79a25bf8c9b1cc8c19ac482c59ea1db82f 100644 (file)
@@ -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
+