Add /*verilator public_flat_rw*/ for timing-specific public access.

This commit is contained in:
Wilson Snyder 2010-04-05 20:01:17 -04:00
parent 7c3048ab9c
commit 936738b750
24 changed files with 243 additions and 57 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
*** Support runtime access to public signal names. *** Support runtime access to public signal names.
*** Add /*verilator public_flat_rw*/ for timing-specific access.
**** Improve error handling on slices of arrays, bug226. [by Bryon Bradley] **** Improve error handling on slices of arrays, bug226. [by Bryon Bradley]
**** Report errors when extra underscores used in meta-comments. **** Report errors when extra underscores used in meta-comments.

View File

@ -1770,6 +1770,18 @@ signal. This will not declare this module public, which means the name of
the signal or path to it may change based upon the module inlining which the signal or path to it may change based upon the module inlining which
takes place. takes place.
=item /*verilator public_flat_rd*/ (variable)
Used after a input, output, register, or wire declaration to indicate the
signal should be declared public_flat (see above), but read-only.
=item /*verilator public_flat_rw @(<edge_list>) */ (variable)
Used after a input, output, register, or wire declaration to indicate the
signal should be declared public_flat_rd (see above), and also writable,
where writes should be considered to have the timing specified by the given
sensitivity edge list.
=item /*verilator public_module*/ =item /*verilator public_module*/
Used after a module statement to indicate the module should not be inlined Used after a module statement to indicate the module should not be inlined

View File

@ -995,6 +995,10 @@ void Verilated::scopesDump() {
VerilatedImp::scopesDump(); VerilatedImp::scopesDump();
} }
const VerilatedScope* Verilated::scopeFind(const char* namep) {
return VerilatedImp::scopeFind(namep);
}
int Verilated::exportFuncNum(const char* namep) { int Verilated::exportFuncNum(const char* namep) {
return VerilatedImp::exportFind(namep); return VerilatedImp::exportFind(namep);
} }
@ -1010,6 +1014,23 @@ VerilatedModule::~VerilatedModule() {
if (m_namep) free((void*)m_namep); m_namep=NULL; if (m_namep) free((void*)m_namep); m_namep=NULL;
} }
//======================================================================
// VerilatedVar:: Methods
vluint32_t VerilatedVar::entSize() const {
vluint32_t size = 1;
switch (vltype()) {
case VLVT_PTR: size=sizeof(void*); break;
case VLVT_UINT8: size=sizeof(CData); break;
case VLVT_UINT16: size=sizeof(SData); break;
case VLVT_UINT32: size=sizeof(IData); break;
case VLVT_UINT64: size=sizeof(QData); break;
case VLVT_WDATA: size=VL_WORDS_I(range().bits())*sizeof(IData); break;
default: size=0; break;
}
return size;
}
//====================================================================== //======================================================================
// VerilatedScope:: Methods // VerilatedScope:: Methods
@ -1060,13 +1081,14 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) {
} }
} }
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int dims, ...) { void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
VerilatedVarType vltype, int vlflags, int dims, ...) {
// Grab dimensions // Grab dimensions
// In the future we may just create a large table at emit time and statically construct from that. // In the future we may just create a large table at emit time and statically construct from that.
if (!finalize) return; if (!finalize) return;
if (!m_varsp) m_varsp = new VerilatedVarNameMap(); if (!m_varsp) m_varsp = new VerilatedVarNameMap();
VerilatedVar var (namep, datap, vltype); VerilatedVar var (namep, datap, vltype, (VerilatedVarFlags)vlflags, dims);
va_list ap; va_list ap;
va_start(ap,dims); va_start(ap,dims);

View File

@ -82,6 +82,17 @@ enum VerilatedVarType {
VLVT_STRING // C++ string VLVT_STRING // C++ string
}; };
enum VerilatedVarFlags {
VLVD_IN=1, // == vpiInput
VLVD_OUT=2, // == vpiOutput
VLVD_INOUT=3, // == vpiInOut
VLVD_NODIR=5, // == vpiNoDirection
VLVF_MASK_DIR=7, // Bit mask for above directions
// Flags
VLVF_PUB_RD=(1<<8), // Public readable
VLVF_PUB_RW=(1<<9) // Public writable
};
//========================================================================= //=========================================================================
/// Base class for all Verilated module classes /// Base class for all Verilated module classes
@ -151,6 +162,9 @@ public:
#ifndef VL_PRINTF #ifndef VL_PRINTF
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired # define VL_PRINTF printf ///< Print ala printf; may redefine if desired
#endif #endif
#ifndef VL_VPRINTF
# define VL_VPRINTF vprintf ///< Print ala vprintf; may redefine if desired
#endif
//=========================================================================== //===========================================================================
/// Verilator symbol table base class /// Verilator symbol table base class
@ -176,7 +190,8 @@ public: // But internals only - called from VerilatedModule's
~VerilatedScope(); ~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp); void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
void exportInsert(int finalize, const char* namep, void* cb); void exportInsert(int finalize, const char* namep, void* cb);
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int dims, ...); void varInsert(int finalize, const char* namep, void* datap,
VerilatedVarType vltype, int vlflags, int dims, ...);
// ACCESSORS // ACCESSORS
const char* name() const { return m_namep; } const char* name() const { return m_namep; }
inline VerilatedSyms* symsp() const { return m_symsp; } inline VerilatedSyms* symsp() const { return m_symsp; }
@ -264,6 +279,8 @@ public:
// METHODS - INTERNAL USE ONLY // METHODS - INTERNAL USE ONLY
// Internal: Create a new module name by concatenating two strings // Internal: Create a new module name by concatenating two strings
static const char* catName(const char* n1, const char* n2); // Returns new'ed data static const char* catName(const char* n1, const char* n2); // Returns new'ed data
// Internal: Find scope
static const VerilatedScope* scopeFind(const char* namep);
// Internal: Get and set DPI context // Internal: Get and set DPI context
static const VerilatedScope* dpiScope() { return t_dpiScopep; } static const VerilatedScope* dpiScope() { return t_dpiScopep; }
static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; } static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; }

View File

@ -57,6 +57,7 @@ public:
~VerilatedRange() {} ~VerilatedRange() {}
int lhs() const { return m_lhs; } int lhs() const { return m_lhs; }
int rhs() const { return m_rhs; } int rhs() const { return m_rhs; }
int bits() const { return (VL_LIKELY(m_lhs>=m_rhs)?(m_lhs-m_rhs+1):(m_rhs-m_lhs+1)); }
}; };
//=========================================================================== //===========================================================================
@ -65,20 +66,27 @@ public:
class VerilatedVar { class VerilatedVar {
void* m_datap; // Location of data void* m_datap; // Location of data
VerilatedVarType m_vltype; // Data type VerilatedVarType m_vltype; // Data type
VerilatedVarFlags m_vlflags; // Direction
VerilatedRange m_range; // First range VerilatedRange m_range; // First range
VerilatedRange m_array; // Array VerilatedRange m_array; // Array
int m_dims; // Dimensions
const char* m_namep; // Name - slowpath const char* m_namep; // Name - slowpath
protected: protected:
friend class VerilatedScope; friend class VerilatedScope;
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype) VerilatedVar(const char* namep, void* datap,
: m_datap(datap), m_vltype(vltype), m_namep(namep) {} VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims)
: m_datap(datap), m_vltype(vltype), m_vlflags(vlflags), m_dims(dims), m_namep(namep) {}
public: public:
~VerilatedVar() {} ~VerilatedVar() {}
void* datap() const { return m_datap; } void* datap() const { return m_datap; }
VerilatedVarType vltype() const { return m_vltype; } VerilatedVarType vltype() const { return m_vltype; }
VerilatedVarFlags vldir() const { return (VerilatedVarFlags)((int)m_vlflags & VLVF_MASK_DIR); }
vluint32_t entSize() const;
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
const VerilatedRange& range() const { return m_range; } const VerilatedRange& range() const { return m_range; }
const VerilatedRange& array() const { return m_array; } const VerilatedRange& array() const { return m_array; }
const char* namep() const { return m_namep; } const char* name() const { return m_namep; }
int dims() const { return m_dims; }
}; };
//====================================================================== //======================================================================

View File

@ -263,22 +263,14 @@ private:
} }
// METHODS // METHODS
virtual void visit(AstAlways* nodep, AstNUser*) { void visitAlways(AstNode* nodep, AstSenTree* oldsensesp) {
// Move always to appropriate ACTIVE based on its sense list // Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALW "<<nodep<<endl); if (oldsensesp
//if (debug()>=9) nodep->dumpTree(cout," Alw: "); && oldsensesp->sensesp()
&& oldsensesp->sensesp()->castSenItem()
if (!nodep->bodysp()) { && oldsensesp->sensesp()->castSenItem()->isNever()) {
// Empty always. Kill it.
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
return;
}
if (nodep->sensesp()
&& nodep->sensesp()->sensesp()
&& nodep->sensesp()->sensesp()->castSenItem()
&& nodep->sensesp()->sensesp()->castSenItem()->isNever()) {
// Never executing. Kill it. // Never executing. Kill it.
if (nodep->sensesp()->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated."); if (oldsensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
return; return;
} }
@ -286,7 +278,7 @@ private:
// Read sensitivitues // Read sensitivitues
m_itemCombo = false; m_itemCombo = false;
m_itemSequent = false; m_itemSequent = false;
nodep->sensesp()->iterateAndNext(*this); oldsensesp->iterateAndNext(*this);
bool combo = m_itemCombo; bool combo = m_itemCombo;
bool sequent = m_itemSequent; bool sequent = m_itemSequent;
@ -308,15 +300,15 @@ private:
// always (posedge RESET) { if (RESET).... } we know RESET is true. // always (posedge RESET) { if (RESET).... } we know RESET is true.
// Summarize a long list of combo inputs as just "combo" // Summarize a long list of combo inputs as just "combo"
#ifndef __COVERITY__ // Else dead code on next line. #ifndef __COVERITY__ // Else dead code on next line.
if (combo) nodep->sensesp()->addSensesp if (combo) oldsensesp->addSensesp
(new AstSenItem(nodep->fileline(),AstSenItem::Combo())); (new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
#endif #endif
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp()); wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
} }
// Delete sensitivity list // Delete sensitivity list
if (AstNode* oldsense = nodep->sensesp()) { if (oldsensesp) {
oldsense->unlinkFrBackWithNext()->deleteTree(); oldsense=NULL; oldsensesp->unlinkFrBackWithNext()->deleteTree(); oldsensesp=NULL;
} }
// Move node to new active // Move node to new active
@ -328,6 +320,24 @@ private:
ActiveDlyVisitor dlyvisitor (nodep); ActiveDlyVisitor dlyvisitor (nodep);
} }
} }
virtual void visit(AstAlways* nodep, AstNUser*) {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALW "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
if (!nodep->bodysp()) {
// Empty always. Kill it.
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
return;
}
visitAlways(nodep, nodep->sensesp());
}
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALWPub "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
visitAlways(nodep, nodep->sensesp());
}
virtual void visit(AstSenGate* nodep, AstNUser*) { virtual void visit(AstSenGate* nodep, AstNUser*) {
AstSenItem* subitemp = nodep->sensesp(); AstSenItem* subitemp = nodep->sensesp();
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE

View File

@ -133,6 +133,9 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) { virtual void visit(AstAlways* nodep, AstNUser*) {
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstFinal* nodep, AstNUser*) { virtual void visit(AstFinal* nodep, AstNUser*) {
nodep->v3fatalSrc("Node should have been deleted"); nodep->v3fatalSrc("Node should have been deleted");
} }

View File

@ -179,6 +179,8 @@ public:
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
}; };
@ -186,7 +188,8 @@ public:
const char* ascii() const { const char* ascii() const {
static const char* names[] = { static const char* names[] = {
"EXPR_BITS", "VAR_BASE", "EXPR_BITS", "VAR_BASE",
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT" "VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT"
}; };
return names[m_e]; return names[m_e];

View File

@ -162,6 +162,18 @@ string AstVar::vlEnumType() const {
return arg; return arg;
} }
string AstVar::vlEnumDir() const {
if (isInout()) {
return "VLVD_INOUT";
} else if (isInOnly()) {
return "VLVD_IN";
} else if (isOutOnly()) {
return "VLVD_OUT";
} else {
return "VLVD_NODIR";
}
}
string AstVar::cPubArgType(bool named, bool forReturn) const { string AstVar::cPubArgType(bool named, bool forReturn) const {
if (forReturn) named=false; if (forReturn) named=false;
string arg; string arg;

View File

@ -544,7 +544,8 @@ private:
bool m_scSensitive:1;// SystemC sensitive() needed bool m_scSensitive:1;// SystemC sensitive() needed
bool m_sigPublic:1; // User C code accesses this signal or is top signal bool m_sigPublic:1; // User C code accesses this signal or is top signal
bool m_sigModPublic:1;// User C code accesses this signal and module bool m_sigModPublic:1;// User C code accesses this signal and module
bool m_sigUserPublic:1; // User C code accesses this signal bool m_sigUserRdPublic:1; // User C code accesses this signal, read only
bool m_sigUserRWPublic:1; // User C code accesses this signal, read-write
bool m_usedClock:1; // Signal used as a clock bool m_usedClock:1; // Signal used as a clock
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup) bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
bool m_funcLocal:1; // Local variable for a function bool m_funcLocal:1; // Local variable for a function
@ -562,7 +563,7 @@ private:
m_primaryIO=false; m_primaryIO=false;
m_sc=false; m_scClocked=false; m_scSensitive=false; m_sc=false; m_scClocked=false; m_scSensitive=false;
m_usedClock=false; m_usedParam=false; m_usedClock=false; m_usedParam=false;
m_sigPublic=false; m_sigModPublic=false; m_sigUserPublic=false; m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false;
m_funcLocal=false; m_funcReturn=false; m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false; m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_fileDescr=false; m_isConst=false; m_isStatic=false;
@ -608,7 +609,8 @@ public:
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
string vlEnumType() const; // Return VerilatorImp enum name for argument: VLVT_UINT32, etc string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
void combineType(AstVarType type); void combineType(AstVarType type);
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
@ -630,7 +632,8 @@ public:
void usedParam(bool flag) { m_usedParam = flag; } void usedParam(bool flag) { m_usedParam = flag; }
void sigPublic(bool flag) { m_sigPublic = flag; } void sigPublic(bool flag) { m_sigPublic = flag; }
void sigModPublic(bool flag) { m_sigModPublic = flag; } void sigModPublic(bool flag) { m_sigModPublic = flag; }
void sigUserPublic(bool flag) { m_sigUserPublic = flag; if (flag) m_sigPublic = flag; } void sigUserRdPublic(bool flag) { m_sigUserRdPublic = flag; if (flag) sigPublic(true); }
void sigUserRWPublic(bool flag) { m_sigUserRWPublic = flag; if (flag) sigUserRdPublic(true); }
void sc(bool flag) { m_sc = flag; } void sc(bool flag) { m_sc = flag; }
void scSensitive(bool flag) { m_scSensitive = flag; } void scSensitive(bool flag) { m_scSensitive = flag; }
void primaryIO(bool flag) { m_primaryIO = flag; } void primaryIO(bool flag) { m_primaryIO = flag; }
@ -673,7 +676,8 @@ public:
bool isScSensitive() const { return m_scSensitive; } bool isScSensitive() const { return m_scSensitive; }
bool isSigPublic() const; bool isSigPublic() const;
bool isSigModPublic() const { return m_sigModPublic; } bool isSigModPublic() const { return m_sigModPublic; }
bool isSigUserPublic() const { return m_sigUserPublic; } bool isSigUserRdPublic() const { return m_sigUserRdPublic; }
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
bool isTrace() const { return m_trace; } bool isTrace() const { return m_trace; }
bool isConst() const { return m_isConst; } bool isConst() const { return m_isConst; }
bool isStatic() const { return m_isStatic; } bool isStatic() const { return m_isStatic; }
@ -703,7 +707,8 @@ public:
combineType(typevarp->varType()); combineType(typevarp->varType());
if (typevarp->isSigPublic()) sigPublic(true); if (typevarp->isSigPublic()) sigPublic(true);
if (typevarp->isSigModPublic()) sigModPublic(true); if (typevarp->isSigModPublic()) sigModPublic(true);
if (typevarp->isSigUserPublic()) sigUserPublic(true); if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true);
if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true);
if (typevarp->attrScClocked()) attrScClocked(true); if (typevarp->attrScClocked()) attrScClocked(true);
} }
void inlineAttrReset(const string& name) { void inlineAttrReset(const string& name) {
@ -1270,6 +1275,24 @@ struct AstAlways : public AstNode {
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
}; };
struct AstAlwaysPublic : public AstNodeStmt {
// "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/
// Body statements are just AstVarRefs to the public signals
AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
: AstNodeStmt(fl) {
addNOp1p(sensesp); addNOp2p(bodysp);
}
ASTNODE_NODE_FUNCS(AlwaysPublic, ALWAYSPUBLIC)
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
//
AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list
AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
// Special accessors
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
struct AstAlwaysPost : public AstNode { struct AstAlwaysPost : public AstNode {
// Like always but post assignments for memory assignment IFs // Like always but post assignments for memory assignment IFs
AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)

View File

@ -642,6 +642,9 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) { virtual void visit(AstAlways* nodep, AstNUser*) {
iterateNewStmt(nodep); iterateNewStmt(nodep);
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
// CDC doesn't care about public variables
}
virtual void visit(AstCFunc* nodep, AstNUser*) { virtual void visit(AstCFunc* nodep, AstNUser*) {
iterateNewStmt(nodep); iterateNewStmt(nodep);
} }

View File

@ -149,6 +149,8 @@ public:
if (decind) ofp()->blockDec(); if (decind) ofp()->blockDec();
if (!m_suppressSemi) puts(";\n"); if (!m_suppressSemi) puts(";\n");
} }
virtual void visit(AstAlwaysPublic*, AstNUser*) {
}
virtual void visit(AstCCall* nodep, AstNUser*) { virtual void visit(AstCCall* nodep, AstNUser*) {
puts(nodep->hiername()); puts(nodep->hiername());
puts(nodep->funcp()->name()); puts(nodep->funcp()->name());

View File

@ -205,7 +205,7 @@ class EmitCSyms : EmitCBaseVisitor {
} }
virtual void visit(AstVar* nodep, AstNUser*) { virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (nodep->isSigUserPublic()) { if (nodep->isSigUserRdPublic()) {
m_modVars.push_back(make_pair(m_modp, nodep)); m_modVars.push_back(make_pair(m_modp, nodep));
} }
} }
@ -487,6 +487,10 @@ void EmitCSyms::emitSymImp() {
puts("), "); puts("), ");
puts(varp->vlEnumType()); // VLVT_UINT32 etc puts(varp->vlEnumType()); // VLVT_UINT32 etc
puts(","); puts(",");
puts(varp->vlEnumDir()); // VLVD_IN etc
if (varp->isSigUserRWPublic()) puts("|VLVF_PUB_RW");
else if (varp->isSigUserRdPublic()) puts("|VLVF_PUB_RD");
puts(",");
puts(cvtToStr(dim)); puts(cvtToStr(dim));
puts(bounds); puts(bounds);
puts(");\n"); puts(");\n");

View File

@ -109,6 +109,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
nodep->bodysp()->iterateAndNext(*this); nodep->bodysp()->iterateAndNext(*this);
putqs(nodep,"end\n"); putqs(nodep,"end\n");
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
putfs(nodep,"/*verilator public_flat_rw ");
if (m_sensesp) m_sensesp->iterateAndNext(*this); // In active
else nodep->sensesp()->iterateAndNext(*this);
putqs(nodep," ");
nodep->bodysp()->iterateAndNext(*this);
putqs(nodep,"*/\n");
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) { virtual void visit(AstNodeAssign* nodep, AstNUser*) {
nodep->lhsp()->iterateAndNext(*this); nodep->lhsp()->iterateAndNext(*this);
putfs(nodep," "+nodep->verilogKwd()+" "); putfs(nodep," "+nodep->verilogKwd()+" ");

View File

@ -357,6 +357,12 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) { virtual void visit(AstAlways* nodep, AstNUser*) {
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL); iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
bool lastslow = m_inSlow;
m_inSlow = true;
iterateNewStmt(nodep, "AlwaysPublic", NULL);
m_inSlow = lastslow;
}
virtual void visit(AstCFunc* nodep, AstNUser*) { virtual void visit(AstCFunc* nodep, AstNUser*) {
iterateNewStmt(nodep, "User C Function", "User C Function"); iterateNewStmt(nodep, "User C Function", "User C Function");
} }

View File

@ -155,7 +155,7 @@ private:
// Public output inside the cell must go via an assign rather than alias // Public output inside the cell must go via an assign rather than alias
// Else the public logic will set the alias, loosing the value to be propagated up // Else the public logic will set the alias, loosing the value to be propagated up
// (InOnly isn't a problem as the AssignAlias will create the assignment for us) // (InOnly isn't a problem as the AssignAlias will create the assignment for us)
pinNewVarp->user3(pinNewVarp->isSigUserPublic() && pinNewVarp->isOutOnly()); pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
} }
// Cleanup var names, etc, to not conflict // Cleanup var names, etc, to not conflict
m_cellp = nodep; m_cellp = nodep;

View File

@ -274,12 +274,22 @@ private:
} }
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) { else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable"); if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->sigUserPublic(true); m_varp->sigModPublic(true); m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
} }
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) { else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable"); if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->sigUserPublic(true); m_varp->sigUserRWPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->sigUserRdPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->sigUserRWPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
} }
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) { else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
@ -294,6 +304,20 @@ private:
} }
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
// AlwaysPublic was attached under a var, but it's a statement that should be
// at the same level as the var
nodep->iterateChildren(*this);
if (m_varp) {
nodep->unlinkFrBack();
m_varp->addNext(nodep);
// lvalue is true, because we know we have a verilator public_flat_rw
// but someday we may be more general
bool lvalue = m_varp->isSigUserRWPublic();
nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue));
}
}
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) { virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {
UINFO(8," DEFIMPLICIT "<<nodep<<endl); UINFO(8," DEFIMPLICIT "<<nodep<<endl);
// Must remember what names we've already created, and combine duplicates // Must remember what names we've already created, and combine duplicates

View File

@ -666,6 +666,9 @@ private:
iterateNewStmt(nodep); iterateNewStmt(nodep);
m_inPost = false; m_inPost = false;
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep, AstNUser*) { virtual void visit(AstAssignAlias* nodep, AstNUser*) {
iterateNewStmt(nodep); iterateNewStmt(nodep);
} }

View File

@ -371,6 +371,13 @@ void V3PreProcImp::comment(const string& text) {
//} //}
// else ignore the comment we don't recognize // else ignore the comment we don't recognize
} // else no assertions } // else no assertions
} else if ((pos=cmd.find("public_flat_rw")) != string::npos) {
// "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)"
cmd = cmd.substr(pos+strlen("public_flat_rw"));
while (isspace(cmd[0])) cmd = cmd.substr(1);
if ((pos=cmd.find("*/")) != string::npos)
cmd.replace(pos, 2, "");
insertUnreadback ("/*verilator public_flat_rw*/ "+cmd+" /**/");
} else { } else {
insertUnreadback ("/*verilator "+cmd+"*/"); insertUnreadback ("/*verilator "+cmd+"*/");
} }

View File

@ -165,6 +165,14 @@ private:
m_scopep->addActivep(clonep); m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone* clonep->iterateChildren(*this); // We iterate under the *clone*
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
virtual void visit(AstCoverToggle* nodep, AstNUser*) { virtual void visit(AstCoverToggle* nodep, AstNUser*) {
// Add to list of blocks under this scope // Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl); UINFO(4," Move "<<nodep<<endl);
@ -291,6 +299,9 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) { virtual void visit(AstAlways* nodep, AstNUser*) {
movedDeleteOrIterate(nodep); movedDeleteOrIterate(nodep);
} }
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstCoverToggle* nodep, AstNUser*) { virtual void visit(AstCoverToggle* nodep, AstNUser*) {
movedDeleteOrIterate(nodep); movedDeleteOrIterate(nodep);
} }

View File

@ -632,6 +632,8 @@ escid \\[^ \t\f\r\n]+
"/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; } "/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; }
"/*verilator public*/" { FL; return yVL_PUBLIC; } "/*verilator public*/" { FL; return yVL_PUBLIC; }
"/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; } "/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; }
"/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; }
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; } "/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; } "/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator sformat*/" { FL; return yVL_SFORMAT; } "/*verilator sformat*/" { FL; return yVL_SFORMAT; }
@ -645,7 +647,8 @@ escid \\[^ \t\f\r\n]+
"/*verilator lint_restore*/" {PARSEP->verilatorCmtLintRestore(); } "/*verilator lint_restore*/" {PARSEP->verilatorCmtLintRestore(); }
"/*verilator lint_save*/" {PARSEP->verilatorCmtLintSave(); } "/*verilator lint_save*/" {PARSEP->verilatorCmtLintSave(); }
"/*"[^*]*"*/" {PARSEP->verilatorCmtBad(yytext); } "/**/" { }
"/*"[^*]+"*/" {PARSEP->verilatorCmtBad(yytext); }
} }
/************************************************************************/ /************************************************************************/

View File

@ -434,6 +434,8 @@ class AstSenTree;
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/" %token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
%token<fl> yVL_PUBLIC "/*verilator public*/" %token<fl> yVL_PUBLIC "/*verilator public*/"
%token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/" %token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/"
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/" %token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
%token<fl> yP_TICK "'" %token<fl> yP_TICK "'"
@ -1541,6 +1543,10 @@ sigAttr<nodep>:
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); } | yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); } | yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); }
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); } | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); }
| yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); }
| yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); }
| yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW);
$$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); }
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); } | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); } | yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
; ;
@ -1679,6 +1685,12 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
//************************************************ //************************************************
// EventControl lists // EventControl lists
attr_event_control<sentreep>: // ==IEEE: event_control
'@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); }
| '@' '(' '*' ')' { $$ = NULL; }
| '@' '*' { $$ = NULL; }
;
event_controlE<sentreep>: event_controlE<sentreep>:
/* empty */ { $$ = NULL; } /* empty */ { $$ = NULL; }
| event_control { $$ = $1; } | event_control { $$ = $1; }

View File

@ -100,11 +100,11 @@ void mon_register_done() {
} }
} }
bool mon_eval() { extern "C" void mon_eval();
void mon_eval() {
// Callback from always@ negedge // Callback from always@ negedge
mon_do(&mons[0]); mon_do(&mons[0]);
mon_do(&mons[1]); mon_do(&mons[1]);
return false;
} }
//====================================================================== //======================================================================

View File

@ -44,11 +44,17 @@ module t (/*AUTOARG*/
end end
end end
always @(posedge t.monclk) begin
mon_eval();
end
endmodule endmodule
import "DPI-C" context function void mon_scope_name (input string formatted /*verilator sformat*/ ); import "DPI-C" context function void mon_scope_name (input string formatted /*verilator sformat*/ );
import "DPI-C" context function void mon_register_b(string name, int isOut); import "DPI-C" context function void mon_register_b(string name, int isOut);
import "DPI-C" context function void mon_register_done(); import "DPI-C" context function void mon_register_done();
import "DPI-C" context function void mon_eval();
module sub (/*AUTOARG*/ module sub (/*AUTOARG*/
// Outputs // Outputs
@ -60,17 +66,13 @@ module sub (/*AUTOARG*/
`systemc_imp_header `systemc_imp_header
void mon_class_name(const char* namep); void mon_class_name(const char* namep);
void mon_register_a(const char* namep, void* sigp, bool isOut); void mon_register_a(const char* namep, void* sigp, bool isOut);
bool mon_eval();
`verilog `verilog
input int in /*verilator public_flat*/; input int in /*verilator public_flat_rd*/;
output int fr_a /*verilator public_flat*/; output int fr_a /*verilator public_flat_rw @(posedge t.monclk)*/;
output int fr_b /*verilator public_flat*/; output int fr_b /*verilator public_flat_rw @(posedge t.monclk)*/;
output int fr_chk; output int fr_chk;
reg [3:0] onearray [1:2] /*verilator public_flat*/;
reg [3:0] twoarray [1:2][3:4] /*verilator public_flat*/;
always @* fr_chk = in + 1; always @* fr_chk = in + 1;
initial begin initial begin
@ -86,15 +88,4 @@ module sub (/*AUTOARG*/
mon_register_done(); mon_register_done();
end end
always @(posedge t.monclk) begin
// Hack - Write all outputs, so the data will get scheduled to propagate out of this module
// FUTURE Long term, we should detect a public signal has been written
// with a new value, and create an event that flips monclk automatically
if ($c1("mon_eval()")) begin
// This code doesn't execute, just is here so verilator schedules the code.
fr_a = 0;
fr_b = 0;
end
end
endmodule endmodule