From: Claire Wolf Date: Mon, 27 Apr 2020 15:04:47 +0000 (+0200) Subject: Add "nowrshmsk" attribute, fix shift-and-mask bit slice write for signed offset,... X-Git-Tag: working-ls180~565^2~6 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bbbce0d1c58f8bfb0a615f1ed53fa046552b5adf;p=yosys.git Add "nowrshmsk" attribute, fix shift-and-mask bit slice write for signed offset, fixes #1990 Signed-off-by: Claire Wolf --- diff --git a/README.md b/README.md index 1e486c3ac..c17c0c3b1 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,9 @@ Verilog Attributes and non-standard features temporary variable within an always block. This is mostly used internally by Yosys to synthesize Verilog functions and access arrays. +- The ``nowrshmsk`` attribute on a register prohibits the generation of + shift-and-mask type circuits for writing to bit slices of that register. + - The ``onehot`` attribute on wires mark them as one-hot state register. This is used for example for memory port sharing and set by the fsm_map pass. diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 6a9af3f57..8daae7dcb 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -110,6 +110,8 @@ std::string AST::type2str(AstNodeType type) X(AST_SHIFT_RIGHT) X(AST_SHIFT_SLEFT) X(AST_SHIFT_SRIGHT) + X(AST_SHIFTX) + X(AST_SHIFT) X(AST_LT) X(AST_LE) X(AST_EQ) @@ -628,6 +630,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_SHIFT_RIGHT: txt = ">>"; } if (0) { case AST_SHIFT_SLEFT: txt = "<<<"; } if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } + if (0) { case AST_SHIFTX: txt = "@shiftx@"; } + if (0) { case AST_SHIFT: txt = "@shift@"; } if (0) { case AST_LT: txt = "<"; } if (0) { case AST_LE: txt = "<="; } if (0) { case AST_EQ: txt = "=="; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 3f6329112..0baea7b63 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -91,6 +91,8 @@ namespace AST AST_SHIFT_RIGHT, AST_SHIFT_SLEFT, AST_SHIFT_SRIGHT, + AST_SHIFTX, + AST_SHIFT, AST_LT, AST_LE, AST_EQ, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d35335747..6a39bbc04 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -856,6 +856,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_SHIFT_RIGHT: case AST_SHIFT_SLEFT: case AST_SHIFT_SRIGHT: + case AST_SHIFTX: + case AST_SHIFT: case AST_POW: children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1356,6 +1358,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_SHIFT_RIGHT: type_name = ID($shr); } if (0) { case AST_SHIFT_SLEFT: type_name = ID($sshl); } if (0) { case AST_SHIFT_SRIGHT: type_name = ID($sshr); } + if (0) { case AST_SHIFTX: type_name = ID($shiftx); } + if (0) { case AST_SHIFT: type_name = ID($shift); } { if (width_hint < 0) detectSignWidth(width_hint, sign_hint); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 837c14ad7..af347b8f1 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1786,7 +1786,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - if (0) + bool use_case_method = false; + + if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { + AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); + while (node->simplify(true, false, false, stage, -1, false, false)) { } + if (node->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); + if (node->asAttrConst().as_bool()) + use_case_method = true; + } + + if (use_case_method) { // big case block @@ -1794,10 +1805,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode = new AstNode(AST_CASE, shift_expr); for (int i = 0; i < source_width; i++) { int start_bit = children[0]->id2ast->range_right + i; + int end_bit = std::min(start_bit+result_width,source_width) - 1; 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()))); @@ -1844,11 +1855,36 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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(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(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, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); + int start_bit = children[0]->id2ast->range_right; + bool use_shift = shamt->is_signed; + + if (start_bit != 0) { + shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); + use_shift = true; + } + + AstNode *t; + + t = mkconst_bits(std::vector(result_width, State::S1), false); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone())); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone()); + t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector(result_width, State::S1), false), children[1]->clone()); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt)); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt); + t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); + t = new AstNode(AST_BIT_OR, t, ref_data); + t = new AstNode(type, lvalue, t); + newNode->children.push_back(t); } goto apply_newNode; diff --git a/kernel/constids.inc b/kernel/constids.inc index 27b652e24..4f8e86969 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -123,6 +123,7 @@ X(nomem2init) X(nomem2reg) X(nomeminit) X(nosync) +X(nowrshmsk) X(O) X(OFFSET) X(onehot)