Added $past, $stable, $rose, $fell SVA functions
authorClifford Wolf <clifford@clifford.at>
Sun, 18 Sep 2016 23:30:07 +0000 (01:30 +0200)
committerClifford Wolf <clifford@clifford.at>
Sun, 18 Sep 2016 23:30:07 +0000 (01:30 +0200)
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc

index d00738ecda813c5df134feef7102ea167a842d4a..3c57162aaf5c3c7864951b0432207a190c61146d 100644 (file)
@@ -765,6 +765,16 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
                        }
                        break;
                }
+               if (str == "\\$past") {
+                       if (GetSize(children) > 0) {
+                               sub_width_hint = 0;
+                               sub_sign_hint = true;
+                               children.at(0)->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
+                               width_hint = max(width_hint, sub_width_hint);
+                               sign_hint = false;
+                       }
+                       break;
+               }
                /* fall through */
 
        // everything should have been handled above -> print error if not.
index 8387c11c6711ae106b486a46acf3c525ab1567e7..57aa648ce6c76b7a30a24621cb867d3ec8cca8d7 100644 (file)
@@ -63,7 +63,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 
 #if 0
        log("-------------\n");
-       log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
+       log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), linenum, type2str(type).c_str(), this);
        log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
                        int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
        // dumpAst(NULL, "> ");
@@ -522,6 +522,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                children_are_self_determined = true;
                break;
 
+       case AST_FCALL:
+       case AST_TCALL:
+               children_are_self_determined = true;
+               break;
+
        default:
                width_hint = -1;
                sign_hint = false;
@@ -537,6 +542,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                detectSignWidth(width_hint, sign_hint);
        }
 
+       if (type == AST_FCALL && str == "\\$past")
+               detectSignWidth(width_hint, sign_hint);
+
        if (type == AST_TERNARY) {
                int width_hint_left, width_hint_right;
                bool sign_hint_left, sign_hint_right;
@@ -1682,9 +1690,128 @@ skip_dynamic_range_lvalue_expansion:;
                                goto apply_newNode;
                        }
 
+                       if (str == "\\$past")
+                       {
+                               if (width_hint <= 0)
+                                       goto replace_fcall_later;
+
+                               int num_steps = 1;
+
+                               if (GetSize(children) != 1 && GetSize(children) != 2)
+                                       log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n",
+                                                       RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+                               if (!current_always_clocked)
+                                       log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
+                                                       RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+                               if (GetSize(children) == 2)
+                               {
+                                       AstNode *buf = children[1]->clone();
+                                       while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+                                       if (buf->type != AST_CONSTANT)
+                                               log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+                                       num_steps = buf->asInt(true);
+                                       delete buf;
+                               }
+
+                               AstNode *block = nullptr;
+
+                               for (auto child : current_always->children)
+                                       if (child->type == AST_BLOCK)
+                                               block = child;
+
+                               log_assert(block != nullptr);
+
+                               int myidx = autoidx++;
+                               AstNode *outreg = nullptr;
+
+                               for (int i = 0; i < num_steps; i++)
+                               {
+                                       AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
+                                                       mkconst_int(width_hint-1, true), mkconst_int(0, true)));
+
+                                       reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), linenum, myidx, i);
+                                       reg->is_reg = true;
+
+                                       current_ast_mod->children.push_back(reg);
+
+                                       while (reg->simplify(true, false, false, 1, -1, false, false)) { }
+
+                                       AstNode *regid = new AstNode(AST_IDENTIFIER);
+                                       regid->str = reg->str;
+                                       regid->id2ast = reg;
+
+                                       AstNode *rhs = nullptr;
+
+                                       if (outreg == nullptr) {
+                                               rhs = children.at(0)->clone();
+                                       } else {
+                                               rhs = new AstNode(AST_IDENTIFIER);
+                                               rhs->str = outreg->str;
+                                               rhs->id2ast = outreg;
+                                       }
+
+                                       block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs));
+                                       outreg = reg;
+                               }
+
+                               newNode = new AstNode(AST_IDENTIFIER);
+                               newNode->str = outreg->str;
+                               newNode->id2ast = outreg;
+                               goto apply_newNode;
+                       }
+
+                       if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell")
+                       {
+                               if (GetSize(children) != 1)
+                                       log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
+                                                       RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+                               if (!current_always_clocked)
+                                       log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
+                                                       RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+                               AstNode *present = children.at(0)->clone();
+                               AstNode *past = clone();
+                               past->str = "\\$past";
+
+                               if (str == "\\$stable")
+                                       newNode = new AstNode(AST_EQ, past, present);
+
+                               else if (str == "\\$rose")
+                                       newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present);
+
+                               else if (str == "\\$fell")
+                                       newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present));
+
+                               else
+                                       log_abort();
+
+                               goto apply_newNode;
+                       }
+
+                       if (str == "\\$rose" || str == "\\$fell")
+                       {
+                               if (GetSize(children) != 1)
+                                       log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
+                                                       RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+                               if (!current_always_clocked)
+                                       log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
+                                                       RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+                               newNode = new AstNode(AST_EQ, children.at(0)->clone(), clone());
+                               newNode->children.at(1)->str = "\\$past";
+                               goto apply_newNode;
+                       }
+
                        // $anyconst is mapped in AstNode::genRTLIL()
-                       if (str == "\\$anyconst")
+                       if (str == "\\$anyconst") {
+                               recursion_counter--;
                                return false;
+                       }
 
                        if (str == "\\$clog2")
                        {
@@ -2092,6 +2219,8 @@ skip_dynamic_range_lvalue_expansion:;
                did_something = true;
        }
 
+replace_fcall_later:;
+
        // perform const folding when activated
        if (const_fold)
        {