aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--frontends/ast/ast.cc4
-rw-r--r--frontends/ast/genrtlil.cc6
-rw-r--r--frontends/verilog/verilog_lexer.l11
-rw-r--r--frontends/verilog/verilog_parser.y69
-rw-r--r--kernel/celltypes.h2
-rw-r--r--kernel/rtlil.cc15
-rw-r--r--manual/CHAPTER_CellLib.tex2
-rw-r--r--passes/opt/opt_clean.cc2
-rw-r--r--techlibs/common/simlib.v28
9 files changed, 133 insertions, 6 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 6b3604ee5..5623541b2 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -952,7 +952,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue;
if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
- (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3"))
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
continue;
blackbox_module = false;
break;
@@ -1039,7 +1039,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child);
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
- (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3")) {
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child);
} else {
delete child;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index b2a22b49a..48bd466e6 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -1538,6 +1538,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
+ if (cell->type == "$specrule") {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
}
break;
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index f49f9d3a2..cd96236a1 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -301,6 +301,12 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+"$"(setup|hold|skew) {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_ID;
+}
+
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
@@ -417,6 +423,11 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
return TOK_SPECIFY_OPER;
}
+"&&&" {
+ if (!specify_mode) REJECT;
+ return TOK_SPECIFY_AND;
+}
+
"/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 218d6f738..0a41ba581 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -136,7 +136,7 @@ struct specify_rise_fall {
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
-%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@@ -153,7 +153,7 @@ struct specify_rise_fall {
%type <specify_target_ptr> specify_target
%type <specify_triple_ptr> specify_triple
%type <specify_rise_fall_ptr> specify_rise_fall
-%type <ast> specify_if
+%type <ast> specify_if specify_condition
%type <ch> specify_edge
// operator precedence from low to high
@@ -815,6 +815,63 @@ specify_item:
delete oper;
delete target;
delete timing;
+ } |
+ TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr ')' ';' {
+ bool limit_gt = false;
+ if (*$1 == "$setup" || *$1 == "$hold")
+ limit_gt = true;
+ else if (*$1 == "$skew")
+ limit_gt = false;
+ else
+ frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
+
+ AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
+ AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
+ AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
+ AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
+ AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *limit = $11;
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = "$specrule";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
+ cell->children.back()->str = "\\SRC_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pen));
+ cell->children.back()->str = "\\SRC_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pol));
+ cell->children.back()->str = "\\SRC_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
+ cell->children.back()->str = "\\DST_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
+ cell->children.back()->str = "\\DST";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
+ cell->children.back()->str = "\\DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
+ cell->children.back()->str = "\\DST_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(limit_gt, false, 1)));
+ cell->children.back()->str = "\\LIMIT_GT";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit));
+ cell->children.back()->str = "\\T_LIMIT";
+
+ delete $1;
};
specify_if:
@@ -825,6 +882,14 @@ specify_if:
$$ = nullptr;
};
+specify_condition:
+ TOK_SPECIFY_AND expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
specify_target:
expr {
$$ = new specify_target;
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index f8c73ed83..4e91eddda 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -86,6 +86,7 @@ struct CellTypes
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
+ IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
setup_type("$tribuf", {A, EN}, {Y}, true);
@@ -102,6 +103,7 @@ struct CellTypes
setup_type("$equiv", {A, B}, {Y}, true);
setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
+ setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
}
void setup_internals_eval()
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 4522b0a08..dae3698a9 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1218,6 +1218,21 @@ namespace {
return;
}
+ if (cell->type == "$specrule") {
+ param_bool("\\SRC_PEN");
+ param_bool("\\SRC_POL");
+ param_bool("\\DST_PEN");
+ param_bool("\\DST_POL");
+ param_bool("\\LIMIT_GT");
+ param("\\T_LIMIT");
+ port("\\SRC_EN", 1);
+ port("\\DST_EN", 1);
+ port("\\SRC", param("\\SRC_WIDTH"));
+ port("\\DST", param("\\DST_WIDTH"));
+ check_expected();
+ return;
+ }
+
if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index 96a309552..cb1bcf1be 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -466,7 +466,7 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
\end{fixme}
\begin{fixme}
-Add information about {\tt \$specify2} and {\tt \$specify3} cells.
+Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
\end{fixme}
\begin{fixme}
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 3f38dd580..3e131d2af 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
- if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true;
if (cell->has_keep_attr())
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index f9e45df67..facecd9a4 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1417,6 +1417,34 @@ endmodule
// --------------------------------------------------------
+module \$specrule (EN_SRC, EN_DST, SRC, DST);
+
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter SRC_PEN = 0;
+parameter SRC_POL = 0;
+
+parameter DST_PEN = 0;
+parameter DST_POL = 0;
+
+parameter LIMIT_GT = 0;
+parameter T_LIMIT = 0;
+
+input EN_SRC, EN_DST;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ // TBD
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
module \$assert (A, EN);
input A, EN;