Add /*verilator public_flat_rw*/ for timing-specific public access.
This commit is contained in:
parent
7c3048ab9c
commit
936738b750
2
Changes
2
Changes
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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()+" ");
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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+"*/");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue