Improved rewrite code for writing to bit slice (disabled for now)
authorClaire Wolf <claire@symbioticeda.com>
Wed, 1 Apr 2020 10:43:42 +0000 (12:43 +0200)
committerClaire Wolf <claire@symbioticeda.com>
Wed, 15 Apr 2020 15:44:37 +0000 (17:44 +0200)
This adds the new rewrite rule. But it's still missing a check that makes
sure the new rewrite rule is actually a valid substitute in the always
block being processed. Therefore the new rewrite rule is just disabled
for now.

Signed-off-by: Claire Wolf <claire@symbioticeda.com>
frontends/ast/simplify.cc

index cb89f58baf0169d5f958db53902061fc331f4873..e181af1406da507921269e0c519926ffb678a5a7 100644 (file)
@@ -1721,8 +1721,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
        }
 
        // replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with
-       // a big case block that selects the correct single-bit assignment.
-       if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) {
+       // either a big case block that selects the correct single-bit assignment, or mask and
+       // shift operations.
+       if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE)
+       {
                if (children[0]->type != AST_IDENTIFIER || children[0]->children.size() == 0)
                        goto skip_dynamic_range_lvalue_expansion;
                if (children[0]->children[0]->range_valid || did_something)
@@ -1731,10 +1733,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        goto skip_dynamic_range_lvalue_expansion;
                if (!children[0]->id2ast->range_valid)
                        goto skip_dynamic_range_lvalue_expansion;
+
                int source_width = children[0]->id2ast->range_left - children[0]->id2ast->range_right + 1;
                int result_width = 1;
+
                AstNode *shift_expr = NULL;
                AstNode *range = children[0]->children[0];
+
                if (range->children.size() == 1) {
                        shift_expr = range->children[0]->clone();
                } else {
@@ -1747,19 +1752,66 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                                log_file_error(filename, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
                        result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
                }
-               did_something = true;
-               newNode = new AstNode(AST_CASE, shift_expr);
-               for (int i = 0; i < source_width; i++) {
-                       int start_bit = children[0]->id2ast->range_right + i;
-                       AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true));
+
+               if (1)
+               {
+                       // big case block
+
+                       did_something = true;
+                       newNode = new AstNode(AST_CASE, shift_expr);
+                       for (int i = 0; i < source_width; i++) {
+                               int start_bit = children[0]->id2ast->range_right + i;
+                               AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true));
+                               AstNode *lvalue = children[0]->clone();
+                               lvalue->delete_children();
+                               int end_bit = std::min(start_bit+result_width,source_width) - 1;
+                               lvalue->children.push_back(new AstNode(AST_RANGE,
+                                               mkconst_int(end_bit, true), mkconst_int(start_bit, true)));
+                               cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone())));
+                               newNode->children.push_back(cond);
+                       }
+               }
+               else
+               {
+                       // mask and shift operations, disabled for now
+
+                       AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
+                       wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+                       wire_mask->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+                       wire_mask->is_logic = true;
+                       while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { }
+                       current_ast_mod->children.push_back(wire_mask);
+
+                       AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
+                       wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+                       wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+                       wire_data->is_logic = true;
+                       while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
+                       current_ast_mod->children.push_back(wire_data);
+
+                       did_something = true;
+                       newNode = new AstNode(AST_BLOCK);
+
                        AstNode *lvalue = children[0]->clone();
                        lvalue->delete_children();
-                       int end_bit = std::min(start_bit+result_width,source_width) - 1;
-                       lvalue->children.push_back(new AstNode(AST_RANGE,
-                                       mkconst_int(end_bit, true), mkconst_int(start_bit, true)));
-                       cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone())));
-                       newNode->children.push_back(cond);
+
+                       AstNode *ref_mask = new AstNode(AST_IDENTIFIER);
+                       ref_mask->str = wire_mask->str;
+                       ref_mask->was_checked = true;
+
+                       AstNode *ref_data = new AstNode(AST_IDENTIFIER);
+                       ref_data->str = wire_data->str;
+                       ref_data->was_checked = true;
+
+                       AstNode *shamt = shift_expr;
+
+                       newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(),
+                                       new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone())));
+                       newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(),
+                                       new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt)));
+                       newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, lvalue->clone(), new AstNode(AST_BIT_NOT, ref_mask)), ref_data)));
                }
+
                goto apply_newNode;
        }
 skip_dynamic_range_lvalue_expansion:;