mirror of
https://github.com/verilator/verilator.git
synced 2025-04-12 07:56:53 +00:00
Add verilator no_inline_task
git-svn-id: file://localhost/svn/verilator/trunk/verilator@816 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
ea6bb21cdc
commit
3ad5872d30
2
Changes
2
Changes
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.62**
|
||||
|
||||
** 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.
|
||||
|
@ -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
|
||||
@ -1344,6 +1352,12 @@ 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
|
||||
|
@ -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,
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
COVERAGE_BLOCK_OFF,
|
||||
INLINE_MODULE,
|
||||
NO_INLINE_MODULE,
|
||||
NO_INLINE_TASK,
|
||||
PUBLIC_MODULE,
|
||||
PUBLIC_TASK
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -45,6 +45,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
|
||||
@ -69,7 +70,7 @@ public:
|
||||
" FIRST_WARN",
|
||||
"BLKANDNBLK",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEX", "CMPCONST",
|
||||
"COMBDLY", "GENCLK", "IMPLICIT",
|
||||
"COMBDLY", "GENCLK", "IMPLICIT", "IMPURE",
|
||||
"MULTIDRIVEN",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
||||
"VARHIDDEN", "WIDTH",
|
||||
@ -79,6 +80,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); }
|
||||
|
@ -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
|
||||
|
412
src/V3Task.cpp
412
src/V3Task.cpp
@ -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->v3error("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->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 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->v3error("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->v3error("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() {}
|
||||
|
@ -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;}
|
||||
|
@ -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; }
|
||||
|
89
test_regress/t/t_case_write1.out
Normal file
89
test_regress/t/t_case_write1.out
Normal 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
test_regress/t/t_case_write2.out
Normal file
89
test_regress/t/t_case_write2.out
Normal 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
test_regress/t/t_case_write2.pl
Executable file
22
test_regress/t/t_case_write2.pl
Executable 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
test_regress/t/t_case_write2.v
Normal file
44
test_regress/t/t_case_write2.v
Normal 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
|
3778
test_regress/t/t_case_write2_tasks.v
Normal file
3778
test_regress/t/t_case_write2_tasks.v
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user