Support .

This commit is contained in:
Wilson Snyder 2008-06-27 11:36:25 -04:00
parent fdcbedef8f
commit d6884db439
12 changed files with 115 additions and 11 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
*** Support $feof, $fflush. [Holger Waechtler]
*** Support $random.
* Verilator 3.665 2008/06/25
**** Ignore "// verilator" comments alone on endif lines. [Rodney Sinclair]

View File

@ -1569,6 +1569,12 @@ $setup, $setuphold, $skew, $timeskew, $width
All specify blocks and timing checks are ignored.
=item $random
$random does not support the optional argument to set the seed. Use the
srand function in C to accomplish this, and note there is only one random
number generator (not one per module).
=item $readmemb, $readmemh
Read memory commands should work properly. Note Verilator and the Verilog

View File

@ -80,23 +80,43 @@ IData VL_RAND32() {
#endif
}
IData VL_RAND_RESET_I(int outBits) {
IData VL_RANDOM_I(int obits) {
return VL_RAND32() & VL_MASK_I(obits);
}
QData VL_RANDOM_Q(int obits) {
QData data = ((QData)VL_RAND32()<<VL_ULL(32)) | (QData)VL_RAND32();
return data & VL_MASK_Q(obits);
}
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) {
for (int i=0; i<VL_WORDS_I(obits); i++) {
if (i<(VL_WORDS_I(obits)-1)) {
outwp[i] = VL_RAND32();
} else {
outwp[i] = VL_RAND32() & VL_MASK_I(obits);
}
}
return outwp;
}
IData VL_RAND_RESET_I(int obits) {
if (Verilated::randReset()==0) return 0;
IData data = ~0;
if (Verilated::randReset()!=1) { // if 2, randomize
data = VL_RAND32();
data = VL_RANDOM_I(obits);
}
if (outBits<32) data &= VL_MASK_I(outBits);
if (obits<32) data &= VL_MASK_I(obits);
return data;
}
QData VL_RAND_RESET_Q(int outBits) {
QData VL_RAND_RESET_Q(int obits) {
if (Verilated::randReset()==0) return 0;
QData data = VL_ULL(~0);
if (Verilated::randReset()!=1) { // if 2, randomize
data = ((QData)VL_RAND32()<<VL_ULL(32)) | (QData)VL_RAND32();
data = VL_RANDOM_Q(obits);
}
if (outBits<64) data &= VL_MASK_Q(outBits);
if (obits<64) data &= VL_MASK_Q(obits);
return data;
}

View File

@ -179,8 +179,13 @@ extern void vl_fatal (const char* filename, int linenum, const char* hier,
const char* msg);
//=========================================================================
// Extern functions -- Init time only, so slow is fine
// Extern functions -- Slow path
extern IData VL_RANDOM_I(int obits); ///< Randomize a signal
extern QData VL_RANDOM_Q(int obits); ///< Randomize a signal
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signal
/// Init time only, so slow is fine
extern IData VL_RAND_RESET_I(int obits); ///< Random reset a signal
extern QData VL_RAND_RESET_Q(int obits); ///< Random reset a signal
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp); ///< Random reset a signal

View File

@ -1768,14 +1768,18 @@ struct AstScopeName : public AstNode {
struct AstRand : public AstNodeTermop {
// Return a random number, based upon width()
AstRand(FileLine* fl, int wwidth) : AstNodeTermop(fl) {
width(wwidth,wwidth); }
private:
bool m_reset; // Random reset, versus always random
public:
AstRand(FileLine* fl, int wwidth, bool reset) : AstNodeTermop(fl) {
width(wwidth,wwidth); m_reset=reset; }
AstRand(FileLine* fl) : AstNodeTermop(fl), m_reset(false) { }
virtual ~AstRand() {}
virtual AstType type() const { return AstType::RAND;}
virtual AstNode* clone() { return new AstRand(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string emitVerilog() { return "$random"; }
virtual string emitOperator() { return "VL_RAND_RESET"; }
virtual string emitOperator() { return (m_reset ? "VL_RAND_RESET":"VL_RANDOM"); }
virtual bool cleanOut() { return true; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }

View File

@ -103,6 +103,10 @@ private:
virtual void visit(AstNeqCase* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
virtual void visit(AstNeqWild* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
//========
// Signed: Output signed
virtual void visit(AstRand* nodep, AstNUser*) { signed_Os_Ix(nodep); }
//=======
// Signed: Output signed iff LHS signed; unary operator
virtual void visit(AstNot* nodep, AstNUser*) { signed_Olhs(nodep); }

View File

@ -212,7 +212,7 @@ private:
new AstAnd(nodep->fileline(),
new AstConst(nodep->fileline(),numbx),
new AstRand(nodep->fileline(),
nodep->width())))));
nodep->width(), true)))));
// Add inits in front of other statement.
// In the future, we should stuff the initp into the module's constructor.
AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext();

View File

@ -362,6 +362,11 @@ private:
}
}
}
virtual void visit(AstRand* nodep, AstNUser* vup) {
if (vup->c()->prelim()) {
nodep->width(32,32); // Says the spec
}
}
virtual void visit(AstTime* nodep, AstNUser*) {
nodep->width(64,64);
}

View File

@ -141,6 +141,7 @@ escid \\[^ \t\f\r\n]+
"$hold" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$nochange" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$period" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$random" {yylval.fileline = CRELINE(); return yD_RANDOM;}
"$readmemb" {yylval.fileline = CRELINE(); return yD_READMEMB;}
"$readmemh" {yylval.fileline = CRELINE(); return yD_READMEMH;}
"$realtime" {yylval.fileline = CRELINE(); return yD_TIME;}

View File

@ -235,6 +235,7 @@ class AstSenTree;
%token<fileline> yD_ISUNKNOWN "$isunknown"
%token<fileline> yD_ONEHOT "$onehot"
%token<fileline> yD_ONEHOT0 "$onehot0"
%token<fileline> yD_RANDOM "$random"
%token<fileline> yD_READMEMB "$readmemb"
%token<fileline> yD_READMEMH "$readmemh"
%token<fileline> yD_SIGNED "$signed"
@ -1085,6 +1086,9 @@ exprNoStr: expr yP_OROR expr { $$ = new AstLogOr ($2,$1,$3); }
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
| yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")\n"); }
| yD_RANDOM '(' ')' { $$ = new AstRand($1); }
| yD_RANDOM { $$ = new AstRand($1); }
| yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); }
| yD_TIME { $$ = new AstTime($1); }
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); }

17
test_regress/t/t_sys_rand.pl Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.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
# General Public License or the Perl Artistic License.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,36 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
module t;
reg [31:0] lastrand;
reg [31:0] thisrand;
integer same = 0;
integer i;
`define TRIES 20
initial begin
// There's a 1^32 chance of the numbers being the same twice,
// so we'll allow one failure
lastrand = $random;
for (i=0; i<`TRIES; i=i+1) begin
thisrand = $random;
`ifdef TEST_VERBOSE
$write("Random = %x\n", thisrand);
`endif
if (thisrand == lastrand) same=same+1;
lastrand = thisrand;
end
if (same > 1) begin
$write("%%Error: Too many similar numbers: %d\n", same);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule