Internals: Refactor common V3JsonFile. No functional change.
This commit is contained in:
parent
5d0fd8b9a7
commit
d22608a49f
|
|
@ -30,111 +30,6 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
// Emit statements
|
// Emit statements
|
||||||
|
|
||||||
class V3EmitMkJsonEmitter final {
|
class V3EmitMkJsonEmitter final {
|
||||||
class Printer final {
|
|
||||||
// MEMBERS
|
|
||||||
private:
|
|
||||||
const std::unique_ptr<std::ofstream>& m_of;
|
|
||||||
std::stack<char>
|
|
||||||
m_scope; // Stack of ']' and '}' to be used to close currently open scopes
|
|
||||||
std::string m_prefix; // Prefix emitted before each line in the current scope (indent *
|
|
||||||
// scope depth)
|
|
||||||
std::string m_indent; // Single indent
|
|
||||||
bool m_empty = true; // Indicates that the current scope is empty
|
|
||||||
|
|
||||||
// METHODS
|
|
||||||
public:
|
|
||||||
explicit Printer(const std::unique_ptr<std::ofstream>& of,
|
|
||||||
const std::string& indent = " ")
|
|
||||||
: m_of(of)
|
|
||||||
, m_indent(indent) {
|
|
||||||
begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Printer() { end(); }
|
|
||||||
|
|
||||||
Printer& begin(const std::string& name, char type = '{') {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << "\"" << name << "\": " << type << "\n";
|
|
||||||
m_prefix += m_indent;
|
|
||||||
m_scope.push(type == '{' ? '}' : ']');
|
|
||||||
m_empty = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& put(const std::string& name, const std::string& value) {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << "\"" << name << "\": \"" << value << "\"";
|
|
||||||
m_empty = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& put(const std::string& name, bool value) {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << "\"" << name << "\": " << (value ? "true" : "false");
|
|
||||||
m_empty = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& put(const std::string& name, int value) {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << "\"" << name << "\": " << value;
|
|
||||||
m_empty = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& begin(char type = '{') {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << type << "\n";
|
|
||||||
m_prefix += m_indent;
|
|
||||||
m_scope.push(type == '{' ? '}' : ']');
|
|
||||||
m_empty = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& put(const std::string& value) {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << "\"" << value << "\"";
|
|
||||||
m_empty = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& put(bool value) {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << (value ? "true" : "false");
|
|
||||||
m_empty = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& put(int value) {
|
|
||||||
if (!m_empty) *m_of << ",\n";
|
|
||||||
*m_of << m_prefix << value;
|
|
||||||
m_empty = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Printer& putList(const std::string& name, const T& list) {
|
|
||||||
if (list.empty()) return *this;
|
|
||||||
begin(name, '[');
|
|
||||||
for (auto it = list.begin(); it != list.end(); ++it) put(*it);
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& end() {
|
|
||||||
assert(m_prefix.length() >= m_indent.length());
|
|
||||||
m_prefix.erase(m_prefix.end() - m_indent.length(), m_prefix.end());
|
|
||||||
assert(!m_scope.empty());
|
|
||||||
*m_of << "\n" << m_prefix << m_scope.top();
|
|
||||||
m_scope.pop();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Printer& operator+=(Printer& cursor) {
|
|
||||||
// Meaningless syntax sugar, at least for now
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
// STATIC FUNCTIONS
|
// STATIC FUNCTIONS
|
||||||
|
|
@ -142,8 +37,7 @@ class V3EmitMkJsonEmitter final {
|
||||||
const std::string makeDir
|
const std::string makeDir
|
||||||
= V3Os::filenameSlashPath(V3Os::filenameRealPath(v3Global.opt.makeDir()));
|
= V3Os::filenameSlashPath(V3Os::filenameRealPath(v3Global.opt.makeDir()));
|
||||||
|
|
||||||
const std::unique_ptr<std::ofstream> of{
|
V3OutJsonFile of{makeDir + "/" + v3Global.opt.prefix() + ".json"};
|
||||||
V3File::new_ofstream(makeDir + "/" + v3Global.opt.prefix() + ".json")};
|
|
||||||
|
|
||||||
std::vector<string> classesFast;
|
std::vector<string> classesFast;
|
||||||
std::vector<string> classesSlow;
|
std::vector<string> classesSlow;
|
||||||
|
|
@ -188,41 +82,40 @@ class V3EmitMkJsonEmitter final {
|
||||||
for (const auto& cppFile : v3Global.opt.cppFiles())
|
for (const auto& cppFile : v3Global.opt.cppFiles())
|
||||||
cppFiles.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(cppFile)));
|
cppFiles.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(cppFile)));
|
||||||
|
|
||||||
Printer manifest(of);
|
of.put("version", 1)
|
||||||
Printer& cursor = manifest.put("version", 1)
|
.begin("system")
|
||||||
.begin("system")
|
.put("perl", V3Options::getenvPERL())
|
||||||
.put("perl", V3Options::getenvPERL())
|
.put("python3", V3Options::getenvPYTHON3())
|
||||||
.put("python3", V3Options::getenvPYTHON3())
|
.put("verilator_root", verilatorRoot)
|
||||||
.put("verilator_root", verilatorRoot)
|
.put("verilator_solver", V3Options::getenvVERILATOR_SOLVER())
|
||||||
.put("verilator_solver", V3Options::getenvVERILATOR_SOLVER())
|
.end()
|
||||||
.end()
|
.begin("options")
|
||||||
.begin("options")
|
.putList("cflags", v3Global.opt.cFlags())
|
||||||
.putList("cflags", v3Global.opt.cFlags())
|
.putList("ldflags", v3Global.opt.ldLibs())
|
||||||
.putList("ldflags", v3Global.opt.ldLibs())
|
.put("system_c", v3Global.opt.systemC())
|
||||||
.put("system_c", v3Global.opt.systemC())
|
.put("coverage", v3Global.opt.coverage())
|
||||||
.put("coverage", v3Global.opt.coverage())
|
.put("use_timing", v3Global.usesTiming())
|
||||||
.put("use_timing", v3Global.usesTiming())
|
.put("threads", v3Global.opt.threads())
|
||||||
.put("threads", v3Global.opt.threads())
|
.put("trace", v3Global.opt.trace())
|
||||||
.put("trace", v3Global.opt.trace())
|
.put("trace_fst", v3Global.opt.traceEnabledFst())
|
||||||
.put("trace_fst", v3Global.opt.traceEnabledFst())
|
.put("trace_saif", v3Global.opt.traceEnabledSaif())
|
||||||
.put("trace_saif", v3Global.opt.traceEnabledSaif())
|
.put("trace_vcd", v3Global.opt.traceEnabledVcd())
|
||||||
.put("trace_vcd", v3Global.opt.traceEnabledVcd())
|
.end()
|
||||||
.end()
|
.begin("sources")
|
||||||
.begin("sources")
|
.putList("global", global)
|
||||||
.putList("global", global)
|
.putList("classes_slow", classesSlow)
|
||||||
.putList("classes_slow", classesSlow)
|
.putList("classes_fast", classesFast)
|
||||||
.putList("classes_fast", classesFast)
|
.putList("support_slow", supportSlow)
|
||||||
.putList("support_slow", supportSlow)
|
.putList("support_fast", supportFast)
|
||||||
.putList("support_fast", supportFast)
|
.putList("deps", deps)
|
||||||
.putList("deps", deps)
|
.putList("user_classes", cppFiles)
|
||||||
.putList("user_classes", cppFiles)
|
.end();
|
||||||
.end();
|
|
||||||
|
|
||||||
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
|
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
|
||||||
// Sorted hierarchical blocks in order of leaf-first.
|
// Sorted hierarchical blocks in order of leaf-first.
|
||||||
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
||||||
|
|
||||||
cursor += cursor.begin("submodules", '[');
|
of.begin("submodules", '[');
|
||||||
|
|
||||||
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
|
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
|
||||||
it != hierBlocks.end(); ++it) {
|
it != hierBlocks.end(); ++it) {
|
||||||
|
|
@ -247,17 +140,16 @@ class V3EmitMkJsonEmitter final {
|
||||||
std::vector<std::string> cflags;
|
std::vector<std::string> cflags;
|
||||||
cflags.emplace_back("-fPIC");
|
cflags.emplace_back("-fPIC");
|
||||||
|
|
||||||
cursor += cursor.begin()
|
of.begin()
|
||||||
.put("prefix", hblockp->hierPrefix())
|
.put("prefix", hblockp->hierPrefix())
|
||||||
.put("top", hblockp->modp()->name())
|
.put("top", hblockp->modp()->name())
|
||||||
.putList("deps", childDeps)
|
.putList("deps", childDeps)
|
||||||
.put("directory", makeDir + "/" + hblockp->hierPrefix())
|
.put("directory", makeDir + "/" + hblockp->hierPrefix())
|
||||||
.putList("sources", sources)
|
.putList("sources", sources)
|
||||||
.putList("cflags", cflags)
|
.putList("cflags", cflags)
|
||||||
.put("verilator_args",
|
.put("verilator_args", V3Os::filenameSlashPath(V3Os::filenameRealPath(
|
||||||
V3Os::filenameSlashPath(
|
hblockp->commandArgsFilename(true))))
|
||||||
V3Os::filenameRealPath(hblockp->commandArgsFilename(true))))
|
.end();
|
||||||
.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> sources;
|
std::vector<std::string> sources;
|
||||||
|
|
@ -268,15 +160,15 @@ class V3EmitMkJsonEmitter final {
|
||||||
for (const string& i : vFiles)
|
for (const string& i : vFiles)
|
||||||
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i)));
|
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i)));
|
||||||
|
|
||||||
cursor += cursor.begin()
|
of.begin()
|
||||||
.put("prefix", v3Global.opt.prefix())
|
.put("prefix", v3Global.opt.prefix())
|
||||||
.put("top", v3Global.rootp()->topModulep()->name())
|
.put("top", v3Global.rootp()->topModulep()->name())
|
||||||
.put("directory", makeDir)
|
.put("directory", makeDir)
|
||||||
.putList("sources", sources)
|
.putList("sources", sources)
|
||||||
.put("verilator_args", V3Os::filenameSlashPath(V3Os::filenameRealPath(
|
.put("verilator_args", V3Os::filenameSlashPath(V3Os::filenameRealPath(
|
||||||
planp->topCommandArgsFilename(true))))
|
planp->topCommandArgsFilename(true))))
|
||||||
.end()
|
.end()
|
||||||
.end();
|
.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
131
src/V3File.h
131
src/V3File.h
|
|
@ -109,12 +109,7 @@ class V3OutFormatter VL_NOT_FINAL {
|
||||||
static constexpr int MAXSPACE = 80; // After this indent, stop indenting more
|
static constexpr int MAXSPACE = 80; // After this indent, stop indenting more
|
||||||
public:
|
public:
|
||||||
enum AlignClass : uint8_t { AL_AUTO = 0, AL_STATIC = 1 };
|
enum AlignClass : uint8_t { AL_AUTO = 0, AL_STATIC = 1 };
|
||||||
enum Language : uint8_t {
|
enum Language : uint8_t { LA_C, LA_JSON, LA_MK, LA_VERILOG, LA_XML };
|
||||||
LA_C = 0,
|
|
||||||
LA_VERILOG = 1,
|
|
||||||
LA_MK = 2,
|
|
||||||
LA_XML = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
|
|
@ -286,6 +281,119 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class V3OutJsonFile final : public V3OutFile {
|
||||||
|
// CONSTANTS
|
||||||
|
static constexpr const char* INDENT = " "; // Single indent (4, per JSON std)
|
||||||
|
|
||||||
|
// MEMBERS
|
||||||
|
private:
|
||||||
|
std::stack<char> m_scope; // Stack of ']' and '}' to close currently open scopes
|
||||||
|
std::string m_prefix; // Prefix emitted before each line in current scope
|
||||||
|
bool m_empty = true; // Current scope is empty, no comma later
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit V3OutJsonFile(const string& filename)
|
||||||
|
: V3OutFile{filename, V3OutFormatter::LA_JSON} {
|
||||||
|
begin();
|
||||||
|
}
|
||||||
|
~V3OutJsonFile() override { end(); }
|
||||||
|
virtual void putsHeader() {}
|
||||||
|
void puts(const char* strg) { putsNoTracking(strg); }
|
||||||
|
void puts(const string& strg) { putsNoTracking(strg); }
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
V3OutJsonFile& begin(const std::string& name, char type = '{') {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + "\"" + name + "\": " + type + "\n");
|
||||||
|
m_prefix += INDENT;
|
||||||
|
m_scope.push(type == '{' ? '}' : ']');
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V3OutJsonFile& begin(char type = '{') {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + type + "\n");
|
||||||
|
m_prefix += INDENT;
|
||||||
|
m_scope.push(type == '{' ? '}' : ']');
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
V3OutJsonFile& put(const std::string& name, const std::string& value) {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + "\"" + name + "\": \"" + value + "\"");
|
||||||
|
m_empty = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V3OutJsonFile& put(const std::string& name, bool value) {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + "\"" + name + "\": " + (value ? "true" : "false"));
|
||||||
|
m_empty = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V3OutJsonFile& put(const std::string& name, int value) {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + "\"" + name + "\": " + std::to_string(value));
|
||||||
|
m_empty = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V3OutJsonFile& put(const std::string& value) {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + "\"" + value + "\"");
|
||||||
|
m_empty = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V3OutJsonFile& put(bool value) {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + (value ? "true" : "false"));
|
||||||
|
m_empty = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V3OutJsonFile& put(int value) {
|
||||||
|
comma();
|
||||||
|
puts(m_prefix + std::to_string(value));
|
||||||
|
m_empty = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
V3OutJsonFile& putList(const std::string& name, const T& list) {
|
||||||
|
if (list.empty()) return *this;
|
||||||
|
begin(name, '[');
|
||||||
|
for (auto it = list.begin(); it != list.end(); ++it) put(*it);
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
V3OutJsonFile& end() {
|
||||||
|
assert(m_prefix.length() >= strlen(INDENT));
|
||||||
|
m_prefix.erase(m_prefix.end() - strlen(INDENT), m_prefix.end());
|
||||||
|
assert(!m_scope.empty());
|
||||||
|
puts("\n" + m_prefix + m_scope.top());
|
||||||
|
m_scope.pop();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
V3OutJsonFile& operator+=(V3OutJsonFile& cursor) {
|
||||||
|
// Meaningless syntax sugar, at least for now
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void comma() {
|
||||||
|
if (!m_empty) puts(",\n");
|
||||||
|
m_empty = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class V3OutMkFile final : public V3OutFile {
|
||||||
|
public:
|
||||||
|
explicit V3OutMkFile(const string& filename)
|
||||||
|
: V3OutFile{filename, V3OutFormatter::LA_MK} {}
|
||||||
|
~V3OutMkFile() override = default;
|
||||||
|
virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); }
|
||||||
|
// No automatic indentation yet.
|
||||||
|
void puts(const char* strg) { putsNoTracking(strg); }
|
||||||
|
void puts(const string& strg) { putsNoTracking(strg); }
|
||||||
|
};
|
||||||
|
|
||||||
class V3OutScFile final : public V3OutCFile {
|
class V3OutScFile final : public V3OutCFile {
|
||||||
public:
|
public:
|
||||||
explicit V3OutScFile(const string& filename)
|
explicit V3OutScFile(const string& filename)
|
||||||
|
|
@ -317,17 +425,6 @@ public:
|
||||||
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
|
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class V3OutMkFile final : public V3OutFile {
|
|
||||||
public:
|
|
||||||
explicit V3OutMkFile(const string& filename)
|
|
||||||
: V3OutFile{filename, V3OutFormatter::LA_MK} {}
|
|
||||||
~V3OutMkFile() override = default;
|
|
||||||
virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); }
|
|
||||||
// No automatic indentation yet.
|
|
||||||
void puts(const char* strg) { putsNoTracking(strg); }
|
|
||||||
void puts(const string& strg) { putsNoTracking(strg); }
|
|
||||||
};
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// 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