Internals: Refactor input/output to new class in prep for ref support.
This commit is contained in:
parent
dc26815b1c
commit
b8098098d8
81
src/V3Ast.h
81
src/V3Ast.h
|
|
@ -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 {
|
||||
public:
|
||||
enum en {
|
||||
UNKNOWN,
|
||||
GPARAM,
|
||||
LPARAM,
|
||||
GENVAR,
|
||||
VAR, // Reg, integer, logic, etc
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
INOUT,
|
||||
SUPPLY0,
|
||||
UNKNOWN,
|
||||
GPARAM,
|
||||
LPARAM,
|
||||
GENVAR,
|
||||
VAR, // Reg, integer, logic, etc
|
||||
SUPPLY0,
|
||||
SUPPLY1,
|
||||
WIRE,
|
||||
WREAL,
|
||||
|
|
@ -497,20 +535,19 @@ public:
|
|||
explicit inline AstVarType(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[] = {
|
||||
"?","GPARAM","LPARAM","GENVAR",
|
||||
"VAR","INPUT","OUTPUT","INOUT",
|
||||
"SUPPLY0","SUPPLY1","WIRE","WREAL","IMPLICITWIRE",
|
||||
"TRIWIRE","TRI0","TRI1",
|
||||
"PORT",
|
||||
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP",
|
||||
"IFACEREF"};
|
||||
return names[m_e]; }
|
||||
static const char* const names[] = {
|
||||
"?", "GPARAM", "LPARAM", "GENVAR", "VAR",
|
||||
"SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "IMPLICITWIRE",
|
||||
"TRIWIRE", "TRI0", "TRI1",
|
||||
"PORT",
|
||||
"BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP",
|
||||
"IFACEREF"};
|
||||
return names[m_e]; }
|
||||
bool isSignal() const { return (m_e==WIRE || m_e==WREAL || m_e==IMPLICITWIRE
|
||||
|| m_e==TRIWIRE
|
||||
|| m_e==TRI0 || m_e==TRI1
|
||||
|| m_e==SUPPLY0 || m_e==SUPPLY1
|
||||
|| m_e==VAR); }
|
||||
|| m_e==TRIWIRE
|
||||
|| m_e==TRI0 || m_e==TRI1 || m_e==PORT
|
||||
|| m_e==SUPPLY0 || m_e==SUPPLY1
|
||||
|| m_e==VAR); }
|
||||
};
|
||||
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); }
|
||||
|
|
|
|||
|
|
@ -178,40 +178,30 @@ void AstVar::combineType(AstVarType type) {
|
|||
// These flags get combined with the existing settings of the flags.
|
||||
// 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.
|
||||
m_varType=type; // For debugging prints only
|
||||
m_varType = type;
|
||||
// These flags get combined with the existing settings of the flags.
|
||||
if (type==AstVarType::INPUT || type==AstVarType::INOUT) {
|
||||
m_input = true;
|
||||
m_declInput = true;
|
||||
if (type==AstVarType::TRIWIRE || type==AstVarType::TRI0 || type==AstVarType::TRI1) {
|
||||
m_tristate = true;
|
||||
}
|
||||
if (type==AstVarType::OUTPUT || type==AstVarType::INOUT) {
|
||||
m_output = true;
|
||||
m_declOutput = true;
|
||||
if (type==AstVarType::TRI0) {
|
||||
m_isPulldown = 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 {
|
||||
if (isInout()) {
|
||||
return "inout";
|
||||
} else if (isInput()) {
|
||||
return "input";
|
||||
} else if (isOutput()) {
|
||||
return "output";
|
||||
if (isIO()) {
|
||||
return direction().verilogKwd();
|
||||
} else if (isTristate()) {
|
||||
return "tri";
|
||||
return "tri";
|
||||
} else if (varType()==AstVarType::WIRE) {
|
||||
return "wire";
|
||||
return "wire";
|
||||
} else if (varType()==AstVarType::WREAL) {
|
||||
return "wreal";
|
||||
return "wreal";
|
||||
} 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) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
if (isWide() && isReadOnly()) arg += "const ";
|
||||
AstBasicDType* bdtypep = basicp();
|
||||
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
|
||||
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) {
|
||||
arg += "float";
|
||||
} else if (strtype) {
|
||||
if (isInOnly()) arg += "const ";
|
||||
arg += "std::string";
|
||||
if (isReadOnly()) arg += "const ";
|
||||
arg += "std::string";
|
||||
} else if (widthMin() <= 8) {
|
||||
arg += "CData";
|
||||
} else if (widthMin() <= 16) {
|
||||
|
|
@ -257,8 +247,9 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
|
|||
arg += "["+cvtToStr(widthWords())+"]";
|
||||
}
|
||||
} else {
|
||||
if (forFunc && (isOutput() || (strtype && isInput()))) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
if (forFunc && (isWritable()
|
||||
|| (strtype && isNonOutput()))) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
|
@ -290,12 +281,12 @@ string AstVar::vlEnumType() const {
|
|||
|
||||
string AstVar::vlEnumDir() const {
|
||||
string out;
|
||||
if (isInout()) {
|
||||
if (isInoutish()) {
|
||||
out = "VLVD_INOUT";
|
||||
} else if (isInOnly()) {
|
||||
out = "VLVD_IN";
|
||||
} else if (isOutOnly()) {
|
||||
} else if (isWritable()) {
|
||||
out = "VLVD_OUT";
|
||||
} else if (isNonOutput()) {
|
||||
out = "VLVD_IN";
|
||||
} else {
|
||||
out = "VLVD_NODIR";
|
||||
}
|
||||
|
|
@ -336,7 +327,7 @@ string AstVar::vlPropInit() const {
|
|||
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
if (isWide() && isReadOnly()) arg += "const ";
|
||||
if (widthMin() == 1) {
|
||||
arg += "bool";
|
||||
} else if (widthMin() <= VL_WORDSIZE) {
|
||||
|
|
@ -351,8 +342,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
|||
arg += " (& "+name();
|
||||
arg += ")["+cvtToStr(widthWords())+"]";
|
||||
} else {
|
||||
if (isOutput() && !forReturn) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
if (!forReturn && isWritable()) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
|
@ -367,11 +358,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|||
} else if (basicp()->keyword().isDpiBitVal()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
} else {
|
||||
if (forReturn) {
|
||||
arg = "svBitVecVal";
|
||||
} else if (isInOnly()) {
|
||||
if (!forReturn && isWritable()) arg += "*";
|
||||
} else {
|
||||
if (forReturn) {
|
||||
arg = "svBitVecVal";
|
||||
} else if (isReadOnly()) {
|
||||
arg = "const svBitVecVal*";
|
||||
} else {
|
||||
arg = "svBitVecVal*";
|
||||
|
|
@ -380,11 +371,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|||
} else if (basicp()->keyword().isDpiLogicVal()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
if (!forReturn && isWritable()) arg += "*";
|
||||
} else {
|
||||
if (forReturn) {
|
||||
arg = "svLogicVecVal";
|
||||
} else if (isInOnly()) {
|
||||
} else if (isReadOnly()) {
|
||||
arg = "const svLogicVecVal*";
|
||||
} else {
|
||||
arg = "svLogicVecVal*";
|
||||
|
|
@ -394,8 +385,8 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|||
arg = basicp()->keyword().dpiType();
|
||||
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
|
||||
arg = "unsigned "+arg;
|
||||
}
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
}
|
||||
if (!forReturn && isWritable()) arg += "*";
|
||||
}
|
||||
if (named) arg += " "+name();
|
||||
return arg;
|
||||
|
|
@ -898,7 +889,7 @@ void AstModportFTaskRef::dump(std::ostream& str) {
|
|||
}
|
||||
void AstModportVarRef::dump(std::ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" "<<varType();
|
||||
if (direction().isAny()) str<<" "<<direction();
|
||||
if (varp()) { str<<" -> "; varp()->dump(str); }
|
||||
else { str<<" -> UNLINKED"; }
|
||||
}
|
||||
|
|
@ -1061,12 +1052,8 @@ void AstVarRef::dump(std::ostream& str) {
|
|||
void AstVar::dump(std::ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (isSc()) str<<" [SC]";
|
||||
if (isPrimaryIO()) str<<(isInout()?" [PIO]":(isInput()?" [PI]":" [PO]"));
|
||||
else {
|
||||
if (isInout()) str<<" [IO]";
|
||||
else if (isInput()) str<<" [I]";
|
||||
else if (isOutput()) str<<" [O]";
|
||||
}
|
||||
if (isPrimaryIO()) str<<(isInoutish()?" [PIO]":(isWritable()?" [PO]":" [PI]"));
|
||||
if (isIO()) str<<" "<<direction().ascii();
|
||||
if (isConst()) str<<" [CONST]";
|
||||
if (isPullup()) str<<" [PULLUP]";
|
||||
if (isPulldown()) str<<" [PULLDOWN]";
|
||||
|
|
|
|||
|
|
@ -1096,12 +1096,10 @@ private:
|
|||
string m_origName; // Original name before dot addition
|
||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||
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
|
||||
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_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_sc:1; // SystemC variable
|
||||
bool m_scClocked:1; // SystemC sc_clk<> needed
|
||||
|
|
@ -1132,10 +1130,9 @@ private:
|
|||
AstVarAttrClocker m_attrClocker;
|
||||
MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var
|
||||
|
||||
void init() {
|
||||
m_input=false; m_output=false; m_tristate=false; m_declInput=false; m_declOutput=false;
|
||||
m_primaryIO=false;
|
||||
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
||||
void init() {
|
||||
m_tristate=false; m_primaryIO=false;
|
||||
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
||||
m_usedClock=false; m_usedParam=false; m_usedLoopIdx=false;
|
||||
m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false;
|
||||
m_funcLocal=false; m_funcReturn=false;
|
||||
|
|
@ -1201,9 +1198,16 @@ public:
|
|||
string origName() const { return m_origName; } // * = Original name
|
||||
void origName(const string& name) { m_origName = name; }
|
||||
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 varType2Out() { m_tristate=0; m_input=0; m_output=1; }
|
||||
void varType2In() { m_tristate=0; m_input=1; m_output=0; }
|
||||
void varType2Out() { m_tristate=0; m_direction=VDirection::OUTPUT; }
|
||||
void varType2In() { m_tristate=0; m_direction=VDirection::INPUT; }
|
||||
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
|
||||
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.
|
||||
|
|
@ -1258,19 +1262,13 @@ public:
|
|||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual void tag(const string& text) { m_tag = text;}
|
||||
virtual string tag() const { return m_tag; }
|
||||
virtual string directionName() const { return (isInout() ? "inout" : isInput() ? "input"
|
||||
: isOutput() ? "output" : varType().ascii()); }
|
||||
bool isInput() const { return m_input; }
|
||||
bool isOutput() const { return m_output; }
|
||||
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 isInoutish() const { return m_direction.isInoutish(); }
|
||||
bool isNonOutput() const { return m_direction.isNonOutput(); }
|
||||
bool isReadOnly() const { return m_direction.isReadOnly(); }
|
||||
bool isWritable() const { return m_direction.isWritable(); }
|
||||
bool isTristate() const { return m_tristate; }
|
||||
bool isDeclInput() const { return m_declInput; }
|
||||
bool isDeclOutput() const { return m_declOutput; }
|
||||
bool isPrimaryIO() const { return m_primaryIO; }
|
||||
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
|
||||
bool isIO() const { return (m_input||m_output); }
|
||||
bool isPrimaryIO() const { return m_primaryIO; }
|
||||
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
|
||||
bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); }
|
||||
bool isIfaceParent() const { return m_isIfaceParent; }
|
||||
bool isSignal() const { return varType().isSignal(); }
|
||||
|
|
@ -1326,8 +1324,9 @@ public:
|
|||
// Ok to gate optimize; must return false if propagateAttrFrom would do anything
|
||||
return (!attrClockEn() && !isUsedClock());
|
||||
}
|
||||
void combineType(AstVar* typevarp) {
|
||||
// This is same as typevarp (for combining input & reg decls)
|
||||
void combineType(AstVar* typevarp) {
|
||||
// This is same as typevarp (for combining input & reg decls)
|
||||
// "this" is the input var. typevarp is the reg var.
|
||||
propagateAttrFrom(typevarp);
|
||||
combineType(typevarp->varType());
|
||||
if (typevarp->isSigPublic()) sigPublic(true);
|
||||
|
|
@ -1337,9 +1336,11 @@ public:
|
|||
if (typevarp->attrScClocked()) attrScClocked(true);
|
||||
}
|
||||
void inlineAttrReset(const string& name) {
|
||||
m_input=m_output=false; m_name = name;
|
||||
if (varType()==AstVarType::INOUT) m_varType = AstVarType::TRIWIRE;
|
||||
if (varType()==AstVarType::INPUT || varType()==AstVarType::OUTPUT) m_varType = AstVarType::WIRE;
|
||||
if (direction()==VDirection::INOUT && varType()==AstVarType::WIRE) {
|
||||
m_varType = AstVarType::TRIWIRE;
|
||||
}
|
||||
m_direction = VDirection::NONE;
|
||||
m_name = name;
|
||||
}
|
||||
static AstVar* scVarRecurse(AstNode* nodep);
|
||||
void addProducingMTaskId(int id) { m_mtaskIds.insert(id); }
|
||||
|
|
@ -1577,10 +1578,13 @@ public:
|
|||
return NULL; }
|
||||
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
virtual string prettyOperatorName() const { return modVarp()
|
||||
? (modVarp()->directionName()+" port connection '"+modVarp()->prettyName()+"'")
|
||||
: "port connection"; }
|
||||
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked
|
||||
virtual string prettyOperatorName() const {
|
||||
return modVarp() ? ((modVarp()->direction().isAny()
|
||||
? modVarp()->direction().prettyName()+" "
|
||||
: "")
|
||||
+"port connection '"+modVarp()->prettyName()+"'")
|
||||
: "port connection"; }
|
||||
bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked
|
||||
int pinNum() const { return m_pinNum; }
|
||||
void exprp(AstNode* nodep) { addOp1p(nodep); }
|
||||
AstNode* exprp() const { return op1p(); } // op1 = Expression connected to pin, NULL if unconnected
|
||||
|
|
@ -1730,19 +1734,18 @@ class AstModportVarRef : public AstNode {
|
|||
// PARENT: AstModport
|
||||
private:
|
||||
string m_name; // Name of the variable referenced
|
||||
AstVarType m_type; // Type of the variable (in/out)
|
||||
AstVar* m_varp; // Link to the actual Var
|
||||
VDirection m_direction; // Direction of the variable (in/out)
|
||||
AstVar* m_varp; // Link to the actual Var
|
||||
public:
|
||||
AstModportVarRef(FileLine* fl, const string& name, AstVarType::en type)
|
||||
: AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { }
|
||||
AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction)
|
||||
: AstNode(fl), m_name(name), m_direction(direction), m_varp(NULL) { }
|
||||
ASTNODE_NODE_FUNCS(ModportVarRef)
|
||||
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
|
||||
virtual void dump(std::ostream& str);
|
||||
virtual void cloneRelink() { if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); }
|
||||
virtual string name() const { return m_name; }
|
||||
AstVarType varType() const { return m_type; } // * = Type of variable
|
||||
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
|
||||
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
|
||||
void direction(const VDirection& flag) { m_direction = flag; }
|
||||
VDirection direction() const { return m_direction; }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
void varp(AstVar* varp) { m_varp=varp; }
|
||||
};
|
||||
|
|
@ -3367,8 +3370,7 @@ private:
|
|||
uint32_t m_codeInc; // Code increment
|
||||
AstVarType m_varType; // Type of variable (for localparam vs. param)
|
||||
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
||||
bool m_declInput:1; // Input or inout
|
||||
bool m_declOutput:1; // Output or inout
|
||||
VDirection m_declDirection; // Declared direction input/output etc
|
||||
public:
|
||||
AstTraceDecl(FileLine* fl, const string& showname,
|
||||
AstVar* varp, // For input/output state etc
|
||||
|
|
@ -3382,8 +3384,7 @@ public:
|
|||
* valuep->dtypep()->widthWords());
|
||||
m_varType = varp->varType();
|
||||
m_declKwd = varp->declKwd();
|
||||
m_declInput = varp->isDeclInput();
|
||||
m_declOutput = varp->isDeclOutput();
|
||||
m_declDirection = varp->declDirection();
|
||||
}
|
||||
virtual int instrCount() const { return 100; } // Large...
|
||||
ASTNODE_NODE_FUNCS(TraceDecl)
|
||||
|
|
@ -3400,9 +3401,7 @@ public:
|
|||
const VNumRange& arrayRange() const { return m_arrayRange; }
|
||||
AstVarType varType() const { return m_varType; }
|
||||
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
|
||||
bool declInput() const { return m_declInput; }
|
||||
bool declOutput() const { return m_declOutput; }
|
||||
bool declInout() const { return m_declInput && m_declOutput; }
|
||||
VDirection declDirection() const { return m_declDirection; }
|
||||
};
|
||||
|
||||
class AstTraceInc : public AstNodeStmt {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ void V3CCtors::evalAsserts() {
|
|||
modp->addStmtp(funcp);
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
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)) {
|
||||
int storedWidth = basicp->widthAlignBytes() * 8;
|
||||
int lastWordWidth = varp->width() % storedWidth;
|
||||
|
|
|
|||
|
|
@ -258,13 +258,13 @@ private:
|
|||
// 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
|
||||
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
|
||||
if (varscp->varp()->isInput()) {
|
||||
new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1);
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (varscp->varp()->isWritable()) {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_inSenItem) {
|
||||
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
|
||||
|
|
@ -372,9 +372,9 @@ private:
|
|||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
if (mark) vvertexp->asyncPath(true);
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryIn()) {
|
||||
// Show the source "input" statement if it exists
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
|
||||
// Show the source "input" statement if it exists
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
eFromVertexp->asyncPath(true);
|
||||
|
|
@ -501,8 +501,8 @@ private:
|
|||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (1) { // varp->isPrimaryIO()
|
||||
const char* whatp = "wire";
|
||||
if (varp->isPrimaryIO()) whatp = (varp->isInout()?"inout":varp->isInput()?"input":"output");
|
||||
string what = "wire";
|
||||
if (varp->isPrimaryIO()) what = varp->direction().prettyName();
|
||||
|
||||
std::ostringstream os;
|
||||
os.setf(std::ios::left);
|
||||
|
|
@ -510,7 +510,7 @@ private:
|
|||
// so we assume the modulename matches the filebasename
|
||||
string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
|
||||
os<<" "<<std::setw(20)<<fname;
|
||||
os<<" "<<std::setw(8)<<whatp;
|
||||
os<<" "<<std::setw(8)<<what;
|
||||
os<<" "<<std::setw(40)<<vvertexp->varScp()->prettyName();
|
||||
os<<" SRC=";
|
||||
if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
|
||||
|
|
@ -545,10 +545,12 @@ private:
|
|||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
// If primary I/O, give it domain of the input
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (varp->isPrimaryIO() && varp->isInput() && !traceDests) {
|
||||
senouts.insert(new AstSenTree(varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
}
|
||||
}
|
||||
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
|
||||
senouts.insert(
|
||||
new AstSenTree(varp->fileline(),
|
||||
new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
}
|
||||
}
|
||||
|
||||
// Now combine domains of sources/dests
|
||||
if (traceDests) {
|
||||
|
|
|
|||
|
|
@ -1538,9 +1538,10 @@ private:
|
|||
&& ((!m_params // Can reduce constant wires into equations
|
||||
&& m_doNConst
|
||||
&& v3Global.opt.oConst()
|
||||
&& !(nodep->varp()->isFuncLocal() // Default value, not a "known" constant for this usage
|
||||
&& nodep->varp()->isInput())
|
||||
&& !nodep->varp()->noSubst()
|
||||
// Default value, not a "known" constant for this usage
|
||||
&& !(nodep->varp()->isFuncLocal()
|
||||
&& nodep->varp()->isNonOutput())
|
||||
&& !nodep->varp()->noSubst()
|
||||
&& !nodep->varp()->isSigPublic())
|
||||
|| nodep->varp()->isParam())) {
|
||||
if (operandConst(valuep)) {
|
||||
|
|
|
|||
|
|
@ -183,13 +183,14 @@ private:
|
|||
AstNode* argsp = NULL;
|
||||
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
AstNode* newp = new AstVarRef(portp->fileline(), portp, portp->isOutput());
|
||||
if (argsp) argsp = argsp->addNextNull(newp);
|
||||
else argsp = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
AstNode* newp = new AstVarRef(portp->fileline(),
|
||||
portp, portp->isWritable());
|
||||
if (argsp) argsp = argsp->addNextNull(newp);
|
||||
else argsp = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* returnp = new AstCReturn(funcp->fileline(),
|
||||
new AstCCall(funcp->fileline(),
|
||||
|
|
|
|||
|
|
@ -1211,13 +1211,13 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
|
|||
if (nodep->isIO()) {
|
||||
if (nodep->isSc()) {
|
||||
m_ctorVarsVec.push_back(nodep);
|
||||
if (nodep->attrScClocked() && nodep->isInput()) {
|
||||
puts("sc_in_clk ");
|
||||
} else {
|
||||
if (nodep->isInout()) puts("sc_inout<");
|
||||
else if (nodep->isInput()) puts("sc_in<");
|
||||
else if (nodep->isOutput()) puts("sc_out<");
|
||||
else nodep->v3fatalSrc("Unknown type");
|
||||
if (nodep->attrScClocked() && nodep->isReadOnly()) {
|
||||
puts("sc_in_clk ");
|
||||
} else {
|
||||
if (nodep->isInoutish()) puts("sc_inout<");
|
||||
else if (nodep->isWritable()) puts("sc_out<");
|
||||
else if (nodep->isNonOutput()) puts("sc_in<");
|
||||
else nodep->v3fatalSrc("Unknown type");
|
||||
|
||||
puts(nodep->scType());
|
||||
puts("> ");
|
||||
|
|
@ -1230,11 +1230,11 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
|
|||
puts(nodep->vlArgType(true,false,false));
|
||||
emitDeclArrayBrackets(nodep);
|
||||
puts(";\n");
|
||||
} else { // C++ signals
|
||||
if (nodep->isInout()) puts("VL_INOUT");
|
||||
else if (nodep->isInput()) puts("VL_IN");
|
||||
else if (nodep->isOutput()) puts("VL_OUT");
|
||||
else nodep->v3fatalSrc("Unknown type");
|
||||
} else { // C++ signals
|
||||
if (nodep->isInoutish()) puts("VL_INOUT");
|
||||
else if (nodep->isWritable()) puts("VL_OUT");
|
||||
else if (nodep->isNonOutput()) puts("VL_IN");
|
||||
else nodep->v3fatalSrc("Unknown type");
|
||||
|
||||
if (nodep->isQuad()) puts("64");
|
||||
else if (nodep->widthMin() <= 8) puts("8");
|
||||
|
|
@ -1990,9 +1990,10 @@ void EmitCImp::emitSensitives() {
|
|||
puts("SC_METHOD(eval);\n");
|
||||
for (AstNode* nodep=m_modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* varp = VN_CAST(nodep, Var)) {
|
||||
if (varp->isInput() && (varp->isScSensitive() || varp->isUsedClock())) {
|
||||
int vects = 0;
|
||||
// This isn't very robust and may need cleanup for other data types
|
||||
if (varp->isNonOutput() && (varp->isScSensitive()
|
||||
|| varp->isUsedClock())) {
|
||||
int vects = 0;
|
||||
// This isn't very robust and may need cleanup for other data types
|
||||
for (AstUnpackArrayDType* arrayp=VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType);
|
||||
arrayp;
|
||||
arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
|
||||
|
|
@ -2852,9 +2853,9 @@ class EmitCTrace : EmitCStmts {
|
|||
if (v3Global.opt.traceFormat() == TraceFormat::FST) {
|
||||
puts(","+cvtToStr(enumNum));
|
||||
// fstVarDir
|
||||
if (nodep->declInout()) puts(",FST_VD_INOUT");
|
||||
else if (nodep->declInput()) puts(",FST_VD_INPUT");
|
||||
else if (nodep->declOutput()) puts(",FST_VD_OUTPUT");
|
||||
if (nodep->declDirection().isInoutish()) puts(",FST_VD_INOUT");
|
||||
else if (nodep->declDirection().isWritable()) puts(",FST_VD_OUTPUT");
|
||||
else if (nodep->declDirection().isNonOutput()) puts(",FST_VD_INPUT");
|
||||
else puts(",FST_VD_IMPLICIT");
|
||||
//
|
||||
// fstVarType
|
||||
|
|
@ -2875,6 +2876,7 @@ class EmitCTrace : EmitCStmts {
|
|||
else if (vartype == AstVarType::TRI1) fstvt = "FST_VT_VCD_TRI1";
|
||||
else if (vartype == AstVarType::TRIWIRE) fstvt = "FST_VT_VCD_TRI";
|
||||
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::BIT) fstvt = "FST_VT_SV_BIT";
|
||||
|
|
|
|||
|
|
@ -113,16 +113,14 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
// What we call a pin in verilator is a port in the IEEE spec.
|
||||
outputTag(nodep, "port"); // IEEE: vpiPort
|
||||
if (nodep->modVarp()->isInOnly()) {
|
||||
puts(" direction=\"in\"");
|
||||
} else if (nodep->modVarp()->isOutOnly()) {
|
||||
puts(" direction=\"out\"");
|
||||
} else puts(" direction=\"inout\"");
|
||||
puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex
|
||||
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
||||
outputChildrenEnd(nodep, "port");
|
||||
// What we call a pin in verilator is a port in the IEEE spec.
|
||||
outputTag(nodep, "port"); // IEEE: vpiPort
|
||||
if (nodep->modVarp()->isIO()) {
|
||||
puts(" direction=\""+nodep->modVarp()->direction().xmlKwd()+"\"");
|
||||
}
|
||||
puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex
|
||||
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
||||
outputChildrenEnd(nodep, "port");
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
outputTag(nodep, "");
|
||||
|
|
|
|||
|
|
@ -1131,11 +1131,11 @@ void GateVisitor::dedupe() {
|
|||
}
|
||||
// Traverse starting from each of the outputs
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isOutput()) {
|
||||
deduper.dedupeTree(vvertexp);
|
||||
}
|
||||
}
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) {
|
||||
deduper.dedupeTree(vvertexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_statDedupLogic += deduper.numDeduped();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,23 +317,26 @@ private:
|
|||
// 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
|
||||
// on the output variable.
|
||||
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
|
||||
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
|
||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
} else if (nodep->isIfaceRef()) {
|
||||
m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
AstNode* nodebp=exprvarrefp->varp();
|
||||
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
|
||||
} else {
|
||||
// Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
|
||||
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
|
||||
if (nodep->isNonOutput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
|
||||
m_modp->addStmtp(
|
||||
new AstAssignW(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
} else if (nodep->isIfaceRef()) {
|
||||
m_modp->addStmtp(
|
||||
new AstAssignVarScope(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
AstNode* nodebp=exprvarrefp->varp();
|
||||
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
|
||||
} else {
|
||||
// Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
|
||||
m_modp->addStmtp(
|
||||
new AstAssignAlias(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
AstNode* nodebp=exprvarrefp->varp();
|
||||
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
|
||||
|
|
@ -549,11 +552,12 @@ private:
|
|||
|
||||
AstNode* connectRefp = pinp->exprp();
|
||||
if (!VN_IS(connectRefp, Const) && !VN_IS(connectRefp, VarRef)) {
|
||||
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
}
|
||||
if (pinNewVarp->isOutOnly() && VN_IS(connectRefp, Const)) {
|
||||
pinp->v3error("Output port is connected to a constant pin, electrical short");
|
||||
}
|
||||
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
}
|
||||
if (pinNewVarp->direction() == VDirection::OUTPUT
|
||||
&& VN_IS(connectRefp, Const)) {
|
||||
pinp->v3error("Output port is connected to a constant pin, electrical short");
|
||||
}
|
||||
|
||||
// Propagate any attributes across the interconnect
|
||||
pinNewVarp->propagateAttrFrom(pinOldVarp);
|
||||
|
|
@ -567,11 +571,13 @@ private:
|
|||
UINFO(6,"One-to-one "<<connectRefp<<endl);
|
||||
UINFO(6," -to "<<pinNewVarp<<endl);
|
||||
pinNewVarp->user2p(connectRefp);
|
||||
// Public output inside the cell must go via an assign rather than alias
|
||||
// Else the public logic will set the alias, losing the value to be propagated up
|
||||
// (InOnly isn't a problem as the AssignAlias will create the assignment for us)
|
||||
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
|
||||
}
|
||||
// Public output inside the cell must go via an assign rather
|
||||
// than alias. Else the public logic will set the alias, losing
|
||||
// the value to be propagated up (InOnly isn't a problem as the
|
||||
// AssignAlias will create the assignment for us)
|
||||
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic()
|
||||
&& pinNewVarp->direction()==VDirection::OUTPUT);
|
||||
}
|
||||
// Cleanup var names, etc, to not conflict
|
||||
{ InlineRelinkVisitor(newmodp, m_modp, nodep); }
|
||||
// Move statements to top module
|
||||
|
|
|
|||
|
|
@ -63,28 +63,31 @@ private:
|
|||
m_cellp = NULL;
|
||||
}
|
||||
virtual void visit(AstPin* nodep) {
|
||||
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
|
||||
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
|
||||
UINFO(4," PIN "<<nodep<<endl);
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
|
||||
if (nodep->modVarp()->isOutOnly() && VN_IS(nodep->exprp(), Const))
|
||||
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||
if (!nodep->user1SetOnce()) {
|
||||
// Simplify it
|
||||
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
|
||||
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
|
||||
UINFO(4," PIN "<<nodep<<endl);
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
|
||||
if (nodep->modVarp()->direction() == VDirection::OUTPUT
|
||||
&& VN_IS(nodep->exprp(), Const)) {
|
||||
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
||||
}
|
||||
// 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);
|
||||
// Make an ASSIGNW (expr, pin)
|
||||
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
||||
if (exprp->width() != nodep->modVarp()->width())
|
||||
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple");
|
||||
if (nodep->modVarp()->isInout()) {
|
||||
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
|
||||
} else if (nodep->modVarp()->isOutput()) {
|
||||
if (exprp->width() != nodep->modVarp()->width()) {
|
||||
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple");
|
||||
}
|
||||
if (nodep->modVarp()->isInoutish()) {
|
||||
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);
|
||||
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
|
||||
m_cellp->addNextHere(assp);
|
||||
} else if (nodep->modVarp()->isInput()) {
|
||||
} else if (nodep->modVarp()->isNonOutput()) {
|
||||
// Don't bother moving constants now,
|
||||
// we'll be pushing the const down to the cell soon enough.
|
||||
AstNode* assp = new AstAssignW
|
||||
|
|
@ -332,8 +335,8 @@ private:
|
|||
nodep->v3warn(LITENDIAN,"Little endian cell range connecting to vector: MSB < LSB of cell range: "
|
||||
<<m_cellRangep->lsbConst()<<":"<<m_cellRangep->msbConst());
|
||||
}
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
bool inputPin = nodep->modVarp()->isInput();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
bool inputPin = nodep->modVarp()->isNonOutput();
|
||||
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, Sel)) { // V3Const will collapse the SEL with the one we're about to make
|
||||
|
|
@ -512,25 +515,29 @@ public:
|
|||
// Make a new temp wire
|
||||
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
|
||||
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
||||
string newvarname = (string(pinVarp->isOutput() ? "__Vcellout" : "__Vcellinp")
|
||||
+(forTristate?"t":"") // Prevent name conflict if both tri & non-tri add signals
|
||||
+"__"+cellp->name()+"__"+pinp->name());
|
||||
AstVar* newvarp = new AstVar(pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
|
||||
// Important to add statement next to cell, in case there is a generate with same named cell
|
||||
cellp->addNextHere(newvarp);
|
||||
if (pinVarp->isInout()) {
|
||||
string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||
// Prevent name conflict if both tri & non-tri add signals
|
||||
+(forTristate?"t":"")
|
||||
+"__"+cellp->name()+"__"+pinp->name());
|
||||
AstVar* newvarp = new AstVar(pinVarp->fileline(),
|
||||
AstVarType::MODULETEMP, newvarname, pinVarp);
|
||||
// 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"
|
||||
" direct one-to-one connection (without any expression)");
|
||||
} else if (pinVarp->isOutput()) {
|
||||
// See also V3Inst
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
|
||||
UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
|
||||
} else if (pinVarp->isWritable()) {
|
||||
// See also V3Inst
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
|
||||
UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "
|
||||
<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
|
||||
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
|
||||
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
|
||||
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
|
||||
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
|
||||
} else {
|
||||
// V3 width should have range/extended to make the widths correct
|
||||
} else {
|
||||
// V3 width should have range/extended to make the widths correct
|
||||
assignp = new AstAssignW(pinp->fileline(),
|
||||
new AstVarRef(pinp->fileline(), newvarp, true),
|
||||
pinexprp);
|
||||
|
|
|
|||
|
|
@ -871,8 +871,9 @@ class LinkDotFindVisitor : public AstNVisitor {
|
|||
// also return the class reference.
|
||||
if (dtypep) dtypep->unlinkFrBack();
|
||||
else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC);
|
||||
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::OUTPUT, nodep->name(),
|
||||
VFlagChildDType(), dtypep); // Not dtype resolved yet
|
||||
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::WIRE, nodep->name(),
|
||||
VFlagChildDType(), dtypep); // Not dtype resolved yet
|
||||
newvarp->direction(VDirection::OUTPUT);
|
||||
newvarp->funcReturn(true);
|
||||
newvarp->trace(false); // Not user visible
|
||||
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
|
||||
|
|
@ -1537,10 +1538,10 @@ private:
|
|||
} else if (VN_IS(symp->nodep(), ModportVarRef)) {
|
||||
AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef);
|
||||
AstVar* varp = snodep->varp();
|
||||
if (lvalue && snodep->isInput()) {
|
||||
if (lvalue && snodep->direction().isReadOnly()) {
|
||||
nodep->v3error("Attempt to drive input-only modport: "<<nodep->prettyName());
|
||||
} // else other simulators don't warn about reading, and IEEE doesn't say illegal
|
||||
return varp;
|
||||
return varp;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,21 +56,21 @@ private:
|
|||
nodep->lvalue(true);
|
||||
}
|
||||
if (nodep->varp()) {
|
||||
if (nodep->lvalue() && nodep->varp()->isInOnly()) {
|
||||
if (!m_ftaskp) {
|
||||
nodep->v3warn(ASSIGNIN,"Assigning to input variable: "<<nodep->prettyName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->lvalue() && !m_ftaskp
|
||||
&& nodep->varp()->isReadOnly()) {
|
||||
nodep->v3warn(ASSIGNIN,"Assigning to input/const variable: "
|
||||
<<nodep->prettyName());
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Nodes that start propagating down lvalues
|
||||
virtual void visit(AstPin* nodep) {
|
||||
if (nodep->modVarp() && nodep->modVarp()->isOutput()) {
|
||||
// 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
|
||||
m_setRefLvalue = true;
|
||||
if (nodep->modVarp() && nodep->modVarp()->isWritable()) {
|
||||
// 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
|
||||
m_setRefLvalue = true;
|
||||
iterateChildren(nodep);
|
||||
m_setRefLvalue = false;
|
||||
} else {
|
||||
|
|
@ -238,14 +238,14 @@ private:
|
|||
if (!taskp) return;
|
||||
for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp=stmtp->nextp()) {
|
||||
if (const AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO()) {
|
||||
if (portp->isInput()) {
|
||||
if (portp->isIO()) {
|
||||
if (portp->isWritable()) {
|
||||
m_setRefLvalue = true;
|
||||
iterate(pinp);
|
||||
} else { // Output or Inout
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = false;
|
||||
} else {
|
||||
iterate(pinp);
|
||||
m_setRefLvalue = false;
|
||||
}
|
||||
}
|
||||
// Advance pin
|
||||
pinp = pinp->nextp();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,10 +126,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|||
AstVar* varp = oldvarp->cloneTree(false);
|
||||
newmodp->addStmtp(varp);
|
||||
varp->sigPublic(true); // User needs to be able to get to it...
|
||||
if (oldvarp->isIO()) {
|
||||
oldvarp->primaryIO(true);
|
||||
varp->primaryIO(true);
|
||||
}
|
||||
if (oldvarp->isIO()) {
|
||||
oldvarp->primaryIO(false);
|
||||
varp->primaryIO(true);
|
||||
}
|
||||
if (varp->isIO() && v3Global.opt.systemC()) {
|
||||
varp->sc(true);
|
||||
// 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(),
|
||||
new AstVarRef(varp->fileline(),
|
||||
varp, oldvarp->isOutput()));
|
||||
// Skip length and width comp; we know it's a direct assignment
|
||||
new AstVarRef(varp->fileline(),
|
||||
varp, oldvarp->isWritable()));
|
||||
// Skip length and width comp; we know it's a direct assignment
|
||||
pinp->modVarp(oldvarp);
|
||||
cellp->addPinsp(pinp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,9 +198,9 @@ private:
|
|||
// A variable with an = value can be three things:
|
||||
FileLine* fl = nodep->valuep()->fileline();
|
||||
// 1. Parameters and function inputs: It's a default to use if not overridden
|
||||
if (nodep->isParam() || (m_ftaskp && nodep->isInOnly())) {
|
||||
}
|
||||
else if (!m_ftaskp && nodep->isInOnly()) {
|
||||
if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) {
|
||||
}
|
||||
else if (!m_ftaskp && nodep->isNonOutput()) {
|
||||
nodep->v3error("Unsupported: Default value on module input: "<<nodep->prettyName());
|
||||
nodep->valuep()->unlinkFrBack()->deleteTree();
|
||||
} // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial
|
||||
|
|
|
|||
|
|
@ -405,14 +405,17 @@ private:
|
|||
AstVar* varoutp = NULL;
|
||||
for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->isInput()) {
|
||||
} else if (varp->isOutput()) {
|
||||
if (varoutp) { varp->v3error("Multiple outputs not allowed in udp modules"); }
|
||||
varoutp = varp;
|
||||
// Tie off
|
||||
m_modp->addStmtp(new AstAssignW(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true),
|
||||
new AstConst(varp->fileline(), AstConst::LogicFalse())));
|
||||
if (varp->isReadOnly()) {
|
||||
} else if (varp->isWritable()) {
|
||||
if (varoutp) {
|
||||
varp->v3error("Multiple outputs not allowed in udp modules");
|
||||
}
|
||||
varoutp = varp;
|
||||
// Tie off
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true),
|
||||
new AstConst(varp->fileline(), AstConst::LogicFalse())));
|
||||
} else {
|
||||
varp->v3error("Only inputs and outputs are allowed in udp modules");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1017,9 +1017,9 @@ private:
|
|||
m_inClocked = false;
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
// Create links to all input signals
|
||||
if (m_modp->isTop() && nodep->varp()->isInput()) {
|
||||
OrderVarVertex* varVxp = newVarUserVertex(nodep, WV_STD);
|
||||
// Create links to all input signals
|
||||
if (m_modp->isTop() && nodep->varp()->isNonOutput()) {
|
||||
OrderVarVertex* varVxp = newVarUserVertex(nodep, WV_STD);
|
||||
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
|
||||
// block. (Not inputs that go only to clocked blocks.)
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(itp)) {
|
||||
if (vvertexp->varScp()->varp()->isInput()) {
|
||||
//UINFO(0," scsen "<<vvertexp<<endl);
|
||||
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(itp)) {
|
||||
if (vvertexp->varScp()->varp()->isNonOutput()) {
|
||||
//UINFO(0," scsen "<<vvertexp<<endl);
|
||||
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (OrderEitherVertex* toVertexp = dynamic_cast<OrderEitherVertex*>(edgep->top())) {
|
||||
if (edgep->weight() && toVertexp->domainp()) {
|
||||
|
|
@ -1501,8 +1501,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
|
|||
OrderVarVertex* vvertexp = dynamic_cast<OrderVarVertex*>(vertexp);
|
||||
AstSenTree* domainp = NULL;
|
||||
UASSERT(m_comboDomainp, "not preset");
|
||||
if (vvertexp && vvertexp->varScp()->varp()->isInput()) {
|
||||
domainp = m_comboDomainp;
|
||||
if (vvertexp && vvertexp->varScp()->varp()->isNonOutput()) {
|
||||
domainp = m_comboDomainp;
|
||||
}
|
||||
if (vvertexp && vvertexp->varScp()->isCircular()) {
|
||||
domainp = m_comboDomainp;
|
||||
|
|
|
|||
|
|
@ -785,11 +785,11 @@ private:
|
|||
AstVar* portp = it->first;
|
||||
AstNode* pinp = it->second->exprp();
|
||||
if (pinp) { // Else too few arguments in function call - ignore it
|
||||
if (portp->isOutput()) {
|
||||
clearOptimizable(portp,"Language violation: Outputs not allowed in constant functions");
|
||||
return;
|
||||
}
|
||||
// Evaluate pin value
|
||||
if (portp->isWritable()) {
|
||||
clearOptimizable(portp, "Language violation: Outputs/refs not allowed in constant functions");
|
||||
return;
|
||||
}
|
||||
// Evaluate pin value
|
||||
iterate(pinp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,9 +332,9 @@ private:
|
|||
AstVarScope* createInputVar(AstCFunc* funcp, const string& name, AstBasicDTypeKwd kwd) {
|
||||
AstVar* newvarp = new AstVar(funcp->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
funcp->findBasicDType(kwd));
|
||||
newvarp->funcLocal(true);
|
||||
newvarp->combineType(AstVarType::INPUT);
|
||||
funcp->addArgsp(newvarp);
|
||||
newvarp->funcLocal(true);
|
||||
newvarp->direction(VDirection::INPUT);
|
||||
funcp->addArgsp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp);
|
||||
m_scopep->addVarp(newvscp);
|
||||
return newvscp;
|
||||
|
|
@ -378,10 +378,13 @@ private:
|
|||
pinp->unlinkFrBack(); // Relinked to assignment below
|
||||
argp->unlinkFrBack()->deleteTree(); // Args no longer needed
|
||||
//
|
||||
if ((portp->isInout() || portp->isOutput()) && VN_IS(pinp, Const)) {
|
||||
pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName());
|
||||
}
|
||||
else if (portp->isInout()) {
|
||||
if (portp->isWritable() && VN_IS(pinp, Const)) {
|
||||
pinp->v3error("Function/task "
|
||||
+portp->direction().prettyName() // e.g. "output"
|
||||
+" connected to constant instead of variable: "
|
||||
+portp->prettyName());
|
||||
}
|
||||
else if (portp->isInoutish()) {
|
||||
// Correct lvalue; see comments below
|
||||
V3LinkLValue::linkLValueSet(pinp);
|
||||
|
||||
|
|
@ -393,9 +396,9 @@ private:
|
|||
} else {
|
||||
pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
}
|
||||
else if (portp->isWritable()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
// This is slightly scary; are we sure no decisions were made
|
||||
// before here based on this not being a lvalue?
|
||||
|
|
@ -412,9 +415,9 @@ private:
|
|||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
else if (portp->isInput()) {
|
||||
// Make input variable
|
||||
}
|
||||
else if (portp->isNonOutput()) {
|
||||
// Make input variable
|
||||
AstVarScope* inVscp = createVarScope(portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(inVscp);
|
||||
AstAssign* assp = new AstAssign(pinp->fileline(),
|
||||
|
|
@ -483,10 +486,13 @@ private:
|
|||
} else {
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
if ((portp->isInout() || portp->isOutput()) && VN_IS(pinp, Const)) {
|
||||
pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName());
|
||||
}
|
||||
else if (portp->isInout()) {
|
||||
if (portp->isWritable() && VN_IS(pinp, Const)) {
|
||||
pinp->v3error("Function/task "
|
||||
+portp->direction().prettyName() // e.g. "output"
|
||||
+" connected to constant instead of variable: "
|
||||
+portp->prettyName());
|
||||
}
|
||||
else if (portp->isInoutish()) {
|
||||
// Correct lvalue; see comments below
|
||||
V3LinkLValue::linkLValueSet(pinp);
|
||||
|
||||
|
|
@ -495,9 +501,9 @@ private:
|
|||
} else {
|
||||
pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
}
|
||||
else if (portp->isWritable()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
// This is slightly scary; are we sure no decisions were made
|
||||
// before here based on this not being a lvalue?
|
||||
|
|
@ -718,12 +724,17 @@ private:
|
|||
// No createDpiTemp; we make a real internal variable instead
|
||||
// SAME CODE BELOW
|
||||
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);
|
||||
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isOutput());
|
||||
argnodesp = argnodesp->addNextNull(refp);
|
||||
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp,
|
||||
portp->isWritable());
|
||||
argnodesp = argnodesp->addNextNull(refp);
|
||||
|
||||
if (portp->isInput()) {
|
||||
if (portp->isNonOutput()) {
|
||||
dpip->addStmtsp(createAssignDpiToInternal(outvscp, portp->name(), false));
|
||||
}
|
||||
}
|
||||
|
|
@ -736,9 +747,9 @@ private:
|
|||
args+= ", ";
|
||||
if (args != "") { argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args=""; }
|
||||
AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp);
|
||||
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isOutput());
|
||||
argnodesp = argnodesp->addNextNull(refp);
|
||||
}
|
||||
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable());
|
||||
argnodesp = argnodesp->addNextNull(refp);
|
||||
}
|
||||
|
||||
{// Call the user function
|
||||
// Add the variables referenced as VarRef's so that lifetime analysis
|
||||
|
|
@ -755,11 +766,11 @@ private:
|
|||
// Convert output/inout arguments back to internal type
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && portp->isOutput() && !portp->isFuncReturn()) {
|
||||
dpip->addStmtsp(createAssignInternalToDpi(portp,false,true,"__Vcvt",""));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (portp->isIO() && portp->isWritable() && !portp->isFuncReturn()) {
|
||||
dpip->addStmtsp(createAssignInternalToDpi(portp,false,true,"__Vcvt",""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rtnvarp) {
|
||||
dpip->addStmtsp(createDpiTemp(rtnvarp,""));
|
||||
|
|
@ -867,14 +878,14 @@ private:
|
|||
else {
|
||||
if (bitvec) {}
|
||||
else if (logicvec) {}
|
||||
else if (portp->isOutput()) args += "&";
|
||||
else if (portp->isWritable()) args += "&";
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
|
||||
&& portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide)
|
||||
|
||||
args += portp->name()+"__Vcvt";
|
||||
|
||||
cfuncp->addStmtsp(createDpiTemp(portp,"__Vcvt"));
|
||||
if (portp->isInput()) {
|
||||
if (portp->isNonOutput()) {
|
||||
cfuncp->addStmtsp(createAssignInternalToDpi(portp,false,false,"","__Vcvt"));
|
||||
}
|
||||
}
|
||||
|
|
@ -900,7 +911,7 @@ private:
|
|||
// Convert output/inout arguments back to internal type
|
||||
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && (portp->isOutput() || portp->isFuncReturn())
|
||||
if (portp->isIO() && (portp->isWritable() || portp->isFuncReturn())
|
||||
&& !portp->isDpiOpenArray()) {
|
||||
AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier
|
||||
cfuncp->addStmtsp(createAssignDpiToInternal(portvscp,portp->name()+"__Vcvt",true));
|
||||
|
|
|
|||
|
|
@ -699,11 +699,11 @@ private:
|
|||
}
|
||||
V3GraphVertex* traceVtxp = m_tracep->user1u().toGraphVertex();
|
||||
new V3GraphEdge(&m_graph, varVtxp, traceVtxp, 1);
|
||||
if (nodep->varp()->isPrimaryIn() // Always need to trace primary inputs
|
||||
|| nodep->varp()->isSigPublic()) { // Or ones user can change
|
||||
new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1);
|
||||
}
|
||||
}
|
||||
if (nodep->varp()->isPrimaryInish() // Always need to trace primary inputs
|
||||
|| nodep->varp()->isSigPublic()) { // Or ones user can change
|
||||
new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1);
|
||||
}
|
||||
}
|
||||
else if (m_funcp && m_finding && nodep->lvalue()) {
|
||||
if (!nodep->varScopep()) nodep->v3fatalSrc("No var scope?");
|
||||
V3GraphVertex* funcVtxp = getCFuncVertexp(m_funcp);
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@
|
|||
// Over each module, from child to parent:
|
||||
// Build a graph, connecting signals together so we can propagate tristates
|
||||
// Variable becomes tristate with
|
||||
// VAR->isInout
|
||||
// VAR->isPullup/isPulldown (converted to AstPullup/AstPulldown
|
||||
// BufIf0/1
|
||||
// VAR->isInoutish
|
||||
// VAR->isPullup/isPulldown (converted to AstPullup/AstPulldown
|
||||
// BufIf0/1
|
||||
// All variables on the LHS need to become tristate when there is:
|
||||
// CONST-> with Z value on the RHS of an assignment
|
||||
// AstPin with lower connection a tristate
|
||||
|
|
@ -1067,18 +1067,20 @@ class TristateVisitor : public TristateBaseVisitor {
|
|||
UINFO(9,dbgState()<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: ");
|
||||
|
||||
// Empty/in-only; need Z to propagate
|
||||
bool inDeclProcessing = (nodep->exprp()
|
||||
&& nodep->modVarp()->isInOnly()
|
||||
// Need to consider the original state instead of current state
|
||||
// as we converted tristates to inputs, which do not want to have this.
|
||||
&& !nodep->modVarp()->isDeclOutput());
|
||||
if (!nodep->exprp()) { // No-connect; covert to empty connection
|
||||
UINFO(5,"Unconnected pin terminate "<<nodep<<endl);
|
||||
AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep());
|
||||
nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp,
|
||||
// We converted, so use declaration output state
|
||||
nodep->modVarp()->isDeclOutput()));
|
||||
// Empty/in-only; need Z to propagate
|
||||
bool inDeclProcessing = (nodep->exprp()
|
||||
&& nodep->modVarp()->direction() == VDirection::INPUT
|
||||
// Need to consider the original state
|
||||
// instead of current state as we converted
|
||||
// tristates to inputs, which do not want
|
||||
// to have this.
|
||||
&& !nodep->modVarp()->declDirection().isWritable());
|
||||
if (!nodep->exprp()) { // No-connect; covert to empty connection
|
||||
UINFO(5,"Unconnected pin terminate "<<nodep<<endl);
|
||||
AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep());
|
||||
nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp,
|
||||
// We converted, so use declaration output state
|
||||
nodep->modVarp()->declDirection().isWritable()));
|
||||
m_tgraph.setTristate(ucVarp);
|
||||
// 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
|
||||
|
|
@ -1245,11 +1247,12 @@ class TristateVisitor : public TristateBaseVisitor {
|
|||
nodep->addNextHere(newp);
|
||||
// We'll iterate on the new AstPull later
|
||||
}
|
||||
if (nodep->isInout()
|
||||
//|| varp->isOutput()
|
||||
// Note unconnected output only changes behavior vs. previous versions and causes outputs
|
||||
// that don't come from anywhere to possibly create connection errors.
|
||||
// One example of problems is this: "output z; task t; z <= {something}; endtask"
|
||||
if (nodep->isInoutish()
|
||||
//|| varp->isOutput()
|
||||
// Note unconnected output only changes behavior vs. previous
|
||||
// versions and causes outputs that don't come from anywhere to
|
||||
// possibly create connection errors.
|
||||
// One example of problems is this: "output z; task t; z <= {something}; endtask"
|
||||
) {
|
||||
UINFO(9," setTristate-inout "<<nodep<<endl);
|
||||
m_tgraph.setTristate(nodep);
|
||||
|
|
|
|||
|
|
@ -272,12 +272,12 @@ private:
|
|||
// 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
|
||||
UndrivenVarEntry* entryp = getEntryp(nodep, usr);
|
||||
if (nodep->isInput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
entryp->drivenWhole();
|
||||
}
|
||||
if (nodep->isOutput()
|
||||
if (nodep->isNonOutput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
entryp->drivenWhole();
|
||||
}
|
||||
if (nodep->isWritable()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| nodep->isSigUserRdPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
|
|
|
|||
|
|
@ -2557,7 +2557,7 @@ private:
|
|||
AstArg* argp = it->second;
|
||||
AstNode* pinp = argp->exprp();
|
||||
if (!pinp) continue; // Argument error we'll find later
|
||||
if ((portp->isOutput() || portp->isInout())
|
||||
if (portp->isWritable()
|
||||
&& pinp->width() != portp->width()) {
|
||||
pinp->v3error("Unsupported: Function output argument '"<<portp->prettyName()<<"'"
|
||||
<<" requires "<<portp->width()
|
||||
|
|
@ -3344,8 +3344,9 @@ private:
|
|||
AstNodeAssign* assignp = VN_CAST(nodep, NodeAssign);
|
||||
AstPin* pinp = VN_CAST(nodep, Pin);
|
||||
if (assignp && VN_IS(assignp->lhsp(), NodeStream)) {
|
||||
} else if (pinp && !pinp->modVarp()->isInput()) { // V3Inst::pinReconnectSimple must deal
|
||||
UINFO(5,"pinInSizeMismatch: "<<pinp);
|
||||
} else if (pinp && pinp->modVarp()->direction() != VDirection::INPUT) {
|
||||
// V3Inst::pinReconnectSimple must deal
|
||||
UINFO(5,"pinInSizeMismatch: "<<pinp);
|
||||
} else {
|
||||
fixWidthExtend(underp, expDTypep, extendRule); VL_DANGLING(underp);//Changed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class V3ParseGrammar {
|
|||
public:
|
||||
bool m_impliedDecl; // Allow implied wire declarations
|
||||
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
|
||||
AstRange* m_gateRangep; // Current range for gate declarations
|
||||
AstCase* m_caseAttrp; // Current case statement for attribute adding
|
||||
|
|
@ -68,7 +68,7 @@ public:
|
|||
V3ParseGrammar() {
|
||||
m_impliedDecl = false;
|
||||
m_varDecl = AstVarType::UNKNOWN;
|
||||
m_varIO = AstVarType::UNKNOWN;
|
||||
m_varIO = VDirection::NONE;
|
||||
m_varDTypep = NULL;
|
||||
m_gateRangep = 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_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 VARIO(type) { GRAMMARP->m_varIO = AstVarType::type; }
|
||||
#define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; }
|
||||
#define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); }
|
||||
|
||||
#define VARDONEA(fl,name,array,attrs) GRAMMARP->createVariable((fl),(name),(array),(attrs))
|
||||
|
|
@ -899,11 +899,11 @@ port<nodep>: // ==IEEE: port
|
|||
// // Expanded interface_port_header
|
||||
// // We use instantCb here because the non-port form looks just like a module instantiation
|
||||
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));
|
||||
$$->addNextNull(VARDONEP($$,$4,$5)); }
|
||||
| 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));
|
||||
$$->addNextNull(VARDONEP($$,$6,$7)); }
|
||||
| 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) {
|
||||
AstNodeDType* dtypep = GRAMMARP->m_varDTypep;
|
||||
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) {
|
||||
// Just a port list with variable name (not v2k format); AstPort already created
|
||||
if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists");
|
||||
return NULL;
|
||||
}
|
||||
AstVarType type = GRAMMARP->m_varIO;
|
||||
if (GRAMMARP->m_varDecl == AstVarType::WREAL) {
|
||||
// dtypep might not be null, might be implicit LOGIC before we knew better
|
||||
dtypep = new AstBasicDType(fileline,AstBasicDTypeKwd::DOUBLE);
|
||||
|
|
@ -4010,21 +4009,28 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstNodeR
|
|||
dtypep = dtypep->cloneTree(false);
|
||||
}
|
||||
//UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<" io="<<GRAMMARP->m_varIO.ascii()<<endl);
|
||||
if (type == AstVarType::UNKNOWN
|
||||
|| (type == AstVarType::PORT && GRAMMARP->m_varDecl != AstVarType::UNKNOWN))
|
||||
type = GRAMMARP->m_varDecl;
|
||||
if (type == AstVarType::UNKNOWN) fileline->v3fatalSrc("Unknown signal type declared");
|
||||
AstVarType type = GRAMMARP->m_varDecl;
|
||||
if (type == AstVarType::UNKNOWN) {
|
||||
if (GRAMMARP->m_varIO.isAny()) {
|
||||
type = AstVarType::PORT;
|
||||
} else {
|
||||
fileline->v3fatalSrc("Unknown signal type declared");
|
||||
}
|
||||
}
|
||||
if (type == AstVarType::GENVAR) {
|
||||
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
|
||||
}
|
||||
|
||||
// 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);
|
||||
nodep->addAttrsp(attrsp);
|
||||
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) {
|
||||
nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0));
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ compile(
|
|||
fails => 1,
|
||||
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'
|
||||
%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:22: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions
|
||||
Called from:
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ scenarios(simulator => 1);
|
|||
compile(
|
||||
fails => 1,
|
||||
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.
|
||||
%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.
|
||||
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 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.*},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$date
|
||||
Thu Oct 4 19:33:38 2018
|
||||
Sun Oct 21 21:57:08 2018
|
||||
|
||||
$end
|
||||
$version
|
||||
|
|
@ -9,7 +9,7 @@ $timescale
|
|||
1ns
|
||||
$end
|
||||
$scope module top $end
|
||||
$var bit 1 ! clk $end
|
||||
$var wire 1 ! clk $end
|
||||
$scope module t $end
|
||||
$var wire 1 ! clk $end
|
||||
$var integer 32 " cyc $end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$date
|
||||
Mon Oct 8 07:13:10 2018
|
||||
Sun Oct 21 21:56:13 2018
|
||||
|
||||
$end
|
||||
$version
|
||||
|
|
@ -9,7 +9,7 @@ $timescale
|
|||
1ns
|
||||
$end
|
||||
$scope module top $end
|
||||
$var bit 1 ! clk $end
|
||||
$var wire 1 ! clk $end
|
||||
$scope module t $end
|
||||
$var wire 1 ! clk $end
|
||||
$var integer 32 " cyc $end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$date
|
||||
Mon Oct 8 07:13:11 2018
|
||||
Sun Oct 21 21:56:26 2018
|
||||
|
||||
$end
|
||||
$version
|
||||
|
|
@ -9,7 +9,7 @@ $timescale
|
|||
1ns
|
||||
$end
|
||||
$scope module top $end
|
||||
$var bit 1 ! clk $end
|
||||
$var wire 1 ! clk $end
|
||||
$scope module t $end
|
||||
$var wire 1 ! clk $end
|
||||
$var integer 32 " cyc $end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$date
|
||||
Mon Oct 8 07:13:12 2018
|
||||
Sun Oct 21 21:56:37 2018
|
||||
|
||||
$end
|
||||
$version
|
||||
|
|
@ -9,7 +9,7 @@ $timescale
|
|||
1ns
|
||||
$end
|
||||
$scope module top $end
|
||||
$var bit 1 ! clk $end
|
||||
$var wire 1 ! clk $end
|
||||
$scope module t $end
|
||||
$var wire 1 ! clk $end
|
||||
$var integer 32 " cyc $end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$date
|
||||
Thu Oct 4 19:26:16 2018
|
||||
Sun Oct 21 21:55:42 2018
|
||||
|
||||
$end
|
||||
$version
|
||||
|
|
@ -9,8 +9,8 @@ $timescale
|
|||
1ns
|
||||
$end
|
||||
$scope module top $end
|
||||
$var bit 1 ! clk $end
|
||||
$var logic 5 " state $end
|
||||
$var wire 1 ! clk $end
|
||||
$var wire 5 " state $end
|
||||
$scope module t $end
|
||||
$var wire 1 ! clk $end
|
||||
$var int 32 # cyc $end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
$date
|
||||
Thu Oct 4 19:33:41 2018
|
||||
Sun Oct 21 21:56:54 2018
|
||||
|
||||
$end
|
||||
$version
|
||||
|
|
@ -9,7 +9,7 @@ $timescale
|
|||
1ns
|
||||
$end
|
||||
$scope module top $end
|
||||
$var bit 1 ! clk $end
|
||||
$var wire 1 ! clk $end
|
||||
$scope module t $end
|
||||
$var wire 1 ! clk $end
|
||||
$var int 32 " cnt $end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# Version 2.0.
|
||||
|
||||
scenarios(vlt_all => 1);
|
||||
scenarios(vlt => 1);
|
||||
|
||||
compile(
|
||||
v_flags2 => ["--lint-only --Mdir obj_lint_only"],
|
||||
fails => 1,
|
||||
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 variable: valueSub
|
||||
'%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/const variable: valueSub
|
||||
%Error: Exiting due to.*',
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue