Detect MSB overflow when under VL_DEBUG, bug1238.
This commit is contained in:
parent
4d074b5414
commit
cbb7cd16d0
2
Changes
2
Changes
|
|
@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
**** Fix MacOS portability, bug1232. [Jeff Bush]
|
**** Fix MacOS portability, bug1232. [Jeff Bush]
|
||||||
|
|
||||||
|
**** Detect MSB overflow when under VL_DEBUG, bug1238. [Junyi Xi]
|
||||||
|
|
||||||
|
|
||||||
* Verilator 3.914 2017-10-14
|
* Verilator 3.914 2017-10-14
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1488,6 +1488,14 @@ const char* Verilated::commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
|
||||||
return outstr;
|
return outstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Verilated::overWidthError(const char* signame) VL_MT_SAFE {
|
||||||
|
// Slowpath - Called only when signal sets too high of a bit
|
||||||
|
std::string msg = (std::string("Testbench C set input '")
|
||||||
|
+ signame
|
||||||
|
+ "' to value that overflows what the signal's width can fit");
|
||||||
|
VL_FATAL_MT("unknown",0,"", msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void Verilated::quiesce() VL_MT_SAFE {
|
void Verilated::quiesce() VL_MT_SAFE {
|
||||||
#ifdef VL_THREADED
|
#ifdef VL_THREADED
|
||||||
// Wait until all threads under this evaluation are quiet
|
// Wait until all threads under this evaluation are quiet
|
||||||
|
|
|
||||||
|
|
@ -429,9 +429,14 @@ public:
|
||||||
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
|
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
|
||||||
// Internal: Create a new module name by concatenating two strings
|
// Internal: Create a new module name by concatenating two strings
|
||||||
static const char* catName(const char* n1, const char* n2); // Returns static data
|
static const char* catName(const char* n1, const char* n2); // Returns static data
|
||||||
|
|
||||||
|
// Internal: Throw signal assertion
|
||||||
|
static void overWidthError(const char* signame) VL_MT_SAFE;
|
||||||
|
|
||||||
// Internal: Find scope
|
// Internal: Find scope
|
||||||
static const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE;
|
static const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE;
|
||||||
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE;
|
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE;
|
||||||
|
|
||||||
// Internal: Get and set DPI context
|
// Internal: Get and set DPI context
|
||||||
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
|
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
|
||||||
static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep=scopep; }
|
static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep=scopep; }
|
||||||
|
|
@ -442,6 +447,7 @@ public:
|
||||||
static const char* dpiFilenamep() VL_MT_SAFE { return t_s.t_dpiFilename; }
|
static const char* dpiFilenamep() VL_MT_SAFE { return t_s.t_dpiFilename; }
|
||||||
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
|
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
|
||||||
static int exportFuncNum(const char* namep) VL_MT_SAFE;
|
static int exportFuncNum(const char* namep) VL_MT_SAFE;
|
||||||
|
|
||||||
static size_t serializedSize() VL_PURE { return sizeof(s_s); }
|
static size_t serializedSize() VL_PURE { return sizeof(s_s); }
|
||||||
static void* serializedPtr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only
|
static void* serializedPtr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only
|
||||||
#ifdef VL_THREADED
|
#ifdef VL_THREADED
|
||||||
|
|
|
||||||
|
|
@ -2878,7 +2878,7 @@ private:
|
||||||
bool m_unique0Pragma; // unique0 case
|
bool m_unique0Pragma; // unique0 case
|
||||||
bool m_priorityPragma; // priority case
|
bool m_priorityPragma; // priority case
|
||||||
public:
|
public:
|
||||||
AstIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
AstIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp=NULL)
|
||||||
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
||||||
m_uniquePragma=false; m_unique0Pragma=false; m_priorityPragma=false;
|
m_uniquePragma=false; m_unique0Pragma=false; m_priorityPragma=false;
|
||||||
}
|
}
|
||||||
|
|
@ -5153,6 +5153,7 @@ private:
|
||||||
string m_cname; // C name, for dpiExports
|
string m_cname; // C name, for dpiExports
|
||||||
string m_rtnType; // void, bool, or other return type
|
string m_rtnType; // void, bool, or other return type
|
||||||
string m_argTypes;
|
string m_argTypes;
|
||||||
|
string m_ifdef; // #ifdef symbol around this function
|
||||||
bool m_dontCombine:1; // V3Combine shouldn't compare this func tree, it's special
|
bool m_dontCombine:1; // V3Combine shouldn't compare this func tree, it's special
|
||||||
bool m_skipDecl:1; // Don't declare it
|
bool m_skipDecl:1; // Don't declare it
|
||||||
bool m_declPrivate:1; // Declare it private
|
bool m_declPrivate:1; // Declare it private
|
||||||
|
|
@ -5225,6 +5226,8 @@ public:
|
||||||
void funcPublic(bool flag) { m_funcPublic = flag; }
|
void funcPublic(bool flag) { m_funcPublic = flag; }
|
||||||
void argTypes(const string& str) { m_argTypes = str; }
|
void argTypes(const string& str) { m_argTypes = str; }
|
||||||
string argTypes() const { return m_argTypes; }
|
string argTypes() const { return m_argTypes; }
|
||||||
|
void ifdef(const string& str) { m_ifdef = str; }
|
||||||
|
string ifdef() const { return m_ifdef; }
|
||||||
void funcType(AstCFuncType flag) { m_funcType = flag; }
|
void funcType(AstCFuncType flag) { m_funcType = flag; }
|
||||||
AstCFuncType funcType() const { return m_funcType; }
|
AstCFuncType funcType() const { return m_funcType; }
|
||||||
bool isInline() const { return m_isInline; }
|
bool isInline() const { return m_isInline; }
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
// for all AstCoverDecl, move the declaration into a _configure_coverage AstCFunc.
|
// for all AstCoverDecl, move the declaration into a _configure_coverage AstCFunc.
|
||||||
// For each variable that needs reset, add a AstCReset node.
|
// For each variable that needs reset, add a AstCReset node.
|
||||||
//
|
//
|
||||||
|
// For primary inputs, add _eval_debug_assertions.
|
||||||
|
//
|
||||||
// This transformation honors outputSplitCFuncs.
|
// This transformation honors outputSplitCFuncs.
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
#include "config_build.h"
|
#include "config_build.h"
|
||||||
|
|
@ -101,8 +103,46 @@ private:
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
|
void V3CCtors::evalAsserts() {
|
||||||
|
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module
|
||||||
|
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", NULL, "void");
|
||||||
|
funcp->declPrivate(true);
|
||||||
|
funcp->isStatic(false);
|
||||||
|
funcp->slow(false);
|
||||||
|
funcp->ifdef("VL_DEBUG");
|
||||||
|
modp->addStmtp(funcp);
|
||||||
|
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||||
|
if (AstVar* varp = np->castVar()) {
|
||||||
|
if (varp->isPrimaryIn() && !varp->isSc()) {
|
||||||
|
if (AstBasicDType* basicp = varp->dtypeSkipRefp()->castBasicDType()) {
|
||||||
|
int storedWidth = basicp->widthAlignBytes() * 8;
|
||||||
|
int lastWordWidth = varp->width() % storedWidth;
|
||||||
|
if (lastWordWidth != 0) {
|
||||||
|
// if (signal & CONST(upper_non_clean_mask)) { fail; }
|
||||||
|
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
|
||||||
|
if (varp->isWide()) {
|
||||||
|
newp = new AstWordSel(varp->fileline(), newp,
|
||||||
|
new AstConst(varp->fileline(), varp->widthWords()-1));
|
||||||
|
}
|
||||||
|
uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
|
||||||
|
V3Number num (varp->fileline(), storedWidth, value);
|
||||||
|
newp = new AstAnd(varp->fileline(), newp,
|
||||||
|
new AstConst(varp->fileline(), num));
|
||||||
|
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
|
||||||
|
new AstCStmt(varp->fileline(), "Verilated::overWidthError(\""+varp->prettyName()+"\");"));
|
||||||
|
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||||
|
newp = ifp;
|
||||||
|
funcp->addStmtsp(newp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void V3CCtors::cctorsAll() {
|
void V3CCtors::cctorsAll() {
|
||||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||||
|
evalAsserts();
|
||||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
|
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
|
||||||
// Process each module in turn
|
// Process each module in turn
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@
|
||||||
class V3CCtors {
|
class V3CCtors {
|
||||||
public:
|
public:
|
||||||
static void cctorsAll();
|
static void cctorsAll();
|
||||||
|
private:
|
||||||
|
static void evalAsserts();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -872,6 +872,7 @@ class EmitCImp : EmitCStmts {
|
||||||
splitSizeInc(nodep);
|
splitSizeInc(nodep);
|
||||||
|
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
if (nodep->ifdef()!="") puts("#ifdef "+nodep->ifdef()+"\n");
|
||||||
if (nodep->isInline()) puts("VL_INLINE_OPT ");
|
if (nodep->isInline()) puts("VL_INLINE_OPT ");
|
||||||
puts(nodep->rtnTypeVoid()); puts(" ");
|
puts(nodep->rtnTypeVoid()); puts(" ");
|
||||||
puts(modClassName(m_modp)+"::"+nodep->name()
|
puts(modClassName(m_modp)+"::"+nodep->name()
|
||||||
|
|
@ -908,6 +909,7 @@ class EmitCImp : EmitCStmts {
|
||||||
|
|
||||||
//puts("__Vm_activity = true;\n");
|
//puts("__Vm_activity = true;\n");
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
|
if (nodep->ifdef()!="") puts("#endif // "+nodep->ifdef()+"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitChangeDet() {
|
void emitChangeDet() {
|
||||||
|
|
@ -1731,14 +1733,18 @@ void EmitCImp::emitSensitives() {
|
||||||
|
|
||||||
void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
void EmitCImp::emitWrapEval(AstNodeModule* modp) {
|
||||||
puts("\nvoid "+modClassName(modp)+"::eval() {\n");
|
puts("\nvoid "+modClassName(modp)+"::eval() {\n");
|
||||||
|
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate "+modClassName(modp)+"::eval\\n\"); );\n");
|
||||||
puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n");
|
puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n");
|
||||||
puts(EmitCBaseVisitor::symTopAssign()+"\n");
|
puts(EmitCBaseVisitor::symTopAssign()+"\n");
|
||||||
|
puts("#ifdef VL_DEBUG\n");
|
||||||
|
putsDecoration("// Debug assertions\n");
|
||||||
|
puts("_eval_debug_assertions();\n");
|
||||||
|
puts("#endif // VL_DEBUG\n");
|
||||||
putsDecoration("// Initialize\n");
|
putsDecoration("// Initialize\n");
|
||||||
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);\n");
|
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);\n");
|
||||||
if (v3Global.opt.inhibitSim()) {
|
if (v3Global.opt.inhibitSim()) {
|
||||||
puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n");
|
puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n");
|
||||||
}
|
}
|
||||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate "+modClassName(modp)+"::eval\\n\"); );\n");
|
|
||||||
|
|
||||||
if (v3Global.opt.threads()) { // THREADED-TODO move to per-train
|
if (v3Global.opt.threads()) { // THREADED-TODO move to per-train
|
||||||
uint32_t trainId = 0;
|
uint32_t trainId = 0;
|
||||||
|
|
@ -1859,9 +1865,11 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
|
||||||
AstCFunc* funcp = *it;
|
AstCFunc* funcp = *it;
|
||||||
if (!funcp->dpiImport()) { // DPI is prototyped in __Dpi.h
|
if (!funcp->dpiImport()) { // DPI is prototyped in __Dpi.h
|
||||||
ofp()->putsPrivate(funcp->declPrivate());
|
ofp()->putsPrivate(funcp->declPrivate());
|
||||||
|
if (funcp->ifdef()!="") puts("#ifdef "+funcp->ifdef()+"\n");
|
||||||
if (funcp->isStatic()) puts("static ");
|
if (funcp->isStatic()) puts("static ");
|
||||||
puts(funcp->rtnTypeVoid()); puts(" ");
|
puts(funcp->rtnTypeVoid()); puts(" ");
|
||||||
puts(funcp->name()); puts("("+cFuncArgs(funcp)+");\n");
|
puts(funcp->name()); puts("("+cFuncArgs(funcp)+");\n");
|
||||||
|
if (funcp->ifdef()!="") puts("#endif // "+funcp->ifdef()+"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ int main(int argc, char **argv, char **env) {
|
||||||
top->clk = 0;
|
top->clk = 0;
|
||||||
|
|
||||||
while (main_time < 190) { // Creates 2 files
|
while (main_time < 190) { // Creates 2 files
|
||||||
top->clk = ~top->clk;
|
top->clk = !top->clk;
|
||||||
top->eval();
|
top->eval();
|
||||||
|
|
||||||
if ((main_time % 100) == 0) {
|
if ((main_time % 100) == 0) {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ int main(int argc, char **argv, char **env) {
|
||||||
top->clk = 0;
|
top->clk = 0;
|
||||||
|
|
||||||
while (main_time < 190*VL_TIME_MULTIPLIER) {
|
while (main_time < 190*VL_TIME_MULTIPLIER) {
|
||||||
top->clk = ~top->clk;
|
top->clk = !top->clk;
|
||||||
top->eval();
|
top->eval();
|
||||||
tfp->dump((unsigned int)(main_time));
|
tfp->dump((unsigned int)(main_time));
|
||||||
// Advance by 0.5 time units, to make sure our fractional
|
// Advance by 0.5 time units, to make sure our fractional
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2010-2011 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.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#include "Vt_var_overwidth_bad.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
double main_time;
|
||||||
|
|
||||||
|
double sc_time_stamp () {
|
||||||
|
return main_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv, char **env) {
|
||||||
|
Verilated::debug(0);
|
||||||
|
|
||||||
|
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
|
||||||
|
|
||||||
|
main_time = 0;
|
||||||
|
|
||||||
|
topp->clk = 0;
|
||||||
|
topp->eval();
|
||||||
|
main_time += 10;
|
||||||
|
|
||||||
|
topp->clk = 0x2; // ILLEGAL
|
||||||
|
topp->eval();
|
||||||
|
topp->final();
|
||||||
|
|
||||||
|
delete topp; topp=NULL;
|
||||||
|
exit(0L);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2010 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 (
|
||||||
|
make_main => 0,
|
||||||
|
verilator_flags2 => ["--exe $Self->{t_dir}/t_var_overwidth_bad.cpp"],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
fails=>1,
|
||||||
|
expect=>
|
||||||
|
qr{%Error: unknown:0: Testbench C set input 'clk' to value that overflows what the signal's width can fit
|
||||||
|
Aborting....*}
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// Copyright 2010 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.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue