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:
Wilson Snyder 2006-10-11 15:41:42 +00:00
parent ea6bb21cdc
commit 3ad5872d30
22 changed files with 5829 additions and 1477 deletions

View File

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

View File

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

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,

View File

@ -57,6 +57,7 @@ public:
COVERAGE_BLOCK_OFF,
INLINE_MODULE,
NO_INLINE_MODULE,
NO_INLINE_TASK,
PUBLIC_MODULE,
PUBLIC_TASK
};

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

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

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

View File

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

View File

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

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

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->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() {}

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

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

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

View File

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

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
test_regress/t/t_case_write2.pl Executable file
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;

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

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