Support inside expressions.

This commit is contained in:
Wilson Snyder 2013-02-02 12:55:28 -05:00
parent 91159da30d
commit 4968a2abc5
8 changed files with 192 additions and 4 deletions

View File

@ -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]

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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); }

View File

@ -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
View 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
View 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