Internals: Enable EmitV to output formatted code to std::ostream (#6239)
Introduce V3OutStream as a V3OutFormatter that writes to a stream instead of a file. This can be used to emit formatted code fragments e.g. in debug prints and graph dumps.
This commit is contained in:
parent
2b62f5a625
commit
9d2adf3e49
|
|
@ -28,12 +28,13 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// Emit statements and expressions
|
// Emit statements and expressions
|
||||||
|
|
||||||
class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
||||||
// STATE - across all visitors
|
// STATE - across all visitors
|
||||||
const bool m_suppressUnknown = false;
|
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)
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
AstSenTree* m_sensesp = nullptr; // Domain for printing one a ALWAYS under a ACTIVE
|
||||||
bool m_suppressSemi = false; // Non-statement, don't print ;
|
bool m_suppressSemi = false; // Non-statement, don't print ;
|
||||||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||||
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
|
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
|
||||||
|
|
@ -72,7 +73,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
|
putfs(nodep, nodep->verilogKwd() + " " + EmitCBase::prefixNameProtect(nodep) + ";\n");
|
||||||
iterateChildrenConst(nodep);
|
iterateChildrenConst(nodep);
|
||||||
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -461,7 +462,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||||
puts(";\n");
|
puts(";\n");
|
||||||
}
|
}
|
||||||
void visit(AstNodeSimpleText* nodep) override {
|
void visit(AstNodeSimpleText* nodep) override {
|
||||||
if (nodep->tracking() || m_trackText) {
|
if (nodep->tracking() || m_alwaysTrackText) {
|
||||||
puts(nodep->text());
|
puts(nodep->text());
|
||||||
} else {
|
} else {
|
||||||
putsNoTracking(nodep->text());
|
putsNoTracking(nodep->text());
|
||||||
|
|
@ -965,9 +966,9 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EmitVBaseVisitorConst(bool suppressUnknown, AstSenTree* domainp)
|
explicit EmitVBaseVisitorConst(bool alwaysTrackText, bool suppressUnknown)
|
||||||
: m_suppressUnknown{suppressUnknown}
|
: m_alwaysTrackText{alwaysTrackText}
|
||||||
, m_sensesp{domainp} {}
|
, m_suppressUnknown{suppressUnknown} {}
|
||||||
~EmitVBaseVisitorConst() override = default;
|
~EmitVBaseVisitorConst() override = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -975,18 +976,19 @@ public:
|
||||||
// Emit to an output file
|
// Emit to an output file
|
||||||
|
|
||||||
class EmitVFileVisitor final : public EmitVBaseVisitorConst {
|
class EmitVFileVisitor final : public EmitVBaseVisitorConst {
|
||||||
|
// STATE
|
||||||
|
V3OutVFile& m_of; // The output file
|
||||||
// METHODS
|
// METHODS
|
||||||
void puts(const string& str) override { ofp()->puts(str); }
|
void putsNoTracking(const string& str) override { m_of.putsNoTracking(str); }
|
||||||
void putbs(const string& str) override { ofp()->putbs(str); }
|
void puts(const string& str) override { m_of.puts(str); }
|
||||||
|
void putbs(const string& str) override { m_of.putbs(str); }
|
||||||
void putfs(AstNode*, const string& str) override { putbs(str); }
|
void putfs(AstNode*, const string& str) override { putbs(str); }
|
||||||
void putqs(AstNode*, const string& str) override { putbs(str); }
|
void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||||
void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmitVFileVisitor(AstNode* nodep, V3OutVFile* ofp, bool trackText, bool suppressUnknown)
|
EmitVFileVisitor(AstNode* nodep, V3OutVFile& of, bool alwaysTrackText, bool suppressUnknown)
|
||||||
: EmitVBaseVisitorConst{suppressUnknown, nullptr} {
|
: EmitVBaseVisitorConst{alwaysTrackText, suppressUnknown}
|
||||||
m_ofp = ofp;
|
, m_of{of} {
|
||||||
m_trackText = trackText;
|
|
||||||
iterateConst(nodep);
|
iterateConst(nodep);
|
||||||
}
|
}
|
||||||
~EmitVFileVisitor() override = default;
|
~EmitVFileVisitor() override = default;
|
||||||
|
|
@ -996,19 +998,25 @@ public:
|
||||||
// Emit to a stream (perhaps stringstream)
|
// Emit to a stream (perhaps stringstream)
|
||||||
|
|
||||||
class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
||||||
// MEMBERS
|
// STATE
|
||||||
std::ostream& m_os;
|
V3OutStream m_os; // The output stream formatter
|
||||||
|
bool m_tracking; // Use line tracking
|
||||||
// METHODS
|
// METHODS
|
||||||
void putsNoTracking(const string& str) override { m_os << str; }
|
void putsNoTracking(const string& str) override { m_os.putsNoTracking(str); }
|
||||||
void puts(const string& str) override { putsNoTracking(str); }
|
void puts(const string& str) override {
|
||||||
void putbs(const string& str) override { puts(str); }
|
m_tracking ? m_os.puts(str) : m_os.putsNoTracking(str);
|
||||||
|
}
|
||||||
|
void putbs(const string& str) override {
|
||||||
|
m_tracking ? m_os.putbs(str) : m_os.putsNoTracking(str);
|
||||||
|
}
|
||||||
void putfs(AstNode*, const string& str) override { putbs(str); }
|
void putfs(AstNode*, const string& str) override { putbs(str); }
|
||||||
void putqs(AstNode*, const string& str) override { putbs(str); }
|
void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os)
|
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os, bool tracking)
|
||||||
: EmitVBaseVisitorConst{false, nullptr}
|
: EmitVBaseVisitorConst{false, false}
|
||||||
, m_os(os) { // Need () or GCC 4.8 false warning
|
, m_os{os, V3OutFormatter::LA_VERILOG}
|
||||||
|
, m_tracking{tracking} {
|
||||||
iterateConst(const_cast<AstNode*>(nodep));
|
iterateConst(const_cast<AstNode*>(nodep));
|
||||||
}
|
}
|
||||||
~EmitVStreamVisitor() override = default;
|
~EmitVStreamVisitor() override = default;
|
||||||
|
|
@ -1018,7 +1026,7 @@ public:
|
||||||
// EmitV class functions
|
// EmitV class functions
|
||||||
|
|
||||||
void V3EmitV::verilogForTree(const AstNode* nodep, std::ostream& os) {
|
void V3EmitV::verilogForTree(const AstNode* nodep, std::ostream& os) {
|
||||||
{ EmitVStreamVisitor{nodep, os}; }
|
{ EmitVStreamVisitor{nodep, os, /* tracking: */ false}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3EmitV::emitvFiles() {
|
void V3EmitV::emitvFiles() {
|
||||||
|
|
@ -1028,9 +1036,8 @@ void V3EmitV::emitvFiles() {
|
||||||
AstVFile* const vfilep = VN_CAST(filep, VFile);
|
AstVFile* const vfilep = VN_CAST(filep, VFile);
|
||||||
if (vfilep && vfilep->tblockp()) {
|
if (vfilep && vfilep->tblockp()) {
|
||||||
V3OutVFile of{vfilep->name()};
|
V3OutVFile of{vfilep->name()};
|
||||||
of.puts("// DESCR"
|
of.puts("// DESCRIPTION: Verilator generated Verilog\n");
|
||||||
"IPTION: Verilator generated Verilog\n");
|
{ EmitVFileVisitor{vfilep->tblockp(), of, true, false}; }
|
||||||
{ EmitVFileVisitor{vfilep->tblockp(), &of, true, false}; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1038,5 +1045,5 @@ void V3EmitV::emitvFiles() {
|
||||||
void V3EmitV::debugEmitV(const string& filename) {
|
void V3EmitV::debugEmitV(const string& filename) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
V3OutVFile of{filename};
|
V3OutVFile of{filename};
|
||||||
{ EmitVFileVisitor{v3Global.rootp(), &of, true, true}; }
|
{ EmitVFileVisitor{v3Global.rootp(), of, true, true}; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -640,11 +640,10 @@ bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl)
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
// V3OutFormatter: A class for printing code with automatic indentation.
|
||||||
|
|
||||||
V3OutFormatter::V3OutFormatter(const string& filename, V3OutFormatter::Language lang)
|
V3OutFormatter::V3OutFormatter(V3OutFormatter::Language lang)
|
||||||
: m_filename{filename}
|
: m_lang{lang} {
|
||||||
, m_lang{lang} {
|
|
||||||
m_blockIndent = v3Global.opt.decoration() ? 4 : 1;
|
m_blockIndent = v3Global.opt.decoration() ? 4 : 1;
|
||||||
m_commaWidth = v3Global.opt.decoration() ? 50 : 150;
|
m_commaWidth = v3Global.opt.decoration() ? 50 : 150;
|
||||||
}
|
}
|
||||||
|
|
@ -962,7 +961,8 @@ void V3OutFormatter::printf(const char* fmt...) {
|
||||||
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
||||||
|
|
||||||
V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang)
|
V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang)
|
||||||
: V3OutFormatter{filename, lang}
|
: V3OutFormatter{lang}
|
||||||
|
, m_filename{filename}
|
||||||
, m_bufferp{new std::array<char, WRITE_BUFFER_SIZE_BYTES>{}} {
|
, m_bufferp{new std::array<char, WRITE_BUFFER_SIZE_BYTES>{}} {
|
||||||
if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) {
|
if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) {
|
||||||
v3fatal("Can't write file: " << filename);
|
v3fatal("Can't write file: " << filename);
|
||||||
|
|
@ -992,6 +992,13 @@ void V3OutCFile::putsGuard() {
|
||||||
puts("#define " + var + " // guard\n");
|
puts("#define " + var + " // guard\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// V3OutStream
|
||||||
|
|
||||||
|
V3OutStream::V3OutStream(std::ostream& ostream, V3OutFormatter::Language lang)
|
||||||
|
: V3OutFormatter{lang}
|
||||||
|
, m_ostream{ostream} {}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// VIdProtect
|
// VIdProtect
|
||||||
|
|
||||||
|
|
|
||||||
29
src/V3File.h
29
src/V3File.h
|
|
@ -102,7 +102,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// V3OutFormatter: A class for automatic indentation of C++ or Verilog code.
|
// V3OutFormatter: A class for automatic indentation of output code.
|
||||||
|
|
||||||
class V3OutFormatter VL_NOT_FINAL {
|
class V3OutFormatter VL_NOT_FINAL {
|
||||||
// TYPES
|
// TYPES
|
||||||
|
|
@ -113,7 +113,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
const string m_filename;
|
|
||||||
const Language m_lang; // Indenting Verilog code
|
const Language m_lang; // Indenting Verilog code
|
||||||
int m_blockIndent; // Characters per block indent
|
int m_blockIndent; // Characters per block indent
|
||||||
int m_commaWidth; // Width after which to break at ,'s
|
int m_commaWidth; // Width after which to break at ,'s
|
||||||
|
|
@ -132,10 +131,9 @@ private:
|
||||||
void putcNoTracking(char chr);
|
void putcNoTracking(char chr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
V3OutFormatter(const string& filename, Language lang);
|
V3OutFormatter(Language lang);
|
||||||
virtual ~V3OutFormatter() = default;
|
virtual ~V3OutFormatter() = default;
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
string filename() const { return m_filename; }
|
|
||||||
int column() const { return m_column; }
|
int column() const { return m_column; }
|
||||||
int blockIndent() const { return m_blockIndent; }
|
int blockIndent() const { return m_blockIndent; }
|
||||||
void blockIndent(int flag) { m_blockIndent = flag; }
|
void blockIndent(int flag) { m_blockIndent = flag; }
|
||||||
|
|
@ -165,7 +163,7 @@ public:
|
||||||
void indentInc() { m_indentLevel += m_blockIndent; }
|
void indentInc() { m_indentLevel += m_blockIndent; }
|
||||||
void indentDec() {
|
void indentDec() {
|
||||||
m_indentLevel -= m_blockIndent;
|
m_indentLevel -= m_blockIndent;
|
||||||
UASSERT(m_indentLevel >= 0, ": " << m_filename << ": Underflow of indentation");
|
UASSERT(m_indentLevel >= 0, "Underflow of indentation");
|
||||||
}
|
}
|
||||||
void blockInc() { m_parenVec.push(m_indentLevel + m_blockIndent); }
|
void blockInc() { m_parenVec.push(m_indentLevel + m_blockIndent); }
|
||||||
void blockDec() {
|
void blockDec() {
|
||||||
|
|
@ -201,6 +199,7 @@ class V3OutFile VL_NOT_FINAL : public V3OutFormatter {
|
||||||
static constexpr std::size_t WRITE_BUFFER_SIZE_BYTES = 128 * 1024;
|
static constexpr std::size_t WRITE_BUFFER_SIZE_BYTES = 128 * 1024;
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
|
const std::string m_filename;
|
||||||
FILE* m_fp = nullptr;
|
FILE* m_fp = nullptr;
|
||||||
std::size_t m_usedBytes = 0; // Number of bytes stored in m_bufferp
|
std::size_t m_usedBytes = 0; // Number of bytes stored in m_bufferp
|
||||||
std::size_t m_writtenBytes = 0; // Number of bytes written to output
|
std::size_t m_writtenBytes = 0; // Number of bytes written to output
|
||||||
|
|
@ -214,6 +213,8 @@ public:
|
||||||
V3OutFile& operator=(V3OutFile&&) = delete;
|
V3OutFile& operator=(V3OutFile&&) = delete;
|
||||||
~V3OutFile() override;
|
~V3OutFile() override;
|
||||||
|
|
||||||
|
std::string filename() const { return m_filename; }
|
||||||
|
|
||||||
void putsForceIncs();
|
void putsForceIncs();
|
||||||
|
|
||||||
void statRecordWritten() {
|
void statRecordWritten() {
|
||||||
|
|
@ -430,6 +431,24 @@ public:
|
||||||
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
|
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// V3OutStream: A class for printing formatted code to any std::ostream
|
||||||
|
|
||||||
|
class V3OutStream VL_NOT_FINAL : public V3OutFormatter {
|
||||||
|
// MEMBERS
|
||||||
|
std::ostream& m_ostream;
|
||||||
|
|
||||||
|
VL_UNCOPYABLE(V3OutStream);
|
||||||
|
VL_UNMOVABLE(V3OutStream);
|
||||||
|
|
||||||
|
public:
|
||||||
|
V3OutStream(std::ostream& ostream, V3OutFormatter::Language lang);
|
||||||
|
~V3OutStream() override = default;
|
||||||
|
|
||||||
|
void putcOutput(char chr) override { m_ostream << chr; };
|
||||||
|
void putsOutput(const char* str) override { m_ostream << str; };
|
||||||
|
};
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// VIdProtect: Hash identifier names in output files to protect them
|
// VIdProtect: Hash identifier names in output files to protect them
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue