Remove the large variety of ways raw "text" is represented in the Ast. Particularly, the only thing that represents a string to be emitted in the output is AstText. There are 5 AstNodes that can contain AstText, and V3Emit will throw an error if an AstText is encountered anywhere else: - AstCStmt: Internally generated procedural statements involving raw text. - AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to AstCStmt, as it's largely equivalent. We should never create this internally unless used to represent user input. It is used for $c, statements in the input, and for some 'systemc_* blocks. - AstCExpr: Internally generaged expression involving raw text. - AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to AstCExpr. It is largely equivalent, but also has more optimizations disabled. This should never be created internally, it is only used for $c expressions in the input. - AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical wrappers. Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and AstTextBlock, as these are always generated by us, and should always be well formed. Tracking is always off for AstCStmtUser and AstCExprUser, as these contain arbitrary user input that might not be safe to parse for indentation. Remove subsequently redundant AstNodeSimpleText and AstNodeText types. This patch also fixes incorrect indentation in emitted waveform tracing functions, and makes the output more readable for hier block SV stubs. With that, all raw text nodes are handled as a proper AstNodeStmt or AstNodeExpr as required for #6280.
This commit is contained in:
parent
14e3448ba6
commit
cf275b6e58
|
|
@ -152,7 +152,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
case VAssertDirectiveType::INTRINSIC: return new AstConst{fl, AstConst::BitTrue{}};
|
||||
case VAssertDirectiveType::VIOLATION_CASE: {
|
||||
if (v3Global.opt.assertCase()) {
|
||||
return new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1};
|
||||
return new AstCExpr{fl, AstCExpr::Pure{}, "vlSymsp->_vm_contextp__->assertOn()",
|
||||
1};
|
||||
}
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
|
|
@ -162,7 +163,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
case VAssertDirectiveType::COVER:
|
||||
case VAssertDirectiveType::ASSUME: {
|
||||
if (v3Global.opt.assertOn()) {
|
||||
return new AstCExpr{fl,
|
||||
return new AstCExpr{fl, AstCExpr::Pure{},
|
||||
"vlSymsp->_vm_contextp__->assertOnGet("s + std::to_string(type)
|
||||
+ ", "s + std::to_string(directiveType) + ")"s,
|
||||
1};
|
||||
|
|
@ -173,7 +174,8 @@ class AssertVisitor final : public VNVisitor {
|
|||
case VAssertDirectiveType::VIOLATION_IF:
|
||||
case VAssertDirectiveType::RESTRICT: {
|
||||
if (v3Global.opt.assertOn()) {
|
||||
return new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1};
|
||||
return new AstCExpr{fl, AstCExpr::Pure{}, "vlSymsp->_vm_contextp__->assertOn()",
|
||||
1};
|
||||
}
|
||||
return new AstConst{fl, AstConst::BitFalse{}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -900,8 +900,6 @@ public:
|
|||
virtual bool isPure() { return true; }
|
||||
// Iff isPure on current node and any nextp()
|
||||
bool isPureAndNext() { return isPure() && (!nextp() || nextp()->isPure()); }
|
||||
// Else a AstTime etc that can't be substituted out
|
||||
virtual bool isSubstOptimizable() const { return true; }
|
||||
// An event control, delay, wait, etc.
|
||||
virtual bool isTimingControl() const { return false; }
|
||||
// isUnlikely handles $stop or similar statement which means an above IF
|
||||
|
|
@ -1556,11 +1554,13 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
|
|||
// For precise details please read the generated macros.
|
||||
#include "V3Ast__gen_macros.h"
|
||||
|
||||
// AstNode subclasses
|
||||
// AstNode subclasses - dependency order matters, so fmt off
|
||||
// clang-format off
|
||||
#include "V3AstNodeDType.h"
|
||||
#include "V3AstNodeExpr.h"
|
||||
#include "V3AstNodeOther.h"
|
||||
#include "V3AstNodeExpr.h"
|
||||
#include "V3AstNodeStmt.h"
|
||||
// clang-format on
|
||||
|
||||
// Inline function definitions need to go last
|
||||
#include "V3AstInlines.h"
|
||||
|
|
|
|||
|
|
@ -154,18 +154,6 @@ AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr*
|
|||
m_displayType = dispType;
|
||||
}
|
||||
|
||||
AstCStmt::AstCStmt(FileLine* fl, const string& textStmt)
|
||||
: ASTGEN_SUPER_CStmt(fl) {
|
||||
addExprsp(new AstText{fl, textStmt, true});
|
||||
}
|
||||
|
||||
AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth)
|
||||
: ASTGEN_SUPER_CExpr(fl)
|
||||
, m_pure{true} {
|
||||
addExprsp(new AstText{fl, textStmt, true});
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
|
||||
bool AstVar::sameNode(const AstNode* samep) const {
|
||||
const AstVar* const asamep = VN_DBG_AS(samep, Var);
|
||||
return m_name == asamep->m_name && varType() == asamep->varType();
|
||||
|
|
|
|||
|
|
@ -563,27 +563,67 @@ public:
|
|||
bool cleanOut() const override { V3ERROR_NA_RETURN(true); }
|
||||
};
|
||||
class AstCExpr final : public AstNodeExpr {
|
||||
// @astgen op1 := exprsp : List[AstNode] // Expressions to print
|
||||
bool m_pure; // Pure optimizable
|
||||
// C expression emitted into output, with some arbitrary nodes interspersed
|
||||
// @astgen op1 := nodesp : List[AstNode<AstNodeExpr|AstText>]
|
||||
const bool m_pure; // Pure optimizable
|
||||
|
||||
void init(const string& text, int setwidth) {
|
||||
if (!text.empty()) add(text);
|
||||
if (setwidth) {
|
||||
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
} else {
|
||||
dtypeSetVoid(); // Caller to override if necessary
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// Emit C textual expr function (like AstUCFunc)
|
||||
AstCExpr(FileLine* fl, AstNode* exprsp)
|
||||
class Pure {};
|
||||
AstCExpr(FileLine* fl, const string& text = "", int setwidth = 0)
|
||||
: ASTGEN_SUPER_CExpr(fl)
|
||||
, m_pure{false} {
|
||||
addExprsp(exprsp);
|
||||
dtypeFrom(exprsp);
|
||||
init(text, setwidth);
|
||||
}
|
||||
AstCExpr(FileLine* fl, Pure, const string& text = "", int setwidth = 0)
|
||||
: ASTGEN_SUPER_CExpr(fl)
|
||||
, m_pure{true} {
|
||||
init(text, setwidth);
|
||||
}
|
||||
inline AstCExpr(FileLine* fl, const string& textStmt, int setwidth);
|
||||
ASTGEN_MEMBERS_AstCExpr;
|
||||
bool isGateOptimizable() const override { return m_pure; }
|
||||
bool isPredictOptimizable() const override { return m_pure; }
|
||||
// METHODS
|
||||
bool cleanOut() const override { return true; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
std::string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return m_pure; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isPredictOptimizable() const override { return m_pure; }
|
||||
bool isPure() override { return m_pure; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
bool isPure() override { return pure(); }
|
||||
bool pure() const { return m_pure; }
|
||||
void pure(bool flag) { m_pure = flag; }
|
||||
// Add some text, or a node to this expression
|
||||
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
|
||||
void add(AstNode* nodep) { addNodesp(nodep); }
|
||||
};
|
||||
class AstCExprUser final : public AstNodeExpr {
|
||||
// User '$c' statement - Like AstCStmt, with text tracking and optimizations disabled.
|
||||
//
|
||||
// Use AstCExpr instead, unless the text is from user input.
|
||||
//
|
||||
// @astgen op1 := nodesp : List[AstNode<AstNodeExpr|AstText>]
|
||||
public:
|
||||
AstCExprUser(FileLine* fl)
|
||||
: ASTGEN_SUPER_CExprUser(fl) {}
|
||||
ASTGEN_MEMBERS_AstCExprUser;
|
||||
// METHODS
|
||||
bool cleanOut() const override { return false; }
|
||||
std::string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() override { return false; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
// Add some text, or a node to this expression
|
||||
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
|
||||
void add(AstNode* nodep) { addNodesp(nodep); }
|
||||
};
|
||||
class AstCMethodHard final : public AstNodeExpr {
|
||||
// A reference to a "C" hardcoded member task (or function)
|
||||
|
|
@ -2354,26 +2394,6 @@ public:
|
|||
VTimescale timeunit() const { return m_timeunit; }
|
||||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||
};
|
||||
class AstUCFunc final : public AstNodeExpr {
|
||||
// User's $c function
|
||||
// @astgen op1 := exprsp : List[AstNode] // Expressions to print (some are AstText)
|
||||
public:
|
||||
AstUCFunc(FileLine* fl, AstNode* exprsp)
|
||||
: ASTGEN_SUPER_UCFunc(fl) {
|
||||
addExprsp(exprsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstUCFunc;
|
||||
bool cleanOut() const override { return false; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isSubstOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstUnbounded final : public AstNodeExpr {
|
||||
// A $ in the parser, used for unbounded and queues
|
||||
// Due to where is used, treated as Signed32
|
||||
|
|
|
|||
|
|
@ -385,37 +385,6 @@ public:
|
|||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
class AstNodeText VL_NOT_FINAL : public AstNode {
|
||||
string m_text;
|
||||
// METHODS
|
||||
string shortText() const;
|
||||
|
||||
protected:
|
||||
// Node that puts text into the output stream
|
||||
AstNodeText(VNType t, FileLine* fl, const string& text)
|
||||
: AstNode{t, fl}
|
||||
, m_text{text} {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstNodeText;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
const AstNodeText* asamep = VN_DBG_AS(samep, NodeText);
|
||||
return text() == asamep->text();
|
||||
}
|
||||
const string& text() const VL_MT_SAFE { return m_text; }
|
||||
void text(const string& value) { m_text = value; }
|
||||
};
|
||||
class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText {
|
||||
const bool m_tracking; // When emit, it's ok to parse the string to do indentation
|
||||
public:
|
||||
AstNodeSimpleText(VNType t, FileLine* fl, const string& textp, bool tracking = false)
|
||||
: AstNodeText{t, fl, textp}
|
||||
, m_tracking{tracking} {}
|
||||
ASTGEN_MEMBERS_AstNodeSimpleText;
|
||||
bool tracking() const { return m_tracking; }
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
|
||||
|
|
@ -1666,6 +1635,49 @@ public:
|
|||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
class AstText final : public AstNode {
|
||||
// Represents a piece of text to be emitted into the output
|
||||
//
|
||||
// Avoid using this directly, internally usually want
|
||||
// AstCStmt::add("text") or AstCExpr::add("text") instead
|
||||
//
|
||||
std::string m_text; // The text to emit
|
||||
public:
|
||||
AstText(FileLine* fl, const std::string& text)
|
||||
: ASTGEN_SUPER_Text(fl)
|
||||
, m_text{text} {}
|
||||
ASTGEN_MEMBERS_AstText;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
return text() == VN_DBG_AS(samep, Text)->text();
|
||||
}
|
||||
const std::string& text() const VL_MT_SAFE { return m_text; }
|
||||
void text(const string& value) { m_text = value; }
|
||||
};
|
||||
class AstTextBlock final : public AstNode {
|
||||
// Text block emitted into output, with some arbitrary nodes interspersed
|
||||
// @astgen op1 := nodesp : List[AstNode] // Nodes to print
|
||||
const std::string m_prefix; // Prefix to print before first element in 'nodesp'
|
||||
const std::string m_separator; // Separator to print between each element in 'nodesp'
|
||||
const std::string m_suffix; // Suffix to pring after last element in 'nodesp'
|
||||
public:
|
||||
AstTextBlock(FileLine* fl, //
|
||||
const std::string& prefix = "", //
|
||||
const std::string& separator = "", //
|
||||
const std::string& suffix = "")
|
||||
: ASTGEN_SUPER_TextBlock(fl)
|
||||
, m_prefix{prefix}
|
||||
, m_separator{separator}
|
||||
, m_suffix{suffix} {}
|
||||
ASTGEN_MEMBERS_AstTextBlock;
|
||||
const std::string& prefix() const { return m_prefix; }
|
||||
const std::string& separator() const { return m_separator; }
|
||||
const std::string& suffix() const { return m_suffix; }
|
||||
// Add some text, or a node to this block
|
||||
void add(const string& text) { addNodesp(new AstText{fileline(), text}); }
|
||||
void add(AstNode* nodep) { addNodesp(nodep); }
|
||||
};
|
||||
class AstTopScope final : public AstNode {
|
||||
// A singleton, held under the top level AstModule. Holds the top level
|
||||
// AstScope, and after V3ActiveTop, the global list of AstSenTrees (list of
|
||||
|
|
@ -2831,27 +2843,4 @@ public:
|
|||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
|
||||
// === AstNodeSimpleText ===
|
||||
class AstText final : public AstNodeSimpleText {
|
||||
public:
|
||||
AstText(FileLine* fl, const string& textp, bool tracking = false)
|
||||
: ASTGEN_SUPER_Text(fl, textp, tracking) {}
|
||||
ASTGEN_MEMBERS_AstText;
|
||||
};
|
||||
class AstTextBlock final : public AstNodeSimpleText {
|
||||
// @astgen op1 := nodesp : List[AstNode]
|
||||
bool m_commas; // Comma separate emitted children
|
||||
public:
|
||||
explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false,
|
||||
bool commas = false)
|
||||
: ASTGEN_SUPER_TextBlock(fl, textp, tracking)
|
||||
, m_commas{commas} {}
|
||||
ASTGEN_MEMBERS_AstTextBlock;
|
||||
bool commas() const { return m_commas; }
|
||||
void commas(bool flag) { m_commas = flag; }
|
||||
void addText(FileLine* fl, const string& textp, bool tracking = false) {
|
||||
addNodesp(new AstText{fl, textp, tracking});
|
||||
}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -289,18 +289,49 @@ public:
|
|||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstCStmt final : public AstNodeStmt {
|
||||
// Emit C statement
|
||||
// @astgen op1 := exprsp : List[AstNode]
|
||||
// C statement emitted into output, with some arbitrary nodes interspersed
|
||||
// @astgen op1 := nodesp : List[AstNode<AstNodeStmt|AstNodeExpr|AstText>]
|
||||
public:
|
||||
AstCStmt(FileLine* fl, AstNode* exprsp)
|
||||
AstCStmt(FileLine* fl, const std::string& text = "")
|
||||
: ASTGEN_SUPER_CStmt(fl) {
|
||||
addExprsp(exprsp);
|
||||
if (!text.empty()) add(text);
|
||||
}
|
||||
inline AstCStmt(FileLine* fl, const string& textStmt);
|
||||
ASTGEN_MEMBERS_AstCStmt;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool sameNode(const AstNode*) const override { return true; }
|
||||
// Add some text, or a node to this statement
|
||||
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
|
||||
void add(AstNode* nodep) { addNodesp(nodep); }
|
||||
};
|
||||
class AstCStmtUser final : public AstNodeStmt {
|
||||
// User '$c' statement, also used for handling some AstSystemCSection.
|
||||
// Same as AstCStmt, with text tracking disabled.
|
||||
//
|
||||
// Note this cannot be modelled as AstStmtExpr(AstCExprUser) because the
|
||||
// latter would have an extra semicolon emitted, which might be undesirable.
|
||||
//
|
||||
// Use AstCStmt instead, unless the text is from user input.
|
||||
//
|
||||
// @astgen op1 := nodesp : List[AstNode<AstNodeExpr|AstText>]
|
||||
const bool m_fromDollarC; // Is from source '$c', emit decoration
|
||||
public:
|
||||
AstCStmtUser(FileLine* fl, bool fromDollarC = false)
|
||||
: ASTGEN_SUPER_CStmtUser(fl)
|
||||
, m_fromDollarC{fromDollarC} {}
|
||||
ASTGEN_MEMBERS_AstCStmtUser;
|
||||
// METHODS
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() override { return false; }
|
||||
bool sameNode(const AstNode*) const override { return true; }
|
||||
bool fromDollarC() const { return m_fromDollarC; }
|
||||
// Add some text, or a node to this statement
|
||||
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
|
||||
void add(AstNode* nodep) { addNodesp(nodep); }
|
||||
};
|
||||
class AstCase final : public AstNodeStmt {
|
||||
// Case statement
|
||||
|
|
@ -1201,21 +1232,6 @@ public:
|
|||
string prefix() const { return m_prefix; }
|
||||
VTracePrefixType prefixType() const { return m_prefixType; }
|
||||
};
|
||||
class AstUCStmt final : public AstNodeStmt {
|
||||
// User $c statement
|
||||
// @astgen op1 := exprsp : List[AstNode] // (some are AstText)
|
||||
public:
|
||||
AstUCStmt(FileLine* fl, AstNode* exprsp)
|
||||
: ASTGEN_SUPER_UCStmt(fl) {
|
||||
addExprsp(exprsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstUCStmt;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstWait final : public AstNodeStmt {
|
||||
// @astgen op1 := condp : AstNodeExpr
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
|
|
|
|||
|
|
@ -3071,21 +3071,21 @@ void AstTraceInc::dump(std::ostream& str) const {
|
|||
}
|
||||
}
|
||||
void AstTraceInc::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
string AstNodeText::shortText() const {
|
||||
string out = text();
|
||||
string::size_type pos;
|
||||
if ((pos = out.find('\n')) != string::npos) {
|
||||
out.erase(pos, out.length() - pos);
|
||||
out += "...";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
void AstNodeText::dump(std::ostream& str) const {
|
||||
void AstText::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " \"" << shortText() << "\"";
|
||||
std::string txt = text();
|
||||
if (txt.size() > 120) {
|
||||
txt.resize(120);
|
||||
txt += " ... omitted ...";
|
||||
}
|
||||
txt = VString::replaceSubstr(txt, "\\", "\\\\");
|
||||
txt = VString::replaceSubstr(txt, "\"", "\\\"");
|
||||
txt = VString::replaceSubstr(txt, "\n", "\\n");
|
||||
txt = VString::replaceSubstr(txt, "\t", "\\t");
|
||||
str << " \"" << txt << "\"";
|
||||
}
|
||||
void AstNodeText::dumpJson(std::ostream& str) const {
|
||||
dumpJsonStrFunc(str, shortText);
|
||||
void AstText::dumpJson(std::ostream& str) const {
|
||||
dumpJsonStrFunc(str, text);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,12 +139,12 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
|
||||
// METHODS
|
||||
static void insertSc(AstCFunc* cfuncp, const AstNodeModule* modp, VSystemCSectionType type) {
|
||||
auto textAndFileline = EmitCBaseVisitorConst::scSection(modp, type);
|
||||
if (!textAndFileline.first.empty()) {
|
||||
AstTextBlock* const newp
|
||||
= new AstTextBlock{textAndFileline.second, textAndFileline.first, false, false};
|
||||
cfuncp->addStmtsp(newp);
|
||||
}
|
||||
const auto txtAndFlp = EmitCBaseVisitorConst::scSection(modp, type);
|
||||
if (txtAndFlp.first.empty()) return;
|
||||
// Use an AstCStmtUser as this is from user input
|
||||
AstCStmtUser* const cstmtp = new AstCStmtUser{txtAndFlp.second};
|
||||
cstmtp->add(txtAndFlp.first);
|
||||
cfuncp->addStmtsp(cstmtp);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
|
|
|||
|
|
@ -219,9 +219,6 @@ class CleanVisitor final : public VNVisitor {
|
|||
computeCppWidth(nodep);
|
||||
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
||||
}
|
||||
void visit(AstText* nodep) override { //
|
||||
setClean(nodep, true);
|
||||
}
|
||||
void visit(AstScopeName* nodep) override { //
|
||||
setClean(nodep, true);
|
||||
}
|
||||
|
|
@ -238,13 +235,13 @@ class CleanVisitor final : public VNVisitor {
|
|||
operandBiop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
setClean(nodep, false);
|
||||
// We always clean, as we don't trust those pesky users.
|
||||
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
|
||||
for (AstNode* argp = nodep->exprsp(); argp; argp = argp->nextp()) {
|
||||
for (AstNode* argp = nodep->nodesp(); argp; argp = argp->nextp()) {
|
||||
if (AstNodeExpr* const exprp = VN_CAST(argp, NodeExpr)) ensureClean(exprp);
|
||||
}
|
||||
}
|
||||
|
|
@ -282,9 +279,9 @@ class CleanVisitor final : public VNVisitor {
|
|||
ensureCleanAndNext(nodep->exprsp());
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
for (AstNode* argp = nodep->exprsp(); argp; argp = argp->nextp()) {
|
||||
for (AstNode* argp = nodep->nodesp(); argp; argp = argp->nextp()) {
|
||||
if (AstNodeExpr* const exprp = VN_CAST(argp, NodeExpr)) ensureClean(exprp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static void makeVlToString(AstClass* nodep) {
|
|||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstNodeExpr* const exprp
|
||||
= new AstCExpr{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0};
|
||||
= new AstCExpr{nodep->fileline(), "obj ? obj->to_string() : \"null\""};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
nodep->addStmtsp(funcp);
|
||||
|
|
@ -71,7 +71,7 @@ static void makeVlToString(AstIface* nodep) {
|
|||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstNodeExpr* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->name() : \"null\"", 0};
|
||||
AstNodeExpr* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->name() : \"null\""};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
nodep->addStmtsp(funcp);
|
||||
|
|
@ -102,7 +102,7 @@ static void makeVlToString(AstNodeUOrStructDType* nodep) {
|
|||
}
|
||||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "out += \"}\";"});
|
||||
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), "out", 0};
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), "out"};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
|
||||
|
|
@ -113,8 +113,7 @@ static void makeToString(AstClass* nodep) {
|
|||
funcp->isConst(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstCExpr* const exprp
|
||||
= new AstCExpr{nodep->fileline(), R"("'{"s + to_string_middle() + "}")", 0};
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), R"("'{"s + to_string_middle() + "}")"};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
nodep->addStmtsp(funcp);
|
||||
|
|
@ -155,7 +154,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
|||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
|
||||
}
|
||||
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), "out", 0};
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), "out"};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
|
||||
|
|
|
|||
|
|
@ -1159,12 +1159,12 @@ class DelayedVisitor final : public VNVisitor {
|
|||
AstNodeExpr* const eventp = nodep->operandp()->unlinkFrBack();
|
||||
|
||||
// Enqueue for clearing 'triggered' state on next eval
|
||||
AstTextBlock* const blockp = new AstTextBlock{flp};
|
||||
blockp->addText(flp, "vlSymsp->fireEvent(", true);
|
||||
blockp->addNodesp(eventp);
|
||||
blockp->addText(flp, ");", true);
|
||||
AstCStmt* const cstmtp = new AstCStmt{flp};
|
||||
cstmtp->add("vlSymsp->fireEvent(");
|
||||
cstmtp->add(eventp);
|
||||
cstmtp->add(");");
|
||||
|
||||
AstNode* newp = new AstCStmt{flp, blockp};
|
||||
AstNode* newp = cstmtp;
|
||||
if (nodep->isDelayed()) {
|
||||
const AstVarRef* const vrefp = VN_AS(eventp, VarRef);
|
||||
const std::string newvarname = "__Vdly__" + vrefp->varp()->shortName();
|
||||
|
|
|
|||
|
|
@ -131,11 +131,11 @@ class DepthVisitor final : public VNVisitor {
|
|||
m_cfuncp->isStatic(false);
|
||||
}
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
needNonStaticFunc(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
needNonStaticFunc(nodep);
|
||||
visitStmt(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ public:
|
|||
V3OutCFile* m_ofp = nullptr;
|
||||
AstCFile* m_outFileNodep = nullptr;
|
||||
int m_splitSize = 0; // # of cfunc nodes placed into output file
|
||||
bool m_trackText = false; // Always track AstText nodes
|
||||
// METHODS
|
||||
|
||||
// Returns pointer to current output file object.
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ class EmitCFunc VL_NOT_FINAL : public EmitCConstInit {
|
|||
VMemberMap m_memberMap;
|
||||
AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting
|
||||
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for AstJumpBlocks
|
||||
bool m_inUC = false; // Inside an AstUCStmt or AstUCExpr
|
||||
bool m_createdScopeHash = false; // Already created a scope hash
|
||||
|
||||
// State associated with processing $display style string formatting
|
||||
|
|
@ -320,6 +319,24 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void emitNodesWithText(AstNode* nodesp, bool useSelfForThis, bool tracking,
|
||||
const std::string& separator) {
|
||||
for (AstNode* nodep = nodesp; nodep; nodep = nodep->nextp()) {
|
||||
if (const AstText* const textp = VN_CAST(nodep, Text)) {
|
||||
const std::string text
|
||||
= VSelfPointerText::replaceThis(useSelfForThis, textp->text());
|
||||
if (tracking) {
|
||||
puts(text);
|
||||
} else {
|
||||
ofp()->putsNoTracking(text);
|
||||
}
|
||||
} else {
|
||||
iterateConst(nodep);
|
||||
}
|
||||
if (nodep->nextp()) puts(separator);
|
||||
}
|
||||
}
|
||||
|
||||
void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp) {
|
||||
// Virtual bases in depth-first left-to-right order
|
||||
std::vector<AstClass*> virtualBases;
|
||||
|
|
@ -433,8 +450,8 @@ public:
|
|||
return true;
|
||||
});
|
||||
if (m_instantiatesOwnProcess) {
|
||||
AstNode* const vlprocp = new AstCStmt{
|
||||
nodep->fileline(), "VlProcessRef vlProcess = std::make_shared<VlProcess>();"};
|
||||
AstCStmt* const vlprocp = new AstCStmt{nodep->fileline()};
|
||||
vlprocp->add("VlProcessRef vlProcess = std::make_shared<VlProcess>();");
|
||||
nodep->stmtsp()->addHereThisAsNext(vlprocp);
|
||||
}
|
||||
|
||||
|
|
@ -1330,48 +1347,43 @@ public:
|
|||
void visit(AstTimePrecision* nodep) override {
|
||||
putns(nodep, "vlSymsp->_vm_contextp__->timeprecision()");
|
||||
}
|
||||
void visit(AstNodeSimpleText* nodep) override {
|
||||
const string text
|
||||
= VSelfPointerText::replaceThis(m_inUC && m_useSelfForThis, nodep->text());
|
||||
if (nodep->tracking() || m_trackText) {
|
||||
puts(text);
|
||||
} else {
|
||||
ofp()->putsNoTracking(text);
|
||||
}
|
||||
|
||||
// Nodes involing AstText
|
||||
void visit(AstText* nodep) override {
|
||||
// All Text should be under TextBlock/CStmt/CStmtUser/CExpr/CExprUser
|
||||
nodep->v3fatalSrc("Text node in unexpected position");
|
||||
}
|
||||
void visit(AstTextBlock* nodep) override {
|
||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterateConst(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
putnbs(nodep, "");
|
||||
puts(nodep->prefix());
|
||||
emitNodesWithText(nodep->nodesp(), false, true, nodep->separator());
|
||||
puts(nodep->suffix());
|
||||
}
|
||||
void visit(AstCStmt* nodep) override {
|
||||
putnbs(nodep, "");
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
puts("\n");
|
||||
emitNodesWithText(nodep->nodesp(), false, true, "");
|
||||
ensureNewLine();
|
||||
}
|
||||
void visit(AstCExpr* nodep) override {
|
||||
putnbs(nodep, "");
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
emitNodesWithText(nodep->nodesp(), false, true, "");
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
VL_RESTORER(m_inUC);
|
||||
m_inUC = true;
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
putnbs(nodep, "");
|
||||
putsDecoration(nodep, VIdProtect::ifNoProtect("// $c statement at "
|
||||
+ nodep->fileline()->ascii() + "\n"));
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
ofp()->putsNoTracking("\n");
|
||||
if (nodep->fromDollarC() && v3Global.opt.decoration() && !v3Global.opt.protectIds()) {
|
||||
ofp()->putsNoTracking("// $c statement at " + nodep->fileline()->ascii() + "\n");
|
||||
}
|
||||
emitNodesWithText(nodep->nodesp(), m_useSelfForThis, false, "");
|
||||
puts("\n");
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
VL_RESTORER(m_inUC);
|
||||
m_inUC = true;
|
||||
puts("\n");
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
putnbs(nodep, "");
|
||||
putsDecoration(nodep, VIdProtect::ifNoProtect("// $c function at "
|
||||
+ nodep->fileline()->ascii() + "\n"));
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
ofp()->putsNoTracking("\n");
|
||||
if (/* is always from $c */ v3Global.opt.decoration() && !v3Global.opt.protectIds()) {
|
||||
ofp()->putsNoTracking("// $c expression at " + nodep->fileline()->ascii() + "\n");
|
||||
}
|
||||
emitNodesWithText(nodep->nodesp(), m_useSelfForThis, false, "");
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
|
|
@ -1729,10 +1741,9 @@ public:
|
|||
|
||||
EmitCFunc()
|
||||
: m_lazyDecls{*this} {}
|
||||
EmitCFunc(AstNode* nodep, V3OutCFile* ofp, AstCFile* cfilep, bool trackText = false)
|
||||
EmitCFunc(AstNode* nodep, V3OutCFile* ofp, AstCFile* cfilep)
|
||||
: EmitCFunc{} {
|
||||
setOutputFile(ofp, cfilep);
|
||||
m_trackText = trackText;
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~EmitCFunc() override = default;
|
||||
|
|
|
|||
|
|
@ -928,14 +928,14 @@ void V3EmitC::emitcImp() {
|
|||
|
||||
void V3EmitC::emitcFiles() {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
|
||||
filep = VN_AS(filep->nextp(), NodeFile)) {
|
||||
for (AstNodeFile *filep = v3Global.rootp()->filesp(), *nextp; filep; filep = nextp) {
|
||||
nextp = VN_AS(filep->nextp(), NodeFile);
|
||||
AstCFile* const cfilep = VN_CAST(filep, CFile);
|
||||
if (cfilep && cfilep->tblockp()) {
|
||||
V3OutCFile of{cfilep->name()};
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated C++\n");
|
||||
const EmitCFunc visitor{cfilep->tblockp(), &of, cfilep, true};
|
||||
EmitCFunc{cfilep->tblockp(), &of, cfilep};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
|
||||
class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
||||
// STATE - across all visitors
|
||||
const bool m_alwaysTrackText; // Always track all NodeSimpleText
|
||||
const bool m_suppressUnknown; // Do not error on unknown node
|
||||
|
||||
// STATE - for current visit position (use VL_RESTORER)
|
||||
|
|
@ -71,6 +70,20 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
}
|
||||
m_packedps.clear();
|
||||
}
|
||||
void emitNodesWithText(AstNode* nodesp, bool tracking, const std::string& separator) {
|
||||
for (AstNode* nodep = nodesp; nodep; nodep = nodep->nextp()) {
|
||||
if (const AstText* const textp = VN_CAST(nodep, Text)) {
|
||||
if (tracking) {
|
||||
puts(textp->text());
|
||||
} else {
|
||||
putsNoTracking(textp->text());
|
||||
}
|
||||
} else {
|
||||
iterateConst(nodep);
|
||||
}
|
||||
if (nodep->nextp()) puts(separator);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
||||
|
|
@ -561,43 +574,41 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
iterateConst(nodep->exprp());
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstNodeSimpleText* nodep) override {
|
||||
if (nodep->tracking() || m_alwaysTrackText) {
|
||||
puts(nodep->text());
|
||||
} else {
|
||||
putsNoTracking(nodep->text());
|
||||
}
|
||||
|
||||
// Nodes involing AstText
|
||||
void visit(AstText* nodep) override {
|
||||
// All Text should be under TextBlock/CStmt/CStmtUser/CExpr/CExprUser
|
||||
nodep->v3fatalSrc("Text node in unexpected position");
|
||||
}
|
||||
void visit(AstTextBlock* nodep) override {
|
||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||
VL_RESTORER(m_suppressVarSemi);
|
||||
m_suppressVarSemi = nodep->commas();
|
||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||
iterateConst(childp);
|
||||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
m_suppressVarSemi = !nodep->separator().empty();
|
||||
puts(nodep->prefix());
|
||||
emitNodesWithText(nodep->nodesp(), true, nodep->separator());
|
||||
puts(nodep->suffix());
|
||||
}
|
||||
void visit(AstScopeName* nodep) override {}
|
||||
void visit(AstCStmt* nodep) override {
|
||||
putfs(nodep, "$_CSTMT(");
|
||||
iterateAndCommaConstNull(nodep->exprsp());
|
||||
emitNodesWithText(nodep->nodesp(), true, "");
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstCExpr* nodep) override {
|
||||
putfs(nodep, "$_CEXPR(");
|
||||
iterateAndCommaConstNull(nodep->exprsp());
|
||||
emitNodesWithText(nodep->nodesp(), true, "");
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
putfs(nodep, "$c(");
|
||||
iterateAndCommaConstNull(nodep->exprsp());
|
||||
emitNodesWithText(nodep->nodesp(), false, "");
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
putfs(nodep, "$c(");
|
||||
iterateAndNextConstNull(nodep->exprsp());
|
||||
emitNodesWithText(nodep->nodesp(), false, "");
|
||||
puts(")");
|
||||
}
|
||||
|
||||
void visit(AstScopeName* nodep) override {}
|
||||
void visit(AstExprStmt* nodep) override {
|
||||
putfs(nodep, "$_EXPRSTMT(\n");
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
|
|
@ -1129,7 +1140,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
iterateConst(methodp->pinsp());
|
||||
}
|
||||
void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); }
|
||||
void visit(AstNodeText*) override {}
|
||||
void visit(AstVarScope*) override {}
|
||||
void visit(AstTraceDecl*) override {}
|
||||
void visit(AstTraceInc*) override {}
|
||||
|
|
@ -1148,9 +1158,8 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
}
|
||||
|
||||
public:
|
||||
explicit EmitVBaseVisitorConst(bool alwaysTrackText, bool suppressUnknown)
|
||||
: m_alwaysTrackText{alwaysTrackText}
|
||||
, m_suppressUnknown{suppressUnknown} {}
|
||||
explicit EmitVBaseVisitorConst(bool suppressUnknown)
|
||||
: m_suppressUnknown{suppressUnknown} {}
|
||||
~EmitVBaseVisitorConst() override = default;
|
||||
};
|
||||
|
||||
|
|
@ -1168,8 +1177,8 @@ class EmitVFileVisitor final : public EmitVBaseVisitorConst {
|
|||
void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutVFile& of, bool alwaysTrackText, bool suppressUnknown)
|
||||
: EmitVBaseVisitorConst{alwaysTrackText, suppressUnknown}
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutVFile& of, bool suppressUnknown)
|
||||
: EmitVBaseVisitorConst{suppressUnknown}
|
||||
, m_of{of} {
|
||||
iterateConst(nodep);
|
||||
}
|
||||
|
|
@ -1182,7 +1191,7 @@ public:
|
|||
class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
||||
// STATE
|
||||
V3OutStream m_os; // The output stream formatter
|
||||
bool m_tracking; // Use line tracking
|
||||
const bool m_tracking; // Use line tracking
|
||||
// METHODS
|
||||
void putsNoTracking(const string& str) override { m_os.putsNoTracking(str); }
|
||||
void puts(const string& str) override {
|
||||
|
|
@ -1196,7 +1205,7 @@ class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
|||
|
||||
public:
|
||||
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os, bool tracking, bool suppressUnknown)
|
||||
: EmitVBaseVisitorConst{false, suppressUnknown}
|
||||
: EmitVBaseVisitorConst{suppressUnknown}
|
||||
, m_os{os, V3OutFormatter::LA_VERILOG}
|
||||
, m_tracking{tracking} {
|
||||
iterateConst(const_cast<AstNode*>(nodep));
|
||||
|
|
@ -1223,7 +1232,7 @@ void V3EmitV::emitvFiles() {
|
|||
if (vfilep && vfilep->tblockp()) {
|
||||
V3OutVFile of{vfilep->name()};
|
||||
of.puts("// DESCRIPTION: Verilator generated Verilog\n");
|
||||
{ EmitVFileVisitor{vfilep->tblockp(), of, true, false}; }
|
||||
EmitVFileVisitor{vfilep->tblockp(), of, false};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1231,5 +1240,5 @@ void V3EmitV::emitvFiles() {
|
|||
void V3EmitV::debugEmitV(const string& filename) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
V3OutVFile of{filename};
|
||||
{ EmitVFileVisitor{v3Global.rootp(), of, true, true}; }
|
||||
EmitVFileVisitor{v3Global.rootp(), of, true};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -911,7 +911,7 @@ void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t threadId,
|
|||
FileLine* const fl = modp->fileline();
|
||||
|
||||
// Helper function to make the code a bit more legible
|
||||
const auto addStrStmt = [=](const string& stmt) -> void { //
|
||||
const auto addCStmt = [=](const string& stmt) -> void { //
|
||||
funcp->addStmtsp(new AstCStmt{fl, stmt});
|
||||
};
|
||||
|
||||
|
|
@ -923,21 +923,21 @@ void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t threadId,
|
|||
= v3Global.rootp()->typeTablep()->findBasicDType(fl, VBasicDTypeKwd::MTASKSTATE);
|
||||
AstVar* const varp = new AstVar{fl, VVarType::MODULETEMP, name, mtaskStateDtypep};
|
||||
varp->valuep(new AstConst{fl, nDependencies});
|
||||
varp->protect(false); // Do not protect as we still have references in AstText
|
||||
varp->protect(false); // Do not protect as we have references in text
|
||||
modp->addStmtsp(varp);
|
||||
// For now, reference is still via text bashing
|
||||
if (v3Global.opt.profExec()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitBegin();");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitBegin();");
|
||||
}
|
||||
addStrStmt("vlSelf->" + name + +".waitUntilUpstreamDone(even_cycle);");
|
||||
addCStmt("vlSelf->" + name + +".waitUntilUpstreamDone(even_cycle);");
|
||||
if (v3Global.opt.profExec()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitEnd();");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitEnd();");
|
||||
}
|
||||
}
|
||||
|
||||
if (v3Global.opt.profPgo()) {
|
||||
// No lock around startCounter, as counter numbers are unique per thread
|
||||
addStrStmt("vlSymsp->_vm_pgoProfiler.startCounter(" + std::to_string(mtaskp->id()) + ");");
|
||||
addCStmt("vlSymsp->_vm_pgoProfiler.startCounter(" + std::to_string(mtaskp->id()) + ");");
|
||||
}
|
||||
|
||||
// Move the actual body into this function
|
||||
|
|
@ -945,15 +945,15 @@ void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t threadId,
|
|||
|
||||
if (v3Global.opt.profPgo()) {
|
||||
// No lock around stopCounter, as counter numbers are unique per thread
|
||||
addStrStmt("vlSymsp->_vm_pgoProfiler.stopCounter(" + std::to_string(mtaskp->id()) + ");");
|
||||
addCStmt("vlSymsp->_vm_pgoProfiler.stopCounter(" + std::to_string(mtaskp->id()) + ");");
|
||||
}
|
||||
|
||||
// For any dependent mtask that's on another thread, signal one dependency completion.
|
||||
for (const V3GraphEdge& edge : mtaskp->outEdges()) {
|
||||
const ExecMTask* const nextp = edge.top()->as<ExecMTask>();
|
||||
if (schedule.threadId(nextp) != threadId && schedule.contains(nextp)) {
|
||||
addStrStmt("vlSelf->__Vm_mtaskstate_" + cvtToStr(nextp->id())
|
||||
+ ".signalUpstreamDone(even_cycle);");
|
||||
addCStmt("vlSelf->__Vm_mtaskstate_" + cvtToStr(nextp->id())
|
||||
+ ".signalUpstreamDone(even_cycle);");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1001,7 +1001,7 @@ const std::vector<AstCFunc*> createThreadFunctions(const ThreadSchedule& schedul
|
|||
= new AstVar{fl, VVarType::MODULETEMP,
|
||||
"__Vm_mtaskstate_final__" + cvtToStr(schedule.id()) + tag, mtaskStateDtypep};
|
||||
varp->valuep(new AstConst(fl, funcps.size()));
|
||||
varp->protect(false); // Do not protect as we still have references in AstText
|
||||
varp->protect(false); // Do not protect as we have references in text
|
||||
modp->addStmtsp(varp);
|
||||
|
||||
return funcps;
|
||||
|
|
@ -1013,30 +1013,28 @@ void addThreadStartWrapper(AstExecGraph* const execGraphp) {
|
|||
const string& tag = execGraphp->name();
|
||||
|
||||
// Add thread function invocations to execGraph
|
||||
const auto addStrStmt = [=](const string& stmt) -> void { //
|
||||
const auto addCStmt = [=](const string& stmt) -> void { //
|
||||
execGraphp->addStmtsp(new AstCStmt{fl, stmt});
|
||||
};
|
||||
|
||||
if (v3Global.opt.profExec()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).execGraphBegin();");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).execGraphBegin();");
|
||||
}
|
||||
|
||||
addStrStmt("vlSymsp->__Vm_even_cycle__" + tag + " = !vlSymsp->__Vm_even_cycle__" + tag + ";");
|
||||
addCStmt("vlSymsp->__Vm_even_cycle__" + tag + " = !vlSymsp->__Vm_even_cycle__" + tag + ";");
|
||||
|
||||
if (!v3Global.opt.hierBlocks().empty()) addStrStmt("std::vector<size_t> indexes;");
|
||||
if (!v3Global.opt.hierBlocks().empty()) addCStmt("std::vector<size_t> indexes;");
|
||||
}
|
||||
|
||||
void addThreadEndWrapper(AstExecGraph* const execGraphp) {
|
||||
// Add thread function invocations to execGraph
|
||||
const auto addStrStmt = [=](const string& stmt) -> void { //
|
||||
const auto addCStmt = [=](const string& stmt) -> void { //
|
||||
FileLine* const flp = v3Global.rootp()->fileline();
|
||||
execGraphp->addStmtsp(new AstCStmt{flp, stmt});
|
||||
};
|
||||
|
||||
addStrStmt("Verilated::mtaskId(0);");
|
||||
if (v3Global.opt.profExec()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).execGraphEnd();");
|
||||
}
|
||||
addCStmt("Verilated::mtaskId(0);");
|
||||
if (v3Global.opt.profExec()) { addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).execGraphEnd();"); }
|
||||
}
|
||||
void addThreadStartToExecGraph(AstExecGraph* const execGraphp,
|
||||
const std::vector<AstCFunc*>& funcps, uint32_t scheduleId) {
|
||||
|
|
@ -1045,30 +1043,31 @@ void addThreadStartToExecGraph(AstExecGraph* const execGraphp,
|
|||
const string& tag = execGraphp->name();
|
||||
|
||||
// Add thread function invocations to execGraph
|
||||
const auto addStrStmt = [=](const string& stmt) -> void { //
|
||||
const auto addCStmt = [=](const string& stmt) -> void { //
|
||||
execGraphp->addStmtsp(new AstCStmt{fl, stmt});
|
||||
};
|
||||
const auto addTextStmt = [=](const string& text) -> void {
|
||||
execGraphp->addStmtsp(new AstText{fl, text, /* tracking: */ true});
|
||||
};
|
||||
|
||||
const uint32_t last = funcps.size() - 1;
|
||||
if (!v3Global.opt.hierBlocks().empty() && last > 0) {
|
||||
addStrStmt("for (size_t i = 0; i < " + cvtToStr(last)
|
||||
+ "; ++i) indexes.push_back(vlSymsp->__Vm_threadPoolp->assignWorkerIndex());");
|
||||
addCStmt("for (size_t i = 0; i < " + std::to_string(last) + "; ++i) {\n" //
|
||||
+ "indexes.push_back(vlSymsp->__Vm_threadPoolp->assignWorkerIndex());\n" //
|
||||
+ "}");
|
||||
}
|
||||
uint32_t i = 0;
|
||||
for (AstCFunc* const funcp : funcps) {
|
||||
if (i != last) {
|
||||
// The first N-1 will run on the thread pool.
|
||||
AstCStmt* const cstmtp = new AstCStmt{fl};
|
||||
execGraphp->addStmtsp(cstmtp);
|
||||
cstmtp->add("vlSymsp->__Vm_threadPoolp->workerp(");
|
||||
if (v3Global.opt.hierChild() || !v3Global.opt.hierBlocks().empty()) {
|
||||
addTextStmt("vlSymsp->__Vm_threadPoolp->workerp(indexes[" + cvtToStr(i)
|
||||
+ "])->addTask(");
|
||||
cstmtp->add("indexes[" + std::to_string(i) + "]");
|
||||
} else {
|
||||
addTextStmt("vlSymsp->__Vm_threadPoolp->workerp(" + cvtToStr(i) + ")->addTask(");
|
||||
cstmtp->add(std::to_string(i));
|
||||
}
|
||||
execGraphp->addStmtsp(new AstAddrOfCFunc{fl, funcp});
|
||||
addTextStmt(", vlSelf, vlSymsp->__Vm_even_cycle__" + tag + ");\n");
|
||||
cstmtp->add(")->addTask(");
|
||||
cstmtp->add(new AstAddrOfCFunc{fl, funcp});
|
||||
cstmtp->add(", vlSelf, vlSymsp->__Vm_even_cycle__" + tag + ");");
|
||||
} else {
|
||||
// The last will run on the main thread.
|
||||
AstCCall* const callp = new AstCCall{fl, funcp};
|
||||
|
|
@ -1081,16 +1080,16 @@ void addThreadStartToExecGraph(AstExecGraph* const execGraphp,
|
|||
V3Stats::addStatSum("Optimizations, Thread schedule total tasks", i);
|
||||
|
||||
if (v3Global.opt.profExec()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitBegin();");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitBegin();");
|
||||
}
|
||||
addStrStmt("vlSelf->__Vm_mtaskstate_final__" + std::to_string(scheduleId) + tag
|
||||
+ ".waitUntilUpstreamDone(vlSymsp->__Vm_even_cycle__" + tag + ");");
|
||||
addCStmt("vlSelf->__Vm_mtaskstate_final__" + std::to_string(scheduleId) + tag
|
||||
+ ".waitUntilUpstreamDone(vlSymsp->__Vm_even_cycle__" + tag + ");");
|
||||
if (v3Global.opt.profExec()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitEnd();");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).threadScheduleWaitEnd();");
|
||||
}
|
||||
// Free all assigned worker indices in this section
|
||||
if (!v3Global.opt.hierBlocks().empty() && last > 0) {
|
||||
addStrStmt("vlSymsp->__Vm_threadPoolp->freeWorkerIndexes(indexes);");
|
||||
addCStmt("vlSymsp->__Vm_threadPoolp->freeWorkerIndexes(indexes);");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1108,35 +1107,35 @@ void wrapMTaskBodies(AstExecGraph* const execGraphp) {
|
|||
modp->addStmtsp(funcp);
|
||||
|
||||
// Helper function to make the code a bit more legible
|
||||
const auto addStrStmt = [=](const string& stmt) -> void { //
|
||||
const auto addCStmt = [=](const string& stmt) -> void { //
|
||||
funcp->addStmtsp(new AstCStmt{flp, stmt});
|
||||
};
|
||||
|
||||
addStrStmt("static constexpr unsigned taskId = " + cvtToStr(mtaskp->id()) + ";");
|
||||
addCStmt("static constexpr unsigned taskId = " + cvtToStr(mtaskp->id()) + ";");
|
||||
|
||||
if (v3Global.opt.profExec()) {
|
||||
const string& predictStart = std::to_string(mtaskp->predictStart());
|
||||
if (v3Global.opt.hierChild()) {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).mtaskBegin(taskId, " + predictStart
|
||||
+ ", \"" + v3Global.opt.topModule() + "\");");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).mtaskBegin(taskId, " + predictStart
|
||||
+ ", \"" + v3Global.opt.topModule() + "\");");
|
||||
} else {
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).mtaskBegin(taskId, " + predictStart
|
||||
+ ");");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).mtaskBegin(taskId, " + predictStart
|
||||
+ ");");
|
||||
}
|
||||
}
|
||||
|
||||
// Set mtask ID in the run-time system
|
||||
addStrStmt("Verilated::mtaskId(taskId);");
|
||||
addCStmt("Verilated::mtaskId(taskId);");
|
||||
|
||||
// Run body
|
||||
funcp->addStmtsp(mtaskBodyp->stmtsp()->unlinkFrBackWithNext());
|
||||
|
||||
// Flush message queue
|
||||
addStrStmt("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);");
|
||||
addCStmt("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);");
|
||||
|
||||
if (v3Global.opt.profExec()) {
|
||||
const string& predictCost = std::to_string(mtaskp->cost());
|
||||
addStrStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).mtaskEnd(" + predictCost + ");");
|
||||
addCStmt("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).mtaskEnd(" + predictCost + ");");
|
||||
}
|
||||
|
||||
// AstMTask will simply contain a call
|
||||
|
|
|
|||
|
|
@ -702,7 +702,7 @@ int V3OutFormatter::endLevels(const char* strg) {
|
|||
case '\n': // Newlines.. No need for whitespace before it
|
||||
return 0;
|
||||
case '#': // Preproc directive
|
||||
return 0;
|
||||
if (m_lang == LA_C) return 0;
|
||||
}
|
||||
{
|
||||
// label/public/private: Deindent by 2 spaces
|
||||
|
|
@ -738,20 +738,25 @@ void V3OutFormatter::putns(const AstNode* nodep, const char* strg) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_prependIndent && strg[0] != '\n') {
|
||||
const bool putNodeDecoration = //
|
||||
nodep //
|
||||
&& v3Global.opt.decorationNodes() //
|
||||
&& !v3Global.opt.protectIds() //
|
||||
&& (m_sourceLastFilenameno != nodep->fileline()->filenameno() //
|
||||
|| m_sourceLastLineno != nodep->fileline()->firstLineno()) //
|
||||
&& FileLine::builtInFilename() != nodep->fileline()->filename();
|
||||
|
||||
if (m_prependIndent && ((strg[0] && strg[0] != '\n') || putNodeDecoration)) {
|
||||
putsNoTracking(indentSpaces(endLevels(strg)));
|
||||
m_prependIndent = false;
|
||||
}
|
||||
|
||||
if (nodep && v3Global.opt.decorationNodes() && !v3Global.opt.protectIds()
|
||||
&& (m_sourceLastFilenameno != nodep->fileline()->filenameno()
|
||||
|| m_sourceLastLineno != nodep->fileline()->firstLineno())
|
||||
&& FileLine::builtInFilename() != nodep->fileline()->filename()) {
|
||||
m_sourceLastLineno = nodep->fileline()->firstLineno();
|
||||
m_sourceLastFilenameno = nodep->fileline()->filenameno();
|
||||
putsNoTracking("/*" + nodep->fileline()->filename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + " " + cvtToStr((void*)nodep)
|
||||
+ "*/");
|
||||
if (putNodeDecoration) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
m_sourceLastLineno = flp->firstLineno();
|
||||
m_sourceLastFilenameno = flp->filenameno();
|
||||
const std::string lineno = std::to_string(flp->lineno());
|
||||
putsNoTracking("/*" + flp->filename() + ":" + lineno + " " + cvtToHex(nodep) + "*/");
|
||||
}
|
||||
|
||||
bool notstart = false;
|
||||
|
|
|
|||
|
|
@ -275,11 +275,6 @@ class HasherVisitor final : public VNVisitorConst {
|
|||
void visit(AstNodeStmt* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, []() {});
|
||||
}
|
||||
void visit(AstNodeText* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
|
||||
m_hash += nodep->text();
|
||||
});
|
||||
}
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
|
||||
iterateConstNull(nodep->funcp());
|
||||
|
|
@ -535,6 +530,30 @@ class HasherVisitor final : public VNVisitorConst {
|
|||
m_hash += nodep->pinNum();
|
||||
});
|
||||
}
|
||||
void visit(AstText* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
|
||||
m_hash += nodep->text();
|
||||
});
|
||||
}
|
||||
void visit(AstTextBlock* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
|
||||
m_hash += nodep->prefix();
|
||||
m_hash += nodep->separator();
|
||||
m_hash += nodep->suffix();
|
||||
});
|
||||
}
|
||||
void visit(AstCStmt* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, []() {});
|
||||
}
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, []() {});
|
||||
}
|
||||
void visit(AstCExpr* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, []() {});
|
||||
}
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, []() {});
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
|
|
|
|||
|
|
@ -135,26 +135,25 @@ public:
|
|||
// METHODS
|
||||
void checkRemoveAssign(AstVarScope* vscp, LifeVarEntry& entr) {
|
||||
const AstVar* const varp = vscp->varp();
|
||||
if (!varp->isSigPublic() && !varp->sensIfacep()) {
|
||||
// Rather than track what sigs AstUCFunc/AstUCStmt may change,
|
||||
// we just don't optimize any public sigs
|
||||
// Check the var entry, and remove if appropriate
|
||||
if (AstNodeStmt* const oldassp = entr.assignp()) {
|
||||
UINFO(7, " PREV: " << oldassp);
|
||||
// Redundant assignment, in same level block
|
||||
// Don't delete it now as it will confuse iteration since it maybe WAY
|
||||
// above our current iteration point.
|
||||
UINFOTREE(7, oldassp, "", "REMOVE/SAMEBLK");
|
||||
entr.complexAssign();
|
||||
oldassp->unlinkFrBack();
|
||||
if (VN_IS(oldassp, CReset)) {
|
||||
++m_statep->m_statCResetDel;
|
||||
} else {
|
||||
++m_statep->m_statAssnDel;
|
||||
}
|
||||
VL_DO_DANGLING(m_deleter.pushDeletep(oldassp), oldassp);
|
||||
}
|
||||
// We don't optimize any public sigs
|
||||
if (varp->isSigPublic()) return;
|
||||
if (varp->sensIfacep()) return;
|
||||
// Check the var entry, and remove if appropriate
|
||||
AstNodeStmt* const oldassp = entr.assignp();
|
||||
if (!oldassp) return;
|
||||
UINFO(7, " PREV: " << oldassp);
|
||||
// Redundant assignment, in same level block
|
||||
// Don't delete it now as it will confuse iteration since it maybe WAY
|
||||
// above our current iteration point.
|
||||
UINFOTREE(7, oldassp, "", "REMOVE/SAMEBLK");
|
||||
entr.complexAssign();
|
||||
oldassp->unlinkFrBack();
|
||||
if (VN_IS(oldassp, CReset)) {
|
||||
++m_statep->m_statCResetDel;
|
||||
} else {
|
||||
++m_statep->m_statAssnDel;
|
||||
}
|
||||
VL_DO_DANGLING(m_deleter.pushDeletep(oldassp), oldassp);
|
||||
}
|
||||
void resetStatement(AstVarScope* nodep, AstCReset* rstp) {
|
||||
// Do we have a old assignment we can nuke?
|
||||
|
|
@ -434,7 +433,7 @@ class LifeVisitor final : public VNVisitor {
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,9 +74,8 @@ public:
|
|||
AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp,
|
||||
AstNode* attrsp) VL_MT_DISABLED;
|
||||
AstAssignW* createSupplyExpr(FileLine* fileline, const string& name, int value) VL_MT_DISABLED;
|
||||
AstText* createTextQuoted(FileLine* fileline, const string& text) {
|
||||
string newtext = singletonp()->unquoteString(fileline, text);
|
||||
return new AstText{fileline, newtext};
|
||||
std::string textQuoted(FileLine* fileline, const std::string& text) {
|
||||
return singletonp()->unquoteString(fileline, text);
|
||||
}
|
||||
AstNode* createCell(FileLine* fileline, const string& name, AstPin* pinlistp,
|
||||
AstNodeRange* rangelistp) {
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ class PremitVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,41 +89,39 @@ class ProtectVisitor final : public VNVisitor {
|
|||
|
||||
// cppcheck-suppress unreadVariable
|
||||
const V3Hash hash = V3Hasher::uncachedHash(m_cfilep);
|
||||
m_hashValuep->addText(fl, cvtToStr(hash.value()) + ";\n");
|
||||
m_cHashValuep->addText(fl, cvtToStr(hash.value()) + "U;\n");
|
||||
m_hashValuep->add(cvtToStr(hash.value()) + ";\n");
|
||||
m_cHashValuep->add(cvtToStr(hash.value()) + "U;\n");
|
||||
m_foundTop = true;
|
||||
}
|
||||
|
||||
void addComment(AstTextBlock* txtp, FileLine* fl, const string& comment) {
|
||||
txtp->addNodesp(new AstComment{fl, comment});
|
||||
txtp->add(new AstComment{fl, comment});
|
||||
}
|
||||
|
||||
void configSection(AstNodeModule* modp, AstTextBlock* txtp, FileLine* fl) {
|
||||
txtp->addText(fl, "\n`ifdef VERILATOR\n");
|
||||
txtp->addText(fl, "`verilator_config\n");
|
||||
txtp->add("\n`ifdef VERILATOR\n");
|
||||
txtp->add("`verilator_config\n");
|
||||
|
||||
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_update\" -cost 64'd"
|
||||
+ std::to_string(v3Global.currentHierBlockCost()) + "\n");
|
||||
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_seq_update\" -cost 64'd"
|
||||
+ std::to_string(v3Global.currentHierBlockCost()) + "\n");
|
||||
txtp->add("profile_data -hier-dpi \"" + m_libName + "_protectlib_combo_update\" -cost 64'd"
|
||||
+ std::to_string(v3Global.currentHierBlockCost()) + "\n");
|
||||
txtp->add("profile_data -hier-dpi \"" + m_libName + "_protectlib_seq_update\" -cost 64'd"
|
||||
+ std::to_string(v3Global.currentHierBlockCost()) + "\n");
|
||||
|
||||
// Mark remaining NBA protectlib wrapper DPIs as non-hazardous by deliberately forwarding
|
||||
// them with non-zero cost.
|
||||
// Also, specify hierarchical workers for those tasks for scheduling.
|
||||
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_ignore\" -cost 64'd1\n");
|
||||
txtp->add("profile_data -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_ignore\" -cost 64'd1\n");
|
||||
|
||||
txtp->addText(fl, "hier_workers -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_update\" -workers 16'd"
|
||||
+ std::to_string(V3Control::getHierWorkers(m_libName)) + "\n");
|
||||
txtp->addText(fl, "hier_workers -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_seq_update\" -workers 16'd"
|
||||
+ std::to_string(V3Control::getHierWorkers(m_libName)) + "\n");
|
||||
txtp->add("hier_workers -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_combo_update\" -workers 16'd"
|
||||
+ std::to_string(V3Control::getHierWorkers(m_libName)) + "\n");
|
||||
txtp->add("hier_workers -hier-dpi \"" + m_libName
|
||||
+ "_protectlib_seq_update\" -workers 16'd"
|
||||
+ std::to_string(V3Control::getHierWorkers(m_libName)) + "\n");
|
||||
// No workers for combo_ignore
|
||||
txtp->addText(fl, "`verilog\n");
|
||||
txtp->addText(fl, "`endif\n");
|
||||
txtp->add("`verilog\n");
|
||||
txtp->add("`endif\n");
|
||||
}
|
||||
|
||||
void hashComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
|
|
@ -165,16 +163,14 @@ class ProtectVisitor final : public VNVisitor {
|
|||
" to use DPI libraries\n");
|
||||
|
||||
// Module declaration
|
||||
m_modPortsp = new AstTextBlock{fl, "module " + m_libName + " (\n", false, true};
|
||||
txtp->addNodesp(m_modPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
m_modPortsp = new AstTextBlock{fl, "module " + m_libName + " (\n", ", ", ");\n\n"};
|
||||
txtp->add(m_modPortsp);
|
||||
|
||||
// Timescale
|
||||
if (v3Global.opt.hierChild() && v3Global.rootp()->timescaleSpecified()) {
|
||||
// Emit timescale for hierarchical Verilation if input HDL specifies timespec
|
||||
txtp->addText(fl, "timeunit "s + modp->timeunit().ascii() + ";\n");
|
||||
txtp->addText(fl,
|
||||
"timeprecision "s + +v3Global.rootp()->timeprecision().ascii() + ";\n");
|
||||
txtp->add("timeunit "s + modp->timeunit().ascii() + ";\n");
|
||||
txtp->add("timeprecision "s + +v3Global.rootp()->timeprecision().ascii() + ";\n");
|
||||
} else {
|
||||
addComment(txtp, fl,
|
||||
"Precision of submodule"
|
||||
|
|
@ -186,131 +182,129 @@ class ProtectVisitor final : public VNVisitor {
|
|||
|
||||
// DPI declarations
|
||||
hashComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_check_hash(int protectlib_hash__V);\n\n");
|
||||
txtp->add("import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_check_hash(int protectlib_hash__V);\n\n");
|
||||
initialComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function chandle " + m_libName
|
||||
+ "_protectlib_create(string scope__V);\n\n");
|
||||
txtp->add("import \"DPI-C\" function chandle " + m_libName
|
||||
+ "_protectlib_create(string scope__V);\n\n");
|
||||
comboComment(txtp, fl);
|
||||
m_comboPortsp = new AstTextBlock{fl,
|
||||
m_comboPortsp = new AstTextBlock{fl, //
|
||||
"import \"DPI-C\" function longint " + m_libName
|
||||
+ "_protectlib_combo_update "
|
||||
"(\n",
|
||||
false, true};
|
||||
m_comboPortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodesp(m_comboPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
+ "_protectlib_combo_update(\n", //
|
||||
", ", //
|
||||
");\n\n"};
|
||||
m_comboPortsp->add("chandle handle__V\n");
|
||||
txtp->add(m_comboPortsp);
|
||||
seqComment(txtp, fl);
|
||||
if (m_hasClk) {
|
||||
m_seqPortsp = new AstTextBlock{fl,
|
||||
m_seqPortsp = new AstTextBlock{fl, //
|
||||
"import \"DPI-C\" function longint " + m_libName
|
||||
+ "_protectlib_seq_update"
|
||||
"(\n",
|
||||
false, true};
|
||||
m_seqPortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodesp(m_seqPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
+ "_protectlib_seq_update(\n", //
|
||||
", ", //
|
||||
");\n\n"};
|
||||
m_seqPortsp->add("chandle handle__V\n");
|
||||
txtp->add(m_seqPortsp);
|
||||
}
|
||||
comboIgnoreComment(txtp, fl);
|
||||
m_comboIgnorePortsp = new AstTextBlock{fl,
|
||||
m_comboIgnorePortsp = new AstTextBlock{fl, //
|
||||
"import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_combo_ignore"
|
||||
"(\n",
|
||||
false, true};
|
||||
m_comboIgnorePortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodesp(m_comboIgnorePortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
+ "_protectlib_combo_ignore(\n", //
|
||||
", ", //
|
||||
");\n\n"};
|
||||
m_comboIgnorePortsp->add("chandle handle__V\n");
|
||||
txtp->add(m_comboIgnorePortsp);
|
||||
|
||||
finalComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_final(chandle handle__V);\n\n");
|
||||
txtp->add("import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_final(chandle handle__V);\n\n");
|
||||
|
||||
// Local variables
|
||||
// Avoid tracing handle, as it is not a stable value, so breaks vcddiff
|
||||
// Likewise other internals aren't interesting to the user
|
||||
txtp->addText(fl, "// verilator tracing_off\n");
|
||||
txtp->add("// verilator tracing_off\n");
|
||||
|
||||
txtp->addText(fl, "chandle handle__V;\n");
|
||||
txtp->addText(fl, "time last_combo_seqnum__V;\n");
|
||||
if (m_hasClk) txtp->addText(fl, "time last_seq_seqnum__V;\n");
|
||||
txtp->addText(fl, "\n");
|
||||
txtp->add("chandle handle__V;\n");
|
||||
txtp->add("time last_combo_seqnum__V;\n");
|
||||
if (m_hasClk) txtp->add("time last_seq_seqnum__V;\n");
|
||||
txtp->add("\n");
|
||||
|
||||
m_comboDeclsp = new AstTextBlock{fl};
|
||||
txtp->addNodesp(m_comboDeclsp);
|
||||
txtp->add(m_comboDeclsp);
|
||||
m_seqDeclsp = new AstTextBlock{fl};
|
||||
txtp->addNodesp(m_seqDeclsp);
|
||||
txtp->add(m_seqDeclsp);
|
||||
m_tmpDeclsp = new AstTextBlock{fl};
|
||||
txtp->addNodesp(m_tmpDeclsp);
|
||||
txtp->add(m_tmpDeclsp);
|
||||
|
||||
// CPP hash value
|
||||
addComment(txtp, fl, "Hash value to make sure this file and the corresponding");
|
||||
addComment(txtp, fl, "library agree");
|
||||
m_hashValuep = new AstTextBlock{fl, "localparam int protectlib_hash__V = 32'd"};
|
||||
txtp->addNodesp(m_hashValuep);
|
||||
txtp->addText(fl, "\n");
|
||||
m_hashValuep = new AstTextBlock{fl, "localparam int protectlib_hash__V = 32'd", "", "\n"};
|
||||
txtp->add(m_hashValuep);
|
||||
|
||||
// Initial
|
||||
txtp->addText(fl, "initial begin\n");
|
||||
txtp->addText(fl, m_libName + "_protectlib_check_hash(protectlib_hash__V);\n");
|
||||
txtp->addText(fl, "handle__V = " + m_libName
|
||||
+ "_protectlib_create"
|
||||
"($sformatf(\"%m\"));\n");
|
||||
txtp->addText(fl, "end\n\n");
|
||||
txtp->add("initial begin\n");
|
||||
txtp->add(m_libName + "_protectlib_check_hash(protectlib_hash__V);\n");
|
||||
txtp->add("handle__V = " + m_libName
|
||||
+ "_protectlib_create"
|
||||
"($sformatf(\"%m\"));\n");
|
||||
txtp->add("end\n\n");
|
||||
|
||||
// Combinatorial process
|
||||
addComment(txtp, fl, "Combinatorially evaluate changes to inputs");
|
||||
m_comboParamsp = new AstTextBlock{fl,
|
||||
"always_comb begin\n"
|
||||
"last_combo_seqnum__V = "
|
||||
+ m_libName + "_protectlib_combo_update(\n",
|
||||
false, true};
|
||||
m_comboParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodesp(m_comboParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
txtp->addText(fl, "end\n\n");
|
||||
txtp->add("always_comb begin\n");
|
||||
m_comboParamsp = new AstTextBlock{fl, //
|
||||
"last_combo_seqnum__V = " + m_libName
|
||||
+ "_protectlib_combo_update(\n", //
|
||||
",\n", //
|
||||
"\n);\n"};
|
||||
m_comboParamsp->add("handle__V");
|
||||
txtp->add(m_comboParamsp);
|
||||
txtp->add("end\n\n");
|
||||
|
||||
// Sequential process
|
||||
if (m_hasClk) {
|
||||
addComment(txtp, fl, "Evaluate clock edges");
|
||||
m_clkSensp = new AstTextBlock{fl, "always @(", false, true};
|
||||
txtp->addNodesp(m_clkSensp);
|
||||
txtp->addText(fl, ") begin\n");
|
||||
m_clkSensp = new AstTextBlock{fl, "always @(", " or ", ")"};
|
||||
txtp->add(m_clkSensp);
|
||||
txtp->add(" begin\n");
|
||||
m_comboIgnoreParamsp
|
||||
= new AstTextBlock{fl, m_libName + "_protectlib_combo_ignore(\n", false, true};
|
||||
m_comboIgnoreParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodesp(m_comboIgnoreParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
m_seqParamsp = new AstTextBlock{
|
||||
fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false,
|
||||
true};
|
||||
m_seqParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodesp(m_seqParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
= new AstTextBlock{fl, //
|
||||
m_libName + "_protectlib_combo_ignore(\n", ",\n", "\n);\n"};
|
||||
m_comboIgnoreParamsp->add("handle__V");
|
||||
txtp->add(m_comboIgnoreParamsp);
|
||||
m_seqParamsp = new AstTextBlock{fl, //
|
||||
"last_seq_seqnum__V <= " + m_libName
|
||||
+ "_protectlib_seq_update(\n", //
|
||||
",\n", //
|
||||
"\n);\n"};
|
||||
m_seqParamsp->add("handle__V");
|
||||
txtp->add(m_seqParamsp);
|
||||
m_nbAssignsp = new AstTextBlock{fl};
|
||||
txtp->addNodesp(m_nbAssignsp);
|
||||
txtp->addText(fl, "end\n\n");
|
||||
txtp->add(m_nbAssignsp);
|
||||
txtp->add("end\n\n");
|
||||
}
|
||||
|
||||
// Select between combinatorial and sequential results
|
||||
addComment(txtp, fl, "Select between combinatorial and sequential results");
|
||||
txtp->addText(fl, "always_comb begin\n");
|
||||
txtp->add("always_comb begin\n");
|
||||
if (m_hasClk) {
|
||||
m_seqAssignsp = new AstTextBlock{fl, "if (last_seq_seqnum__V > "
|
||||
"last_combo_seqnum__V) begin\n"};
|
||||
txtp->addNodesp(m_seqAssignsp);
|
||||
m_comboAssignsp = new AstTextBlock{fl, "end\nelse begin\n"};
|
||||
txtp->addNodesp(m_comboAssignsp);
|
||||
txtp->addText(fl, "end\n");
|
||||
txtp->add("if (last_seq_seqnum__V > last_combo_seqnum__V) begin\n");
|
||||
m_seqAssignsp = new AstTextBlock{fl};
|
||||
txtp->add(m_seqAssignsp);
|
||||
txtp->add("end else begin\n");
|
||||
m_comboAssignsp = new AstTextBlock{fl};
|
||||
txtp->add(m_comboAssignsp);
|
||||
txtp->add("end\n");
|
||||
} else {
|
||||
m_comboAssignsp = new AstTextBlock{fl, ""};
|
||||
txtp->addNodesp(m_comboAssignsp);
|
||||
m_comboAssignsp = new AstTextBlock{fl};
|
||||
txtp->add(m_comboAssignsp);
|
||||
}
|
||||
txtp->addText(fl, "end\n\n");
|
||||
txtp->add("end\n\n");
|
||||
|
||||
// Final
|
||||
txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n");
|
||||
txtp->add("final " + m_libName + "_protectlib_final(handle__V);\n\n");
|
||||
|
||||
txtp->addText(fl, "endmodule\n");
|
||||
txtp->add("endmodule\n");
|
||||
|
||||
configSection(modp, txtp, fl);
|
||||
|
||||
|
|
@ -318,10 +312,10 @@ class ProtectVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
void castPtr(FileLine* fl, AstTextBlock* txtp) {
|
||||
txtp->addText(fl, m_topName
|
||||
+ "_container* const handlep__V = " // LCOV_EXCL_LINE // lcov bug
|
||||
"static_cast<"
|
||||
+ m_topName + "_container*>(vhandlep__V);\n");
|
||||
txtp->add(m_topName
|
||||
+ "_container* const handlep__V = " // LCOV_EXCL_LINE // lcov bug
|
||||
"static_cast<"
|
||||
+ m_topName + "_container*>(vhandlep__V);\n");
|
||||
}
|
||||
|
||||
void createCppFile(FileLine* fl) {
|
||||
|
|
@ -330,95 +324,93 @@ class ProtectVisitor final : public VNVisitor {
|
|||
addComment(txtp, fl, "Wrapper functions for DPI protected library\n");
|
||||
|
||||
// Includes
|
||||
txtp->addText(fl, "#include \"" + m_topName + ".h\"\n");
|
||||
txtp->addText(fl, "#include \"verilated_dpi.h\"\n\n");
|
||||
txtp->addText(fl, "#include <cstdio>\n");
|
||||
txtp->addText(fl, "#include <cstdlib>\n\n");
|
||||
txtp->add("#include \"" + m_topName + ".h\"\n");
|
||||
txtp->add("#include \"verilated_dpi.h\"\n\n");
|
||||
txtp->add("#include <cstdio>\n");
|
||||
txtp->add("#include <cstdlib>\n\n");
|
||||
|
||||
// Verilated module plus sequence number
|
||||
addComment(txtp, fl, "Container class to house verilated object and sequence number");
|
||||
txtp->addText(fl, "class " + m_topName + "_container: public " + m_topName + " {\n");
|
||||
txtp->addText(fl, "public:\n");
|
||||
txtp->addText(fl, "long long m_seqnum;\n");
|
||||
txtp->addText(fl, m_topName + "_container(const char* scopep__V):\n");
|
||||
txtp->addText(fl, m_topName + "(scopep__V) {}\n");
|
||||
txtp->addText(fl, "};\n\n");
|
||||
txtp->add("class " + m_topName + "_container: public " + m_topName + " {\n");
|
||||
txtp->add("public:\n");
|
||||
txtp->add("long long m_seqnum;\n");
|
||||
txtp->add(m_topName + "_container(const char* scopep__V):\n");
|
||||
txtp->add(m_topName + "(scopep__V) {}\n");
|
||||
txtp->add("};\n\n");
|
||||
|
||||
// Extern C
|
||||
txtp->addText(fl, "extern \"C\" {\n\n");
|
||||
txtp->add("extern \"C\" {\n\n");
|
||||
|
||||
// Hash check
|
||||
hashComment(txtp, fl);
|
||||
txtp->addText(fl, "void " + m_libName
|
||||
+ "_protectlib_check_hash"
|
||||
"(int protectlib_hash__V) {\n");
|
||||
m_cHashValuep = new AstTextBlock{fl, "const int expected_hash__V = "};
|
||||
txtp->addNodesp(m_cHashValuep);
|
||||
txtp->addText(fl, /**/ "if (protectlib_hash__V != expected_hash__V) {\n");
|
||||
txtp->addText(fl, /****/ "fprintf(stderr, \"%%Error: cannot use " + m_libName
|
||||
+ " library, "
|
||||
"Verliog (%u) and library (%u) hash values do not "
|
||||
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
|
||||
txtp->addText(fl, /****/ "std::exit(EXIT_FAILURE);\n");
|
||||
txtp->addText(fl, /**/ "}\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
txtp->add("void " + m_libName
|
||||
+ "_protectlib_check_hash"
|
||||
"(int protectlib_hash__V) {\n");
|
||||
m_cHashValuep = new AstTextBlock{fl, "const int expected_hash__V = ", "", ""};
|
||||
txtp->add(m_cHashValuep);
|
||||
txtp->add(/**/ "if (protectlib_hash__V != expected_hash__V) {\n");
|
||||
txtp->add(/****/ "fprintf(stderr, \"%%Error: cannot use " + m_libName
|
||||
+ " library, "
|
||||
"Verliog (%u) and library (%u) hash values do not "
|
||||
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
|
||||
txtp->add(/****/ "std::exit(EXIT_FAILURE);\n");
|
||||
txtp->add(/**/ "}\n");
|
||||
txtp->add("}\n\n");
|
||||
|
||||
// Initial
|
||||
initialComment(txtp, fl);
|
||||
txtp->addText(fl, "void* " + m_libName + "_protectlib_create(const char* scopep__V) {\n");
|
||||
txtp->addText(fl, /**/ m_topName + "_container* const handlep__V = new " + m_topName
|
||||
+ "_container{scopep__V};\n");
|
||||
txtp->addText(fl, /**/ "return handlep__V;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
txtp->add("void* " + m_libName + "_protectlib_create(const char* scopep__V) {\n");
|
||||
txtp->add(/**/ m_topName + "_container* const handlep__V = new " + m_topName
|
||||
+ "_container{scopep__V};\n");
|
||||
txtp->add(/**/ "return handlep__V;\n");
|
||||
txtp->add("}\n\n");
|
||||
|
||||
// Updates
|
||||
comboComment(txtp, fl);
|
||||
m_cComboParamsp = new AstTextBlock{
|
||||
fl, "long long " + m_libName + "_protectlib_combo_update(\n", false, true};
|
||||
m_cComboParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodesp(m_cComboParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
m_cComboInsp = new AstTextBlock{fl, "{\n"};
|
||||
fl, "long long " + m_libName + "_protectlib_combo_update(\n", ",\n", "\n) {\n"};
|
||||
m_cComboParamsp->add("void* vhandlep__V");
|
||||
txtp->add(m_cComboParamsp);
|
||||
m_cComboInsp = new AstTextBlock{fl};
|
||||
castPtr(fl, m_cComboInsp);
|
||||
txtp->addNodesp(m_cComboInsp);
|
||||
m_cComboOutsp = new AstTextBlock{fl, "handlep__V->eval();\n"};
|
||||
txtp->addNodesp(m_cComboOutsp);
|
||||
txtp->addText(fl, "return handlep__V->m_seqnum++;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
txtp->add(m_cComboInsp);
|
||||
txtp->add("handlep__V->eval();\n");
|
||||
m_cComboOutsp = new AstTextBlock{fl};
|
||||
txtp->add(m_cComboOutsp);
|
||||
txtp->add("return handlep__V->m_seqnum++;\n");
|
||||
txtp->add("}\n\n");
|
||||
|
||||
if (m_hasClk) {
|
||||
seqComment(txtp, fl);
|
||||
m_cSeqParamsp = new AstTextBlock{
|
||||
fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true};
|
||||
m_cSeqParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodesp(m_cSeqParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
m_cSeqClksp = new AstTextBlock{fl, "{\n"};
|
||||
fl, "long long " + m_libName + "_protectlib_seq_update(\n", ",\n", "\n) {\n"};
|
||||
m_cSeqParamsp->add("void* vhandlep__V");
|
||||
txtp->add(m_cSeqParamsp);
|
||||
m_cSeqClksp = new AstTextBlock{fl};
|
||||
castPtr(fl, m_cSeqClksp);
|
||||
txtp->addNodesp(m_cSeqClksp);
|
||||
m_cSeqOutsp = new AstTextBlock{fl, "handlep__V->eval();\n"};
|
||||
txtp->addNodesp(m_cSeqOutsp);
|
||||
txtp->addText(fl, "return handlep__V->m_seqnum++;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
txtp->add(m_cSeqClksp);
|
||||
txtp->add("handlep__V->eval();\n");
|
||||
m_cSeqOutsp = new AstTextBlock{fl};
|
||||
txtp->add(m_cSeqOutsp);
|
||||
txtp->add("return handlep__V->m_seqnum++;\n");
|
||||
txtp->add("}\n\n");
|
||||
}
|
||||
|
||||
comboIgnoreComment(txtp, fl);
|
||||
m_cIgnoreParamsp = new AstTextBlock{
|
||||
fl, "void " + m_libName + "_protectlib_combo_ignore(\n", false, true};
|
||||
m_cIgnoreParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodesp(m_cIgnoreParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
txtp->addText(fl, "{ }\n\n");
|
||||
fl, "void " + m_libName + "_protectlib_combo_ignore(\n", ",\n", "\n)\n{ }\n\n"};
|
||||
m_cIgnoreParamsp->add("void* vhandlep__V");
|
||||
txtp->add(m_cIgnoreParamsp);
|
||||
|
||||
// Final
|
||||
finalComment(txtp, fl);
|
||||
txtp->addText(fl, "void " + m_libName + "_protectlib_final(void* vhandlep__V) {\n");
|
||||
txtp->add("void " + m_libName + "_protectlib_final(void* vhandlep__V) {\n");
|
||||
castPtr(fl, txtp);
|
||||
txtp->addText(fl, /**/ "handlep__V->final();\n");
|
||||
txtp->addText(fl, /**/ "delete handlep__V;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
txtp->add(/**/ "handlep__V->final();\n");
|
||||
txtp->add(/**/ "delete handlep__V;\n");
|
||||
txtp->add("}\n\n");
|
||||
|
||||
txtp->addText(fl, "}\n");
|
||||
txtp->add("}\n");
|
||||
m_cfilep->tblockp(txtp);
|
||||
}
|
||||
|
||||
|
|
@ -446,46 +438,44 @@ class ProtectVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
void handleClock(AstVar* varp) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
handleInput(varp);
|
||||
m_seqPortsp->addNodesp(varp->cloneTree(false));
|
||||
m_seqPortsp->add(varp->cloneTree(false));
|
||||
if (m_hasClk) {
|
||||
m_seqParamsp->addText(fl, varp->prettyName() + "\n");
|
||||
m_clkSensp->addText(fl, "posedge " + varp->prettyName() + " or negedge "
|
||||
+ varp->prettyName());
|
||||
const std::string pname = varp->prettyName();
|
||||
m_seqParamsp->add(pname);
|
||||
m_clkSensp->add("posedge " + pname + " or negedge " + pname);
|
||||
}
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cSeqClksp->addText(fl, cInputConnection(varp));
|
||||
m_cSeqParamsp->add(varp->dpiArgType(true, false));
|
||||
m_cSeqClksp->add(cInputConnection(varp));
|
||||
}
|
||||
|
||||
void handleDataInput(AstVar* varp) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
handleInput(varp);
|
||||
m_comboPortsp->addNodesp(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->prettyName() + "\n");
|
||||
m_comboIgnorePortsp->addNodesp(varp->cloneTree(false));
|
||||
if (m_hasClk) m_comboIgnoreParamsp->addText(fl, varp->prettyName() + "\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cComboInsp->addText(fl, cInputConnection(varp));
|
||||
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_comboPortsp->add(varp->cloneTree(false));
|
||||
m_comboParamsp->add(varp->prettyName());
|
||||
m_comboIgnorePortsp->add(varp->cloneTree(false));
|
||||
if (m_hasClk) m_comboIgnoreParamsp->add(varp->prettyName());
|
||||
m_cComboParamsp->add(varp->dpiArgType(true, false));
|
||||
m_cComboInsp->add(cInputConnection(varp));
|
||||
m_cIgnoreParamsp->add(varp->dpiArgType(true, false));
|
||||
}
|
||||
|
||||
void handleInput(AstVar* varp) { m_modPortsp->addNodesp(varp->cloneTree(false)); }
|
||||
void handleInput(AstVar* varp) { m_modPortsp->add(varp->cloneTree(false)); }
|
||||
|
||||
static void addLocalVariable(AstTextBlock* textp, const AstVar* varp, const char* suffix) {
|
||||
AstVar* const newVarp
|
||||
= new AstVar{varp->fileline(), VVarType::VAR, varp->name() + suffix, varp->dtypep()};
|
||||
textp->addNodesp(newVarp);
|
||||
textp->add(newVarp);
|
||||
}
|
||||
|
||||
void handleOutput(AstVar* varp) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
m_modPortsp->addNodesp(varp->cloneTree(false));
|
||||
m_comboPortsp->addNodesp(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->prettyName() + "_combo__V\n");
|
||||
void handleOutput(AstVar* const varp) {
|
||||
const std::string pname = varp->prettyName();
|
||||
m_modPortsp->add(varp->cloneTree(false));
|
||||
m_comboPortsp->add(varp->cloneTree(false));
|
||||
m_comboParamsp->add(pname + "_combo__V");
|
||||
if (m_hasClk) {
|
||||
m_seqPortsp->addNodesp(varp->cloneTree(false));
|
||||
m_seqParamsp->addText(fl, varp->prettyName() + "_tmp__V\n");
|
||||
m_seqPortsp->add(varp->cloneTree(false));
|
||||
m_seqParamsp->add(pname + "_tmp__V");
|
||||
}
|
||||
|
||||
addLocalVariable(m_comboDeclsp, varp, "_combo__V");
|
||||
|
|
@ -494,20 +484,16 @@ class ProtectVisitor final : public VNVisitor {
|
|||
addLocalVariable(m_seqDeclsp, varp, "_seq__V");
|
||||
addLocalVariable(m_tmpDeclsp, varp, "_tmp__V");
|
||||
|
||||
m_nbAssignsp->addText(fl, varp->prettyName() + "_seq__V <= " + varp->prettyName()
|
||||
+ "_tmp__V;\n");
|
||||
m_seqAssignsp->addText(fl,
|
||||
varp->prettyName() + " = " + varp->prettyName() + "_seq__V;\n");
|
||||
m_nbAssignsp->add(pname + "_seq__V <= " + pname + "_tmp__V;\n");
|
||||
m_seqAssignsp->add(pname + " = " + pname + "_seq__V;\n");
|
||||
}
|
||||
m_comboAssignsp->addText(fl,
|
||||
varp->prettyName() + " = " + varp->prettyName() + "_combo__V;\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cComboOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")
|
||||
+ "\n");
|
||||
m_comboAssignsp->add(pname + " = " + pname + "_combo__V;\n");
|
||||
m_cComboParamsp->add(varp->dpiArgType(true, false));
|
||||
m_cComboOutsp->add(V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->") + "\n");
|
||||
if (m_hasClk) {
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cSeqOutsp->addText(
|
||||
fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->") + "\n");
|
||||
m_cSeqParamsp->add(varp->dpiArgType(true, false));
|
||||
m_cSeqOutsp->add(V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")
|
||||
+ "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -947,28 +947,25 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
// Convert to plain foreach
|
||||
FileLine* const fl = nodep->fileline();
|
||||
|
||||
AstNode* const arrayp = nodep->arrayp()->unlinkFrBack();
|
||||
if (m_wantSingle) {
|
||||
AstNode* const itemp = editSingle(fl, nodep->stmtsp());
|
||||
AstNode* const cstmtp = new AstText{fl, "ret += \" \" + "};
|
||||
cstmtp->addNext(itemp);
|
||||
cstmtp->addNext(new AstText{fl, ";"});
|
||||
AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"};
|
||||
exprsp->addNext(new AstBegin{
|
||||
fl, "",
|
||||
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstCStmt{fl, cstmtp}},
|
||||
true});
|
||||
exprsp->addNext(
|
||||
new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";})()"});
|
||||
AstNodeExpr* const newp = new AstCExpr{fl, exprsp};
|
||||
newp->dtypeSetString();
|
||||
nodep->replaceWith(new AstSFormatF{fl, "%@", false, newp});
|
||||
AstNodeExpr* const itemp = editSingle(fl, nodep->stmtsp());
|
||||
AstCStmt* const cstmtp = new AstCStmt{fl};
|
||||
cstmtp->add("ret += \" \";\n");
|
||||
cstmtp->add("ret += ");
|
||||
cstmtp->add(itemp);
|
||||
cstmtp->add(";");
|
||||
AstCExpr* const cexprp = new AstCExpr{fl};
|
||||
cexprp->dtypeSetString();
|
||||
cexprp->add("([&]{\nstd::string ret;\n");
|
||||
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true});
|
||||
cexprp->add("return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";\n})()");
|
||||
nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp});
|
||||
} else {
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
nodep->replaceWith(
|
||||
new AstBegin{fl, "",
|
||||
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(),
|
||||
nodep->stmtsp()->unlinkFrBackWithNext()},
|
||||
true});
|
||||
nodep->replaceWith(new AstBegin{
|
||||
fl, "", new AstForeach{fl, arrayp, nodep->stmtsp()->unlinkFrBackWithNext()},
|
||||
true});
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
|
@ -1028,17 +1025,18 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
selp->user1(randArr);
|
||||
AstNode* const itemp = new AstEq{fl, selp, nodep->pinsp()->unlinkFrBack()};
|
||||
itemp->user1(true);
|
||||
AstNode* const cstmtp = new AstText{fl, "ret += \" \" + "};
|
||||
cstmtp->addNext(iterateSubtreeReturnEdits(itemp));
|
||||
cstmtp->addNext(new AstText{fl, ";"});
|
||||
AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"};
|
||||
exprsp->addNext(
|
||||
new AstBegin{fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, true});
|
||||
exprsp->addNext(
|
||||
new AstText{fl, "return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";})()"});
|
||||
AstNodeExpr* const newp = new AstCExpr{fl, exprsp};
|
||||
newp->dtypeSetString();
|
||||
nodep->replaceWith(new AstSFormatF{fl, "%@", false, newp});
|
||||
|
||||
AstCStmt* const cstmtp = new AstCStmt{fl};
|
||||
cstmtp->add("ret += \" \";\n");
|
||||
cstmtp->add("ret += ");
|
||||
cstmtp->add(iterateSubtreeReturnEdits(itemp));
|
||||
cstmtp->add(";");
|
||||
AstCExpr* const cexprp = new AstCExpr{fl};
|
||||
cexprp->dtypeSetString();
|
||||
cexprp->add("([&]{\nstd::string ret;\n");
|
||||
cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true});
|
||||
cexprp->add("return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";\n})()");
|
||||
nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1772,14 +1770,14 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
AstNodeExpr* newRandValue(FileLine* const fl, AstVar* const randcVarp,
|
||||
AstNodeDType* const dtypep) {
|
||||
if (randcVarp) {
|
||||
AstVarRef* const argsp = new AstVarRef{fl, randcVarp, VAccess::READWRITE};
|
||||
argsp->AstNode::addNext(new AstText{fl, ".randomize(__Vm_rng)"});
|
||||
AstCExpr* const newp = new AstCExpr{fl, argsp};
|
||||
newp->dtypep(dtypep);
|
||||
return newp;
|
||||
} else {
|
||||
return new AstRandRNG{fl, dtypep};
|
||||
AstCExpr* const cexprp = new AstCExpr{fl};
|
||||
cexprp->add(new AstVarRef{fl, randcVarp, VAccess::READWRITE});
|
||||
cexprp->add(".randomize(__Vm_rng)");
|
||||
cexprp->dtypep(dtypep);
|
||||
return cexprp;
|
||||
}
|
||||
|
||||
return new AstRandRNG{fl, dtypep};
|
||||
}
|
||||
void addPrePostCall(AstClass* const classp, AstFunc* const funcp, const string& name) {
|
||||
if (AstTask* userFuncp = VN_CAST(m_memberMap.findMember(classp, name), Task)) {
|
||||
|
|
@ -2153,14 +2151,12 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
randomizep->addStmtsp(setupTaskRefp->makeStmt());
|
||||
|
||||
AstNodeModule* const genModp = VN_AS(genp->user2p(), NodeModule);
|
||||
AstVarRef* const genRefp = new AstVarRef{fl, genModp, genp, VAccess::READWRITE};
|
||||
AstNode* const argsp = genRefp;
|
||||
argsp->addNext(new AstText{fl, ".next(__Vm_rng)"});
|
||||
|
||||
AstNodeExpr* const solverCallp = new AstCExpr{fl, argsp};
|
||||
AstCExpr* const solverCallp = new AstCExpr{fl};
|
||||
solverCallp->dtypeSetBit();
|
||||
solverCallp->add(new AstVarRef{fl, genModp, genp, VAccess::READWRITE});
|
||||
solverCallp->add(".next(__Vm_rng)");
|
||||
beginValp = solverCallp;
|
||||
|
||||
if (randModeVarp) {
|
||||
AstNodeModule* const randModeClassp = VN_AS(randModeVarp->user2p(), Class);
|
||||
AstNodeFTask* const newp
|
||||
|
|
@ -2434,11 +2430,10 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
// Call the solver and set return value
|
||||
AstVarRef* const randNextp
|
||||
= new AstVarRef{nodep->fileline(), localGenp, VAccess::READWRITE};
|
||||
randNextp->AstNode::addNext(new AstText{nodep->fileline(), ".next(__Vm_rng)"});
|
||||
AstNodeExpr* const solverCallp = new AstCExpr{nodep->fileline(), randNextp};
|
||||
AstCExpr* const solverCallp = new AstCExpr{nodep->fileline()};
|
||||
solverCallp->dtypeSetBit();
|
||||
solverCallp->add(new AstVarRef{nodep->fileline(), localGenp, VAccess::READWRITE});
|
||||
solverCallp->add(".next(__Vm_rng)");
|
||||
randomizeFuncp->addStmtsp(new AstAssign{
|
||||
nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var), VAccess::WRITE},
|
||||
|
|
|
|||
|
|
@ -158,18 +158,16 @@ AstNodeStmt* checkIterationLimit(AstNetlist* netlistp, const string& name, AstVa
|
|||
AstNodeExpr* const condp = new AstGt{flp, counterRefp, constp};
|
||||
AstIf* const ifp = new AstIf{flp, condp};
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
AstTextBlock* const blockp = new AstTextBlock{flp};
|
||||
ifp->addThensp(blockp);
|
||||
AstCStmt* const stmtp = new AstCStmt{flp};
|
||||
ifp->addThensp(stmtp);
|
||||
FileLine* const locp = netlistp->topModulep()->fileline();
|
||||
const string& file = VIdProtect::protect(locp->filename());
|
||||
const string& line = cvtToStr(locp->lineno());
|
||||
const auto add = [&](const string& text) { blockp->addText(flp, text, true); };
|
||||
add("#ifdef VL_DEBUG\n");
|
||||
blockp->addNodesp(callVoidFunc(trigDumpp));
|
||||
add("#endif\n");
|
||||
add("VL_FATAL_MT(\"" + V3OutFormatter::quoteNameControls(file) + "\", " + line + ", \"\", ");
|
||||
add("\"" + name + " region did not converge.\");\n");
|
||||
|
||||
const std::string& file = VIdProtect::protect(locp->filename());
|
||||
const std::string& line = std::to_string(locp->lineno());
|
||||
stmtp->add("#ifdef VL_DEBUG\n");
|
||||
stmtp->add(callVoidFunc(trigDumpp));
|
||||
stmtp->add("#endif\n");
|
||||
stmtp->add("VL_FATAL_MT(\"" + V3OutFormatter::quoteNameControls(file) + "\", " + line
|
||||
+ ", \"\", \"" + name + " region did not converge.\");");
|
||||
return ifp;
|
||||
}
|
||||
|
||||
|
|
@ -696,15 +694,14 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
// Add a debug dumping statement for this trigger
|
||||
const auto addDebug = [&](uint32_t index, const string& text = "") {
|
||||
std::stringstream ss;
|
||||
ss << "VL_DBG_MSGF(\" '" << name << "' region trigger index " << cvtToStr(index)
|
||||
<< " is active";
|
||||
ss << "VL_DBG_MSGF(\" ";
|
||||
ss << "'" << name << "' region trigger index " << std::to_string(index) << " is active";
|
||||
if (!text.empty()) ss << ": " << text;
|
||||
ss << "\\n\");\n";
|
||||
const string message{ss.str()};
|
||||
ss << "\\n\");";
|
||||
|
||||
AstIf* const ifp = new AstIf{flp, getTrig(index)};
|
||||
dumpp->addStmtsp(ifp);
|
||||
ifp->addThensp(new AstText{flp, message, true});
|
||||
ifp->addThensp(new AstCStmt{flp, ss.str()});
|
||||
};
|
||||
|
||||
// Add a print for each of the extra triggers
|
||||
|
|
@ -832,14 +829,13 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
|
||||
// Add a call to the dumping function if debug is enabled
|
||||
{
|
||||
AstTextBlock* const blockp = new AstTextBlock{flp};
|
||||
funcp->addStmtsp(blockp);
|
||||
const auto add = [&](const string& text) { blockp->addText(flp, text, true); };
|
||||
add("#ifdef VL_DEBUG\n");
|
||||
add("if (VL_UNLIKELY(vlSymsp->_vm_contextp__->debug())) {\n");
|
||||
blockp->addNodesp(callVoidFunc(dumpp));
|
||||
add("}\n");
|
||||
add("#endif\n");
|
||||
AstCStmt* const stmtp = new AstCStmt{flp};
|
||||
funcp->addStmtsp(stmtp);
|
||||
stmtp->add("#ifdef VL_DEBUG\n");
|
||||
stmtp->add("if (VL_UNLIKELY(vlSymsp->_vm_contextp__->debug())) {\n");
|
||||
stmtp->add(callVoidFunc(dumpp));
|
||||
stmtp->add("}\n");
|
||||
stmtp->add("#endif");
|
||||
}
|
||||
|
||||
if (v3Global.opt.profExec()) funcp->addStmtsp(profExecSectionPop(flp));
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ TimingKit prepareTiming(AstNetlist* const netlistp) {
|
|||
// Add arguments to a resume() call based on arguments in the suspending call
|
||||
void addResumePins(AstCMethodHard* const resumep, AstNodeExpr* pinsp) {
|
||||
AstCExpr* const exprp = VN_CAST(pinsp, CExpr);
|
||||
AstText* const textp = VN_CAST(exprp->exprsp(), Text);
|
||||
AstText* const textp = VN_CAST(exprp->nodesp(), Text);
|
||||
if (textp) {
|
||||
// The first argument, vlProcess, isn't used by any of resume() methods, skip it
|
||||
if ((pinsp = VN_CAST(pinsp->nextp(), NodeExpr))) {
|
||||
|
|
|
|||
|
|
@ -1366,7 +1366,7 @@ private:
|
|||
// default
|
||||
// These types are definitely not reducible
|
||||
// AstCoverInc, AstFinish,
|
||||
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
||||
// AstRand, AstTime, AstCCall, AstCStmt*, AstCExpr*
|
||||
void visit(AstNode* nodep) override {
|
||||
if (jumpingOver()) return;
|
||||
badNodeType(nodep);
|
||||
|
|
|
|||
|
|
@ -382,9 +382,18 @@ class SubstVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// Do not optimzie across user $c input
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
m_ops = SUBST_MAX_OPS_NA;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
m_ops = SUBST_MAX_OPS_NA;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
++m_ops;
|
||||
if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
225
src/V3Task.cpp
225
src/V3Task.cpp
|
|
@ -672,15 +672,15 @@ class TaskVisitor final : public VNVisitor {
|
|||
if (needSyms) ccallp->argTypes("vlSymsp");
|
||||
|
||||
if (refp->taskp()->dpiContext()) {
|
||||
// __Vscopep
|
||||
AstScopeName* const snp = refp->scopeNamep()->unlinkFrBack();
|
||||
UASSERT_OBJ(snp, refp, "Missing scoping context");
|
||||
FileLine* const flp = refp->fileline();
|
||||
// __Vscopep
|
||||
ccallp->addArgsp(snp);
|
||||
// __Vfilenamep
|
||||
ccallp->addArgsp(
|
||||
new AstCExpr{refp->fileline(), "\"" + refp->fileline()->filenameEsc() + "\"", 64});
|
||||
ccallp->addArgsp(new AstCExpr{flp, "\"" + flp->filenameEsc() + "\"", 64});
|
||||
// __Vlineno
|
||||
ccallp->addArgsp(new AstConst(refp->fileline(), refp->fileline()->lineno()));
|
||||
ccallp->addArgsp(new AstConst(flp, flp->lineno()));
|
||||
}
|
||||
|
||||
// Create connections
|
||||
|
|
@ -802,11 +802,10 @@ class TaskVisitor final : public VNVisitor {
|
|||
|
||||
// Extract a scalar from DPI temporary var that is scalar or 1D array
|
||||
if (useSvVec) {
|
||||
const std::string offset = std::to_string(i * widthWords);
|
||||
AstCStmt* const cstmtp = new AstCStmt{flp, nullptr};
|
||||
cstmtp->addExprsp(new AstText{flp, cvt});
|
||||
cstmtp->addExprsp(lhsp);
|
||||
cstmtp->addExprsp(new AstText{flp, ", " + rhsName + " + " + offset + ");"});
|
||||
AstCStmt* const cstmtp = new AstCStmt{flp};
|
||||
cstmtp->add(cvt);
|
||||
cstmtp->add(lhsp);
|
||||
cstmtp->add(", " + rhsName + " + " + std::to_string(i * widthWords) + ");");
|
||||
stmtsp = AstNode::addNext(stmtsp, cstmtp);
|
||||
} else {
|
||||
const std::string elem = strides.empty() ? "" : "[" + std::to_string(i) + "]";
|
||||
|
|
@ -818,120 +817,97 @@ class TaskVisitor final : public VNVisitor {
|
|||
return stmtsp;
|
||||
}
|
||||
|
||||
AstCFunc* makeDpiExportDispatcher(AstNodeFTask* nodep, AstVar* rtnvarp) {
|
||||
// Create dispatch wrapper
|
||||
AstCFunc* makeDpiExportDispatcher(AstNodeFTask* const nodep, AstVar* const rtnvarp) {
|
||||
// Verilog name has __ conversion and other tricks, to match DPI C code, back that out
|
||||
const string name = AstNode::prettyName(nodep->cname());
|
||||
checkLegalCIdentifier(nodep, name);
|
||||
FileLine* const flp = nodep->fileline();
|
||||
const std::string cname = AstNode::prettyName(nodep->cname());
|
||||
checkLegalCIdentifier(nodep, cname);
|
||||
const char* const tmpSuffixp = V3Task::dpiTemporaryVarSuffix();
|
||||
AstCFunc* const funcp = new AstCFunc{nodep->fileline(), name, m_scopep,
|
||||
(rtnvarp ? rtnvarp->dpiArgType(true, true) : "")};
|
||||
const std::string rtnType = rtnvarp ? rtnvarp->dpiArgType(true, true) : "";
|
||||
// The function we are building
|
||||
AstCFunc* const funcp = new AstCFunc{flp, cname, m_scopep, rtnType};
|
||||
funcp->dpiExportDispatcher(true);
|
||||
funcp->dpiContext(nodep->dpiContext());
|
||||
funcp->dontCombine(true);
|
||||
funcp->entryPoint(true);
|
||||
funcp->isStatic(true);
|
||||
funcp->protect(false);
|
||||
funcp->cname(name);
|
||||
funcp->cname(cname);
|
||||
// Add DPI Export to top, since it's a global function
|
||||
m_topScopep->scopep()->addBlocksp(funcp);
|
||||
|
||||
{ // Create dispatch wrapper
|
||||
// Note this function may dispatch to myfunc on a different class.
|
||||
// Thus we need to be careful not to assume a particular function layout.
|
||||
//
|
||||
// Func numbers must be the same for each function, even when there are
|
||||
// completely different models with the same function name.
|
||||
// Thus we can't just use a constant computed at Verilation time.
|
||||
// We could use 64-bits of a MD5/SHA hash rather than a string here,
|
||||
// but the compare is only done on first call then memoized, so
|
||||
// it's not worth optimizing.
|
||||
// Note this function may dispatch on a different class.
|
||||
// Thus we need to be careful not to assume a particular function layout.
|
||||
//
|
||||
// Func numbers must be the same for each function, even when there are
|
||||
// completely different models with the same function name.
|
||||
// Thus we can't just use a constant computed at Verilation time.
|
||||
// We could use 64-bits of a MD5/SHA hash rather than a string here,
|
||||
// but the compare is only done on first call then memoized, so
|
||||
// it's not worth optimizing.
|
||||
|
||||
// Static doesn't need save-restore as if below will re-fill proper value
|
||||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "static int __Vfuncnum = -1;"});
|
||||
// First time init (faster than what the compiler does if we did a singleton
|
||||
funcp->addStmtsp(new AstCStmt{
|
||||
nodep->fileline(),
|
||||
"if (VL_UNLIKELY(__Vfuncnum == -1)) __Vfuncnum = Verilated::exportFuncNum(\""
|
||||
+ nodep->cname() + "\");"});
|
||||
// If the find fails, it will throw an error
|
||||
funcp->addStmtsp(
|
||||
new AstCStmt{nodep->fileline(),
|
||||
"const VerilatedScope* const __Vscopep = Verilated::dpiScope();"});
|
||||
// If dpiScope is fails and is null; the exportFind function throws and error
|
||||
// If __Vcb is null the exportFind function throws and error
|
||||
const string cbtype
|
||||
= VIdProtect::protect(v3Global.opt.prefix() + "__Vcb_" + nodep->cname() + "_t");
|
||||
funcp->addStmtsp(
|
||||
new AstCStmt{nodep->fileline(),
|
||||
cbtype + " __Vcb = (" + cbtype + ")(" // Can't use static_cast
|
||||
+ "VerilatedScope::exportFind(__Vscopep, __Vfuncnum));"});
|
||||
}
|
||||
// Peramble - fetch the exproted function from the scope table
|
||||
AstCStmt* const prep = new AstCStmt{flp};
|
||||
funcp->addStmtsp(prep);
|
||||
// Static doesn't need save-restore as if below will re-fill proper value
|
||||
prep->add("static int __Vfuncnum = -1;\n");
|
||||
// First time init (faster than what the compiler does if we did a singleton
|
||||
prep->add("if (VL_UNLIKELY(__Vfuncnum == -1)) {\n");
|
||||
prep->add("__Vfuncnum = Verilated::exportFuncNum(\"" + nodep->cname() + "\");\n");
|
||||
prep->add("}\n");
|
||||
// If the find fails, it will throw an error
|
||||
prep->add("const VerilatedScope* const __Vscopep = Verilated::dpiScope();\n");
|
||||
// If 'dpiScope()' fails and '__Vscopep' is null; the exportFind function throws an error
|
||||
// If __Vcb is null the exportFind function throws and error
|
||||
const std::string cbtype
|
||||
= VIdProtect::protect(v3Global.opt.prefix() + "__Vcb_" + nodep->cname() + "_t");
|
||||
prep->add(cbtype + " __Vcb = reinterpret_cast<" + cbtype
|
||||
+ ">(VerilatedScope::exportFind(__Vscopep, __Vfuncnum));");
|
||||
|
||||
// Convert input/inout DPI arguments to Internal types
|
||||
string args;
|
||||
args += ("(" + EmitCUtil::symClassName()
|
||||
+ "*)(__Vscopep->symsp())"); // Upcast w/o overhead
|
||||
AstNode* argnodesp = nullptr;
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn() && portp != rtnvarp) {
|
||||
// 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 = "";
|
||||
}
|
||||
AstVarScope* const outvscp
|
||||
= createFuncVar(funcp, portp->name() + tmpSuffixp, portp);
|
||||
// No information exposure; is already visible in import/export func template
|
||||
outvscp->varp()->protect(false);
|
||||
portp->protect(false);
|
||||
AstVarRef* const refp
|
||||
= new AstVarRef{portp->fileline(), outvscp,
|
||||
portp->isWritable() ? VAccess::WRITE : VAccess::READ};
|
||||
argnodesp = argnodesp->addNext(refp);
|
||||
|
||||
if (portp->isNonOutput()) {
|
||||
std::string frName
|
||||
= portp->isInout() && portp->basicp()->isDpiPrimitive()
|
||||
&& portp->dtypep()->skipRefp()->dimensions(false).second == 0
|
||||
? "*"
|
||||
: "";
|
||||
frName += portp->name();
|
||||
funcp->addStmtsp(createAssignDpiToInternal(outvscp, frName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rtnvarp) {
|
||||
AstVar* const portp = rtnvarp;
|
||||
// SAME CODE ABOVE
|
||||
args += ", ";
|
||||
if (args != "") {
|
||||
argnodesp = argnodesp->addNext(new AstText{portp->fileline(), args, true});
|
||||
args = "";
|
||||
}
|
||||
AstVarScope* const outvscp = createFuncVar(funcp, portp->name() + tmpSuffixp, portp);
|
||||
// Convert input/inout DPI arguments to Internal types, and construct the call
|
||||
AstCStmt* const callp = new AstCStmt{flp};
|
||||
const auto addFuncArg = [&](AstVar* portp) -> AstVarScope* {
|
||||
// No createDpiTemp; we make a real internal variable instead
|
||||
AstVarScope* const vscp = createFuncVar(funcp, portp->name() + tmpSuffixp, portp);
|
||||
// No information exposure; is already visible in import/export func template
|
||||
outvscp->varp()->protect(false);
|
||||
AstVarRef* const refp = new AstVarRef{
|
||||
portp->fileline(), outvscp, portp->isWritable() ? VAccess::WRITE : VAccess::READ};
|
||||
argnodesp = argnodesp->addNext(refp);
|
||||
vscp->varp()->protect(false);
|
||||
portp->protect(false);
|
||||
// Add argument to call
|
||||
const VAccess access = portp->isWritable() ? VAccess::WRITE : VAccess::READ;
|
||||
callp->add(", ");
|
||||
callp->add(new AstVarRef{portp->fileline(), vscp, access});
|
||||
return vscp;
|
||||
};
|
||||
// Call callback
|
||||
callp->add("(*__Vcb)(");
|
||||
// First argument is the Syms
|
||||
callp->add("(" + EmitCUtil::symClassName() + "*)(__Vscopep->symsp())");
|
||||
// Add function arguments
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
AstVar* const portp = VN_CAST(stmtp, Var);
|
||||
if (!portp) continue;
|
||||
if (!portp->isIO()) continue;
|
||||
if (portp->isFuncReturn()) continue;
|
||||
if (portp == rtnvarp) continue; // Handled below
|
||||
// Add argument to call
|
||||
AstVarScope* const outvscp = addFuncArg(portp);
|
||||
if (!portp->isNonOutput()) continue;
|
||||
// Convert input/inout arguments to dpi type
|
||||
const std::string deref
|
||||
= portp->isInout() //
|
||||
&& portp->basicp()->isDpiPrimitive() //
|
||||
&& portp->dtypep()->skipRefp()->dimensions(false).second == 0
|
||||
? "*"
|
||||
: "";
|
||||
funcp->addStmtsp(createAssignDpiToInternal(outvscp, deref + portp->name()));
|
||||
}
|
||||
|
||||
{ // Call the user function
|
||||
// Add the variables referenced as VarRef's so that lifetime analysis
|
||||
// doesn't rip up the variables on us
|
||||
args += ");\n";
|
||||
AstCStmt* const newp = new AstCStmt{nodep->fileline(), "(*__Vcb)("};
|
||||
newp->addExprsp(argnodesp);
|
||||
VL_DANGLING(argnodesp);
|
||||
newp->addExprsp(new AstText{nodep->fileline(), args, true});
|
||||
funcp->addStmtsp(newp);
|
||||
}
|
||||
|
||||
// Return value argument goes last
|
||||
if (rtnvarp) addFuncArg(rtnvarp);
|
||||
// Close statement
|
||||
callp->add(");");
|
||||
// Call the user function
|
||||
funcp->addStmtsp(callp);
|
||||
// Convert output/inout arguments back to internal type
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||
|
|
@ -940,13 +916,12 @@ class TaskVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert return value
|
||||
if (rtnvarp) {
|
||||
funcp->addStmtsp(createDpiTemp(rtnvarp, ""));
|
||||
funcp->addStmtsp(createAssignInternalToDpi(rtnvarp, false, tmpSuffixp, ""));
|
||||
string stmt = "return " + rtnvarp->name(); // TODO use AstCReturn?
|
||||
stmt += rtnvarp->basicp()->isDpiPrimitive() ? ";"s : "[0];"s;
|
||||
funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
|
||||
const std::string index = rtnvarp->basicp()->isDpiPrimitive() ? "" : "[0]";
|
||||
funcp->addStmtsp(new AstCStmt{flp, "return " + rtnvarp->name() + index + ";"});
|
||||
}
|
||||
if (!makePortList(nodep, funcp)) return nullptr;
|
||||
return funcp;
|
||||
|
|
@ -1114,17 +1089,23 @@ class TaskVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
{ // Call the imported function
|
||||
if (rtnvscp) { // isFunction will no longer work as we unlinked the return var
|
||||
cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), tmpSuffixp));
|
||||
string stmt = rtnvscp->varp()->name();
|
||||
stmt += tmpSuffixp;
|
||||
stmt += rtnvscp->varp()->basicp()->isDpiPrimitive() ? " = " : "[0] = ";
|
||||
cfuncp->addStmtsp(new AstText{nodep->fileline(), stmt, /* tracking: */ true});
|
||||
}
|
||||
AstCCall* const callp = new AstCCall{nodep->fileline(), dpiFuncp};
|
||||
callp->dtypeSetVoid();
|
||||
callp->argTypes(args);
|
||||
cfuncp->addStmtsp(callp->makeStmt());
|
||||
if (rtnvscp) {
|
||||
// If it has a return value, capture it
|
||||
cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), tmpSuffixp));
|
||||
const std::string sel = rtnvscp->varp()->basicp()->isDpiPrimitive() ? "" : "[0]";
|
||||
AstCStmt* const cstmtp = new AstCStmt{nodep->fileline()};
|
||||
cstmtp->add(rtnvscp->varp()->name() + tmpSuffixp + sel); // LHS
|
||||
cstmtp->add(" = ");
|
||||
cstmtp->add(callp); // RHS
|
||||
cstmtp->add(";");
|
||||
cfuncp->addStmtsp(cstmtp);
|
||||
} else {
|
||||
// Othervise just call it
|
||||
cfuncp->addStmtsp(callp->makeStmt());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert output/inout arguments back to internal type
|
||||
|
|
@ -1515,8 +1496,8 @@ class TaskVisitor final : public VNVisitor {
|
|||
lambdap->stmtsp()->addHereThisAsNext(newvarp);
|
||||
lambdap->hasResult(false);
|
||||
|
||||
// Add return statement
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), varp->name(), 0};
|
||||
// Add return statement - TODO: Why not VarRef(outvscp)?
|
||||
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), varp->name()};
|
||||
exprp->dtypeSetString();
|
||||
lambdap->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -645,7 +645,7 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
// possibly a multiline string
|
||||
std::string comment = ss.str();
|
||||
std::replace(comment.begin(), comment.end(), '\n', ' ');
|
||||
AstCExpr* const commentp = new AstCExpr{sentreep->fileline(), comment, 0};
|
||||
AstCExpr* const commentp = new AstCExpr{sentreep->fileline(), comment};
|
||||
commentp->dtypeSetString();
|
||||
sentreep->user2p(commentp);
|
||||
return commentp;
|
||||
|
|
@ -656,10 +656,10 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
void addDebugInfo(AstCMethodHard* const methodp) const {
|
||||
if (v3Global.opt.protectIds()) return;
|
||||
FileLine* const flp = methodp->fileline();
|
||||
AstCExpr* const ap = new AstCExpr{flp, '"' + flp->filenameEsc() + '"', 0};
|
||||
AstCExpr* const ap = new AstCExpr{flp, '"' + flp->filenameEsc() + '"'};
|
||||
ap->dtypeSetString();
|
||||
methodp->addPinsp(ap);
|
||||
AstCExpr* const bp = new AstCExpr{flp, cvtToStr(flp->lineno()), 0};
|
||||
AstCExpr* const bp = new AstCExpr{flp, cvtToStr(flp->lineno())};
|
||||
bp->dtypeSetString();
|
||||
methodp->addPinsp(bp);
|
||||
}
|
||||
|
|
@ -673,8 +673,7 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
void addProcessInfo(AstCMethodHard* const methodp) const {
|
||||
FileLine* const flp = methodp->fileline();
|
||||
AstCExpr* const ap = new AstCExpr{
|
||||
flp, m_procp && (hasFlags(m_procp, T_HAS_PROC)) ? "vlProcess" : "nullptr", 0};
|
||||
ap->dtypeSetVoid();
|
||||
flp, m_procp && (hasFlags(m_procp, T_HAS_PROC)) ? "vlProcess" : "nullptr"};
|
||||
methodp->addPinsp(ap);
|
||||
}
|
||||
// Creates the fork handle type and returns it
|
||||
|
|
@ -1164,10 +1163,9 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstWaitFork* nodep) override {
|
||||
if (hasFlags(m_procp, T_HAS_PROC)) {
|
||||
AstCExpr* const exprp
|
||||
= new AstCExpr{nodep->fileline(), "vlProcess->completedFork()", 1};
|
||||
exprp->pure(false);
|
||||
AstWait* const waitp = new AstWait{nodep->fileline(), exprp, nullptr};
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstCExpr* const exprp = new AstCExpr{flp, "vlProcess->completedFork()", 1};
|
||||
AstWait* const waitp = new AstWait{flp, exprp, nullptr};
|
||||
nodep->replaceWith(waitp);
|
||||
} else {
|
||||
// never reached by any process; remove to avoid compilation error
|
||||
|
|
@ -1186,8 +1184,7 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
if (constp->isZero()) {
|
||||
// We have to await forever instead of simply returning in case we're deep in a
|
||||
// callstack
|
||||
AstCExpr* const foreverp = new AstCExpr{flp, "VlForever{}", 0};
|
||||
foreverp->dtypeSetVoid(); // TODO: this is sloppy but harmless
|
||||
AstCExpr* const foreverp = new AstCExpr{flp, "VlForever{}"};
|
||||
AstCAwait* const awaitp = new AstCAwait{flp, foreverp};
|
||||
awaitp->dtypeSetVoid();
|
||||
nodep->replaceWith(awaitp->makeStmt());
|
||||
|
|
|
|||
|
|
@ -528,19 +528,21 @@ class TraceVisitor final : public VNVisitor {
|
|||
addInitStr("if (VL_UNLIKELY(!vlSymsp->__Vm_activity)) return;\n");
|
||||
}
|
||||
// Register function
|
||||
std::string str;
|
||||
AstCStmt* const cstmtp = new AstCStmt{flp};
|
||||
m_regFuncp->addStmtsp(cstmtp);
|
||||
if (traceType == VTraceType::CONSTANT) {
|
||||
str = "tracep->addConstCb(";
|
||||
cstmtp->add("tracep->addConstCb(");
|
||||
cstmtp->add(new AstAddrOfCFunc{flp, funcp});
|
||||
cstmtp->add(", " + std::to_string(funcNum) + ", vlSelf);");
|
||||
} else if (traceType == VTraceType::FULL) {
|
||||
str = "tracep->addFullCb(";
|
||||
cstmtp->add("tracep->addFullCb(");
|
||||
cstmtp->add(new AstAddrOfCFunc{flp, funcp});
|
||||
cstmtp->add(", " + std::to_string(funcNum) + ", vlSelf);");
|
||||
} else {
|
||||
str = "tracep->addChgCb(";
|
||||
cstmtp->add("tracep->addChgCb(");
|
||||
cstmtp->add(new AstAddrOfCFunc{flp, funcp});
|
||||
cstmtp->add(", " + std::to_string(funcNum) + ", vlSelf);");
|
||||
}
|
||||
m_regFuncp->addStmtsp(new AstText{flp, str, true});
|
||||
m_regFuncp->addStmtsp(new AstAddrOfCFunc{flp, funcp});
|
||||
m_regFuncp->addStmtsp(new AstText{flp, ", ", true});
|
||||
m_regFuncp->addStmtsp(new AstConst{flp, funcNum});
|
||||
m_regFuncp->addStmtsp(new AstText{flp, ", vlSelf);\n", true});
|
||||
} else {
|
||||
// Sub functions
|
||||
funcp->argTypes(bufArg);
|
||||
|
|
@ -739,10 +741,11 @@ class TraceVisitor final : public VNVisitor {
|
|||
|
||||
// Register it
|
||||
{
|
||||
AstNode* const argsp = new AstText{fl, "tracep->addCleanupCb(", true};
|
||||
argsp->addNext(new AstAddrOfCFunc{fl, cleanupFuncp});
|
||||
argsp->addNext(new AstText{fl, ", vlSelf);"});
|
||||
m_regFuncp->addStmtsp(new AstCStmt{fl, argsp});
|
||||
AstCStmt* const cstmtp = new AstCStmt{fl};
|
||||
m_regFuncp->addStmtsp(cstmtp);
|
||||
cstmtp->add("tracep->addCleanupCb(");
|
||||
cstmtp->add(new AstAddrOfCFunc{fl, cleanupFuncp});
|
||||
cstmtp->add(", vlSelf);");
|
||||
}
|
||||
|
||||
// Clear global activity flag
|
||||
|
|
|
|||
|
|
@ -1599,7 +1599,11 @@ class WidthVisitor final : public VNVisitor {
|
|||
nodep->dtypeSetBit();
|
||||
}
|
||||
}
|
||||
void visit(AstUCFunc* nodep) override {
|
||||
void visit(AstCExpr* nodep) override {
|
||||
// Inserted by V3Width only so we know has been resolved
|
||||
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
|
||||
}
|
||||
void visit(AstCExprUser* nodep) override {
|
||||
// Give it the size the user wants.
|
||||
if (m_vup && m_vup->prelim()) {
|
||||
nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // We don't care
|
||||
|
|
@ -3502,10 +3506,6 @@ class WidthVisitor final : public VNVisitor {
|
|||
return false;
|
||||
}
|
||||
|
||||
void visit(AstCExpr* nodep) override {
|
||||
// Inserted by V3Width only so we know has been resolved
|
||||
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
// Never created before V3Width, so no need to redo it
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized");
|
||||
|
|
@ -6060,7 +6060,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (nodep->suffixp()) iterateCheckString(nodep, "suffix", nodep->suffixp(), BOTH);
|
||||
if (nodep->widthp()) iterateCheckSigned32(nodep, "width", nodep->widthp(), BOTH);
|
||||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
void visit(AstCStmtUser* nodep) override {
|
||||
// Just let all arguments seek their natural sizes
|
||||
assertAtStatement(nodep);
|
||||
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
|
||||
|
|
@ -6724,8 +6724,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
v3Global.useRandomizeMethods(true);
|
||||
AstCExpr* const newp
|
||||
= new AstCExpr{nodep->fileline(), "__Vm_rng.set_randstate(", 1};
|
||||
newp->addExprsp(exprp->unlinkFrBack());
|
||||
newp->addExprsp(new AstText{nodep->fileline(), ")", true});
|
||||
newp->add(exprp->unlinkFrBack());
|
||||
newp->add(")");
|
||||
newp->dtypeSetString();
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
|
|
|||
|
|
@ -4103,8 +4103,15 @@ system_t_call<nodeStmtp>: // IEEE: system_tf_call (as task)
|
|||
| yD_DUMPON parenE { $$ = new AstDumpCtl{$<fl>1, VDumpCtlType::ON}; }
|
||||
| yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl{$<fl>1, VDumpCtlType::ON}; DEL($3); }
|
||||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCStmt{$1, $3}); }
|
||||
| yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); DEL($3); }
|
||||
| yD_C '(' cStrList ')' {
|
||||
AstCStmtUser* cstmtp = nullptr;
|
||||
if (!v3Global.opt.ignc()) {
|
||||
cstmtp = new AstCStmtUser{$1, true};
|
||||
cstmtp->add($3);
|
||||
}
|
||||
$$ = cstmtp;
|
||||
}
|
||||
| yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); DEL($3); }
|
||||
| yD_STACKTRACE parenE { $$ = new AstStackTraceT{$1}; }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT{$1, $3}; }
|
||||
//
|
||||
|
|
@ -4263,7 +4270,14 @@ system_t_call<nodeStmtp>: // IEEE: system_tf_call (as task)
|
|||
system_f_call<nodeExprp>: // IEEE: system_tf_call (as func)
|
||||
yaD_PLI systemDpiArgsE { $$ = new AstFuncRef{$<fl>1, *$1, $2}; VN_CAST($$, FuncRef)->pli(true); }
|
||||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCFunc{$1, $3}); }
|
||||
| yD_C '(' cStrList ')' {
|
||||
AstCExprUser* cexprp = nullptr;
|
||||
if (!v3Global.opt.ignc()) {
|
||||
cexprp = new AstCExprUser{$1};
|
||||
cexprp->add($3);
|
||||
}
|
||||
$$ = cexprp;
|
||||
}
|
||||
| yD_CAST '(' expr ',' expr ')' { $$ = new AstCastDynamic{$1, $5, $3}; }
|
||||
| yD_STACKTRACE parenE { $$ = new AstStackTraceF{$1}; }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF{$1, $3}; }
|
||||
|
|
@ -5192,7 +5206,7 @@ pexprScope<nodeExprp>: // exprScope, For use by property_expr
|
|||
// For $c("foo","bar") we want "bar" as a string, not a Verilog integer.
|
||||
exprStrText<nodep>:
|
||||
exprNoStr { $$ = $1; }
|
||||
| strAsText { $$ = $1; }
|
||||
| yaSTRING { $$ = new AstText{$<fl>1, GRAMMARP->textQuoted($<fl>1, *$1)}; }
|
||||
;
|
||||
|
||||
exprTypeCompare<nodeExprp>:
|
||||
|
|
@ -6080,10 +6094,6 @@ strAsIntIgnore<nodeExprp>: // strAsInt, but never matches for when expr
|
|||
yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); }
|
||||
;
|
||||
|
||||
strAsText<nodep>:
|
||||
yaSTRING { $$ = GRAMMARP->createTextQuoted($<fl>1, *$1); }
|
||||
;
|
||||
|
||||
endLabelE<strp>:
|
||||
/* empty */ { $$ = nullptr; $<fl>$ = nullptr; }
|
||||
| ':' idAny { $$ = $2; $<fl>$ = $<fl>2; }
|
||||
|
|
|
|||
|
|
@ -1678,18 +1678,18 @@
|
|||
"valuep": [
|
||||
{"type":"CVTPACKSTRING","name":"","addr":"(OZ)","loc":"d,227:18,227:24","dtypep":"(FG)",
|
||||
"lhsp": [
|
||||
{"type":"UCFUNC","name":"","addr":"(PZ)","loc":"d,227:26,227:28","dtypep":"UNLINKED",
|
||||
"exprsp": [
|
||||
{"type":"TEXT","name":"","addr":"(QZ)","loc":"d,227:29,227:32","shortText":"0"}
|
||||
{"type":"CEXPRUSER","name":"","addr":"(PZ)","loc":"d,227:26,227:28","dtypep":"UNLINKED",
|
||||
"nodesp": [
|
||||
{"type":"TEXT","name":"","addr":"(QZ)","loc":"d,227:29,227:32","text":"0"}
|
||||
]}
|
||||
]}
|
||||
],"attrsp": []},
|
||||
{"type":"UCSTMT","name":"","addr":"(RZ)","loc":"d,229:7,229:9",
|
||||
"exprsp": [
|
||||
{"type":"CSTMTUSER","name":"","addr":"(RZ)","loc":"d,229:7,229:9",
|
||||
"nodesp": [
|
||||
{"type":"PARSEREF","name":"s","addr":"(SZ)","loc":"d,229:10,229:11","dtypep":"UNLINKED","lhsp": [],"ftaskrefp": []},
|
||||
{"type":"TEXT","name":"","addr":"(TZ)","loc":"d,229:13,229:18","shortText":" = "},
|
||||
{"type":"TEXT","name":"","addr":"(TZ)","loc":"d,229:13,229:18","text":" = "},
|
||||
{"type":"PARSEREF","name":"m_process","addr":"(UZ)","loc":"d,229:20,229:29","dtypep":"UNLINKED","lhsp": [],"ftaskrefp": []},
|
||||
{"type":"TEXT","name":"","addr":"(VZ)","loc":"d,229:31,229:47","shortText":"->randstate();"}
|
||||
{"type":"TEXT","name":"","addr":"(VZ)","loc":"d,229:31,229:47","text":"->randstate();"}
|
||||
]},
|
||||
{"type":"RETURN","name":"","addr":"(WZ)","loc":"d,230:7,230:13",
|
||||
"lhsp": [
|
||||
|
|
@ -1702,12 +1702,12 @@
|
|||
"childDTypep": [
|
||||
{"type":"BASICDTYPE","name":"string","addr":"(AAB)","loc":"d,233:33,233:39","dtypep":"(AAB)","keyword":"string","generic":false,"rangep": []}
|
||||
],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"UCSTMT","name":"","addr":"(BAB)","loc":"d,234:7,234:9",
|
||||
"exprsp": [
|
||||
{"type":"CSTMTUSER","name":"","addr":"(BAB)","loc":"d,234:7,234:9",
|
||||
"nodesp": [
|
||||
{"type":"PARSEREF","name":"m_process","addr":"(CAB)","loc":"d,234:10,234:19","dtypep":"UNLINKED","lhsp": [],"ftaskrefp": []},
|
||||
{"type":"TEXT","name":"","addr":"(DAB)","loc":"d,234:21,234:35","shortText":"->randstate("},
|
||||
{"type":"TEXT","name":"","addr":"(DAB)","loc":"d,234:21,234:35","text":"->randstate("},
|
||||
{"type":"PARSEREF","name":"s","addr":"(EAB)","loc":"d,234:37,234:38","dtypep":"UNLINKED","lhsp": [],"ftaskrefp": []},
|
||||
{"type":"TEXT","name":"","addr":"(FAB)","loc":"d,234:40,234:44","shortText":");"}
|
||||
{"type":"TEXT","name":"","addr":"(FAB)","loc":"d,234:40,234:44","text":");"}
|
||||
]}
|
||||
],"scopeNamep": []}
|
||||
],"extendsp": []},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -540,7 +540,7 @@
|
|||
<varref loc="d,63,22,63,25" name="clk" dtype_id="8"/>
|
||||
<varref loc="d,63,22,63,25" name="__Vtrigprevexpr___TOP__clk__0" dtype_id="8"/>
|
||||
</assign>
|
||||
<textblock loc="d,11,8,11,9">
|
||||
<cstmt loc="d,11,8,11,9">
|
||||
<text loc="d,11,8,11,9"/>
|
||||
<text loc="d,11,8,11,9"/>
|
||||
<stmtexpr loc="a,0,0,0,0">
|
||||
|
|
@ -548,7 +548,7 @@
|
|||
</stmtexpr>
|
||||
<text loc="d,11,8,11,9"/>
|
||||
<text loc="d,11,8,11,9"/>
|
||||
</textblock>
|
||||
</cstmt>
|
||||
</cfunc>
|
||||
<cfunc loc="a,0,0,0,0" name="_dump_triggers__act">
|
||||
<if loc="d,11,8,11,9">
|
||||
|
|
@ -575,7 +575,9 @@
|
|||
</cmethodhard>
|
||||
</and>
|
||||
<begin>
|
||||
<text loc="d,11,8,11,9"/>
|
||||
<cstmt loc="d,11,8,11,9">
|
||||
<text loc="d,11,8,11,9"/>
|
||||
</cstmt>
|
||||
</begin>
|
||||
</if>
|
||||
</cfunc>
|
||||
|
|
@ -604,7 +606,9 @@
|
|||
</cmethodhard>
|
||||
</and>
|
||||
<begin>
|
||||
<text loc="d,11,8,11,9"/>
|
||||
<cstmt loc="d,11,8,11,9">
|
||||
<text loc="d,11,8,11,9"/>
|
||||
</cstmt>
|
||||
</begin>
|
||||
</if>
|
||||
</cfunc>
|
||||
|
|
@ -1529,15 +1533,14 @@
|
|||
<varref loc="a,0,0,0,0" name="__VnbaIterCount" dtype_id="5"/>
|
||||
</lt>
|
||||
<begin>
|
||||
<textblock loc="a,0,0,0,0">
|
||||
<cstmt loc="a,0,0,0,0">
|
||||
<text loc="a,0,0,0,0"/>
|
||||
<stmtexpr loc="a,0,0,0,0">
|
||||
<ccall loc="a,0,0,0,0" dtype_id="7" func="_dump_triggers__nba"/>
|
||||
</stmtexpr>
|
||||
<text loc="a,0,0,0,0"/>
|
||||
<text loc="a,0,0,0,0"/>
|
||||
<text loc="a,0,0,0,0"/>
|
||||
</textblock>
|
||||
</cstmt>
|
||||
</begin>
|
||||
</if>
|
||||
<assign loc="d,11,8,11,9" dtype_id="5">
|
||||
|
|
@ -1572,15 +1575,14 @@
|
|||
<varref loc="a,0,0,0,0" name="__VactIterCount" dtype_id="5"/>
|
||||
</lt>
|
||||
<begin>
|
||||
<textblock loc="a,0,0,0,0">
|
||||
<cstmt loc="a,0,0,0,0">
|
||||
<text loc="a,0,0,0,0"/>
|
||||
<stmtexpr loc="a,0,0,0,0">
|
||||
<ccall loc="a,0,0,0,0" dtype_id="7" func="_dump_triggers__act"/>
|
||||
</stmtexpr>
|
||||
<text loc="a,0,0,0,0"/>
|
||||
<text loc="a,0,0,0,0"/>
|
||||
<text loc="a,0,0,0,0"/>
|
||||
</textblock>
|
||||
</cstmt>
|
||||
</begin>
|
||||
</if>
|
||||
<assign loc="d,11,8,11,9" dtype_id="5">
|
||||
|
|
|
|||
Loading…
Reference in New Issue