mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support inside expressions.
This commit is contained in:
parent
91159da30d
commit
4968a2abc5
2
Changes
2
Changes
@ -18,6 +18,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
*** Support $left, $right and related functions, bug448. [Iztok Jeras]
|
||||
|
||||
*** Support inside expressions.
|
||||
|
||||
*** Define SYSTEMVERILOG, SV_COV_START and other IEEE mandated predefines.
|
||||
|
||||
**** Fix pin width mismatch error, bug595. [Alex Solomatnikov]
|
||||
|
@ -2558,6 +2558,11 @@ the disable statement itself is inside. This was commonly used to provide
|
||||
loop break and continue functionality before SystemVerilog added the break
|
||||
and continue keywords.
|
||||
|
||||
=item inside
|
||||
|
||||
Inside expressions may not include unpacked array traversal or $ as an
|
||||
upper bound. Case inside and case matches are also unsupported.
|
||||
|
||||
=item priority if, unique if
|
||||
|
||||
Priority and unique if's are treated as normal ifs and not asserted to be
|
||||
|
@ -2552,6 +2552,33 @@ struct AstFinal : public AstNode {
|
||||
AstNode* bodysp() const { return op1p()->castNode(); } // op1 = Expressions to evaluate
|
||||
};
|
||||
|
||||
struct AstInside : public AstNodeMath {
|
||||
AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp)
|
||||
: AstNodeMath(fl) {
|
||||
addOp1p(exprp); addOp2p(itemsp);
|
||||
dtypeSetLogicBool();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Inside, INSIDE)
|
||||
AstNode* exprp() const { return op1p()->castNode(); } // op1 = LHS expression to compare with
|
||||
AstNode* itemsp() const { return op2p()->castNode(); } // op2 = RHS, possibly a list of expr or AstInsideRange
|
||||
virtual string emitVerilog() { return "%l inside { %r }"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return false; } // NA
|
||||
};
|
||||
|
||||
struct AstInsideRange : public AstNodeMath {
|
||||
AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: AstNodeMath(fl) {
|
||||
addOp1p(lhsp); addOp2p(rhsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(InsideRange, INSIDERANGE)
|
||||
AstNode* lhsp() const { return op1p()->castNode(); } // op1 = LHS
|
||||
AstNode* rhsp() const { return op2p()->castNode(); } // op2 = RHS
|
||||
virtual string emitVerilog() { return "[%l:%r]"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return false; } // NA
|
||||
};
|
||||
|
||||
struct AstInitArray : public AstNode {
|
||||
// Set a var to a large list of values
|
||||
// The values must be in sorted order, and not exceed the size of the var's array.
|
||||
|
@ -996,6 +996,58 @@ private:
|
||||
// Should be correct by construction, so we'll just loop through all types
|
||||
nodep->iterateChildren(*this, vup);
|
||||
}
|
||||
virtual void visit(AstInside* nodep, AstNUser* vup) {
|
||||
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) {
|
||||
nextip = itemp->nextp(); // Prelim may cause the node to get replaced
|
||||
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p()); itemp=NULL;
|
||||
}
|
||||
// Take width as maximum across all items
|
||||
int width = nodep->exprp()->width();
|
||||
int mwidth = nodep->exprp()->widthMin();
|
||||
for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) {
|
||||
width = max(width,itemp->width());
|
||||
mwidth = max(mwidth,itemp->widthMin());
|
||||
}
|
||||
// Apply width
|
||||
nodep->exprp()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
|
||||
for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) {
|
||||
widthCheck(nodep,"Inside Item",itemp,width,mwidth);
|
||||
}
|
||||
widthCheck(nodep,"Inside expression",nodep->exprp(),width,mwidth);
|
||||
nodep->dtypeSetLogicBool();
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-inside-in: ");
|
||||
// Now rip out the inside and replace with simple math
|
||||
AstNode* newp = NULL;
|
||||
for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) {
|
||||
nextip = itemp->nextp(); // Will be unlinking
|
||||
AstNode* inewp;
|
||||
if (AstInsideRange* irangep = itemp->castInsideRange()) {
|
||||
inewp = new AstAnd(itemp->fileline(),
|
||||
new AstGte(itemp->fileline(),
|
||||
nodep->exprp()->cloneTree(true),
|
||||
irangep->lhsp()->unlinkFrBack()),
|
||||
new AstLte(itemp->fileline(),
|
||||
nodep->exprp()->cloneTree(true),
|
||||
irangep->rhsp()->unlinkFrBack()));
|
||||
} else {
|
||||
inewp = new AstEqWild(itemp->fileline(),
|
||||
nodep->exprp()->cloneTree(true),
|
||||
itemp->unlinkFrBack());
|
||||
}
|
||||
if (newp) newp = new AstOr(nodep->fileline(), newp, inewp);
|
||||
else newp = inewp;
|
||||
}
|
||||
if (!newp) newp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
|
||||
if (debug()>=9) newp->dumpTree(cout,"-inside-out: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstInsideRange* nodep, AstNUser* vup) {
|
||||
// Just do each side; AstInside will rip these nodes out later
|
||||
nodep->lhsp()->iterateAndNext(*this,vup);
|
||||
nodep->rhsp()->iterateAndNext(*this,vup);
|
||||
nodep->dtypeFrom(nodep->lhsp());
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
|
@ -424,6 +424,7 @@ word [a-zA-Z0-9_]+
|
||||
"final" { FL; return yFINAL; }
|
||||
"iff" { FL; return yIFF; }
|
||||
"import" { FL; return yIMPORT; }
|
||||
"inside" { FL; return yINSIDE; }
|
||||
"int" { FL; return yINT; }
|
||||
"logic" { FL; return yLOGIC; }
|
||||
"longint" { FL; return yLONGINT; }
|
||||
@ -469,7 +470,6 @@ word [a-zA-Z0-9_]+
|
||||
"forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"inside" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
|
@ -332,6 +332,7 @@ class AstSenTree;
|
||||
%token<fl> yINITIAL "initial"
|
||||
%token<fl> yINOUT "inout"
|
||||
%token<fl> yINPUT "input"
|
||||
%token<fl> yINSIDE "inside"
|
||||
%token<fl> yINT "int"
|
||||
%token<fl> yINTEGER "integer"
|
||||
%token<fl> yLOCALPARAM "localparam"
|
||||
@ -557,7 +558,7 @@ class AstSenTree;
|
||||
// PSL op precedence
|
||||
%right yP_MINUSGT yP_LOGIFF
|
||||
%right yP_ORMINUSGT yP_OREQGT
|
||||
%left<fl> prPSLCLK
|
||||
%left<fl> prPSLCLK
|
||||
|
||||
// Verilog op precedence
|
||||
%right '?' ':'
|
||||
@ -567,7 +568,7 @@ class AstSenTree;
|
||||
%left '^' yP_XNOR
|
||||
%left '&' yP_NAND
|
||||
%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL
|
||||
%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE
|
||||
%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE
|
||||
%left yP_SLEFT yP_SRIGHT yP_SSRIGHT
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
@ -2245,6 +2246,20 @@ case_itemList<caseitemp>: // IEEE: { case_item + ... }
|
||||
| case_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,NULL,$4)); }
|
||||
;
|
||||
|
||||
open_range_list<nodep>: // ==IEEE: open_range_list + open_value_range
|
||||
open_value_range { $$ = $1; }
|
||||
| open_range_list ',' open_value_range { $$ = $1;$1->addNext($3); }
|
||||
;
|
||||
|
||||
open_value_range<nodep>: // ==IEEE: open_value_range
|
||||
value_range { $$ = $1; }
|
||||
;
|
||||
|
||||
value_range<nodep>: // ==IEEE: value_range
|
||||
expr { $$ = $1; }
|
||||
| '[' expr ':' expr ']' { $$ = new AstInsideRange($3,$2,$4); }
|
||||
;
|
||||
|
||||
caseCondList<nodep>: // IEEE: part of case_item
|
||||
expr { $$ = $1; }
|
||||
| caseCondList ',' expr { $$ = $1;$1->addNext($3); }
|
||||
@ -2757,7 +2772,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
||||
| ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); }
|
||||
//
|
||||
// // IEEE: inside_expression
|
||||
//UNSUP ~l~expr yINSIDE '{' open_range_list '}' { UNSUP }
|
||||
| ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside($2,$1,$4); }
|
||||
//
|
||||
// // IEEE: tagged_union_expression
|
||||
//UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP }
|
||||
|
18
test_regress/t/t_inside.pl
Executable file
18
test_regress/t/t_inside.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
69
test_regress/t/t_inside.v
Normal file
69
test_regress/t/t_inside.v
Normal file
@ -0,0 +1,69 @@
|
||||
// DESCRIPTION::Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2013 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||
|
||||
typedef enum logic [1:0]
|
||||
{ ZERO = 2'd0,
|
||||
ONE = 2'd1,
|
||||
TWO = 2'd2,
|
||||
THREE = 2'd3,
|
||||
XXX = 2'dx
|
||||
} num_t;
|
||||
|
||||
function automatic logic is_odd;
|
||||
input en;
|
||||
input num_t number;
|
||||
case (en)
|
||||
1'b1: begin
|
||||
unique if (number inside {ONE, THREE})
|
||||
is_odd = 1'b1;
|
||||
else if (number inside {ZERO, TWO})
|
||||
is_odd = 1'b0;
|
||||
else
|
||||
is_odd = 1'bx;
|
||||
end
|
||||
1'b0: is_odd = 1'bx;
|
||||
default: is_odd = 1'bx;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
`checkh ((4'd4 inside {4'd1,4'd5}), 1'b0);
|
||||
`checkh ((4'd4 inside {4'd1,4'd4}), 1'b1);
|
||||
//
|
||||
`checkh ((4'b1011 inside {4'b1001}), 1'b0);
|
||||
`checkh ((4'b1011 inside {4'b1xx1}), 1'b1); // Uses ==?
|
||||
`checkh ((4'b1001 inside {4'b1xx1}), 1'b1); // Uses ==?
|
||||
`checkh ((4'b1001 inside {4'b1??1}), 1'b1);
|
||||
`ifndef VERILATOR
|
||||
`checkh ((4'b1z11 inside {4'b11?1, 4'b1011}),1'bx);
|
||||
`endif
|
||||
// Range
|
||||
`checkh ((4'd4 inside {[4'd5:4'd3], [4'd10:4'd8]}), 1'b0); // If left of colon < never matches
|
||||
`checkh ((4'd3 inside {[4'd1:4'd2], [4'd3:4'd5]}), 1'b1);
|
||||
`checkh ((4'd4 inside {[4'd1:4'd2], [4'd3:4'd5]}), 1'b1);
|
||||
`checkh ((4'd5 inside {[4'd1:4'd2], [4'd3:4'd5]}), 1'b1);
|
||||
//
|
||||
// Unsupported $ bound
|
||||
//
|
||||
// Unsupported if unpacked array, elements tranversed
|
||||
//int unpackedarray [$] = '{8,9};
|
||||
//( expr inside {2, 3, unpackedarray}) // { 2,3,8,9}
|
||||
//
|
||||
`checkh (is_odd(1'b1, ZERO), 1'd0);
|
||||
`checkh (is_odd(1'b1, ONE), 1'd1);
|
||||
`checkh (is_odd(1'b1, TWO), 1'd0);
|
||||
`checkh (is_odd(1'b1, THREE),1'd1);
|
||||
`ifndef VERILATOR
|
||||
`checkh (is_odd(1'b1, XXX), 1'dx);
|
||||
`endif
|
||||
//
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user