Skip to content

Commit

Permalink
fmt: rename TIME to VLOG_TIME.
Browse files Browse the repository at this point in the history
The behavior of these format specifiers is highly specific to Verilog
(`$time` and `$realtime` are only defined relative to `$timescale`)
and may not fit other languages well, if at all. If they choose to use
it, it is now clear what they are opting into.

This commit also simplifies the CXXRTL code generation for these format
specifiers.
  • Loading branch information
whitequark committed Jan 19, 2024
1 parent 08d7f54 commit b74d33d
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 33 deletions.
8 changes: 4 additions & 4 deletions backends/cxxrtl/cxxrtl_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1072,21 +1072,21 @@ struct CxxrtlWorker {
dump_sigspec_rhs(cell->getPort(ID::EN));
f << " == value<1>{1u}) {\n";
inc_indent();
f << indent << "auto formatter = [&](int64_t itime, double ftime) {\n";
f << indent << "auto formatter = [&](struct performer *performer) {\n";
inc_indent();
fmt.emit_cxxrtl(f, indent, [this](const RTLIL::SigSpec &sig) { dump_sigspec_rhs(sig); });
fmt.emit_cxxrtl(f, indent, [this](const RTLIL::SigSpec &sig) { dump_sigspec_rhs(sig); }, "performer");
dec_indent();
f << indent << "};\n";
f << indent << "if (performer) {\n";
inc_indent();
f << indent << "static const metadata_map attributes = ";
dump_metadata_map(cell->attributes);
f << ";\n";
f << indent << "performer->on_print(formatter(performer->time(), performer->realtime()), attributes);\n";
f << indent << "performer->on_print(formatter(performer), attributes);\n";
dec_indent();
f << indent << "} else {\n";
inc_indent();
f << indent << print_output << " << formatter(0, 0.0);\n";
f << indent << print_output << " << formatter(performer);\n";
dec_indent();
f << indent << "}\n";
dec_indent();
Expand Down
26 changes: 15 additions & 11 deletions backends/cxxrtl/runtime/cxxrtl/cxxrtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -948,10 +948,10 @@ typedef std::map<std::string, metadata> metadata_map;
// An object that can be passed to a `eval()` method in order to act on side effects.
struct performer {
// Called to evaluate a Verilog `$time` expression.
virtual int64_t time() const { return 0; }
virtual int64_t vlog_time() const { return 0; }

// Called to evaluate a Verilog `$realtime` expression.
virtual double realtime() const { return time(); }
virtual double vlog_realtime() const { return vlog_time(); }

// Called when a `$print` cell is triggered.
virtual void on_print(const std::string &output, const metadata_map &attributes) { std::cout << output; }
Expand All @@ -976,10 +976,10 @@ struct observer {
// Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
struct fmt_part {
enum {
STRING = 0,
INTEGER = 1,
STRING = 0,
INTEGER = 1,
CHARACTER = 2,
TIME = 3,
VLOG_TIME = 3,
} type;

// STRING type
Expand All @@ -988,7 +988,7 @@ struct fmt_part {
// INTEGER/CHARACTER types
// + value<Bits> val;

// INTEGER/CHARACTER/TIME types
// INTEGER/CHARACTER/VLOG_TIME types
enum {
RIGHT = 0,
LEFT = 1,
Expand All @@ -1001,16 +1001,16 @@ struct fmt_part {
bool signed_; // = false;
bool plus; // = false;

// TIME type
// VLOG_TIME type
bool realtime; // = false;
// + int64_t itime;
// + double ftime;

// Format the part as a string.
//
// The values of `itime` and `ftime` are used for `$time` and `$realtime`, correspondingly.
// The values of `vlog_time` and `vlog_realtime` are used for Verilog `$time` and `$realtime`, correspondingly.
template<size_t Bits>
std::string render(value<Bits> val, int64_t itime, double ftime)
std::string render(value<Bits> val, performer *performer = nullptr)
{
// We might want to replace some of these bit() calls with direct
// chunk access if it turns out to be slow enough to matter.
Expand Down Expand Up @@ -1077,8 +1077,12 @@ struct fmt_part {
break;
}

case TIME: {
buf = realtime ? std::to_string(ftime) : std::to_string(itime);
case VLOG_TIME: {
if (performer) {
buf = realtime ? std::to_string(performer->vlog_realtime()) : std::to_string(performer->vlog_time());
} else {
buf = realtime ? std::to_string(0.0) : std::to_string(0);
}
break;
}
}
Expand Down
26 changes: 13 additions & 13 deletions kernel/fmt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
} else if (fmt[i] == 'c') {
part.type = FmtPart::CHARACTER;
} else if (fmt[i] == 't') {
part.type = FmtPart::TIME;
part.type = FmtPart::VLOG_TIME;
} else if (fmt[i] == 'r') {
part.type = FmtPart::TIME;
part.type = FmtPart::VLOG_TIME;
part.realtime = true;
} else {
log_assert(false && "Unexpected character in format substitution");
Expand Down Expand Up @@ -172,7 +172,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
}
break;

case FmtPart::TIME:
case FmtPart::VLOG_TIME:
log_assert(part.sig.size() == 0);
YS_FALLTHROUGH
case FmtPart::CHARACTER:
Expand Down Expand Up @@ -205,7 +205,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
fmt += part.signed_ ? 's' : 'u';
} else if (part.type == FmtPart::CHARACTER) {
fmt += 'c';
} else if (part.type == FmtPart::TIME) {
} else if (part.type == FmtPart::VLOG_TIME) {
if (part.realtime)
fmt += 'r';
else
Expand Down Expand Up @@ -328,7 +328,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik

case VerilogFmtArg::TIME: {
FmtPart part = {};
part.type = FmtPart::TIME;
part.type = FmtPart::VLOG_TIME;
part.realtime = arg->realtime;
part.padding = ' ';
part.width = 20;
Expand Down Expand Up @@ -419,7 +419,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
part.padding = ' ';
} else if (fmt[i] == 't' || fmt[i] == 'T') {
if (arg->type == VerilogFmtArg::TIME) {
part.type = FmtPart::TIME;
part.type = FmtPart::VLOG_TIME;
part.realtime = arg->realtime;
if (!has_width && !has_leading_zero)
part.width = 20;
Expand Down Expand Up @@ -541,7 +541,7 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
break;
}

case FmtPart::TIME: {
case FmtPart::VLOG_TIME: {
VerilogFmtArg arg;
arg.type = VerilogFmtArg::TIME;
if (part.realtime)
Expand Down Expand Up @@ -592,7 +592,7 @@ std::string escape_cxx_string(const std::string &input)
return output;
}

void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(const RTLIL::SigSpec &)> emit_sig) const
void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(const RTLIL::SigSpec &)> emit_sig, const std::string &context) const
{
os << indent << "std::string buf;\n";
for (auto &part : parts) {
Expand All @@ -602,7 +602,7 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
case FmtPart::STRING: os << "STRING"; break;
case FmtPart::INTEGER: os << "INTEGER"; break;
case FmtPart::CHARACTER: os << "CHARACTER"; break;
case FmtPart::TIME: os << "TIME"; break;
case FmtPart::VLOG_TIME: os << "VLOG_TIME"; break;
}
os << ", ";
os << escape_cxx_string(part.str) << ", ";
Expand All @@ -620,7 +620,7 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
os << part.realtime;
os << " }.render(";
emit_sig(part.sig);
os << ", itime, ftime);\n";
os << ", " << context << ");\n";
}
os << indent << "return buf;\n";
}
Expand All @@ -636,8 +636,8 @@ std::string Fmt::render() const
break;

case FmtPart::INTEGER:
case FmtPart::TIME:
case FmtPart::CHARACTER: {
case FmtPart::CHARACTER:
case FmtPart::VLOG_TIME: {
std::string buf;
if (part.type == FmtPart::INTEGER) {
RTLIL::Const value = part.sig.as_const();
Expand Down Expand Up @@ -720,7 +720,7 @@ std::string Fmt::render() const
} else log_abort();
} else if (part.type == FmtPart::CHARACTER) {
buf = part.sig.as_const().decode_string();
} else if (part.type == FmtPart::TIME) {
} else if (part.type == FmtPart::VLOG_TIME) {
// We only render() during initial, so time is always zero.
buf = "0";
}
Expand Down
8 changes: 4 additions & 4 deletions kernel/fmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct FmtPart {
STRING = 0,
INTEGER = 1,
CHARACTER = 2,
TIME = 3,
VLOG_TIME = 3,
} type;

// STRING type
Expand All @@ -65,7 +65,7 @@ struct FmtPart {
// INTEGER/CHARACTER types
RTLIL::SigSpec sig;

// INTEGER/CHARACTER/TIME types
// INTEGER/CHARACTER/VLOG_TIME types
enum {
RIGHT = 0,
LEFT = 1,
Expand All @@ -78,7 +78,7 @@ struct FmtPart {
bool signed_ = false;
bool plus = false;

// TIME type
// VLOG_TIME type
bool realtime = false;
};

Expand All @@ -94,7 +94,7 @@ struct Fmt {
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 &os, std::string indent, 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 &context) const;

std::string render() const;

Expand Down
2 changes: 1 addition & 1 deletion tests/fmt/always_full_tb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
int main()
{
struct : public performer {
int64_t time() const override { return 1; }
int64_t vlog_time() const override { return 1; }
void on_print(const std::string &output, const cxxrtl::metadata_map &) override { std::cerr << output; }
} performer;

Expand Down

0 comments on commit b74d33d

Please sign in to comment.