mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
cxxrtl: refactor the formatter and use a closure.
This commit achieves three roughly equally important goals: 1. To bring the rendering code in kernel/fmt.cc and in cxxrtl.h as close together as possible, with an ideal of only having the bigint library as the difference between the render functions. 2. To make the treatment of `$time` and `$realtime` in CXXRTL closer to the Verilog semantics, at least in the formatting code. 3. To change the code generator so that all of the `$print`-to-`string` conversion code is contained inside of a closure. There are two reasons to aim for goal (3): a. Because output redirection through definition of a global ostream object is neither convenient nor useful for environments where the output is consumed by other code rather than being printed on a terminal. b. Because it may be desirable to, in some cases, ignore the `$print` cells that are present in the netlist based on a runtime decision. This is doubly true for an upcoming `$check` cell implementing assertions, since failing a `$check` would by default cause a crash.
This commit is contained in:
parent
bf1a99da09
commit
a33acb7cd9
5 changed files with 192 additions and 173 deletions
124
kernel/fmt.cc
124
kernel/fmt.cc
|
@ -569,82 +569,60 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
|||
return args;
|
||||
}
|
||||
|
||||
void Fmt::emit_cxxrtl(std::ostream &f, std::function<void(const RTLIL::SigSpec &)> emit_sig) const
|
||||
std::string escape_cxx_string(const std::string &input)
|
||||
{
|
||||
for (auto &part : parts) {
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING:
|
||||
f << " << \"";
|
||||
for (char c : part.str) {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
YS_FALLTHROUGH
|
||||
case '"':
|
||||
f << '\\' << c;
|
||||
break;
|
||||
case '\a':
|
||||
f << "\\a";
|
||||
break;
|
||||
case '\b':
|
||||
f << "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
f << "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
f << "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
f << "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
f << "\\t";
|
||||
break;
|
||||
case '\v':
|
||||
f << "\\v";
|
||||
break;
|
||||
default:
|
||||
f << c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
f << '"';
|
||||
break;
|
||||
|
||||
case FmtPart::INTEGER:
|
||||
case FmtPart::CHARACTER: {
|
||||
f << " << value_formatted<" << part.sig.size() << ">(";
|
||||
emit_sig(part.sig);
|
||||
f << ", " << (part.type == FmtPart::CHARACTER);
|
||||
f << ", " << (part.justify == FmtPart::LEFT);
|
||||
f << ", (char)" << (int)part.padding;
|
||||
f << ", " << part.width;
|
||||
f << ", " << part.base;
|
||||
f << ", " << part.signed_;
|
||||
f << ", " << part.plus;
|
||||
f << ')';
|
||||
break;
|
||||
}
|
||||
|
||||
case FmtPart::TIME: {
|
||||
// CXXRTL only records steps taken, so there's no difference between
|
||||
// the values taken by $time and $realtime.
|
||||
f << " << value_formatted<64>(";
|
||||
f << "value<64>{steps}";
|
||||
f << ", " << (part.type == FmtPart::CHARACTER);
|
||||
f << ", " << (part.justify == FmtPart::LEFT);
|
||||
f << ", (char)" << (int)part.padding;
|
||||
f << ", " << part.width;
|
||||
f << ", " << part.base;
|
||||
f << ", " << part.signed_;
|
||||
f << ", " << part.plus;
|
||||
f << ')';
|
||||
break;
|
||||
}
|
||||
|
||||
default: log_abort();
|
||||
std::string output = "\"";
|
||||
for (auto c : input) {
|
||||
if (::isprint(c)) {
|
||||
if (c == '\\')
|
||||
output.push_back('\\');
|
||||
output.push_back(c);
|
||||
} else {
|
||||
char l = c & 0xf, h = (c >> 4) & 0xf;
|
||||
output.append("\\x");
|
||||
output.push_back((h < 10 ? '0' + h : 'a' + h - 10));
|
||||
output.push_back((l < 10 ? '0' + l : 'a' + l - 10));
|
||||
}
|
||||
}
|
||||
output.push_back('"');
|
||||
if (output.find('\0') != std::string::npos) {
|
||||
output.insert(0, "std::string {");
|
||||
output.append(stringf(", %zu}", input.size()));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(const RTLIL::SigSpec &)> emit_sig) const
|
||||
{
|
||||
os << indent << "std::string buf;\n";
|
||||
for (auto &part : parts) {
|
||||
os << indent << "buf += fmt_part { ";
|
||||
os << "fmt_part::";
|
||||
switch (part.type) {
|
||||
case FmtPart::STRING: os << "STRING"; break;
|
||||
case FmtPart::INTEGER: os << "INTEGER"; break;
|
||||
case FmtPart::CHARACTER: os << "CHARACTER"; break;
|
||||
case FmtPart::TIME: os << "TIME"; break;
|
||||
}
|
||||
os << ", ";
|
||||
os << escape_cxx_string(part.str) << ", ";
|
||||
os << "fmt_part::";
|
||||
switch (part.justify) {
|
||||
case FmtPart::LEFT: os << "LEFT"; break;
|
||||
case FmtPart::RIGHT: os << "RIGHT"; break;
|
||||
}
|
||||
os << ", ";
|
||||
os << "(char)" << (int)part.padding << ", ";
|
||||
os << part.width << ", ";
|
||||
os << part.base << ", ";
|
||||
os << part.signed_ << ", ";
|
||||
os << part.plus << ", ";
|
||||
os << part.realtime;
|
||||
os << " }.render(";
|
||||
emit_sig(part.sig);
|
||||
os << ", itime, ftime);\n";
|
||||
}
|
||||
os << indent << "return buf;\n";
|
||||
}
|
||||
|
||||
std::string Fmt::render() const
|
||||
|
|
|
@ -50,6 +50,7 @@ struct VerilogFmtArg {
|
|||
|
||||
// RTLIL format part, such as the substitutions in:
|
||||
// "foo {4:> 4du} bar {2:<01hs}"
|
||||
// Must be kept in sync with `struct fmt_part` in backends/cxxrtl/runtime/cxxrtl/cxxrtl.h!
|
||||
struct FmtPart {
|
||||
enum {
|
||||
STRING = 0,
|
||||
|
@ -71,7 +72,7 @@ struct FmtPart {
|
|||
} justify = RIGHT;
|
||||
char padding = '\0';
|
||||
size_t width = 0;
|
||||
|
||||
|
||||
// INTEGER type
|
||||
unsigned base = 10;
|
||||
bool signed_ = false;
|
||||
|
@ -93,7 +94,7 @@ public:
|
|||
void parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_like, int default_base, RTLIL::IdString task_name, RTLIL::IdString module_name);
|
||||
std::vector<VerilogFmtArg> emit_verilog() const;
|
||||
|
||||
void emit_cxxrtl(std::ostream &f, std::function<void(const RTLIL::SigSpec &)> emit_sig) const;
|
||||
void emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(const RTLIL::SigSpec &)> emit_sig) const;
|
||||
|
||||
std::string render() const;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue