Internals: Refactor input/output to new class in prep for ref support.

This commit is contained in:
Wilson Snyder 2018-10-27 17:29:00 -04:00
parent dc26815b1c
commit b8098098d8
34 changed files with 456 additions and 391 deletions

View File

@ -464,18 +464,56 @@ public:
//###################################################################### //######################################################################
class VDirection {
public:
enum en {
NONE,
INPUT,
OUTPUT,
INOUT
};
enum en m_e;
inline VDirection() : m_e(NONE) {}
// cppcheck-suppress noExplicitConstructor
inline VDirection(en _e) : m_e(_e) {}
explicit inline VDirection(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {
"NONE", "INPUT", "OUTPUT", "INOUT"};
return names[m_e]; }
string verilogKwd() const {
static const char* const names[] = {
"", "input", "output", "inout"};
return names[m_e]; }
string xmlKwd() const { // For historical reasons no "put" suffix
static const char* const names[] = {
"", "in", "out", "inout"};
return names[m_e]; }
string prettyName() const { return verilogKwd(); }
bool isAny() const { return m_e != NONE; }
// Looks like inout - "ish" because not identical to being an INOUT
bool isInoutish() const { return m_e == INOUT; }
bool isNonOutput() const { return m_e == INPUT || m_e == INOUT; }
bool isReadOnly() const { return m_e == INPUT; }
bool isWritable() const { return m_e == OUTPUT || m_e == INOUT; }
};
inline bool operator== (VDirection lhs, VDirection rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (VDirection lhs, VDirection::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (VDirection::en lhs, VDirection rhs) { return (lhs == rhs.m_e); }
inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) { return os<<rhs.ascii(); }
//######################################################################
class AstVarType { class AstVarType {
public: public:
enum en { enum en {
UNKNOWN, UNKNOWN,
GPARAM, GPARAM,
LPARAM, LPARAM,
GENVAR, GENVAR,
VAR, // Reg, integer, logic, etc VAR, // Reg, integer, logic, etc
INPUT, SUPPLY0,
OUTPUT,
INOUT,
SUPPLY0,
SUPPLY1, SUPPLY1,
WIRE, WIRE,
WREAL, WREAL,
@ -497,20 +535,19 @@ public:
explicit inline AstVarType(int _e) : m_e(static_cast<en>(_e)) {} explicit inline AstVarType(int _e) : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; } operator en() const { return m_e; }
const char* ascii() const { const char* ascii() const {
static const char* const names[] = { static const char* const names[] = {
"?","GPARAM","LPARAM","GENVAR", "?", "GPARAM", "LPARAM", "GENVAR", "VAR",
"VAR","INPUT","OUTPUT","INOUT", "SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "IMPLICITWIRE",
"SUPPLY0","SUPPLY1","WIRE","WREAL","IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1",
"TRIWIRE","TRI0","TRI1", "PORT",
"PORT", "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP",
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP", "IFACEREF"};
"IFACEREF"}; return names[m_e]; }
return names[m_e]; }
bool isSignal() const { return (m_e==WIRE || m_e==WREAL || m_e==IMPLICITWIRE bool isSignal() const { return (m_e==WIRE || m_e==WREAL || m_e==IMPLICITWIRE
|| m_e==TRIWIRE || m_e==TRIWIRE
|| m_e==TRI0 || m_e==TRI1 || m_e==TRI0 || m_e==TRI1 || m_e==PORT
|| m_e==SUPPLY0 || m_e==SUPPLY1 || m_e==SUPPLY0 || m_e==SUPPLY1
|| m_e==VAR); } || m_e==VAR); }
}; };
inline bool operator== (AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator== (AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstVarType lhs, AstVarType::en rhs) { return (lhs.m_e == rhs); } inline bool operator== (AstVarType lhs, AstVarType::en rhs) { return (lhs.m_e == rhs); }

View File

@ -178,40 +178,30 @@ void AstVar::combineType(AstVarType type) {
// These flags get combined with the existing settings of the flags. // These flags get combined with the existing settings of the flags.
// We don't test varType for certain types, instead set flags since // We don't test varType for certain types, instead set flags since
// when we combine wires cross-hierarchy we need a union of all characteristics. // when we combine wires cross-hierarchy we need a union of all characteristics.
m_varType=type; // For debugging prints only m_varType = type;
// These flags get combined with the existing settings of the flags. // These flags get combined with the existing settings of the flags.
if (type==AstVarType::INPUT || type==AstVarType::INOUT) { if (type==AstVarType::TRIWIRE || type==AstVarType::TRI0 || type==AstVarType::TRI1) {
m_input = true; m_tristate = true;
m_declInput = true;
} }
if (type==AstVarType::OUTPUT || type==AstVarType::INOUT) { if (type==AstVarType::TRI0) {
m_output = true; m_isPulldown = true;
m_declOutput = true; }
if (type==AstVarType::TRI1) {
m_isPullup = true;
} }
if (type==AstVarType::INOUT || type==AstVarType::TRIWIRE
|| type==AstVarType::TRI0 || type==AstVarType::TRI1)
m_tristate = true;
if (type==AstVarType::TRI0)
m_isPulldown = true;
if (type==AstVarType::TRI1)
m_isPullup = true;
} }
string AstVar::verilogKwd() const { string AstVar::verilogKwd() const {
if (isInout()) { if (isIO()) {
return "inout"; return direction().verilogKwd();
} else if (isInput()) {
return "input";
} else if (isOutput()) {
return "output";
} else if (isTristate()) { } else if (isTristate()) {
return "tri"; return "tri";
} else if (varType()==AstVarType::WIRE) { } else if (varType()==AstVarType::WIRE) {
return "wire"; return "wire";
} else if (varType()==AstVarType::WREAL) { } else if (varType()==AstVarType::WREAL) {
return "wreal"; return "wreal";
} else { } else {
return dtypep()->name(); return dtypep()->name();
} }
} }
@ -219,7 +209,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
if (forReturn) named=false; if (forReturn) named=false;
if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument"); if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
string arg; string arg;
if (isWide() && isInOnly()) arg += "const "; if (isWide() && isReadOnly()) arg += "const ";
AstBasicDType* bdtypep = basicp(); AstBasicDType* bdtypep = basicp();
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING; bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) { if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
@ -231,8 +221,8 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::FLOAT) { } else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::FLOAT) {
arg += "float"; arg += "float";
} else if (strtype) { } else if (strtype) {
if (isInOnly()) arg += "const "; if (isReadOnly()) arg += "const ";
arg += "std::string"; arg += "std::string";
} else if (widthMin() <= 8) { } else if (widthMin() <= 8) {
arg += "CData"; arg += "CData";
} else if (widthMin() <= 16) { } else if (widthMin() <= 16) {
@ -257,8 +247,9 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
arg += "["+cvtToStr(widthWords())+"]"; arg += "["+cvtToStr(widthWords())+"]";
} }
} else { } else {
if (forFunc && (isOutput() || (strtype && isInput()))) arg += "&"; if (forFunc && (isWritable()
if (named) arg += " "+name(); || (strtype && isNonOutput()))) arg += "&";
if (named) arg += " "+name();
} }
return arg; return arg;
} }
@ -290,12 +281,12 @@ string AstVar::vlEnumType() const {
string AstVar::vlEnumDir() const { string AstVar::vlEnumDir() const {
string out; string out;
if (isInout()) { if (isInoutish()) {
out = "VLVD_INOUT"; out = "VLVD_INOUT";
} else if (isInOnly()) { } else if (isWritable()) {
out = "VLVD_IN";
} else if (isOutOnly()) {
out = "VLVD_OUT"; out = "VLVD_OUT";
} else if (isNonOutput()) {
out = "VLVD_IN";
} else { } else {
out = "VLVD_NODIR"; out = "VLVD_NODIR";
} }
@ -336,7 +327,7 @@ string AstVar::vlPropInit() const {
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;
if (isWide() && isInOnly()) arg += "const "; if (isWide() && isReadOnly()) arg += "const ";
if (widthMin() == 1) { if (widthMin() == 1) {
arg += "bool"; arg += "bool";
} else if (widthMin() <= VL_WORDSIZE) { } else if (widthMin() <= VL_WORDSIZE) {
@ -351,8 +342,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
arg += " (& "+name(); arg += " (& "+name();
arg += ")["+cvtToStr(widthWords())+"]"; arg += ")["+cvtToStr(widthWords())+"]";
} else { } else {
if (isOutput() && !forReturn) arg += "&"; if (!forReturn && isWritable()) arg += "&";
if (named) arg += " "+name(); if (named) arg += " "+name();
} }
return arg; return arg;
} }
@ -367,11 +358,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
} else if (basicp()->keyword().isDpiBitVal()) { } else if (basicp()->keyword().isDpiBitVal()) {
if (widthMin() == 1) { if (widthMin() == 1) {
arg = "unsigned char"; arg = "unsigned char";
if (!forReturn && isOutput()) arg += "*"; if (!forReturn && isWritable()) arg += "*";
} else { } else {
if (forReturn) { if (forReturn) {
arg = "svBitVecVal"; arg = "svBitVecVal";
} else if (isInOnly()) { } else if (isReadOnly()) {
arg = "const svBitVecVal*"; arg = "const svBitVecVal*";
} else { } else {
arg = "svBitVecVal*"; arg = "svBitVecVal*";
@ -380,11 +371,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
} else if (basicp()->keyword().isDpiLogicVal()) { } else if (basicp()->keyword().isDpiLogicVal()) {
if (widthMin() == 1) { if (widthMin() == 1) {
arg = "unsigned char"; arg = "unsigned char";
if (!forReturn && isOutput()) arg += "*"; if (!forReturn && isWritable()) arg += "*";
} else { } else {
if (forReturn) { if (forReturn) {
arg = "svLogicVecVal"; arg = "svLogicVecVal";
} else if (isInOnly()) { } else if (isReadOnly()) {
arg = "const svLogicVecVal*"; arg = "const svLogicVecVal*";
} else { } else {
arg = "svLogicVecVal*"; arg = "svLogicVecVal*";
@ -394,8 +385,8 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
arg = basicp()->keyword().dpiType(); arg = basicp()->keyword().dpiType();
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) { if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
arg = "unsigned "+arg; arg = "unsigned "+arg;
} }
if (!forReturn && isOutput()) arg += "*"; if (!forReturn && isWritable()) arg += "*";
} }
if (named) arg += " "+name(); if (named) arg += " "+name();
return arg; return arg;
@ -898,7 +889,7 @@ void AstModportFTaskRef::dump(std::ostream& str) {
} }
void AstModportVarRef::dump(std::ostream& str) { void AstModportVarRef::dump(std::ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);
str<<" "<<varType(); if (direction().isAny()) str<<" "<<direction();
if (varp()) { str<<" -> "; varp()->dump(str); } if (varp()) { str<<" -> "; varp()->dump(str); }
else { str<<" -> UNLINKED"; } else { str<<" -> UNLINKED"; }
} }
@ -1061,12 +1052,8 @@ void AstVarRef::dump(std::ostream& str) {
void AstVar::dump(std::ostream& str) { void AstVar::dump(std::ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);
if (isSc()) str<<" [SC]"; if (isSc()) str<<" [SC]";
if (isPrimaryIO()) str<<(isInout()?" [PIO]":(isInput()?" [PI]":" [PO]")); if (isPrimaryIO()) str<<(isInoutish()?" [PIO]":(isWritable()?" [PO]":" [PI]"));
else { if (isIO()) str<<" "<<direction().ascii();
if (isInout()) str<<" [IO]";
else if (isInput()) str<<" [I]";
else if (isOutput()) str<<" [O]";
}
if (isConst()) str<<" [CONST]"; if (isConst()) str<<" [CONST]";
if (isPullup()) str<<" [PULLUP]"; if (isPullup()) str<<" [PULLUP]";
if (isPulldown()) str<<" [PULLDOWN]"; if (isPulldown()) str<<" [PULLDOWN]";

View File

@ -1096,12 +1096,10 @@ private:
string m_origName; // Original name before dot addition string m_origName; // Original name before dot addition
string m_tag; // Holds the string of the verilator tag -- used in XML output. string m_tag; // Holds the string of the verilator tag -- used in XML output.
AstVarType m_varType; // Type of variable AstVarType m_varType; // Type of variable
VDirection m_direction; // Direction input/output etc
VDirection m_declDirection; // Declared direction input/output etc
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
bool m_input:1; // Input or inout
bool m_output:1; // Output or inout
bool m_tristate:1; // Inout or triwire or trireg bool m_tristate:1; // Inout or triwire or trireg
bool m_declInput:1; // Inout or input before tristate and inline resolution
bool m_declOutput:1; // Inout or output before tristate and inline resolution
bool m_primaryIO:1; // In/out to top level (or directly assigned from same) bool m_primaryIO:1; // In/out to top level (or directly assigned from same)
bool m_sc:1; // SystemC variable bool m_sc:1; // SystemC variable
bool m_scClocked:1; // SystemC sc_clk<> needed bool m_scClocked:1; // SystemC sc_clk<> needed
@ -1132,10 +1130,9 @@ private:
AstVarAttrClocker m_attrClocker; AstVarAttrClocker m_attrClocker;
MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var
void init() { void init() {
m_input=false; m_output=false; m_tristate=false; m_declInput=false; m_declOutput=false; m_tristate=false; 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_usedLoopIdx=false; m_usedClock=false; m_usedParam=false; m_usedLoopIdx=false;
m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=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;
@ -1201,9 +1198,16 @@ public:
string origName() const { return m_origName; } // * = Original name string origName() const { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; } void origName(const string& name) { m_origName = name; }
AstVarType varType() const { return m_varType; } // * = Type of variable AstVarType varType() const { return m_varType; } // * = Type of variable
void direction(const VDirection& flag) {
m_direction = flag;
if (m_direction == VDirection::INOUT) m_tristate = true; }
VDirection direction() const { return m_direction; }
bool isIO() const { return m_direction != VDirection::NONE; }
void declDirection(const VDirection& flag) { m_declDirection = flag; }
VDirection declDirection() const { return m_declDirection; }
void varType(AstVarType type) { m_varType = type; } void varType(AstVarType type) { m_varType = type; }
void varType2Out() { m_tristate=0; m_input=0; m_output=1; } void varType2Out() { m_tristate=0; m_direction=VDirection::OUTPUT; }
void varType2In() { m_tristate=0; m_input=1; m_output=0; } void varType2In() { m_tristate=0; m_direction=VDirection::INPUT; }
AstBasicDTypeKwd declKwd() const { return m_declKwd; } AstBasicDTypeKwd declKwd() const { return m_declKwd; }
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
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.
@ -1258,19 +1262,13 @@ public:
virtual void name(const string& name) { m_name = name; } virtual void name(const string& name) { m_name = name; }
virtual void tag(const string& text) { m_tag = text;} virtual void tag(const string& text) { m_tag = text;}
virtual string tag() const { return m_tag; } virtual string tag() const { return m_tag; }
virtual string directionName() const { return (isInout() ? "inout" : isInput() ? "input" bool isInoutish() const { return m_direction.isInoutish(); }
: isOutput() ? "output" : varType().ascii()); } bool isNonOutput() const { return m_direction.isNonOutput(); }
bool isInput() const { return m_input; } bool isReadOnly() const { return m_direction.isReadOnly(); }
bool isOutput() const { return m_output; } bool isWritable() const { return m_direction.isWritable(); }
bool isInOnly() const { return m_input && !m_output; }
bool isOutOnly() const { return m_output && !m_input; }
bool isInout() const { return m_input && m_output; }
bool isTristate() const { return m_tristate; } bool isTristate() const { return m_tristate; }
bool isDeclInput() const { return m_declInput; } bool isPrimaryIO() const { return m_primaryIO; }
bool isDeclOutput() const { return m_declOutput; } bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output); }
bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); } bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); }
bool isIfaceParent() const { return m_isIfaceParent; } bool isIfaceParent() const { return m_isIfaceParent; }
bool isSignal() const { return varType().isSignal(); } bool isSignal() const { return varType().isSignal(); }
@ -1326,8 +1324,9 @@ public:
// Ok to gate optimize; must return false if propagateAttrFrom would do anything // Ok to gate optimize; must return false if propagateAttrFrom would do anything
return (!attrClockEn() && !isUsedClock()); return (!attrClockEn() && !isUsedClock());
} }
void combineType(AstVar* typevarp) { void combineType(AstVar* typevarp) {
// This is same as typevarp (for combining input & reg decls) // This is same as typevarp (for combining input & reg decls)
// "this" is the input var. typevarp is the reg var.
propagateAttrFrom(typevarp); propagateAttrFrom(typevarp);
combineType(typevarp->varType()); combineType(typevarp->varType());
if (typevarp->isSigPublic()) sigPublic(true); if (typevarp->isSigPublic()) sigPublic(true);
@ -1337,9 +1336,11 @@ public:
if (typevarp->attrScClocked()) attrScClocked(true); if (typevarp->attrScClocked()) attrScClocked(true);
} }
void inlineAttrReset(const string& name) { void inlineAttrReset(const string& name) {
m_input=m_output=false; m_name = name; if (direction()==VDirection::INOUT && varType()==AstVarType::WIRE) {
if (varType()==AstVarType::INOUT) m_varType = AstVarType::TRIWIRE; m_varType = AstVarType::TRIWIRE;
if (varType()==AstVarType::INPUT || varType()==AstVarType::OUTPUT) m_varType = AstVarType::WIRE; }
m_direction = VDirection::NONE;
m_name = name;
} }
static AstVar* scVarRecurse(AstNode* nodep); static AstVar* scVarRecurse(AstNode* nodep);
void addProducingMTaskId(int id) { m_mtaskIds.insert(id); } void addProducingMTaskId(int id) { m_mtaskIds.insert(id); }
@ -1577,10 +1578,13 @@ public:
return NULL; } return NULL; }
virtual string name() const { return m_name; } // * = Pin name, ""=go by number virtual string name() const { return m_name; } // * = Pin name, ""=go by number
virtual void name(const string& name) { m_name = name; } virtual void name(const string& name) { m_name = name; }
virtual string prettyOperatorName() const { return modVarp() virtual string prettyOperatorName() const {
? (modVarp()->directionName()+" port connection '"+modVarp()->prettyName()+"'") return modVarp() ? ((modVarp()->direction().isAny()
: "port connection"; } ? modVarp()->direction().prettyName()+" "
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked : "")
+"port connection '"+modVarp()->prettyName()+"'")
: "port connection"; }
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
int pinNum() const { return m_pinNum; } int pinNum() const { return m_pinNum; }
void exprp(AstNode* nodep) { addOp1p(nodep); } void exprp(AstNode* nodep) { addOp1p(nodep); }
AstNode* exprp() const { return op1p(); } // op1 = Expression connected to pin, NULL if unconnected AstNode* exprp() const { return op1p(); } // op1 = Expression connected to pin, NULL if unconnected
@ -1730,19 +1734,18 @@ class AstModportVarRef : public AstNode {
// PARENT: AstModport // PARENT: AstModport
private: private:
string m_name; // Name of the variable referenced string m_name; // Name of the variable referenced
AstVarType m_type; // Type of the variable (in/out) VDirection m_direction; // Direction of the variable (in/out)
AstVar* m_varp; // Link to the actual Var AstVar* m_varp; // Link to the actual Var
public: public:
AstModportVarRef(FileLine* fl, const string& name, AstVarType::en type) AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction)
: AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { } : AstNode(fl), m_name(name), m_direction(direction), m_varp(NULL) { }
ASTNODE_NODE_FUNCS(ModportVarRef) ASTNODE_NODE_FUNCS(ModportVarRef)
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; } virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
virtual void dump(std::ostream& str); virtual void dump(std::ostream& str);
virtual void cloneRelink() { if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); } virtual void cloneRelink() { if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); }
virtual string name() const { return m_name; } virtual string name() const { return m_name; }
AstVarType varType() const { return m_type; } // * = Type of variable void direction(const VDirection& flag) { m_direction = flag; }
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); } VDirection direction() const { return m_direction; }
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) { m_varp=varp; } void varp(AstVar* varp) { m_varp=varp; }
}; };
@ -3367,8 +3370,7 @@ private:
uint32_t m_codeInc; // Code increment uint32_t m_codeInc; // Code increment
AstVarType m_varType; // Type of variable (for localparam vs. param) AstVarType m_varType; // Type of variable (for localparam vs. param)
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
bool m_declInput:1; // Input or inout VDirection m_declDirection; // Declared direction input/output etc
bool m_declOutput:1; // Output or inout
public: public:
AstTraceDecl(FileLine* fl, const string& showname, AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc AstVar* varp, // For input/output state etc
@ -3382,8 +3384,7 @@ public:
* valuep->dtypep()->widthWords()); * valuep->dtypep()->widthWords());
m_varType = varp->varType(); m_varType = varp->varType();
m_declKwd = varp->declKwd(); m_declKwd = varp->declKwd();
m_declInput = varp->isDeclInput(); m_declDirection = varp->declDirection();
m_declOutput = varp->isDeclOutput();
} }
virtual int instrCount() const { return 100; } // Large... virtual int instrCount() const { return 100; } // Large...
ASTNODE_NODE_FUNCS(TraceDecl) ASTNODE_NODE_FUNCS(TraceDecl)
@ -3400,9 +3401,7 @@ public:
const VNumRange& arrayRange() const { return m_arrayRange; } const VNumRange& arrayRange() const { return m_arrayRange; }
AstVarType varType() const { return m_varType; } AstVarType varType() const { return m_varType; }
AstBasicDTypeKwd declKwd() const { return m_declKwd; } AstBasicDTypeKwd declKwd() const { return m_declKwd; }
bool declInput() const { return m_declInput; } VDirection declDirection() const { return m_declDirection; }
bool declOutput() const { return m_declOutput; }
bool declInout() const { return m_declInput && m_declOutput; }
}; };
class AstTraceInc : public AstNodeStmt { class AstTraceInc : public AstNodeStmt {

View File

@ -114,7 +114,7 @@ void V3CCtors::evalAsserts() {
modp->addStmtp(funcp); modp->addStmtp(funcp);
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) { if (AstVar* varp = VN_CAST(np, Var)) {
if (varp->isPrimaryIn() && !varp->isSc()) { if (varp->isPrimaryInish() && !varp->isSc()) {
if (AstBasicDType* basicp = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) { if (AstBasicDType* basicp = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
int storedWidth = basicp->widthAlignBytes() * 8; int storedWidth = basicp->widthAlignBytes() * 8;
int lastWordWidth = varp->width() % storedWidth; int lastWordWidth = varp->width() % storedWidth;

View File

@ -258,13 +258,13 @@ private:
// Create IO vertex - note it's relative to the pointed to var, not where we are now // Create IO vertex - note it's relative to the pointed to var, not where we are now
// This allows reporting to easily print the input statement // This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL); CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
if (varscp->varp()->isInput()) { if (varscp->varp()->isWritable()) {
new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1); new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
} else { } else {
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1); new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1);
} }
} }
} }
if (m_inSenItem) { if (m_inSenItem) {
varscp->user2(true); // It's like a clock... varscp->user2(true); // It's like a clock...
// TODO: In the future we could mark it here and do normal clock tree glitch checks also // TODO: In the future we could mark it here and do normal clock tree glitch checks also
@ -372,9 +372,9 @@ private:
} }
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) { else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true); if (mark) vvertexp->asyncPath(true);
// If primary I/O, it's ok here back // If primary I/O, it's ok here back
if (vvertexp->varScp()->varp()->isPrimaryIn()) { if (vvertexp->varScp()->varp()->isPrimaryInish()) {
// Show the source "input" statement if it exists // Show the source "input" statement if it exists
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp()); CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true); eFromVertexp->asyncPath(true);
@ -501,8 +501,8 @@ private:
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) { if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
AstVar* varp = vvertexp->varScp()->varp(); AstVar* varp = vvertexp->varScp()->varp();
if (1) { // varp->isPrimaryIO() if (1) { // varp->isPrimaryIO()
const char* whatp = "wire"; string what = "wire";
if (varp->isPrimaryIO()) whatp = (varp->isInout()?"inout":varp->isInput()?"input":"output"); if (varp->isPrimaryIO()) what = varp->direction().prettyName();
std::ostringstream os; std::ostringstream os;
os.setf(std::ios::left); os.setf(std::ios::left);
@ -510,7 +510,7 @@ private:
// so we assume the modulename matches the filebasename // so we assume the modulename matches the filebasename
string fname = vvertexp->varScp()->fileline()->filebasename() + ":"; string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
os<<" "<<std::setw(20)<<fname; os<<" "<<std::setw(20)<<fname;
os<<" "<<std::setw(8)<<whatp; os<<" "<<std::setw(8)<<what;
os<<" "<<std::setw(40)<<vvertexp->varScp()->prettyName(); os<<" "<<std::setw(40)<<vvertexp->varScp()->prettyName();
os<<" SRC="; os<<" SRC=";
if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os); if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
@ -545,10 +545,12 @@ private:
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) { else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
// If primary I/O, give it domain of the input // If primary I/O, give it domain of the input
AstVar* varp = vvertexp->varScp()->varp(); AstVar* varp = vvertexp->varScp()->varp();
if (varp->isPrimaryIO() && varp->isInput() && !traceDests) { if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
senouts.insert(new AstSenTree(varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo()))); senouts.insert(
} new AstSenTree(varp->fileline(),
} new AstSenItem(varp->fileline(), AstSenItem::Combo())));
}
}
// Now combine domains of sources/dests // Now combine domains of sources/dests
if (traceDests) { if (traceDests) {

View File

@ -1538,9 +1538,10 @@ private:
&& ((!m_params // Can reduce constant wires into equations && ((!m_params // Can reduce constant wires into equations
&& m_doNConst && m_doNConst
&& v3Global.opt.oConst() && v3Global.opt.oConst()
&& !(nodep->varp()->isFuncLocal() // Default value, not a "known" constant for this usage // Default value, not a "known" constant for this usage
&& nodep->varp()->isInput()) && !(nodep->varp()->isFuncLocal()
&& !nodep->varp()->noSubst() && nodep->varp()->isNonOutput())
&& !nodep->varp()->noSubst()
&& !nodep->varp()->isSigPublic()) && !nodep->varp()->isSigPublic())
|| nodep->varp()->isParam())) { || nodep->varp()->isParam())) {
if (operandConst(valuep)) { if (operandConst(valuep)) {

View File

@ -183,13 +183,14 @@ private:
AstNode* argsp = NULL; AstNode* argsp = NULL;
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) { if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) { if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* newp = new AstVarRef(portp->fileline(), portp, portp->isOutput()); AstNode* newp = new AstVarRef(portp->fileline(),
if (argsp) argsp = argsp->addNextNull(newp); portp, portp->isWritable());
else argsp = newp; if (argsp) argsp = argsp->addNextNull(newp);
} else argsp = newp;
} }
} }
}
AstNode* returnp = new AstCReturn(funcp->fileline(), AstNode* returnp = new AstCReturn(funcp->fileline(),
new AstCCall(funcp->fileline(), new AstCCall(funcp->fileline(),

View File

@ -1211,13 +1211,13 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
if (nodep->isIO()) { if (nodep->isIO()) {
if (nodep->isSc()) { if (nodep->isSc()) {
m_ctorVarsVec.push_back(nodep); m_ctorVarsVec.push_back(nodep);
if (nodep->attrScClocked() && nodep->isInput()) { if (nodep->attrScClocked() && nodep->isReadOnly()) {
puts("sc_in_clk "); puts("sc_in_clk ");
} else { } else {
if (nodep->isInout()) puts("sc_inout<"); if (nodep->isInoutish()) puts("sc_inout<");
else if (nodep->isInput()) puts("sc_in<"); else if (nodep->isWritable()) puts("sc_out<");
else if (nodep->isOutput()) puts("sc_out<"); else if (nodep->isNonOutput()) puts("sc_in<");
else nodep->v3fatalSrc("Unknown type"); else nodep->v3fatalSrc("Unknown type");
puts(nodep->scType()); puts(nodep->scType());
puts("> "); puts("> ");
@ -1230,11 +1230,11 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
puts(nodep->vlArgType(true,false,false)); puts(nodep->vlArgType(true,false,false));
emitDeclArrayBrackets(nodep); emitDeclArrayBrackets(nodep);
puts(";\n"); puts(";\n");
} else { // C++ signals } else { // C++ signals
if (nodep->isInout()) puts("VL_INOUT"); if (nodep->isInoutish()) puts("VL_INOUT");
else if (nodep->isInput()) puts("VL_IN"); else if (nodep->isWritable()) puts("VL_OUT");
else if (nodep->isOutput()) puts("VL_OUT"); else if (nodep->isNonOutput()) puts("VL_IN");
else nodep->v3fatalSrc("Unknown type"); else nodep->v3fatalSrc("Unknown type");
if (nodep->isQuad()) puts("64"); if (nodep->isQuad()) puts("64");
else if (nodep->widthMin() <= 8) puts("8"); else if (nodep->widthMin() <= 8) puts("8");
@ -1990,9 +1990,10 @@ void EmitCImp::emitSensitives() {
puts("SC_METHOD(eval);\n"); puts("SC_METHOD(eval);\n");
for (AstNode* nodep=m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { for (AstNode* nodep=m_modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) { if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (varp->isInput() && (varp->isScSensitive() || varp->isUsedClock())) { if (varp->isNonOutput() && (varp->isScSensitive()
int vects = 0; || varp->isUsedClock())) {
// This isn't very robust and may need cleanup for other data types int vects = 0;
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType); for (AstUnpackArrayDType* arrayp=VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType);
arrayp; arrayp;
arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
@ -2852,9 +2853,9 @@ class EmitCTrace : EmitCStmts {
if (v3Global.opt.traceFormat() == TraceFormat::FST) { if (v3Global.opt.traceFormat() == TraceFormat::FST) {
puts(","+cvtToStr(enumNum)); puts(","+cvtToStr(enumNum));
// fstVarDir // fstVarDir
if (nodep->declInout()) puts(",FST_VD_INOUT"); if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT");
else if (nodep->declInput()) puts(",FST_VD_INPUT"); else if (nodep->declDirection().isWritable()) puts(",FST_VD_OUTPUT");
else if (nodep->declOutput()) puts(",FST_VD_OUTPUT"); else if (nodep->declDirection().isNonOutput()) puts(",FST_VD_INPUT");
else puts(",FST_VD_IMPLICIT"); else puts(",FST_VD_IMPLICIT");
// //
// fstVarType // fstVarType
@ -2875,6 +2876,7 @@ class EmitCTrace : EmitCStmts {
else if (vartype == AstVarType::TRI1) fstvt = "FST_VT_VCD_TRI1"; else if (vartype == AstVarType::TRI1) fstvt = "FST_VT_VCD_TRI1";
else if (vartype == AstVarType::TRIWIRE) fstvt = "FST_VT_VCD_TRI"; else if (vartype == AstVarType::TRIWIRE) fstvt = "FST_VT_VCD_TRI";
else if (vartype == AstVarType::WIRE) fstvt = "FST_VT_VCD_WIRE"; else if (vartype == AstVarType::WIRE) fstvt = "FST_VT_VCD_WIRE";
else if (vartype == AstVarType::PORT) fstvt = "FST_VT_VCD_WIRE";
// //
else if (kwd == AstBasicDTypeKwd::INTEGER) fstvt = "FST_VT_VCD_INTEGER"; else if (kwd == AstBasicDTypeKwd::INTEGER) fstvt = "FST_VT_VCD_INTEGER";
else if (kwd == AstBasicDTypeKwd::BIT) fstvt = "FST_VT_SV_BIT"; else if (kwd == AstBasicDTypeKwd::BIT) fstvt = "FST_VT_SV_BIT";

View File

@ -113,16 +113,14 @@ class EmitXmlFileVisitor : public AstNVisitor {
outputChildrenEnd(nodep, ""); outputChildrenEnd(nodep, "");
} }
virtual void visit(AstPin* nodep) { virtual void visit(AstPin* nodep) {
// What we call a pin in verilator is a port in the IEEE spec. // What we call a pin in verilator is a port in the IEEE spec.
outputTag(nodep, "port"); // IEEE: vpiPort outputTag(nodep, "port"); // IEEE: vpiPort
if (nodep->modVarp()->isInOnly()) { if (nodep->modVarp()->isIO()) {
puts(" direction=\"in\""); puts(" direction=\""+nodep->modVarp()->direction().xmlKwd()+"\"");
} else if (nodep->modVarp()->isOutOnly()) { }
puts(" direction=\"out\""); puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex
} else puts(" direction=\"inout\""); // Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex outputChildrenEnd(nodep, "port");
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
outputChildrenEnd(nodep, "port");
} }
virtual void visit(AstSenItem* nodep) { virtual void visit(AstSenItem* nodep) {
outputTag(nodep, ""); outputTag(nodep, "");

View File

@ -1131,11 +1131,11 @@ void GateVisitor::dedupe() {
} }
// Traverse starting from each of the outputs // Traverse starting from each of the outputs
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) { if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isOutput()) { if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) {
deduper.dedupeTree(vvertexp); deduper.dedupeTree(vvertexp);
} }
} }
} }
m_statDedupLogic += deduper.numDeduped(); m_statDedupLogic += deduper.numDeduped();
} }

View File

@ -317,23 +317,26 @@ private:
// Public variable at the lower module end - we need to make sure we propagate // Public variable at the lower module end - we need to make sure we propagate
// the logic changes up and down; if we aliased, we might remove the change detection // the logic changes up and down; if we aliased, we might remove the change detection
// on the output variable. // on the output variable.
UINFO(9,"public pin assign: "<<exprvarrefp<<endl); UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias"); if (nodep->isNonOutput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
m_modp->addStmtp(new AstAssignW(nodep->fileline(), m_modp->addStmtp(
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, false))); new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
} else if (nodep->isIfaceRef()) { new AstVarRef(nodep->fileline(), nodep, false)));
m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(), } else if (nodep->isIfaceRef()) {
new AstVarRef(nodep->fileline(), nodep, true), m_modp->addStmtp(
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); new AstAssignVarScope(nodep->fileline(),
AstNode* nodebp=exprvarrefp->varp(); new AstVarRef(nodep->fileline(), nodep, true),
nodep ->fileline()->modifyStateInherit(nodebp->fileline()); new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
nodebp->fileline()->modifyStateInherit(nodep ->fileline()); AstNode* nodebp=exprvarrefp->varp();
} else { nodep ->fileline()->modifyStateInherit(nodebp->fileline());
// Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below nodebp->fileline()->modifyStateInherit(nodep ->fileline());
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(), } else {
new AstVarRef(nodep->fileline(), nodep, true), // Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); m_modp->addStmtp(
new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp(); AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline()); nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline()); nodebp->fileline()->modifyStateInherit(nodep ->fileline());
@ -549,11 +552,12 @@ private:
AstNode* connectRefp = pinp->exprp(); AstNode* connectRefp = pinp->exprp();
if (!VN_IS(connectRefp, Const) && !VN_IS(connectRefp, VarRef)) { if (!VN_IS(connectRefp, Const) && !VN_IS(connectRefp, VarRef)) {
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up"); pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
} }
if (pinNewVarp->isOutOnly() && VN_IS(connectRefp, Const)) { if (pinNewVarp->direction() == VDirection::OUTPUT
pinp->v3error("Output port is connected to a constant pin, electrical short"); && VN_IS(connectRefp, Const)) {
} pinp->v3error("Output port is connected to a constant pin, electrical short");
}
// Propagate any attributes across the interconnect // Propagate any attributes across the interconnect
pinNewVarp->propagateAttrFrom(pinOldVarp); pinNewVarp->propagateAttrFrom(pinOldVarp);
@ -567,11 +571,13 @@ private:
UINFO(6,"One-to-one "<<connectRefp<<endl); UINFO(6,"One-to-one "<<connectRefp<<endl);
UINFO(6," -to "<<pinNewVarp<<endl); UINFO(6," -to "<<pinNewVarp<<endl);
pinNewVarp->user2p(connectRefp); pinNewVarp->user2p(connectRefp);
// Public output inside the cell must go via an assign rather than alias // Public output inside the cell must go via an assign rather
// Else the public logic will set the alias, losing the value to be propagated up // than alias. Else the public logic will set the alias, losing
// (InOnly isn't a problem as the AssignAlias will create the assignment for us) // the value to be propagated up (InOnly isn't a problem as the
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly()); // AssignAlias will create the assignment for us)
} pinNewVarp->user3(pinNewVarp->isSigUserRWPublic()
&& pinNewVarp->direction()==VDirection::OUTPUT);
}
// Cleanup var names, etc, to not conflict // Cleanup var names, etc, to not conflict
{ InlineRelinkVisitor(newmodp, m_modp, nodep); } { InlineRelinkVisitor(newmodp, m_modp, nodep); }
// Move statements to top module // Move statements to top module

View File

@ -63,28 +63,31 @@ private:
m_cellp = NULL; m_cellp = NULL;
} }
virtual void visit(AstPin* nodep) { virtual void visit(AstPin* nodep) {
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input) // PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
// or ASSIGNW(expr,VARXREF(p)) (if sub's output) // or ASSIGNW(expr,VARXREF(p)) (if sub's output)
UINFO(4," PIN "<<nodep<<endl); UINFO(4," PIN "<<nodep<<endl);
if (!nodep->exprp()) return; // No-connect if (!nodep->exprp()) return; // No-connect
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: "); if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
if (nodep->modVarp()->isOutOnly() && VN_IS(nodep->exprp(), Const)) if (nodep->modVarp()->direction() == VDirection::OUTPUT
nodep->v3error("Output port is connected to a constant pin, electrical short"); && VN_IS(nodep->exprp(), Const)) {
// Use user1p on the PIN to indicate we created an assign for this pin nodep->v3error("Output port is connected to a constant pin, electrical short");
if (!nodep->user1SetOnce()) { }
// Simplify it // Use user1p on the PIN to indicate we created an assign for this pin
if (!nodep->user1SetOnce()) {
// Simplify it
V3Inst::pinReconnectSimple(nodep, m_cellp, false); V3Inst::pinReconnectSimple(nodep, m_cellp, false);
// Make an ASSIGNW (expr, pin) // Make an ASSIGNW (expr, pin)
AstNode* exprp = nodep->exprp()->cloneTree(false); AstNode* exprp = nodep->exprp()->cloneTree(false);
if (exprp->width() != nodep->modVarp()->width()) if (exprp->width() != nodep->modVarp()->width()) {
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple"); nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple");
if (nodep->modVarp()->isInout()) { }
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator"); if (nodep->modVarp()->isInoutish()) {
} else if (nodep->modVarp()->isOutput()) { nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isWritable()) {
AstNode* rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); AstNode* rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp); AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
m_cellp->addNextHere(assp); m_cellp->addNextHere(assp);
} else if (nodep->modVarp()->isInput()) { } else if (nodep->modVarp()->isNonOutput()) {
// Don't bother moving constants now, // Don't bother moving constants now,
// we'll be pushing the const down to the cell soon enough. // we'll be pushing the const down to the cell soon enough.
AstNode* assp = new AstAssignW AstNode* assp = new AstAssignW
@ -332,8 +335,8 @@ private:
nodep->v3warn(LITENDIAN,"Little endian cell range connecting to vector: MSB < LSB of cell range: " nodep->v3warn(LITENDIAN,"Little endian cell range connecting to vector: MSB < LSB of cell range: "
<<m_cellRangep->lsbConst()<<":"<<m_cellRangep->msbConst()); <<m_cellRangep->lsbConst()<<":"<<m_cellRangep->msbConst());
} }
AstNode* exprp = nodep->exprp()->unlinkFrBack(); AstNode* exprp = nodep->exprp()->unlinkFrBack();
bool inputPin = nodep->modVarp()->isInput(); bool inputPin = nodep->modVarp()->isNonOutput();
if (!inputPin && !VN_IS(exprp, VarRef) if (!inputPin && !VN_IS(exprp, VarRef)
&& !VN_IS(exprp, Concat) // V3Const will collapse the SEL with the one we're about to make && !VN_IS(exprp, Concat) // V3Const will collapse the SEL with the one we're about to make
&& !VN_IS(exprp, Sel)) { // V3Const will collapse the SEL with the one we're about to make && !VN_IS(exprp, Sel)) { // V3Const will collapse the SEL with the one we're about to make
@ -512,25 +515,29 @@ public:
// Make a new temp wire // Make a new temp wire
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); } //if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
AstNode* pinexprp = pinp->exprp()->unlinkFrBack(); AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
string newvarname = (string(pinVarp->isOutput() ? "__Vcellout" : "__Vcellinp") string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
+(forTristate?"t":"") // Prevent name conflict if both tri & non-tri add signals // Prevent name conflict if both tri & non-tri add signals
+"__"+cellp->name()+"__"+pinp->name()); +(forTristate?"t":"")
AstVar* newvarp = new AstVar(pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp); +"__"+cellp->name()+"__"+pinp->name());
// Important to add statement next to cell, in case there is a generate with same named cell AstVar* newvarp = new AstVar(pinVarp->fileline(),
cellp->addNextHere(newvarp); AstVarType::MODULETEMP, newvarname, pinVarp);
if (pinVarp->isInout()) { // Important to add statement next to cell, in case there is a
// generate with same named cell
cellp->addNextHere(newvarp);
if (pinVarp->isInoutish()) {
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be" pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be"
" direct one-to-one connection (without any expression)"); " direct one-to-one connection (without any expression)");
} else if (pinVarp->isOutput()) { } else if (pinVarp->isWritable()) {
// See also V3Inst // See also V3Inst
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false); AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "<<rhsp->width()<<" >? "<<pinexprp->width()<<endl); UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "
<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp); rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true)); pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp); AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp); assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
} else { } else {
// V3 width should have range/extended to make the widths correct // V3 width should have range/extended to make the widths correct
assignp = new AstAssignW(pinp->fileline(), assignp = new AstAssignW(pinp->fileline(),
new AstVarRef(pinp->fileline(), newvarp, true), new AstVarRef(pinp->fileline(), newvarp, true),
pinexprp); pinexprp);

View File

@ -871,8 +871,9 @@ class LinkDotFindVisitor : public AstNVisitor {
// also return the class reference. // also return the class reference.
if (dtypep) dtypep->unlinkFrBack(); if (dtypep) dtypep->unlinkFrBack();
else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC); else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC);
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::OUTPUT, nodep->name(), AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::WIRE, nodep->name(),
VFlagChildDType(), dtypep); // Not dtype resolved yet VFlagChildDType(), dtypep); // Not dtype resolved yet
newvarp->direction(VDirection::OUTPUT);
newvarp->funcReturn(true); newvarp->funcReturn(true);
newvarp->trace(false); // Not user visible newvarp->trace(false); // Not user visible
newvarp->attrIsolateAssign(nodep->attrIsolateAssign()); newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
@ -1537,10 +1538,10 @@ private:
} else if (VN_IS(symp->nodep(), ModportVarRef)) { } else if (VN_IS(symp->nodep(), ModportVarRef)) {
AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef); AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef);
AstVar* varp = snodep->varp(); AstVar* varp = snodep->varp();
if (lvalue && snodep->isInput()) { if (lvalue && snodep->direction().isReadOnly()) {
nodep->v3error("Attempt to drive input-only modport: "<<nodep->prettyName()); nodep->v3error("Attempt to drive input-only modport: "<<nodep->prettyName());
} // else other simulators don't warn about reading, and IEEE doesn't say illegal } // else other simulators don't warn about reading, and IEEE doesn't say illegal
return varp; return varp;
} else { } else {
return NULL; return NULL;
} }

View File

@ -56,21 +56,21 @@ private:
nodep->lvalue(true); nodep->lvalue(true);
} }
if (nodep->varp()) { if (nodep->varp()) {
if (nodep->lvalue() && nodep->varp()->isInOnly()) { if (nodep->lvalue() && !m_ftaskp
if (!m_ftaskp) { && nodep->varp()->isReadOnly()) {
nodep->v3warn(ASSIGNIN,"Assigning to input variable: "<<nodep->prettyName()); nodep->v3warn(ASSIGNIN,"Assigning to input/const variable: "
} <<nodep->prettyName());
} }
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
// Nodes that start propagating down lvalues // Nodes that start propagating down lvalues
virtual void visit(AstPin* nodep) { virtual void visit(AstPin* nodep) {
if (nodep->modVarp() && nodep->modVarp()->isOutput()) { if (nodep->modVarp() && nodep->modVarp()->isWritable()) {
// When the varref's were created, we didn't know the I/O state // When the varref's were created, we didn't know the I/O state
// Now that we do, and it's from a output, we know it's a lvalue // Now that we do, and it's from a output, we know it's a lvalue
m_setRefLvalue = true; m_setRefLvalue = true;
iterateChildren(nodep); iterateChildren(nodep);
m_setRefLvalue = false; m_setRefLvalue = false;
} else { } else {
@ -238,14 +238,14 @@ private:
if (!taskp) return; if (!taskp) return;
for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp=stmtp->nextp()) {
if (const AstVar* portp = VN_CAST(stmtp, Var)) { if (const AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO()) { if (portp->isIO()) {
if (portp->isInput()) { if (portp->isWritable()) {
m_setRefLvalue = true;
iterate(pinp); iterate(pinp);
} else { // Output or Inout m_setRefLvalue = false;
m_setRefLvalue = true; } else {
iterate(pinp); iterate(pinp);
m_setRefLvalue = false; }
}
// Advance pin // Advance pin
pinp = pinp->nextp(); pinp = pinp->nextp();
} }

View File

@ -126,10 +126,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
AstVar* varp = oldvarp->cloneTree(false); AstVar* varp = oldvarp->cloneTree(false);
newmodp->addStmtp(varp); newmodp->addStmtp(varp);
varp->sigPublic(true); // User needs to be able to get to it... varp->sigPublic(true); // User needs to be able to get to it...
if (oldvarp->isIO()) { if (oldvarp->isIO()) {
oldvarp->primaryIO(true); oldvarp->primaryIO(false);
varp->primaryIO(true); varp->primaryIO(true);
} }
if (varp->isIO() && v3Global.opt.systemC()) { if (varp->isIO() && v3Global.opt.systemC()) {
varp->sc(true); varp->sc(true);
// User can see trace one level down from the wrapper // User can see trace one level down from the wrapper
@ -138,9 +138,9 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
} }
AstPin* pinp = new AstPin(oldvarp->fileline(),0,oldvarp->name(), AstPin* pinp = new AstPin(oldvarp->fileline(),0,oldvarp->name(),
new AstVarRef(varp->fileline(), new AstVarRef(varp->fileline(),
varp, oldvarp->isOutput())); varp, oldvarp->isWritable()));
// Skip length and width comp; we know it's a direct assignment // Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp); pinp->modVarp(oldvarp);
cellp->addPinsp(pinp); cellp->addPinsp(pinp);
} }

View File

@ -198,9 +198,9 @@ private:
// A variable with an = value can be three things: // A variable with an = value can be three things:
FileLine* fl = nodep->valuep()->fileline(); FileLine* fl = nodep->valuep()->fileline();
// 1. Parameters and function inputs: It's a default to use if not overridden // 1. Parameters and function inputs: It's a default to use if not overridden
if (nodep->isParam() || (m_ftaskp && nodep->isInOnly())) { if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) {
} }
else if (!m_ftaskp && nodep->isInOnly()) { else if (!m_ftaskp && nodep->isNonOutput()) {
nodep->v3error("Unsupported: Default value on module input: "<<nodep->prettyName()); nodep->v3error("Unsupported: Default value on module input: "<<nodep->prettyName());
nodep->valuep()->unlinkFrBack()->deleteTree(); nodep->valuep()->unlinkFrBack()->deleteTree();
} // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial } // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial

View File

@ -405,14 +405,17 @@ private:
AstVar* varoutp = NULL; AstVar* varoutp = NULL;
for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* varp = VN_CAST(stmtp, Var)) { if (AstVar* varp = VN_CAST(stmtp, Var)) {
if (varp->isInput()) { if (varp->isReadOnly()) {
} else if (varp->isOutput()) { } else if (varp->isWritable()) {
if (varoutp) { varp->v3error("Multiple outputs not allowed in udp modules"); } if (varoutp) {
varoutp = varp; varp->v3error("Multiple outputs not allowed in udp modules");
// Tie off }
m_modp->addStmtp(new AstAssignW(varp->fileline(), varoutp = varp;
new AstVarRef(varp->fileline(), varp, true), // Tie off
new AstConst(varp->fileline(), AstConst::LogicFalse()))); m_modp->addStmtp(new AstAssignW(
varp->fileline(),
new AstVarRef(varp->fileline(), varp, true),
new AstConst(varp->fileline(), AstConst::LogicFalse())));
} else { } else {
varp->v3error("Only inputs and outputs are allowed in udp modules"); varp->v3error("Only inputs and outputs are allowed in udp modules");
} }

View File

@ -1017,9 +1017,9 @@ private:
m_inClocked = false; m_inClocked = false;
} }
virtual void visit(AstVarScope* nodep) { virtual void visit(AstVarScope* nodep) {
// Create links to all input signals // Create links to all input signals
if (m_modp->isTop() && nodep->varp()->isInput()) { if (m_modp->isTop() && nodep->varp()->isNonOutput()) {
OrderVarVertex* varVxp = newVarUserVertex(nodep, WV_STD); OrderVarVertex* varVxp = newVarUserVertex(nodep, WV_STD);
new OrderEdge(&m_graph, m_inputsVxp, varVxp, WEIGHT_INPUT); new OrderEdge(&m_graph, m_inputsVxp, varVxp, WEIGHT_INPUT);
} }
} }
@ -1463,9 +1463,9 @@ void OrderVisitor::processSensitive() {
// Sc sensitives are required on all inputs that go to a combo // Sc sensitives are required on all inputs that go to a combo
// block. (Not inputs that go only to clocked blocks.) // block. (Not inputs that go only to clocked blocks.)
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(itp)) { if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(itp)) {
if (vvertexp->varScp()->varp()->isInput()) { if (vvertexp->varScp()->varp()->isNonOutput()) {
//UINFO(0," scsen "<<vvertexp<<endl); //UINFO(0," scsen "<<vvertexp<<endl);
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (OrderEitherVertex* toVertexp = dynamic_cast<OrderEitherVertex*>(edgep->top())) { if (OrderEitherVertex* toVertexp = dynamic_cast<OrderEitherVertex*>(edgep->top())) {
if (edgep->weight() && toVertexp->domainp()) { if (edgep->weight() && toVertexp->domainp()) {
@ -1501,8 +1501,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
OrderVarVertex* vvertexp = dynamic_cast<OrderVarVertex*>(vertexp); OrderVarVertex* vvertexp = dynamic_cast<OrderVarVertex*>(vertexp);
AstSenTree* domainp = NULL; AstSenTree* domainp = NULL;
UASSERT(m_comboDomainp, "not preset"); UASSERT(m_comboDomainp, "not preset");
if (vvertexp && vvertexp->varScp()->varp()->isInput()) { if (vvertexp && vvertexp->varScp()->varp()->isNonOutput()) {
domainp = m_comboDomainp; domainp = m_comboDomainp;
} }
if (vvertexp && vvertexp->varScp()->isCircular()) { if (vvertexp && vvertexp->varScp()->isCircular()) {
domainp = m_comboDomainp; domainp = m_comboDomainp;

View File

@ -785,11 +785,11 @@ private:
AstVar* portp = it->first; AstVar* portp = it->first;
AstNode* pinp = it->second->exprp(); AstNode* pinp = it->second->exprp();
if (pinp) { // Else too few arguments in function call - ignore it if (pinp) { // Else too few arguments in function call - ignore it
if (portp->isOutput()) { if (portp->isWritable()) {
clearOptimizable(portp,"Language violation: Outputs not allowed in constant functions"); clearOptimizable(portp, "Language violation: Outputs/refs not allowed in constant functions");
return; return;
} }
// Evaluate pin value // Evaluate pin value
iterate(pinp); iterate(pinp);
} }
} }

View File

@ -332,9 +332,9 @@ private:
AstVarScope* createInputVar(AstCFunc* funcp, const string& name, AstBasicDTypeKwd kwd) { AstVarScope* createInputVar(AstCFunc* funcp, const string& name, AstBasicDTypeKwd kwd) {
AstVar* newvarp = new AstVar(funcp->fileline(), AstVarType::BLOCKTEMP, name, AstVar* newvarp = new AstVar(funcp->fileline(), AstVarType::BLOCKTEMP, name,
funcp->findBasicDType(kwd)); funcp->findBasicDType(kwd));
newvarp->funcLocal(true); newvarp->funcLocal(true);
newvarp->combineType(AstVarType::INPUT); newvarp->direction(VDirection::INPUT);
funcp->addArgsp(newvarp); funcp->addArgsp(newvarp);
AstVarScope* newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp); AstVarScope* newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp);
m_scopep->addVarp(newvscp); m_scopep->addVarp(newvscp);
return newvscp; return newvscp;
@ -378,10 +378,13 @@ private:
pinp->unlinkFrBack(); // Relinked to assignment below pinp->unlinkFrBack(); // Relinked to assignment below
argp->unlinkFrBack()->deleteTree(); // Args no longer needed argp->unlinkFrBack()->deleteTree(); // Args no longer needed
// //
if ((portp->isInout() || portp->isOutput()) && VN_IS(pinp, Const)) { if (portp->isWritable() && VN_IS(pinp, Const)) {
pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName()); pinp->v3error("Function/task "
} +portp->direction().prettyName() // e.g. "output"
else if (portp->isInout()) { +" connected to constant instead of variable: "
+portp->prettyName());
}
else if (portp->isInoutish()) {
// Correct lvalue; see comments below // Correct lvalue; see comments below
V3LinkLValue::linkLValueSet(pinp); V3LinkLValue::linkLValueSet(pinp);
@ -393,9 +396,9 @@ private:
} else { } else {
pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable"); pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
} }
} }
else if (portp->isOutput()) { else if (portp->isWritable()) {
// Make output variables // Make output variables
// Correct lvalue; we didn't know when we linked // Correct lvalue; we didn't know when we linked
// This is slightly scary; are we sure no decisions were made // This is slightly scary; are we sure no decisions were made
// before here based on this not being a lvalue? // before here based on this not being a lvalue?
@ -412,9 +415,9 @@ private:
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block
// Put assignment BEHIND of all other statements // Put assignment BEHIND of all other statements
beginp->addNext(assp); beginp->addNext(assp);
} }
else if (portp->isInput()) { else if (portp->isNonOutput()) {
// Make input variable // Make input variable
AstVarScope* inVscp = createVarScope(portp, namePrefix+"__"+portp->shortName()); AstVarScope* inVscp = createVarScope(portp, namePrefix+"__"+portp->shortName());
portp->user2p(inVscp); portp->user2p(inVscp);
AstAssign* assp = new AstAssign(pinp->fileline(), AstAssign* assp = new AstAssign(pinp->fileline(),
@ -483,10 +486,13 @@ private:
} else { } else {
UINFO(9, " Port "<<portp<<endl); UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl); UINFO(9, " pin "<<pinp<<endl);
if ((portp->isInout() || portp->isOutput()) && VN_IS(pinp, Const)) { if (portp->isWritable() && VN_IS(pinp, Const)) {
pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName()); pinp->v3error("Function/task "
} +portp->direction().prettyName() // e.g. "output"
else if (portp->isInout()) { +" connected to constant instead of variable: "
+portp->prettyName());
}
else if (portp->isInoutish()) {
// Correct lvalue; see comments below // Correct lvalue; see comments below
V3LinkLValue::linkLValueSet(pinp); V3LinkLValue::linkLValueSet(pinp);
@ -495,9 +501,9 @@ private:
} else { } else {
pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable"); pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
} }
} }
else if (portp->isOutput()) { else if (portp->isWritable()) {
// Make output variables // Make output variables
// Correct lvalue; we didn't know when we linked // Correct lvalue; we didn't know when we linked
// This is slightly scary; are we sure no decisions were made // This is slightly scary; are we sure no decisions were made
// before here based on this not being a lvalue? // before here based on this not being a lvalue?
@ -718,12 +724,17 @@ private:
// No createDpiTemp; we make a real internal variable instead // No createDpiTemp; we make a real internal variable instead
// SAME CODE BELOW // SAME CODE BELOW
args+= ", "; args+= ", ";
if (args != "") { argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args=""; } if (args != "") {
argnodesp = argnodesp->addNext(
new AstText(portp->fileline(), args, true));
args="";
}
AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp); AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp);
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isOutput()); AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp,
argnodesp = argnodesp->addNextNull(refp); portp->isWritable());
argnodesp = argnodesp->addNextNull(refp);
if (portp->isInput()) { if (portp->isNonOutput()) {
dpip->addStmtsp(createAssignDpiToInternal(outvscp, portp->name(), false)); dpip->addStmtsp(createAssignDpiToInternal(outvscp, portp->name(), false));
} }
} }
@ -736,9 +747,9 @@ private:
args+= ", "; args+= ", ";
if (args != "") { argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args=""; } if (args != "") { argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args=""; }
AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp); AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp);
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isOutput()); AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable());
argnodesp = argnodesp->addNextNull(refp); argnodesp = argnodesp->addNextNull(refp);
} }
{// Call the user function {// Call the user function
// Add the variables referenced as VarRef's so that lifetime analysis // Add the variables referenced as VarRef's so that lifetime analysis
@ -755,11 +766,11 @@ private:
// Convert output/inout arguments back to internal type // Convert output/inout arguments back to internal type
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) { if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && portp->isOutput() && !portp->isFuncReturn()) { if (portp->isIO() && portp->isWritable() && !portp->isFuncReturn()) {
dpip->addStmtsp(createAssignInternalToDpi(portp,false,true,"__Vcvt","")); dpip->addStmtsp(createAssignInternalToDpi(portp,false,true,"__Vcvt",""));
} }
} }
} }
if (rtnvarp) { if (rtnvarp) {
dpip->addStmtsp(createDpiTemp(rtnvarp,"")); dpip->addStmtsp(createDpiTemp(rtnvarp,""));
@ -867,14 +878,14 @@ private:
else { else {
if (bitvec) {} if (bitvec) {}
else if (logicvec) {} else if (logicvec) {}
else if (portp->isOutput()) args += "&"; else if (portp->isWritable()) args += "&";
else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal() else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
&& portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide) && portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide)
args += portp->name()+"__Vcvt"; args += portp->name()+"__Vcvt";
cfuncp->addStmtsp(createDpiTemp(portp,"__Vcvt")); cfuncp->addStmtsp(createDpiTemp(portp,"__Vcvt"));
if (portp->isInput()) { if (portp->isNonOutput()) {
cfuncp->addStmtsp(createAssignInternalToDpi(portp,false,false,"","__Vcvt")); cfuncp->addStmtsp(createAssignInternalToDpi(portp,false,false,"","__Vcvt"));
} }
} }
@ -900,7 +911,7 @@ private:
// Convert output/inout arguments back to internal type // Convert output/inout arguments back to internal type
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) { if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && (portp->isOutput() || portp->isFuncReturn()) if (portp->isIO() && (portp->isWritable() || portp->isFuncReturn())
&& !portp->isDpiOpenArray()) { && !portp->isDpiOpenArray()) {
AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier
cfuncp->addStmtsp(createAssignDpiToInternal(portvscp,portp->name()+"__Vcvt",true)); cfuncp->addStmtsp(createAssignDpiToInternal(portvscp,portp->name()+"__Vcvt",true));

View File

@ -699,11 +699,11 @@ private:
} }
V3GraphVertex* traceVtxp = m_tracep->user1u().toGraphVertex(); V3GraphVertex* traceVtxp = m_tracep->user1u().toGraphVertex();
new V3GraphEdge(&m_graph, varVtxp, traceVtxp, 1); new V3GraphEdge(&m_graph, varVtxp, traceVtxp, 1);
if (nodep->varp()->isPrimaryIn() // Always need to trace primary inputs if (nodep->varp()->isPrimaryInish() // Always need to trace primary inputs
|| nodep->varp()->isSigPublic()) { // Or ones user can change || nodep->varp()->isSigPublic()) { // Or ones user can change
new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1); new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1);
} }
} }
else if (m_funcp && m_finding && nodep->lvalue()) { else if (m_funcp && m_finding && nodep->lvalue()) {
if (!nodep->varScopep()) nodep->v3fatalSrc("No var scope?"); if (!nodep->varScopep()) nodep->v3fatalSrc("No var scope?");
V3GraphVertex* funcVtxp = getCFuncVertexp(m_funcp); V3GraphVertex* funcVtxp = getCFuncVertexp(m_funcp);

View File

@ -27,9 +27,9 @@
// Over each module, from child to parent: // Over each module, from child to parent:
// Build a graph, connecting signals together so we can propagate tristates // Build a graph, connecting signals together so we can propagate tristates
// Variable becomes tristate with // Variable becomes tristate with
// VAR->isInout // VAR->isInoutish
// VAR->isPullup/isPulldown (converted to AstPullup/AstPulldown // VAR->isPullup/isPulldown (converted to AstPullup/AstPulldown
// BufIf0/1 // BufIf0/1
// All variables on the LHS need to become tristate when there is: // All variables on the LHS need to become tristate when there is:
// CONST-> with Z value on the RHS of an assignment // CONST-> with Z value on the RHS of an assignment
// AstPin with lower connection a tristate // AstPin with lower connection a tristate
@ -1067,18 +1067,20 @@ class TristateVisitor : public TristateBaseVisitor {
UINFO(9,dbgState()<<nodep<<endl); UINFO(9,dbgState()<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: "); if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: ");
// Empty/in-only; need Z to propagate // Empty/in-only; need Z to propagate
bool inDeclProcessing = (nodep->exprp() bool inDeclProcessing = (nodep->exprp()
&& nodep->modVarp()->isInOnly() && nodep->modVarp()->direction() == VDirection::INPUT
// Need to consider the original state instead of current state // Need to consider the original state
// as we converted tristates to inputs, which do not want to have this. // instead of current state as we converted
&& !nodep->modVarp()->isDeclOutput()); // tristates to inputs, which do not want
if (!nodep->exprp()) { // No-connect; covert to empty connection // to have this.
UINFO(5,"Unconnected pin terminate "<<nodep<<endl); && !nodep->modVarp()->declDirection().isWritable());
AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep()); if (!nodep->exprp()) { // No-connect; covert to empty connection
nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp, UINFO(5,"Unconnected pin terminate "<<nodep<<endl);
// We converted, so use declaration output state AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep());
nodep->modVarp()->isDeclOutput())); nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp,
// We converted, so use declaration output state
nodep->modVarp()->declDirection().isWritable()));
m_tgraph.setTristate(ucVarp); m_tgraph.setTristate(ucVarp);
// We don't need a driver on the wire; the lack of one will default to tristate // We don't need a driver on the wire; the lack of one will default to tristate
} else if (inDeclProcessing) { // Not an input that was a converted tristate } else if (inDeclProcessing) { // Not an input that was a converted tristate
@ -1245,11 +1247,12 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->addNextHere(newp); nodep->addNextHere(newp);
// We'll iterate on the new AstPull later // We'll iterate on the new AstPull later
} }
if (nodep->isInout() if (nodep->isInoutish()
//|| varp->isOutput() //|| varp->isOutput()
// Note unconnected output only changes behavior vs. previous versions and causes outputs // Note unconnected output only changes behavior vs. previous
// that don't come from anywhere to possibly create connection errors. // versions and causes outputs that don't come from anywhere to
// One example of problems is this: "output z; task t; z <= {something}; endtask" // possibly create connection errors.
// One example of problems is this: "output z; task t; z <= {something}; endtask"
) { ) {
UINFO(9," setTristate-inout "<<nodep<<endl); UINFO(9," setTristate-inout "<<nodep<<endl);
m_tgraph.setTristate(nodep); m_tgraph.setTristate(nodep);

View File

@ -272,12 +272,12 @@ private:
// For assigns and non-combo always, do just usr==1, to look for module-wide undriven etc // For assigns and non-combo always, do just usr==1, to look for module-wide undriven etc
// For non-combo always, run both usr==1 for above, and also usr==2 for always-only checks // For non-combo always, run both usr==1 for above, and also usr==2 for always-only checks
UndrivenVarEntry* entryp = getEntryp(nodep, usr); UndrivenVarEntry* entryp = getEntryp(nodep, usr);
if (nodep->isInput() if (nodep->isNonOutput()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic() || nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) { || (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->drivenWhole(); entryp->drivenWhole();
} }
if (nodep->isOutput() if (nodep->isWritable()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic() || nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| nodep->isSigUserRdPublic() || nodep->isSigUserRdPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) { || (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {

View File

@ -2557,7 +2557,7 @@ private:
AstArg* argp = it->second; AstArg* argp = it->second;
AstNode* pinp = argp->exprp(); AstNode* pinp = argp->exprp();
if (!pinp) continue; // Argument error we'll find later if (!pinp) continue; // Argument error we'll find later
if ((portp->isOutput() || portp->isInout()) if (portp->isWritable()
&& pinp->width() != portp->width()) { && pinp->width() != portp->width()) {
pinp->v3error("Unsupported: Function output argument '"<<portp->prettyName()<<"'" pinp->v3error("Unsupported: Function output argument '"<<portp->prettyName()<<"'"
<<" requires "<<portp->width() <<" requires "<<portp->width()
@ -3344,8 +3344,9 @@ private:
AstNodeAssign* assignp = VN_CAST(nodep, NodeAssign); AstNodeAssign* assignp = VN_CAST(nodep, NodeAssign);
AstPin* pinp = VN_CAST(nodep, Pin); AstPin* pinp = VN_CAST(nodep, Pin);
if (assignp && VN_IS(assignp->lhsp(), NodeStream)) { if (assignp && VN_IS(assignp->lhsp(), NodeStream)) {
} else if (pinp && !pinp->modVarp()->isInput()) { // V3Inst::pinReconnectSimple must deal } else if (pinp && pinp->modVarp()->direction() != VDirection::INPUT) {
UINFO(5,"pinInSizeMismatch: "<<pinp); // V3Inst::pinReconnectSimple must deal
UINFO(5,"pinInSizeMismatch: "<<pinp);
} else { } else {
fixWidthExtend(underp, expDTypep, extendRule); VL_DANGLING(underp);//Changed fixWidthExtend(underp, expDTypep, extendRule); VL_DANGLING(underp);//Changed
} }

View File

@ -51,7 +51,7 @@ class V3ParseGrammar {
public: public:
bool m_impliedDecl; // Allow implied wire declarations bool m_impliedDecl; // Allow implied wire declarations
AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc) AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc)
AstVarType m_varIO; // Type for next signal declaration (input/output/etc) VDirection m_varIO; // Direction for next signal declaration (reg/wire/etc)
AstVar* m_varAttrp; // Current variable for attribute adding AstVar* m_varAttrp; // Current variable for attribute adding
AstRange* m_gateRangep; // Current range for gate declarations AstRange* m_gateRangep; // Current range for gate declarations
AstCase* m_caseAttrp; // Current case statement for attribute adding AstCase* m_caseAttrp; // Current case statement for attribute adding
@ -68,7 +68,7 @@ public:
V3ParseGrammar() { V3ParseGrammar() {
m_impliedDecl = false; m_impliedDecl = false;
m_varDecl = AstVarType::UNKNOWN; m_varDecl = AstVarType::UNKNOWN;
m_varIO = AstVarType::UNKNOWN; m_varIO = VDirection::NONE;
m_varDTypep = NULL; m_varDTypep = NULL;
m_gateRangep = NULL; m_gateRangep = NULL;
m_memDTypep = NULL; m_memDTypep = NULL;
@ -182,9 +182,9 @@ int V3ParseGrammar::s_modTypeImpNum = 0;
#define VARRESET_LIST(decl) { GRAMMARP->m_pinNum=1; VARRESET(); VARDECL(decl); } // Start of pinlist #define VARRESET_LIST(decl) { GRAMMARP->m_pinNum=1; VARRESET(); VARDECL(decl); } // Start of pinlist
#define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; VARRESET(); VARDECL(decl); } // Not in a pinlist #define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; VARRESET(); VARDECL(decl); } // Not in a pinlist
#define VARRESET() { VARDECL(UNKNOWN); VARIO(UNKNOWN); VARDTYPE(NULL); } #define VARRESET() { VARDECL(UNKNOWN); VARIO(NONE); VARDTYPE(NULL); }
#define VARDECL(type) { GRAMMARP->m_varDecl = AstVarType::type; } #define VARDECL(type) { GRAMMARP->m_varDecl = AstVarType::type; }
#define VARIO(type) { GRAMMARP->m_varIO = AstVarType::type; } #define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; }
#define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); } #define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); }
#define VARDONEA(fl,name,array,attrs) GRAMMARP->createVariable((fl),(name),(array),(attrs)) #define VARDONEA(fl,name,array,attrs) GRAMMARP->createVariable((fl),(name),(array),(attrs))
@ -899,11 +899,11 @@ port<nodep>: // ==IEEE: port
// // Expanded interface_port_header // // Expanded interface_port_header
// // We use instantCb here because the non-port form looks just like a module instantiation // // We use instantCb here because the non-port form looks just like a module instantiation
portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE
{ $$ = $3; VARDECL(AstVarType::IFACEREF); VARIO(UNKNOWN); { $$ = $3; VARDECL(AstVarType::IFACEREF); VARIO(NONE);
VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2)); VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2));
$$->addNextNull(VARDONEP($$,$4,$5)); } $$->addNextNull(VARDONEP($$,$4,$5)); }
| portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE | portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE
{ $$ = $5; VARDECL(AstVarType::IFACEREF); VARIO(UNKNOWN); { $$ = $5; VARDECL(AstVarType::IFACEREF); VARIO(NONE);
VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2,*$4)); VARDTYPE(new AstIfaceRefDType($<fl>2,"",*$2,*$4));
$$->addNextNull(VARDONEP($$,$6,$7)); } $$->addNextNull(VARDONEP($$,$6,$7)); }
| portDirNetE yINTERFACE portSig rangeListE sigAttrListE | portDirNetE yINTERFACE portSig rangeListE sigAttrListE
@ -3993,13 +3993,12 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstNodeRange* arrayp, AstNode* attrsp) { AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstNodeRange* arrayp, AstNode* attrsp) {
AstNodeDType* dtypep = GRAMMARP->m_varDTypep; AstNodeDType* dtypep = GRAMMARP->m_varDTypep;
UINFO(5," creVar "<<name<<" decl="<<GRAMMARP->m_varDecl<<" io="<<GRAMMARP->m_varIO<<" dt="<<(dtypep?"set":"")<<endl); UINFO(5," creVar "<<name<<" decl="<<GRAMMARP->m_varDecl<<" io="<<GRAMMARP->m_varIO<<" dt="<<(dtypep?"set":"")<<endl);
if (GRAMMARP->m_varIO == AstVarType::UNKNOWN if (GRAMMARP->m_varIO == VDirection::NONE
&& GRAMMARP->m_varDecl == AstVarType::PORT) { && GRAMMARP->m_varDecl == AstVarType::PORT) {
// Just a port list with variable name (not v2k format); AstPort already created // Just a port list with variable name (not v2k format); AstPort already created
if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists"); if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists");
return NULL; return NULL;
} }
AstVarType type = GRAMMARP->m_varIO;
if (GRAMMARP->m_varDecl == AstVarType::WREAL) { if (GRAMMARP->m_varDecl == AstVarType::WREAL) {
// dtypep might not be null, might be implicit LOGIC before we knew better // dtypep might not be null, might be implicit LOGIC before we knew better
dtypep = new AstBasicDType(fileline,AstBasicDTypeKwd::DOUBLE); dtypep = new AstBasicDType(fileline,AstBasicDTypeKwd::DOUBLE);
@ -4010,21 +4009,28 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstNodeR
dtypep = dtypep->cloneTree(false); dtypep = dtypep->cloneTree(false);
} }
//UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<" io="<<GRAMMARP->m_varIO.ascii()<<endl); //UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<" io="<<GRAMMARP->m_varIO.ascii()<<endl);
if (type == AstVarType::UNKNOWN AstVarType type = GRAMMARP->m_varDecl;
|| (type == AstVarType::PORT && GRAMMARP->m_varDecl != AstVarType::UNKNOWN)) if (type == AstVarType::UNKNOWN) {
type = GRAMMARP->m_varDecl; if (GRAMMARP->m_varIO.isAny()) {
if (type == AstVarType::UNKNOWN) fileline->v3fatalSrc("Unknown signal type declared"); type = AstVarType::PORT;
} else {
fileline->v3fatalSrc("Unknown signal type declared");
}
}
if (type == AstVarType::GENVAR) { if (type == AstVarType::GENVAR) {
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name); if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
} }
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE) // Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
AstNodeDType* arrayDTypep = createArray(dtypep,arrayp,false); AstNodeDType* arrayDTypep = createArray(dtypep, arrayp, false);
AstVar* nodep = new AstVar(fileline, type, name, VFlagChildDType(), arrayDTypep); AstVar* nodep = new AstVar(fileline, type, name, VFlagChildDType(), arrayDTypep);
nodep->addAttrsp(attrsp); nodep->addAttrsp(attrsp);
if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
if (GRAMMARP->m_varIO != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varIO); if (GRAMMARP->m_varIO != VDirection::NONE) {
nodep->declDirection(GRAMMARP->m_varIO);
nodep->direction(GRAMMARP->m_varIO);
}
if (GRAMMARP->m_varDecl == AstVarType::SUPPLY0) { if (GRAMMARP->m_varDecl == AstVarType::SUPPLY0) {
nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0)); nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0));

View File

@ -14,7 +14,7 @@ compile(
fails => 1, fails => 1,
expect => expect =>
q{%Error: t/t_func_const_bad.v:11: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output' q{%Error: t/t_func_const_bad.v:11: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output'
%Error: t/t_func_const_bad.v:12: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions %Error: t/t_func_const_bad.v:12: ... Location of non-constant VAR 'o': Language violation: Outputs/refs not allowed in constant functions
%Error: t/t_func_const_bad.v:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted' %Error: t/t_func_const_bad.v:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted'
%Error: t/t_func_const_bad.v:22: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions %Error: t/t_func_const_bad.v:22: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions
Called from: Called from:

View File

@ -12,8 +12,8 @@ scenarios(simulator => 1);
compile( compile(
fails => 1, fails => 1,
expect => expect =>
q{%Error: t/t_interface_size_bad.v:\d+: Illegal IFACEREF port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 4. q{%Error: t/t_interface_size_bad.v:\d+: Illegal port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 4.
%Error: t/t_interface_size_bad.v:\d+: Illegal IFACEREF port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 6. %Error: t/t_interface_size_bad.v:\d+: Illegal port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 6.
%Error: Exiting due to.*}, %Error: Exiting due to.*},
); );

View File

@ -1,5 +1,5 @@
$date $date
Thu Oct 4 19:33:38 2018 Sun Oct 21 21:57:08 2018
$end $end
$version $version
@ -9,7 +9,7 @@ $timescale
1ns 1ns
$end $end
$scope module top $end $scope module top $end
$var bit 1 ! clk $end $var wire 1 ! clk $end
$scope module t $end $scope module t $end
$var wire 1 ! clk $end $var wire 1 ! clk $end
$var integer 32 " cyc $end $var integer 32 " cyc $end

View File

@ -1,5 +1,5 @@
$date $date
Mon Oct 8 07:13:10 2018 Sun Oct 21 21:56:13 2018
$end $end
$version $version
@ -9,7 +9,7 @@ $timescale
1ns 1ns
$end $end
$scope module top $end $scope module top $end
$var bit 1 ! clk $end $var wire 1 ! clk $end
$scope module t $end $scope module t $end
$var wire 1 ! clk $end $var wire 1 ! clk $end
$var integer 32 " cyc $end $var integer 32 " cyc $end

View File

@ -1,5 +1,5 @@
$date $date
Mon Oct 8 07:13:11 2018 Sun Oct 21 21:56:26 2018
$end $end
$version $version
@ -9,7 +9,7 @@ $timescale
1ns 1ns
$end $end
$scope module top $end $scope module top $end
$var bit 1 ! clk $end $var wire 1 ! clk $end
$scope module t $end $scope module t $end
$var wire 1 ! clk $end $var wire 1 ! clk $end
$var integer 32 " cyc $end $var integer 32 " cyc $end

View File

@ -1,5 +1,5 @@
$date $date
Mon Oct 8 07:13:12 2018 Sun Oct 21 21:56:37 2018
$end $end
$version $version
@ -9,7 +9,7 @@ $timescale
1ns 1ns
$end $end
$scope module top $end $scope module top $end
$var bit 1 ! clk $end $var wire 1 ! clk $end
$scope module t $end $scope module t $end
$var wire 1 ! clk $end $var wire 1 ! clk $end
$var integer 32 " cyc $end $var integer 32 " cyc $end

View File

@ -1,5 +1,5 @@
$date $date
Thu Oct 4 19:26:16 2018 Sun Oct 21 21:55:42 2018
$end $end
$version $version
@ -9,8 +9,8 @@ $timescale
1ns 1ns
$end $end
$scope module top $end $scope module top $end
$var bit 1 ! clk $end $var wire 1 ! clk $end
$var logic 5 " state $end $var wire 5 " state $end
$scope module t $end $scope module t $end
$var wire 1 ! clk $end $var wire 1 ! clk $end
$var int 32 # cyc $end $var int 32 # cyc $end

View File

@ -1,5 +1,5 @@
$date $date
Thu Oct 4 19:33:41 2018 Sun Oct 21 21:56:54 2018
$end $end
$version $version
@ -9,7 +9,7 @@ $timescale
1ns 1ns
$end $end
$scope module top $end $scope module top $end
$var bit 1 ! clk $end $var wire 1 ! clk $end
$scope module t $end $scope module t $end
$var wire 1 ! clk $end $var wire 1 ! clk $end
$var int 32 " cnt $end $var int 32 " cnt $end

View File

@ -7,14 +7,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
scenarios(vlt_all => 1); scenarios(vlt => 1);
compile( compile(
v_flags2 => ["--lint-only --Mdir obj_lint_only"], v_flags2 => ["--lint-only --Mdir obj_lint_only"],
fails => 1, fails => 1,
expect => expect =>
'%Error-ASSIGNIN: t/t_var_in_assign_bad.v:\d+: Assigning to input variable: value '%Error-ASSIGNIN: t/t_var_in_assign_bad.v:\d+: Assigning to input/const variable: value
%Error-ASSIGNIN: t/t_var_in_assign_bad.v:\d+: Assigning to input variable: valueSub %Error-ASSIGNIN: t/t_var_in_assign_bad.v:\d+: Assigning to input/const variable: valueSub
%Error: Exiting due to.*', %Error: Exiting due to.*',
); );