aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--frontends/ast/ast.cc4
-rw-r--r--frontends/ast/ast.h2
-rw-r--r--frontends/ast/genrtlil.cc4
-rw-r--r--frontends/ast/simplify.cc50
-rw-r--r--kernel/constids.inc1
6 files changed, 57 insertions, 7 deletions
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<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, 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<RTLIL::State>(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<RTLIL::State>(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)