Compare commits

..
10 Commits
Author SHA1 Message Date
Wilson Snyder 58fc922737 Test fix
git-svn-id: file://localhost/svn/verilator/trunk/verilator@825 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:56:54 +00:00
Wilson Snyder 3b5c791332 Test fix
git-svn-id: file://localhost/svn/verilator/trunk/verilator@824 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:54:36 +00:00
Wilson Snyder 6e16bc1b7b Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@823 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:50:44 +00:00
Wilson Snyder 1aba0f6379 Show error code on non-generic errors; add TASKNSVAR
git-svn-id: file://localhost/svn/verilator/trunk/verilator@822 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:45:50 +00:00
Wilson Snyder 11cfa3c072 Suppress unused warnings using attribute
git-svn-id: file://localhost/svn/verilator/trunk/verilator@821 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 12:59:30 +00:00
Wilson Snyder 59141b1678 Fix --skip-identical
git-svn-id: file://localhost/svn/verilator/trunk/verilator@820 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-12 14:01:06 +00:00
Wilson Snyder 2083c071ce Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@817 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 15:42:32 +00:00
Wilson Snyder 3ad5872d30 Add verilator no_inline_task
git-svn-id: file://localhost/svn/verilator/trunk/verilator@816 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 15:41:42 +00:00
Wilson Snyder ea6bb21cdc Fix V3Subst mis-optimizing concats in t_case_write
git-svn-id: file://localhost/svn/verilator/trunk/verilator@815 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 15:34:50 +00:00
Wilson Snyder 3d4fe0364a No functional change; have V3Subst use a sub-structure.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@814 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 14:13:37 +00:00
38 changed files with 6118 additions and 1568 deletions
+14 -6
View File
@@ -3,17 +3,25 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.62**
* Verilator 3.622 10/17/2006 Stable
**** Fix link error when using --exe with --trace. [Eugene Weber]
**** Fix --skip-identical without --debug, broken in 3.621. [Andy Meier]
**** Public functions now allow > 64 bit arguments.
* Verilator 3.621 10/11/2006 Beta
**** Don't core dump on errors when not under --debug. [Allan Cochrane]
** Add /*verilator no_inline_task*/ to prevent over-expansion. [Eugene Weber]
*** Public functions now allow > 64 bit arguments.
**** Remove .vpp intermediate files when not under --debug.
* Verilator 3.620 10/04/2006
**** Fix link error when using --exe with --trace. [Eugene Weber]
**** Fix mis-optimization of wide concats with constants.
**** Fix core dump on printing error when not under --debug. [Allan Cochrane]
* Verilator 3.620 10/04/2006 Stable
*** Support simple inout task ports. [Eugene Weber]
@@ -436,7 +444,7 @@ indicates the contributor was also the author of the fix; Thanks!
**** Added NC Verilog as alternative to VCS for reference tests.
**** Support implicit wire declarations on input-only signals.
(Dangerous, as leads to wires without drivers, but allowed by spec.)
(Dangerous, as leads to wires without drivers, but allowed by spec.)
**** Fixed compile warnings on Suse 9.1
+68 -18
View File
@@ -407,7 +407,7 @@ compatibility.
=item --psl
Enable PSL parsing. Without this switch, psl meta-comments are ignored.
Enable PSL parsing. Without this switch, PSL meta-comments are ignored.
See the --assert flag to enable all assertions, and --coverage-user to
enable functional coverage.
@@ -609,7 +609,7 @@ Then we convert the SystemPerl output to SystemC.
$SYSTEMPERL/sp_preproc --preproc *.sp
(You can also skip the above sp_preproc by getting pure SystemC from
verilator by replacing the verilator --sp flag in the previous step with
Verilator by replacing the verilator --sp flag in the previous step with
-sc.)
We then can compile it
@@ -938,7 +938,7 @@ call C++ functions from your Verilog code.
String arguments will be put directly into the output C++ code. Expression
arguments will have the code to evaluate the expression inserted. Thus to
call a C++ function, $c("func(",a,")") will result in 'func(a)' in the
output C++ code. For input arguments, rather then hardcoding variable
output C++ code. For input arguments, rather then hard-coding variable
names in the string $c("func(a)"), instead pass the variable as an
expression $c("func(",a,")"). This will allow the call to work inside
Verilog functions where the variable is flattened out, and also enable
@@ -1056,6 +1056,14 @@ Disable the specified warning message for any warnings following the comment.
Re-enable the specified warning message for any warnings following the comment.
=item /*verilator no_inline_task*/
Used in a function or task variable definition section to specify the
function or task should not be inlined into where it is used. This may
reduce the size of the final executable when a task is used a very large
number of times. For this flag to work, the task and tasks below it must
be pure; they cannot reference any variables outside the task itself.
=item /*verilator sc_clock*/
Used after a input declaration to indicate the signal should be declared in
@@ -1271,7 +1279,7 @@ appropriate width.
$display and friends must have a constant format string as the first
argument (as with C's printf), you cannot simply list variables standalone.
=head1 ERRORS
=head1 ERRORS AND WARNINGS
Warnings may be disabled in two ways. First, when the warning is
printed it will include a warning code. Simply surround the offending
@@ -1281,13 +1289,13 @@ line with a warn_off/warn_on pair:
if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop;
// verilator lint_on UNSIGNED
They may also be globally disabled by invoking Verilator with the
C<-Wno-I<warning>> switch. This should be avoided, as it removes
all checking across the designs, and prevents other users from
compiling your code without knowing the magic set of disables needed
to successfully compile your design.
Warnings may also be globally disabled by invoking Verilator with the
C<-Wno-I<warning>> switch. This should be avoided, as it removes all
checking across the designs, and prevents other users from compiling your
code without knowing the magic set of disables needed to successfully
compile your design.
Warnings:
List of all warnings:
=over 4
@@ -1344,12 +1352,41 @@ signal before it is implicitly declared by a cell, and can lead to dangling
nets. A better option is the /*AUTOWIRE*/ feature of Verilog-Mode for
Emacs, available from L<http://www.veripool.com/>
=item IMPURE
Warns that a task or function that has been marked with /*verilator
no_inline_task*/ references variables that are not local to the task.
Verilator cannot schedule these variables correctly.
=item MULTIDRIVEN
Warns that the specified signal comes from multiple always blocks. This is
often unsupported by synthesis tools, and is considered bad style. It will
also cause longer runtimes due to reduced optimizations.
=item TASKNSVAR
Error when a call to a task or function has a output from that task tied to
a non-simple signal. Instead connect the task output to a temporary signal
of the appropriate width, and use that signal to set the appropriate
expression as the next statement. For example:
task foo; output sig; ... endtask
always @* begin
foo(bus_we_select_from[2]); // Will get TASKNSVAR error
end
Change this to:
reg foo_temp_out;
always @* begin
foo(foo_temp_out);
bus_we_select_from[2] = foo_temp_out;
end
Verilator doesn't do this conversion for you, as some more complicated
cases would result in simulator mismatches.
=item UNDRIVEN
Warns that the specified signal is never sourced.
@@ -1375,11 +1412,11 @@ may be only one particular usage of a multiply instantiated block. The
construct should be cleaned up to improve runtime; two times better
performance may be possible by fixing these warnings.
Unlike UNOPT this occurs after netlist flattening, and indicates a more
basic problem, as the less obvious case described under UNOPT does not
apply.
Unlike the UNOPT warning, this occurs after netlist flattening, and
indicates a more basic problem, as the less obvious case described under
UNOPT does not apply.
Often this is caused by logic that isn't truly circular as viewed by
Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
synthesis which analyzes interconnection per-bit, but is circular to
simulation which analyzes per-bus:
@@ -1387,12 +1424,25 @@ simulation which analyzes per-bus:
This statement needs to be evaluated multiple times, as a change in
"shift_in" requires "x" to be computed 3 times before it becomes stable.
For significantly better performance, split this into 2 separate signals:
For significantly better performance, split this into 2 separate signals,
and then if necessary generate the original signal:
wire [2:1] x_21 = x[1:0];
wire [0:0] x_0 = shift_in;
wire [2:0] x = {x_21, x_0};
This warning may also be due to clock enables. To fix these, use the
This logic needs to be evaluated only once. These sort of changes may also
speed up your traditional event driven simulator, as it will result in
fewer events per cycle.
The most complicated UNOPTFLAT path we've seen was due to low bits of a bus
being generated from an always statement that consumed high bits of the
same bus processed by another series of always blocks. The fix is the
same; split it into two separate signals, then create the bus from the two
separate signals.
The UNOPTFLAT warning may also be due to clock enables, identified from the
reported path going through a clock gating cell. To fix these, use the
clock_enable meta comment described above.
=item UNSIGNED
@@ -1450,8 +1500,8 @@ that is not yet supported in Verilator. See the Limitations chapter.
=item Verilated model didn't converge
Verilator sometimes has to evaluate combinatorial logic multiple times,
usually around code where a UNOPT warning was issued, but disabled. For
example:
usually around code where a UNOPTFLAT warning was issued, but disabled.
For example:
always @ (a) b=~a;
always @ (b) a=b
+32
View File
@@ -1328,6 +1328,38 @@ static inline WDataOutP VL_CONST_W_16X(int obits, WDataOutP o,
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
_END(obits,16); }
static inline WDataOutP VL_CONST_W_17X(int obits, WDataOutP o,
I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16;
_END(obits,17); }
static inline WDataOutP VL_CONST_W_18X(int obits, WDataOutP o,
I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16; o[17]=d17;
_END(obits,18); }
static inline WDataOutP VL_CONST_W_19X(int obits, WDataOutP o,
I d18,I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16; o[17]=d17; o[18]=d18;
_END(obits,19); }
static inline WDataOutP VL_CONST_W_20X(int obits, WDataOutP o,
I d19,I d18,I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16; o[17]=d17; o[18]=d18; o[19]=d19;
_END(obits,20); }
static inline WDataOutP VL_CONST_W_24X(int obits, WDataOutP o,
I d23,I d22,I d21,I d20,I d19,I d18,I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
+1
View File
@@ -57,6 +57,7 @@ public:
COVERAGE_BLOCK_OFF,
INLINE_MODULE,
NO_INLINE_MODULE,
NO_INLINE_TASK,
PUBLIC_MODULE,
PUBLIC_TASK
};
+3 -1
View File
@@ -349,7 +349,8 @@ void AstVar::dump(ostream& str) {
if (isSigPublic()) str<<" [P]";
if (attrClockEn()) str<<" [aCLKEN]";
if (attrFileDescr()) str<<" [aFD]";
if (isFuncLocal() || isFuncReturn()) str<<" [FUNC]";
if (isFuncReturn()) str<<" [FUNCRTN]";
else if (isFuncLocal()) str<<" [FUNC]";
str<<" "<<varType();
}
void AstSenTree::dump(ostream& str) {
@@ -375,6 +376,7 @@ void AstNodeFTaskRef::dump(ostream& str) {
}
void AstNodeFTask::dump(ostream& str) {
this->AstNode::dump(str);
if (taskPublic()) str<<" [PUBLIC]";
}
void AstCoverDecl::dump(ostream& str) {
this->AstNode::dump(str);
+4
View File
@@ -239,6 +239,10 @@ private:
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->bodysp());
}
virtual void visit(AstCCall* nodep, AstNUser*) {
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->argsp());
}
//--------------------
// Default: Just iterate
+14 -16
View File
@@ -96,22 +96,20 @@ public:
string cFuncArgs(AstCFunc* nodep) {
// Return argument list for given C function
string args = nodep->argTypes();
if (args=="") {
// Might be a user function with argument list.
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args+= ", ";
if (portp->isWide()) {
if (portp->isInOnly()) args += "const ";
args += portp->cType();
args += " (& "+portp->name();
args += ")["+cvtToStr(portp->widthWords())+"]";
} else {
args += portp->cType();
if (portp->isOutput()) args += "&";
args += " "+portp->name();
}
// Might be a user function with argument list.
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args+= ", ";
if (portp->isWide()) {
if (portp->isInOnly()) args += "const ";
args += portp->cType();
args += " (& "+portp->name();
args += ")["+cvtToStr(portp->widthWords())+"]";
} else {
args += portp->cType();
if (portp->isOutput()) args += "&";
args += " "+portp->name();
}
}
}
+1 -1
View File
@@ -109,7 +109,7 @@ public:
bool optSystemPerl() { return v3Global.opt.systemPerl(); }
static string symClassName() { return v3Global.opt.prefix()+"__Syms"; }
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp = vlSymsp->TOPp;"; }
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
static string modClassName(AstModule* modp) { // Return name of current module being processed
if (modp->isTop()) {
return v3Global.opt.prefix();
+5 -5
View File
@@ -92,7 +92,7 @@ void FileLine::lineDirective(const char* textp) {
bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code (msg.c_str());
if (code == V3ErrorCode::ERROR) {
if (code < V3ErrorCode::FIRST_WARN) {
return false;
} else {
warnOff(code, flag);
@@ -168,9 +168,8 @@ void FileLine::v3errorEnd(ostringstream& str) {
void V3Error::init() {
for (int i=0; i<V3ErrorCode::MAX; i++) {
s_describedEachWarn[i] = false;
s_pretendError[i] = false;
s_pretendError[i] = V3ErrorCode(i).pretendError();
}
pretendError(V3ErrorCode::BLKANDNBLK, true);
if (string(V3ErrorCode(V3ErrorCode::MAX).ascii()) != " MAX") {
v3fatalSrc("Enum table in V3ErrorCode::ascii() is munged");
@@ -204,8 +203,9 @@ void V3Error::abortIfErrors() {
string V3Error::msgPrefix(V3ErrorCode code) {
if (code==V3ErrorCode::SUPPRESS) return "-arning-suppressed: ";
else if (code==V3ErrorCode::FATAL) return "%Error: ";
else if (code==V3ErrorCode::ERROR
|| s_pretendError[code]) return "%Error: ";
else if (code==V3ErrorCode::ERROR) return "%Error: ";
else if (code<V3ErrorCode::FIRST_WARN
|| s_pretendError[code]) return "%Error-"+(string)code.ascii()+": ";
else return "%Warning-"+(string)code.ascii()+": ";
}
+10 -2
View File
@@ -34,9 +34,12 @@ public:
enum en {
SUPPRESS, // Warning suppressed by user
FATAL, // Kill the program
ERROR, // Error out, can't suppress
ERROR, // General error out, can't suppress
// Error codes:
TASKNSVAR, // Error: Task I/O not simple
// Warning codes:
FIRST_WARN, // Just a code so the program knows where to start warnings
//
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
CASEINCOMPLETE, // Case statement has missing values
CASEOVERLAP, // Case statements overlap
@@ -45,6 +48,7 @@ public:
COMBDLY, // Combinatorial delayed assignment
GENCLK, // Generated Clock
IMPLICIT, // Implicit wire
IMPURE, // Impure function not being inlined
MULTIDRIVEN, // Driven from multiple blocks
UNDRIVEN, // No drivers
UNOPT, // Unoptimizable block
@@ -66,10 +70,11 @@ public:
const char* names[] = {
// Leading spaces indicate it can't be disabled.
" SUPPRESS", " FATAL", " ERROR",
"TASKNSVAR",
" FIRST_WARN",
"BLKANDNBLK",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEX", "CMPCONST",
"COMBDLY", "GENCLK", "IMPLICIT",
"COMBDLY", "GENCLK", "IMPLICIT", "IMPURE",
"MULTIDRIVEN",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH",
@@ -79,6 +84,9 @@ public:
};
// Warnings that warn about nasty side effects
bool dangerous() const { return ( m_e==COMBDLY );};
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const { return ( m_e==BLKANDNBLK || m_e==IMPURE); };
};
inline bool operator== (V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); }
+3
View File
@@ -660,6 +660,9 @@ private:
// Lhs or Rhs may be word, long, or quad.
// newAstWordSelClone nicely abstracts the difference.
int rhsshift = rhsp->rhsp()->widthMin();
// Sometimes doing the words backwards is preferrable.
// When we have x={x,foo} backwards is better, when x={foo,x} forward is better
// However V3Subst tends to rip this up, so not worth optimizing now.
for (int w=0; w<rhsp->widthWords(); w++) {
addWordAssign(nodep, w,
new AstOr (rhsp->fileline(),
+3
View File
@@ -42,6 +42,9 @@ public:
}
static ofstream* new_ofstream(const string& filename, bool append=false) {
addTgtDepend(filename);
return new_ofstream_nodepend (filename, append);
}
static ofstream* new_ofstream_nodepend(const string& filename, bool append=false) {
if (append) {
return new ofstream(filename.c_str(), ios::app);
} else {
+3 -1
View File
@@ -374,7 +374,9 @@ private:
//UINFO(4," CCALL "<<nodep<<endl);
nodep->iterateChildren(*this);
// Enter the function and trace it
nodep->funcp()->accept(*this);
if (!nodep->funcp()->entryPoint()) { // else is non-inline or public function we optimize separately
nodep->funcp()->accept(*this);
}
}
virtual void visit(AstUCFunc* nodep, AstNUser*) {
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
+1
View File
@@ -141,6 +141,7 @@ class V3Options {
bool trace() const { return m_trace; }
bool traceDups() const { return m_traceDups; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool pins64() const { return m_pins64; }
bool profileCFuncs() const { return m_profileCFuncs; }
bool psl() const { return m_psl; }
+2
View File
@@ -79,6 +79,8 @@ protected:
ostream* osp;
if (v3Global.opt.preprocOnly()) {
osp = &cout;
} else if (!v3Global.opt.keepTempFiles()) { // Must match unlink rule in V3Read.cpp
osp = ofp = V3File::new_ofstream_nodepend(vppFilename);
} else {
osp = ofp = V3File::new_ofstream(vppFilename);
}
+1 -1
View File
@@ -92,7 +92,7 @@ void V3Read::readFile(FileLine* fileline, const string& modfilename, bool inLibr
lexFile (vppfilename, modfilename);
}
if (!V3Error::debugDefault()) {
if (!v3Global.opt.keepTempFiles()) { // Must match new_ofstream_nodepend rule in V3PreShell.cpp
unlink (vppfilename.c_str());
}
}
+153 -52
View File
@@ -19,10 +19,11 @@
//
//*************************************************************************
// V3Subst's Transformations:
//
//
// Each module:
// Search all ASSIGN(WORDSEL(...)) and build what it's assigned to
// Later usages of that word may then be replaced
// Later usages of that word may then be replaced as long as
// the RHS hasn't changed value.
//
//*************************************************************************
@@ -44,76 +45,97 @@
class SubstBaseVisitor : public AstNVisitor {
public:
static int debug() { return 0; }
static int debug() { return V3Error::debugDefault(); }
// static int debug() { return 9; }
};
//######################################################################
// Subst state, as a visitor of each AstNode
// Class for each word of a multi-word variable
class SubstVarWord {
protected:
// MEMBERS
AstNodeAssign* m_assignp; // Last assignment to each word of this var
int m_step; // Step number of last assignment
bool m_use; // True if each word was consumed
bool m_complex; // True if each word is complex
friend class SubstVarEntry;
// METHODS
void clear() {
m_assignp = NULL;
m_step = 0;
m_use = false;
m_complex = false;
}
};
//######################################################################
// Class for every variable we may process
class SubstVarEntry {
// MEMBERS
AstVar* m_varp; // Variable this tracks
bool m_complexAssign;// True if assigned multiple times or in complex mannor
AstNodeAssign* m_wholeAssignp; // Last assignment to entire array
bool m_wholeUse; // True if used as entire wide array
bool m_wordAssign; // True if any word assignments
bool m_wordUse; // True if any individual word usage
vector<AstNodeAssign*> m_wordAssignps; // Last assignment to each word of this var
vector<bool> m_wordUses; // True if each word was consumed
vector<bool> m_wordComplex; // True if each word is complex
SubstVarWord m_whole; // Data for whole vector used at once
vector<SubstVarWord> m_words; // Data for every word, if multi word variable
int debug() { return SubstBaseVisitor::debug(); }
public:
// CONSTRUCTORS
SubstVarEntry (AstVar* varp) { // Construction for when a var is used
m_varp = varp;
m_complexAssign = false;
m_wholeAssignp = NULL;
m_wholeUse = false;
m_whole.m_use = false;
m_wordAssign = false;
m_wordUse = false;
m_wordAssignps.resize(varp->widthWords());
m_wordUses.resize(varp->widthWords());
m_wordComplex.resize(varp->widthWords());
m_words.resize(varp->widthWords());
m_whole.clear();
for (int i=0; i<varp->widthWords(); i++) {
m_wordAssignps[i] = NULL;
m_wordUses[i] = false;
m_wordComplex[i] = false;
m_words[i].clear();
}
}
bool wordNumOk(int word) {
~SubstVarEntry() {}
private:
// METHODS
bool wordNumOk(int word) const {
return word < m_varp->widthWords();
}
AstNodeAssign* getWordAssignp(int word) {
AstNodeAssign* getWordAssignp(int word) const {
if (!wordNumOk(word)) return NULL;
else return m_wordAssignps[word];
else return m_words[word].m_assignp;
}
void assignWhole (AstNodeAssign* assp) {
if (m_wholeAssignp) m_complexAssign = true;
m_wholeAssignp = assp;
public:
void assignWhole (int step, AstNodeAssign* assp) {
if (m_whole.m_assignp) m_whole.m_complex = true;
m_whole.m_assignp = assp;
m_whole.m_step = step;
}
void assignWord (int word, AstNodeAssign* assp) {
if (!wordNumOk(word) || getWordAssignp(word) || m_wordComplex[word]) m_complexAssign = true;
void assignWord (int step, int word, AstNodeAssign* assp) {
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) m_whole.m_complex = true;
m_wordAssign = true;
if (wordNumOk(word)) m_wordAssignps[word] = assp;
if (wordNumOk(word)) {
m_words[word].m_assignp = assp;
m_words[word].m_step = step;
}
}
void assignWordComplex (int word) {
if (!wordNumOk(word) || getWordAssignp(word) || m_wordComplex[word]) m_complexAssign = true;
m_wordComplex[word] = true;
void assignWordComplex (int step, int word) {
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) m_whole.m_complex = true;
m_words[word].m_complex = true;
}
void assignComplex() {
m_complexAssign = true;
void assignComplex(int step) {
m_whole.m_complex = true;
}
void consumeWhole() { //==consumeComplex as we don't know the difference
m_wholeUse = true;
m_whole.m_use = true;
}
void consumeWord(int word) {
m_wordUses[word] = true;
m_words[word].m_use = true;
m_wordUse = true;
}
// ACCESSORS
AstNode* substWhole(AstNode* errp) {
if (!m_varp->isWide()
&& !m_complexAssign && m_wholeAssignp && !m_wordAssign) {
AstNodeAssign* assp = m_wholeAssignp;
&& !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
AstNodeAssign* assp = m_whole.m_assignp;
if (!assp) errp->v3fatalSrc("Reading whole that was never assigned");
return (assp->rhsp());
} else {
@@ -121,7 +143,7 @@ public:
}
}
AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for
if (!m_complexAssign && !m_wholeAssignp && !m_wordComplex[word]) {
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
AstNodeAssign* assp = getWordAssignp(word);
if (!assp) errp->v3fatalSrc("Reading a word that was never assigned, or bad word #");
return (assp->rhsp());
@@ -129,34 +151,90 @@ public:
return NULL;
}
}
int getWholeStep() const {
return m_whole.m_step;
}
int getWordStep(int word) const {
if (!wordNumOk(word)) return 0; else return m_words[word].m_step;
}
void deleteAssign (AstNodeAssign* nodep) {
UINFO(5, "Delete "<<nodep<<endl);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
void deleteUnusedAssign() {
// If there are unused assignments in this var, kill them
if (!m_wholeUse && !m_wordUse && m_wholeAssignp) {
deleteAssign (m_wholeAssignp); m_wholeAssignp=NULL;
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
deleteAssign (m_whole.m_assignp); m_whole.m_assignp=NULL;
}
for (unsigned i=0; i<m_wordUses.size(); i++) {
if (!m_wholeUse && !m_wordUses[i] && m_wordAssignps[i] && !m_wordComplex[i]) {
deleteAssign (m_wordAssignps[i]); m_wordAssignps[i]=NULL;
for (unsigned i=0; i<m_words.size(); i++) {
if (!m_whole.m_use && !m_words[i].m_use && m_words[i].m_assignp && !m_words[i].m_complex) {
deleteAssign (m_words[i].m_assignp); m_words[i].m_assignp=NULL;
}
}
}
};
//######################################################################
// See if any variables have changed value since we determined subst value, as a visitor of each AstNode
class SubstUseVisitor : public SubstBaseVisitor {
private:
// NODE STATE
// See SubstVisitor
//
// STATE
int m_origStep; // Step number where subst was recorded
bool m_ok; // No misassignments found
// METHODS
SubstVarEntry* findEntryp(AstVarRef* nodep) {
return (SubstVarEntry*)(nodep->varp()->userp()); // Might be NULL
}
// VISITORS
virtual void visit(AstVarRef* nodep, AstNUser*) {
SubstVarEntry* entryp = findEntryp (nodep);
if (entryp) {
// Don't sweat it. We assign a new temp variable for every new assignment,
// so there's no way we'd ever replace a old value.
} else {
// A simple variable; needs checking.
if (m_origStep < nodep->varp()->user2()) {
if (m_ok) UINFO(9," RHS variable changed since subst recorded: "<<nodep<<endl);
m_ok = false;
}
}
}
virtual void visit(AstConst* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
SubstUseVisitor(AstNode* nodep, int origStep) {
UINFO(9, " SubstUseVisitor "<<origStep<<" "<<nodep<<endl);
m_ok = true;
m_origStep = origStep;
nodep->accept(*this);
}
virtual ~SubstUseVisitor() {}
// METHODS
bool ok() const { return m_ok; }
};
//######################################################################
// Subst state, as a visitor of each AstNode
class SubstVisitor : public SubstBaseVisitor {
private:
// NODE STATE
// Passed to SubstElimVisitor
// Passed to SubstUseVisitor
// AstVar::userp -> SubstVar* for usage var, 0=not set yet
// AstVar::user2 -> int step number for last assignment, 0=not set yet
//
// STATE
vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
int m_ops; // Number of operators on assign rhs
int m_assignStep; // Assignment number to determine var lifetime
V3Double0 m_statSubsts; // Statistic tracking
enum { SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
@@ -178,6 +256,7 @@ private:
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
m_ops = 0;
m_assignStep++;
nodep->rhsp()->iterateAndNext(*this);
bool hit=false;
if (AstVarRef* varrefp = nodep->lhsp()->castVarRef()) {
@@ -186,10 +265,10 @@ private:
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
entryp->assignComplex();
entryp->assignComplex(m_assignStep);
} else {
UINFO(8," ASSIGNwhole "<<varrefp<<endl);
entryp->assignWhole(nodep);
entryp->assignWhole(m_assignStep, nodep);
}
}
}
@@ -202,10 +281,10 @@ private:
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
entryp->assignWordComplex(word);
entryp->assignWordComplex(m_assignStep, word);
} else {
UINFO(8," ASSIGNword"<<word<<" "<<varrefp<<endl);
entryp->assignWord(word, nodep);
entryp->assignWord(m_assignStep, word, nodep);
}
}
}
@@ -238,7 +317,13 @@ private:
UINFO(8," USEword"<<word<<" "<<varrefp<<endl);
SubstVarEntry* entryp = getEntryp(varrefp);
if (AstNode* substp = entryp->substWord (nodep, word)) {
replaceSubstEtc(nodep, substp); nodep=NULL;
// Check that the RHS hasn't changed value since we recorded it.
SubstUseVisitor visitor (substp, entryp->getWordStep(word));
if (visitor.ok()) {
replaceSubstEtc(nodep, substp); nodep=NULL;
} else {
entryp->consumeWord(word);
}
} else {
entryp->consumeWord(word);
}
@@ -247,14 +332,27 @@ private:
}
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// Any variable
if (nodep->lvalue()) {
m_assignStep++;
nodep->varp()->user2(m_assignStep);
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
}
if (nodep->varp()->isStatementTemp()) {
SubstVarEntry* entryp = getEntryp (nodep);
if (nodep->lvalue()) {
UINFO(8," ASSIGNcpx "<<nodep<<endl);
entryp->assignComplex();
entryp->assignComplex(m_assignStep);
} else if (AstNode* substp = entryp->substWhole(nodep)) {
UINFO(8," USEwhole "<<nodep<<endl);
replaceSubstEtc(nodep, substp); nodep=NULL;
// Check that the RHS hasn't changed value since we recorded it.
SubstUseVisitor visitor (substp, entryp->getWholeStep());
if (visitor.ok()) {
UINFO(8," USEwhole "<<nodep<<endl);
replaceSubstEtc(nodep, substp); nodep=NULL;
} else {
UINFO(8," USEwholeButChg "<<nodep<<endl);
entryp->consumeWhole();
}
} else { // Consumed w/o substitute
UINFO(8," USEwtf "<<nodep<<endl);
entryp->consumeWhole();
@@ -262,6 +360,7 @@ private:
}
}
virtual void visit(AstVar* nodep, AstNUser*) {}
virtual void visit(AstConst* nodep, AstNUser*) {}
virtual void visit(AstNode* nodep, AstNUser*) {
m_ops++;
if (!nodep->isSubstOptimizable()) {
@@ -273,7 +372,9 @@ public:
// CONSTUCTORS
SubstVisitor(AstNode* nodep) {
AstNode::userClearTree(); // userp() used on entire tree
AstNode::user2ClearTree(); // user2p() used on entire tree
m_ops = 0;
m_assignStep = 0;
nodep->accept(*this);
}
virtual ~SubstVisitor() {
+310 -102
View File
@@ -39,6 +39,54 @@
#include "V3Inst.h"
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include "V3Graph.h"
//######################################################################
// Graph subclasses
class TaskBaseVertex : public V3GraphVertex {
AstNode* m_impurep; // Node causing impure function w/ outside references
bool m_noInline; // Marked with pragma
public:
TaskBaseVertex(V3Graph* graphp)
: V3GraphVertex(graphp), m_impurep(NULL), m_noInline(false) {}
virtual ~TaskBaseVertex() {}
bool pure() const { return m_impurep==NULL; }
AstNode* impureNode() const { return m_impurep; }
void impure(AstNode* nodep) { m_impurep = nodep; }
bool noInline() const { return m_noInline; }
void noInline(bool flag) { m_noInline = flag; }
};
class TaskFTaskVertex : public TaskBaseVertex {
// Every task gets a vertex, and we link tasks together based on funcrefs.
AstNodeFTask* m_nodep;
public:
TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep)
: TaskBaseVertex(graphp), m_nodep(nodep) {}
virtual ~TaskFTaskVertex() {}
AstNodeFTask* nodep() const { return m_nodep; }
virtual string name() const { return nodep()->name(); }
virtual string dotColor() const { return pure() ? "black" : "red"; }
};
class TaskCodeVertex : public TaskBaseVertex {
// Top vertex for all calls not under another task
public:
TaskCodeVertex(V3Graph* graphp)
: TaskBaseVertex(graphp) {}
virtual ~TaskCodeVertex() {}
virtual string name() const { return "*CODE*"; }
virtual string dotColor() const { return "green"; }
};
class TaskEdge : public V3GraphEdge {
public:
TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top)
: V3GraphEdge(graphp, fromp, top, 1, false) {}
virtual ~TaskEdge() {}
virtual string dotLabel() const { return "w"+cvtToStr(weight()); }
};
//######################################################################
@@ -47,12 +95,17 @@ private:
// NODE STATE
// Output:
// AstNodeFTask::user3p // AstScope* this FTask is under
// AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under
// AstVar::user4p // GraphFTaskVertex* this variable is declared in
// TYPES
typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap;
// MEMBERS
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
AstAssignW* m_assignwp; // Current assignment
V3Graph m_callGraph; // Task call graph
TaskBaseVertex* m_curVxp; // Current vertex we're adding to
public:
// METHODS
AstScope* getScope(AstNodeFTask* nodep) {
@@ -65,7 +118,30 @@ public:
if (iter == m_varToScopeMap.end()) nodep->v3fatalSrc("No scope for var");
return iter->second;
}
bool ftaskNoInline(AstNodeFTask* nodep) {
return (getFTaskVertex(nodep)->noInline());
}
void checkPurity(AstNodeFTask* nodep) {
checkPurity(nodep, getFTaskVertex(nodep));
}
void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) {
if (!vxp->pure()) {
nodep->v3warn(IMPURE,"Unsupported: External variable referenced by non-inlined function/task: "<<nodep->prettyName());
vxp->impureNode()->v3warn(IMPURE,"... Location of the external reference: "<<vxp->impureNode()->prettyName());
}
// And, we need to check all tasks this task calls
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep=edgep->outNextp()) {
checkPurity(nodep, static_cast<TaskBaseVertex*>(edgep->top()));
}
}
private:
TaskBaseVertex* getFTaskVertex(AstNodeFTask* nodep) {
if (!nodep->user4p()) {
nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
}
return static_cast<TaskBaseVertex*>(nodep->user4p()->castGraphVertex());
}
// VISITORS
virtual void visit(AstScope* nodep, AstNUser*) {
// Each FTask is unique per-scope, so AstNodeFTaskRefs do not need
@@ -90,7 +166,7 @@ private:
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
m_assignwp = nodep;
nodep->iterateChildren(*this); // May delete nodep.
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
m_assignwp = NULL;
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
@@ -104,6 +180,37 @@ private:
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
}
// We make multiple edges if a task is called multiple times from another task.
new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp()));
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
UINFO(9," TASK "<<nodep<<endl);
TaskBaseVertex* lastVxp = m_curVxp;
m_curVxp = getFTaskVertex(nodep);
nodep->iterateChildren(*this);
m_curVxp = lastVxp;
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::NO_INLINE_TASK) {
// Just mark for the next steps, and we're done with it.
m_curVxp->noInline(true);
nodep->unlinkFrBack()->deleteTree();
}
else {
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
nodep->user4p(m_curVxp); // Remember what task it's under
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->varp()->user4p() != m_curVxp) {
if (m_curVxp->pure()) {
m_curVxp->impure(nodep);
}
}
}
//--------------------
// Default: Just iterate
@@ -112,10 +219,16 @@ private:
}
public:
// CONSTUCTORS
TaskStateVisitor(AstNode* nodep) {
TaskStateVisitor(AstNetlist* nodep) {
m_assignwp = NULL;
m_curVxp = new TaskCodeVertex(&m_callGraph);
AstNode::user3ClearTree();
AstNode::user4ClearTree();
//
nodep->iterateAndNext(*this, NULL);
//
m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue);
m_callGraph.dumpDotFilePrefixed("task_call");
}
virtual ~TaskStateVisitor() {}
};
@@ -165,6 +278,7 @@ private:
// AstNodeFTask::user // True if its been expanded
// Each funccall
// AstVar::user2p // AstVarScope* to replace varref with
// AstNodeFTask::user5p // AstCFunc* created for non-inlined tasks
// TYPES
enum InsertMode {
@@ -207,79 +321,81 @@ private:
//
// Create input variables
AstNode::user2ClearTree();
AstNode* pinp = refp->pinsp();
AstNode* nextpinp = pinp;
AstNode* nextstmtp;
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
nextstmtp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
portp->unlinkFrBack(); // Remove it from the clone (not original)
pushDeletep(portp);
if (portp->isIO()) {
if (pinp==NULL) {
refp->v3error("Too few arguments in function call");
pinp = new AstConst(refp->fileline(), 0);
m_modp->addStmtp(pinp); // For below unlink
}
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
//
nextpinp = pinp->nextp();
pinp->unlinkFrBack(); // Relinked to assignment below
//
if (portp->isInout()) {
if (AstVarRef* varrefp = pinp->castVarRef()) {
// Connect to this exact variable
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
portp->user2p(localVscp);
} else {
pinp->v3error("Unsupported: Function/task input argument is not simple variable");
{
AstNode* pinp = refp->pinsp();
AstNode* nextpinp = pinp;
AstNode* nextstmtp;
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
nextstmtp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
portp->unlinkFrBack(); // Remove it from the clone (not original)
pushDeletep(portp);
if (portp->isIO()) {
if (pinp==NULL) {
refp->v3error("Too few arguments in function call");
pinp = new AstConst(refp->fileline(), 0);
m_modp->addStmtp(pinp); // For below unlink
}
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
//
nextpinp = pinp->nextp();
pinp->unlinkFrBack(); // Relinked to assignment below
//
if (portp->isInout()) {
if (AstVarRef* varrefp = pinp->castVarRef()) {
// Connect to this exact variable
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
portp->user2p(localVscp);
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
}
}
else if (portp->isOutput() && outvscp) {
refp->v3error("Outputs not allowed in function declarations");
}
else if (portp->isOutput()) {
// Make output variables
// Correct lvalue; we didn't know when we linked
if (AstVarRef* varrefp = pinp->castVarRef()) {
varrefp->lvalue(true);
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Task output pin connected to non-variable");
}
// Even if it's referencing a varref, we still make a temporary
// Else task(x,x,x) might produce incorrect results
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(outvscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
pinp,
new AstVarRef(outvscp->fileline(), outvscp, false));
// Put assignment BEHIND of all other statements
beginp->addNext(assp);
}
else if (portp->isInput()) {
// Make input variable
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(inVscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
new AstVarRef(inVscp->fileline(), inVscp, true),
pinp);
// Put assignment in FRONT of all other statements
if (AstNode* afterp = beginp->nextp()) {
afterp->unlinkFrBackWithNext();
assp->addNext(afterp);
}
beginp->addNext(assp);
}
}
else if (portp->isOutput() && outvscp) {
refp->v3error("Outputs not allowed in function declarations");
else { // Var is not I/O
// Move it to a new localized variable
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(localVscp);
}
else if (portp->isOutput()) {
// Make output variables
// Correct lvalue; we didn't know when we linked
if (AstVarRef* varrefp = pinp->castVarRef()) {
varrefp->lvalue(true);
} else {
pinp->v3error("Unsupported: Task output pin connected to non-variable");
}
// Even if it's referencing a varref, we still make a temporary
// Else task(x,x,x) might produce incorrect results
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(outvscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
pinp,
new AstVarRef(outvscp->fileline(), outvscp, false));
// Put assignment BEHIND of all other statements
beginp->addNext(assp);
}
else if (portp->isInput()) {
// Make input variable
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(inVscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
new AstVarRef(inVscp->fileline(), inVscp, true),
pinp);
// Put assignment in FRONT of all other statements
if (AstNode* afterp = beginp->nextp()) {
afterp->unlinkFrBackWithNext();
assp->addNext(afterp);
}
beginp->addNext(assp);
}
}
else { // Var is not I/O
// Move it to a new localized variable
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(localVscp);
}
}
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
}
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
// Create function output variables
if (outvscp) {
//UINFO(0, "setflag on "<<funcp->fvarp()<<" to "<<outvscp<<endl);
@@ -292,9 +408,71 @@ private:
return beginp;
}
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
// outvscp is the variable for functions only, if NULL, it's a task
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?");
AstCFunc* cfuncp = refp->taskp()->user5p()->castNode()->castCFunc();
AstCFunc* makeUserFunc(AstNodeFTask* nodep) {
// Given a already cloned node, make a public C function.
if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?");
//
AstNode* beginp = new AstComment(refp->fileline(), (string)("Function: ")+refp->name());
AstCCall* ccallp = new AstCCall(refp->fileline(), cfuncp, NULL);
beginp->addNext(ccallp);
// Convert complicated outputs to temp signals
{
AstNode* pinp = refp->pinsp();
AstNode* nextpinp = pinp;
AstNode* nextstmtp;
for (AstNode* stmtp = refp->taskp()->stmtsp(); stmtp; pinp=nextpinp, stmtp=nextstmtp) {
nextstmtp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()) {
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
//
nextpinp = pinp->nextp();
//
if (portp->isInout()) {
if (pinp->castVarRef()) {
// Connect to this exact variable
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
}
}
else if (portp->isOutput()) {
// Make output variables
// Correct lvalue; we didn't know when we linked
if (AstVarRef* varrefp = pinp->castVarRef()) {
varrefp->lvalue(true);
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Task output pin connected to non-variable");
}
}
}
}
}
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
}
// First argument is symbol table, then output if a function
ccallp->argTypes("vlSymsp");
if (outvscp) {
ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
}
// Create connections
AstNode* nextpinp;
for (AstNode* pinp = refp->pinsp(); pinp; pinp=nextpinp) {
nextpinp = pinp->nextp();
// Move pin to the CCall
pinp->unlinkFrBack();
ccallp->addArgsp(pinp);
}
if (debug()>=9) { beginp->dumpTree(cout,"-nitask: "); }
return beginp;
}
AstCFunc* makeUserFunc(AstNodeFTask* nodep, bool forUser) {
// Given a already cloned node, make a public C function, or a non-inline C function
// Probably some of this work should be done later, but...
// should the type of the function be bool/uint32/64 etc (based on lookup) or IData?
AstNode::user2ClearTree();
@@ -305,6 +483,7 @@ private:
if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) {
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
if (!forUser) portp->funcReturn(false); // Converting return to 'outputs'
portp->unlinkFrBack();
rtnvarp = portp;
rtnvarp->funcLocal(true);
@@ -315,20 +494,28 @@ private:
nodep->v3fatalSrc("function without function output variable");
}
}
AstCFunc* funcp = new AstCFunc(nodep->fileline(), nodep->name(),
m_scopep,
(rtnvarp?rtnvarp->cType():""));
if (rtnvarp) funcp->addArgsp(rtnvarp);
funcp->dontCombine(true);
funcp->funcPublic(true);
funcp->entryPoint(true);
funcp->isStatic(false);
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
string(forUser?"":"__VnoInFunc_") + nodep->name(),
m_scopep,
((forUser && rtnvarp)?rtnvarp->cType():""));
cfuncp->dontCombine(true);
cfuncp->entryPoint(true);
cfuncp->funcPublic(forUser);
cfuncp->isStatic(!forUser);
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
funcp->addInitsp(
new AstCStmt(nodep->fileline(),
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
if (forUser) {
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
cfuncp->addInitsp(
new AstCStmt(nodep->fileline(),
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
} else {
// Need symbol table
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
}
// Fake output variable if was a function
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
cfuncp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
// Create list of arguments and move to function
for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp=nextp) {
@@ -338,7 +525,7 @@ private:
// Move it to new function
portp->unlinkFrBack();
portp->funcLocal(true);
funcp->addArgsp(portp);
cfuncp->addArgsp(portp);
} else {
// "Normal" variable, mark inside function
portp->funcLocal(true);
@@ -350,18 +537,19 @@ private:
}
// Move body
AstNode* bodysp = nodep->stmtsp();
if (bodysp) { bodysp->unlinkFrBackWithNext(); funcp->addStmtsp(bodysp); }
if (bodysp) { bodysp->unlinkFrBackWithNext(); cfuncp->addStmtsp(bodysp); }
// Return statement
if (rtnvscp) {
funcp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
if (rtnvscp && forUser) {
cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
}
// Replace variable refs
TaskRelinkVisitor visit (funcp);
TaskRelinkVisitor visit (cfuncp);
// Delete rest of cloned task and return new func
pushDeletep(nodep); nodep=NULL;
if (debug()>=9) { funcp->dumpTree(cout,"-userFunc: "); }
return funcp;
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
if (debug()>=9 && !forUser) { cfuncp->dumpTree(cout,"-noInFunc: "); }
return cfuncp;
}
void iterateIntoFTask(AstNodeFTask* nodep) {
@@ -421,7 +609,12 @@ private:
if (debug()>=9) { nodep->dumpTree(cout,"-inltask:"); }
// Create cloned statements
string namePrefix = "__Vtask_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
AstNode* beginp = createInlinedFTask(nodep, namePrefix, NULL);
AstNode* beginp;
if (m_statep->ftaskNoInline(nodep->taskp())) {
beginp = createNonInlinedFTask(nodep, namePrefix, NULL);
} else {
beginp = createInlinedFTask(nodep, namePrefix, NULL);
}
// Replace the ref
nodep->replaceWith(beginp);
nodep->deleteTree(); nodep=NULL;
@@ -442,7 +635,13 @@ private:
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
AstNode* beginp = createInlinedFTask(nodep, namePrefix, outvscp);
AstNode* beginp;
if (m_statep->ftaskNoInline(nodep->taskp())) {
// This may share VarScope's with a public task, if any. Yuk.
beginp = createNonInlinedFTask(nodep, namePrefix, outvscp);
} else {
beginp = createInlinedFTask(nodep, namePrefix, outvscp);
}
// Replace the ref
AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false);
nodep->replaceWith(outrefp);
@@ -450,27 +649,34 @@ private:
insertBeforeStmt(nodep, beginp);
// Cleanup
nodep->deleteTree(); nodep=NULL;
UINFO(4," Done.\n");
UINFO(4," Func REF Done.\n");
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
UINFO(4," Inline "<<nodep<<endl);
InsertMode prevInsMode = m_insMode;
AstNode* prevInsStmtp = m_insStmtp;
m_insMode = IM_BEFORE;
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
if (!nodep->user()) {
// Expand functions in it & Mark for later delete
// Expand functions in it
nodep->user(true);
if (!nodep->taskPublic()) {
nodep->unlinkFrBack();
} else {
if (nodep->taskPublic()) {
// Clone it first, because we may have later FTaskRef's that still need
// the original version.
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
AstCFunc* cfuncp = makeUserFunc(clonedFuncp);
// Replace it
nodep->replaceWith(cfuncp);
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, true);
nodep->addNextHere(cfuncp);
iterateIntoFTask(clonedFuncp); // Do the clone too
}
if (m_statep->ftaskNoInline(nodep)) {
m_statep->checkPurity(nodep);
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false);
nodep->user5p(cfuncp);
nodep->addNextHere(cfuncp);
iterateIntoFTask(clonedFuncp); // Do the clone too
}
// Any variables inside the function still have varscopes pointing to them.
// We're going to delete the vars, so delete the varscopes.
if (nodep->castFunc()) {
@@ -489,6 +695,7 @@ private:
}
}
// Just push, as other references to func may remain until visitor exits
nodep->unlinkFrBack();
pushDeletep(nodep); nodep=NULL;
}
m_insMode = prevInsMode;
@@ -532,6 +739,7 @@ public:
m_scopep = NULL;
m_insStmtp = NULL;
AstNode::userClearTree();
AstNode::user5ClearTree();
nodep->accept(*this);
}
virtual ~TaskVisitor() {}
+1 -1
View File
@@ -24,7 +24,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.620 10/04/2006"
#define DTVERSION "Verilator 3.622 10/17/2006"
//**********************************************************************
//**** Functions
+1
View File
@@ -429,6 +429,7 @@ escid \\[^ \t\f\r\n]+
<VLG,PSL>"/*verilator full_case*/" {yylval.fileline = CRELINE(); return yVL_FULL_CASE;}
<VLG,PSL>"/*verilator inline_module*/" {yylval.fileline = CRELINE(); return yVL_INLINE_MODULE;}
<VLG,PSL>"/*verilator no_inline_module*/" {yylval.fileline = CRELINE(); return yVL_NO_INLINE_MODULE;}
<VLG,PSL>"/*verilator no_inline_task*/" {yylval.fileline = CRELINE(); return yVL_NO_INLINE_TASK;}
<VLG,PSL>"/*verilator one_cold*/" {yylval.fileline = CRELINE(); return yVL_ONE_COLD;}
<VLG,PSL>"/*verilator one_hot*/" {yylval.fileline = CRELINE(); return yVL_ONE_HOT;}
<VLG,PSL>"/*verilator parallel_case*/" {yylval.fileline = CRELINE(); return yVL_PARALLEL_CASE;}
+3 -1
View File
@@ -168,6 +168,7 @@ class AstSenTree;
%token<fileline> yVL_FULL_CASE "/*verilator full_case*/"
%token<fileline> yVL_INLINE_MODULE "/*verilator inline_module*/"
%token<fileline> yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/"
%token<fileline> yVL_NO_INLINE_TASK "/*verilator no_inline_task*/"
%token<fileline> yVL_ONE_COLD "/*verilator one_cold*/"
%token<fileline> yVL_ONE_HOT "/*verilator one_hot*/"
%token<fileline> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
@@ -729,7 +730,8 @@ funcVarList: funcVar { $$ = $1; }
funcVar: ioDecl { $$ = $1; }
| varDecl { $$ = $1; }
| yVL_PUBLIC { $$ = new AstPragma ($1,AstPragmaType::PUBLIC_TASK); }
| yVL_PUBLIC { $$ = new AstPragma($1,AstPragmaType::PUBLIC_TASK); }
| yVL_NO_INLINE_TASK { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_TASK); }
;
constExpr: expr { $$ = $1; }
+2 -2
View File
@@ -20,8 +20,8 @@ include Vtop.mk
CPPFLAGS += -DVL_DEBUG=1
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
CPPFLAGS += -DVL_THREADED=1
CPPFLAGS += -W
CPPFLAGS += -Werror
CPPFLAGS += -W -Werror -Wall
#CPPFLAGS += -Wno-unused-variable # Instead, add VL_ATTR_UNUSED in gen'ed code
#CPPFLAGS += -pedantic-errors
endif
+2 -2
View File
@@ -673,8 +673,8 @@ sub verilator_version {
sub files_identical {
my $fn1 = shift;
my $fn2 = shift;
my $f1 = IO::File->new ("<$fn1") or die "%Error: $! $fn1,";
my $f2 = IO::File->new ("<$fn2") or die "%Error: $! $fn2,";
my $f1 = IO::File->new ("<$fn1"); if (!$f1) { warn "%Error: $! $fn1\n"; return 0; }
my $f2 = IO::File->new ("<$fn2"); if (!$f2) { warn "%Error: $! $fn2\n"; return 0; }
my @l1 = $f1->getlines();
my @l2 = $f2->getlines();
my $nl = $#l1; $nl = $#l2 if ($#l2 > $nl);
+89
View File
@@ -0,0 +1,89 @@
[2] crc=0000000000000097 1410
[3] crc=000000000000012e 1410
[4] crc=000000000000025d 1410
[5] crc=00000000000004ba 1410
[6] crc=0000000000000974 1410
[7] crc=00000000000012e9 1410
[8] crc=00000000000025d3 1410
[9] crc=0000000000004ba7 1410
[10] crc=000000000000974e 1410
[11] crc=0000000000012e9d 1410
[12] crc=0000000000025d3a 1410
[13] crc=000000000004ba74 1410
[14] crc=00000000000974e9 1410
[15] crc=000000000012e9d3 1410
[16] crc=000000000025d3a7 1410
[17] crc=00000000004ba74e 1410
[18] crc=0000000000974e9d 1410
[19] crc=00000000012e9d3a 1410
[20] crc=00000000025d3a74 1410
[21] crc=0000000004ba74e9 1410
[22] crc=000000000974e9d3 1304a:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039;17 1304b:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039203233 1304c:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020313030392032332031333033;4 1304d:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039203233203133303320313338 1304e:203130303920323320313330332031333820202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020 1304: 1009 23 1303 138
[23] crc=0000000012e9d3a7 1313: 1009 46 1309 1311 143 1312
[24] crc=0000000025d3a74e 1129: 1009 172 407 175 408 409 410 1106
[25] crc=000000004ba74e9d 1017: 1009 223 1014 880 885 1015 1016 1007
[26] crc=00000000974e9d3a 1231: 1229 967 1230 718
[27] crc=000000012e9d3a74 1410
[28] crc=000000025d3a74e9 1370: 1009 58 1369 19
[29] crc=00000004ba74e9d3 1036: 1009 194 1033 1034 1008 1035 880
[30] crc=0000000974e9d3a7 1409:i
[31] crc=00000012e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[32] crc=00000025d3a74e9d 1383:§
[33] crc=0000004ba74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[34] crc=000000974e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[35] crc=0000012e9d3a74e9 1231: 1228 979 1230 713
[36] crc=0000025d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[37] crc=000004ba74e9d3a7 1409:i
[38] crc=00000974e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[39] crc=000012e9d3a74e9d 1383:§
[40] crc=000025d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[41] crc=00004ba74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[42] crc=0000974e9d3a74e9 1231: 1228 979 1230 713
[43] crc=00012e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[44] crc=00025d3a74e9d3a7 1409:i
[45] crc=0004ba74e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[46] crc=000974e9d3a74e9d 1383:§
[47] crc=0012e9d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[48] crc=0025d3a74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[49] crc=004ba74e9d3a74e9 1231: 1228 979 1230 713
[50] crc=00974e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[51] crc=012e9d3a74e9d3a7 1409:i
[52] crc=025d3a74e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[53] crc=04ba74e9d3a74e9d 1383:§
[54] crc=0974e9d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[55] crc=12e9d3a74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[56] crc=25d3a74e9d3a74e9 1231: 1228 979 1230 713
[57] crc=4ba74e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[58] crc=974e9d3a74e9d3a7 1409:i
[59] crc=2e9d3a74e9d3a74f 1321: 1009 29 1320 137 144 141 138 149
[60] crc=5d3a74e9d3a74e9e 1383:§
[61] crc=ba74e9d3a74e9d3d 1021: 1009 216 1018 882 884 1019 1020 1007
[62] crc=74e9d3a74e9d3a7b 1017: 1009 197 1014 882 883 1015 1016 1008
[63] crc=e9d3a74e9d3a74f7 1231: 1228 979 1230 713
[64] crc=d3a74e9d3a74e9ef 1013: 1009 194 1011 1006 1008 1012 880
[65] crc=a74e9d3a74e9d3df 1409:i
[66] crc=4e9d3a74e9d3a7bf 1321: 1009 29 1320 137 144 141 145 149
[67] crc=9d3a74e9d3a74f7e 1383:§
[68] crc=3a74e9d3a74e9efc 1021: 1009 216 1018 882 884 1019 1020 1007
[69] crc=74e9d3a74e9d3df9 1017: 1009 197 1014 882 883 1015 1016 1008
[70] crc=e9d3a74e9d3a7bf3 1231: 1228 979 1230 713
[71] crc=d3a74e9d3a74f7e6 1013: 1009 194 1011 1006 1008 1012 880
[72] crc=a74e9d3a74e9efcc 1409:i
[73] crc=4e9d3a74e9d3df98 1321: 1009 29 1320 137 147 149 143 142
[74] crc=9d3a74e9d3a7bf30 1383:§
[75] crc=3a74e9d3a74f7e61 1021: 1009 216 1018 882 885 1019 1020 1007
[76] crc=74e9d3a74e9efcc3 1017: 1009 197 1014 882 884 1015 1016 1008
[77] crc=e9d3a74e9d3df987 1231: 1228 982 1230 713
[78] crc=d3a74e9d3a7bf30f 1013: 1009 194 1011 1006 1008 1012 881 885
[79] crc=a74e9d3a74f7e61f 1409:w
[80] crc=4e9d3a74e9efcc3f 1321: 1009 30 1320 149 146 146 137 149
[81] crc=9d3a74e9d3df987e 1383:ß
[82] crc=3a74e9d3a7bf30fc 1021: 1009 225 1018 882 885 1019 1020 1008
[83] crc=74e9d3a74f7e61f9 1017: 1009 218 1014 882 884 1015 1016 1008
[84] crc=e9d3a74e9efcc3f3 1231: 1228 981 1230 708
[85] crc=d3a74e9d3df987e6 1013: 1009 232 1011 1005 1008 1012 881 883
[86] crc=a74e9d3a7bf30fcc 1409:s
[87] crc=4e9d3a74f7e61f98 1262: 1009 1006 1258 846 1259 1006 1260 833 1261
[88] crc=9d3a74e9efcc3f30 1321: 1009 124 1320 146 137 149 137 134
[89] crc=3a74e9d3df987e61 1383:˜
[90] crc=74e9d3a7bf30fcc3 1036: 1009 215 1033 1034 1008 1035 879
@@ -16,12 +16,12 @@ module t (/*AUTOARG*/
reg [63:0] crc;
`verilator_file_descriptor fd;
t_case_write_tasks tasks ();
t_case_write1_tasks tasks ();
integer cyc; initial cyc=0;
always @ (posedge clk) begin
$fwrite(fd, "[%03d] ", cyc);
$fwrite(fd, "[%0d] crc=%x ", cyc, crc);
tasks.big_case(fd, crc[31:0]);
$fwrite(fd, "\n");
end
@@ -32,8 +32,8 @@ module t (/*AUTOARG*/
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
if (cyc==1) begin
crc <= 64'h00000000_00000097;
$write("Open obj_dir/t_case_write_logger.log\n");
fd = $fopen("obj_dir/t_case_write_logger.log", "w");
$write("Open obj_dir/t_case_write1_logger.log\n");
fd = $fopen("obj_dir/t_case_write1_logger.log", "w");
end
if (cyc==90) begin
$write("*-* All Finished *-*\n");
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
[2] crc=0000000000000097 1009 1410
[3] crc=000000000000012e 1009 1410
[4] crc=000000000000025d 1009 1410
[5] crc=00000000000004ba 1009 1410
[6] crc=0000000000000974 1009 1410
[7] crc=00000000000012e9 1009 1410
[8] crc=00000000000025d3 1009 1410
[9] crc=0000000000004ba7 1009 1410
[10] crc=000000000000974e 1009 1410
[11] crc=0000000000012e9d 1009 1410
[12] crc=0000000000025d3a 1009 1410
[13] crc=000000000004ba74 1009 1410
[14] crc=00000000000974e9 1009 1410
[15] crc=000000000012e9d3 1009 1410
[16] crc=000000000025d3a7 1009 1410
[17] crc=00000000004ba74e 1009 1410
[18] crc=0000000000974e9d 1009 1410
[19] crc=00000000012e9d3a 1009 1410
[20] crc=00000000025d3a74 1009 1410
[21] crc=0000000004ba74e9 1009 1410
[22] crc=000000000974e9d3 1009 23 1303 138 dude 1304
[23] crc=0000000012e9d3a7 1009 46 1309 1311 143 1312 dude 1313
[24] crc=0000000025d3a74e 1009 172 407 175 408 409 410 1106 dude 1129
[25] crc=000000004ba74e9d 1009 223 1014 880 885 1015 1016:0 1007 dude 1017
[26] crc=00000000974e9d3a 1009 1229 967 1230 718 dude 1231
[27] crc=000000012e9d3a74 1009 1410
[28] crc=000000025d3a74e9 1009 58 1369 19 dude 1370
[29] crc=00000004ba74e9d3 1009 194 1033 1034 1008 1035 880 dude 1036
[30] crc=0000000974e9d3a7 1009 1409:69
[31] crc=00000012e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[32] crc=00000025d3a74e9d 1009 1383:3a7
[33] crc=0000004ba74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[34] crc=000000974e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[35] crc=0000012e9d3a74e9 1009 1228 979 1230 713 dude 1231
[36] crc=0000025d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[37] crc=000004ba74e9d3a7 1009 1409:69
[38] crc=00000974e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[39] crc=000012e9d3a74e9d 1009 1383:3a7
[40] crc=000025d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[41] crc=00004ba74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[42] crc=0000974e9d3a74e9 1009 1228 979 1230 713 dude 1231
[43] crc=00012e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[44] crc=00025d3a74e9d3a7 1009 1409:69
[45] crc=0004ba74e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[46] crc=000974e9d3a74e9d 1009 1383:3a7
[47] crc=0012e9d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[48] crc=0025d3a74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[49] crc=004ba74e9d3a74e9 1009 1228 979 1230 713 dude 1231
[50] crc=00974e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[51] crc=012e9d3a74e9d3a7 1009 1409:69
[52] crc=025d3a74e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[53] crc=04ba74e9d3a74e9d 1009 1383:3a7
[54] crc=0974e9d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[55] crc=12e9d3a74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[56] crc=25d3a74e9d3a74e9 1009 1228 979 1230 713 dude 1231
[57] crc=4ba74e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[58] crc=974e9d3a74e9d3a7 1009 1409:69
[59] crc=2e9d3a74e9d3a74f 1009 29 1320 137 144 141 138 149 dude 1321
[60] crc=5d3a74e9d3a74e9e 1009 1383:3a7
[61] crc=ba74e9d3a74e9d3d 1009 216 1018 882 884 1019 1020 1007 dude 1021
[62] crc=74e9d3a74e9d3a7b 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[63] crc=e9d3a74e9d3a74f7 1009 1228 979 1230 713 dude 1231
[64] crc=d3a74e9d3a74e9ef 1009 194 1011 1006 1008 1012 880 dude 1013
[65] crc=a74e9d3a74e9d3df 1009 1409:69
[66] crc=4e9d3a74e9d3a7bf 1009 29 1320 137 144 141 145 149 dude 1321
[67] crc=9d3a74e9d3a74f7e 1009 1383:3a7
[68] crc=3a74e9d3a74e9efc 1009 216 1018 882 884 1019 1020 1007 dude 1021
[69] crc=74e9d3a74e9d3df9 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[70] crc=e9d3a74e9d3a7bf3 1009 1228 979 1230 713 dude 1231
[71] crc=d3a74e9d3a74f7e6 1009 194 1011 1006 1008 1012 880 dude 1013
[72] crc=a74e9d3a74e9efcc 1009 1409:69
[73] crc=4e9d3a74e9d3df98 1009 29 1320 137 147 149 143 142 dude 1321
[74] crc=9d3a74e9d3a7bf30 1009 1383:3a7
[75] crc=3a74e9d3a74f7e61 1009 216 1018 882 885 1019 1020 1007 dude 1021
[76] crc=74e9d3a74e9efcc3 1009 197 1014 882 884 1015 1016:1 1008 dude 1017
[77] crc=e9d3a74e9d3df987 1009 1228 982 1230 713 dude 1231
[78] crc=d3a74e9d3a7bf30f 1009 194 1011 1006 1008 1012 881 885 dude 1013
[79] crc=a74e9d3a74f7e61f 1009 1409:77
[80] crc=4e9d3a74e9efcc3f 1009 30 1320 149 146 146 137 149 dude 1321
[81] crc=9d3a74e9d3df987e 1009 1383:3df
[82] crc=3a74e9d3a7bf30fc 1009 225 1018 882 885 1019 1020 1008 dude 1021
[83] crc=74e9d3a74f7e61f9 1009 218 1014 882 884 1015 1016:1 1008 dude 1017
[84] crc=e9d3a74e9efcc3f3 1009 1228 981 1230 708 dude 1231
[85] crc=d3a74e9d3df987e6 1009 232 1011 1005 1008 1012 881 883 dude 1013
[86] crc=a74e9d3a7bf30fcc 1009 1409:73
[87] crc=4e9d3a74f7e61f98 1009 1006 1258 846 1259 1006 1260 833 1261 dude 1262
[88] crc=9d3a74e9efcc3f30 1009 124 1320 146 137 149 137 134 dude 1321
[89] crc=3a74e9d3df987e61 1009 1383:f98
[90] crc=74e9d3a7bf30fcc3 1009 215 1033 1034 1008 1035 879 dude 1036
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2006 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.
$golden_out ||= "t/$Last_Self->{name}.out";
compile (
v_flags2 => [$Last_Self->{v3}?"--stats --O3 -x-assign 0":""],
);
execute (
check_finished=>1,
);
ok(files_identical("obj_dir/$Last_Self->{name}_logger.log", $golden_out));
1;
+44
View File
@@ -0,0 +1,44 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
`include "verilated.v"
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [63:0] crc;
`verilator_file_descriptor fd;
t_case_write2_tasks tasks ();
integer cyc; initial cyc=0;
always @ (posedge clk) begin
$fwrite(fd, "[%0d] crc=%x ", cyc, crc);
tasks.big_case(fd, crc[31:0]);
$fwrite(fd, "\n");
end
always @ (posedge clk) begin
//$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
if (cyc==1) begin
crc <= 64'h00000000_00000097;
$write("Open obj_dir/t_case_write2_logger.log\n");
fd = $fopen("obj_dir/t_case_write2_logger.log", "w");
end
if (cyc==90) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# 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.
if ($Last_Self->{v3}) {
compile ();
my $outfile = "obj_dir/V".$Last_Self->{name}.".cpp";
my @oldstats = stat($outfile);
print "Old mtime=",$oldstats[9],"\n";
$oldstats[9] or $Last_Self->error("No output file found: $outfile\n");
sleep (1); # Or else it might take < 1 second to compile and see no diff.
compile ();
my @newstats = stat($outfile);
print "New mtime=",$newstats[9],"\n";
($oldstats[9] == $newstats[9])
or $Last_Self->error("--skip-identical was ignored -- recompiled\n");
}
ok(1);
1;
+9
View File
@@ -0,0 +1,9 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (/*AUTOARG*/);
endmodule
+1 -1
View File
@@ -13,7 +13,7 @@ compile (
fails=>$Last_Self->{v3},
verilator_flags=> [qw(-sp -Werror-WIDTH)],
expect=>
'%Error: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
'%Error-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
%Error: Exiting due to',
) if $Last_Self->{v3};
+19
View File
@@ -27,6 +27,10 @@ module t;
flipupperbit(global,4'd12);
if (global !== 32'h10100001) $stop;
if (nil_func(32'h12,32'h12) != 32'h24) $stop;
nil_task(32'h012,32'h112,global);
if (global !== 32'h124) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
@@ -85,4 +89,19 @@ module t;
end
endtask
task nil_task;
input [31:0] a;
input [31:0] b;
output [31:0] q;
// verilator no_inline_task
q = nil_func(a, b);
endtask
function [31:0] nil_func;
input [31:0] fa;
input [31:0] fb;
// verilator no_inline_task
nil_func = fa + fb;
endfunction
endmodule
+2 -2
View File
@@ -1,6 +1,6 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id:$
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
@@ -13,7 +13,7 @@ compile (
'%Error: t/t_func_bad.v:\d+: Too few arguments in function call
%Error: t/t_func_bad.v:\d+: Too many arguments in function call
%Error: t/t_func_bad.v:\d+: Too few arguments in function call
%Error: t/t_func_bad.v:\d+: Unsupported: Task output pin connected to non-variable
%Error-TASKNSVAR: t/t_func_bad.v:\d+: Unsupported: Task output pin connected to non-variable
%Error: t/t_func_bad.v:\d+: Outputs not allowed in function declarations
%Error: Exiting due to',
);
-1
View File
@@ -39,7 +39,6 @@ module t (/*AUTOARG*/
a <= 256'h0e17c88f3d5fe51a982646c8e2bd68c3e236ddfddddbdad20a48e039c9f395b8;
divisor <= 61'h1238123771;
a[60] <= 1'b0; divisor[60] <= 1'b0; // Unsigned
//$display("FIX");
if (qq!==61'h00000403ad81c0da) $stop;
if (rq!==61'h00000000000090ec) $stop;
if (qqs!==61'h00000403ad81c0da) $stop;
+3
View File
@@ -21,6 +21,9 @@ CPPFLAGS += -DUTIL_PRINTF=sp_log_printf
CPPFLAGS += -Wno-deprecated
CPPFLAGS += $(SYSTEMC_CXX_FLAGS)
CPPFLAGS += $(OPT)
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
#CPPFLAGS += -W -Wall -Wno-char-subscripts -Wno-unused-parameter -Wno-unused-variable -Wno-uninitialized -Werror
endif
LDFLAGS += $(SYSTEMC_CXX_FLAGS)