fmt: %t/$time support

This commit is contained in:
Charlotte 2023-06-28 11:51:20 +10:00 committed by Marcelina Kościelnicka
parent 52dc397a50
commit c382d7d3ac
7 changed files with 133 additions and 26 deletions

View File

@ -1330,7 +1330,10 @@ struct module {
virtual bool eval() = 0; virtual bool eval() = 0;
virtual bool commit() = 0; virtual bool commit() = 0;
unsigned int steps = 0;
size_t step() { size_t step() {
++steps;
size_t deltas = 0; size_t deltas = 0;
bool converged = false; bool converged = false;
do { do {

View File

@ -1797,6 +1797,12 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
dump_sigspec(f, arg.sig); dump_sigspec(f, arg.sig);
f << ")"; f << ")";
break; break;
case VerilogFmtArg::TIME:
if (arg.realtime)
f << "$realtime";
else
f << "$time";
break;
default: log_abort(); default: log_abort();
} }
} }

View File

@ -748,6 +748,11 @@ struct AST_INTERNAL::ProcessGenerator
// and in case this will be used as an argument... // and in case this will be used as an argument...
arg.sig = node->bitsAsConst(); arg.sig = node->bitsAsConst();
arg.signed_ = false; arg.signed_ = false;
} else if (node->type == AST_IDENTIFIER && node->str == "$time") {
arg.type = VerilogFmtArg::TIME;
} else if (node->type == AST_IDENTIFIER && node->str == "$realtime") {
arg.type = VerilogFmtArg::TIME;
arg.realtime = true;
} else { } else {
arg.type = VerilogFmtArg::INTEGER; arg.type = VerilogFmtArg::INTEGER;
arg.sig = node->genRTLIL(); arg.sig = node->genRTLIL();

View File

@ -386,7 +386,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
supply0 { return TOK_SUPPLY0; } supply0 { return TOK_SUPPLY0; }
supply1 { return TOK_SUPPLY1; } supply1 { return TOK_SUPPLY1; }
"$"(display[bho]?|write[bho]?|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { "$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
yylval->string = new std::string(yytext); yylval->string = new std::string(yytext);
return TOK_ID; return TOK_ID;
} }

View File

@ -51,8 +51,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
part = {}; part = {};
} }
if (++i == fmt.size())
log_assert(false && "Unexpected end in format substitution");
size_t arg_size = 0; size_t arg_size = 0;
for (++i; i < fmt.size(); i++) { for (; i < fmt.size(); i++) {
if (fmt[i] >= '0' && fmt[i] <= '9') { if (fmt[i] >= '0' && fmt[i] <= '9') {
arg_size *= 10; arg_size *= 10;
arg_size += fmt[i] - '0'; arg_size += fmt[i] - '0';
@ -106,6 +109,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
part.base = 16; part.base = 16;
} else if (fmt[i] == 'c') { } else if (fmt[i] == 'c') {
part.type = FmtPart::CHARACTER; part.type = FmtPart::CHARACTER;
} else if (fmt[i] == 't') {
part.type = FmtPart::TIME;
} else if (fmt[i] == 'r') {
part.type = FmtPart::TIME;
part.realtime = true;
} else { } else {
log_assert(false && "Unexpected character in format substitution"); log_assert(false && "Unexpected character in format substitution");
} }
@ -170,6 +178,9 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
} }
break; break;
case FmtPart::TIME:
log_assert(part.sig.size() == 0);
YS_FALLTHROUGH
case FmtPart::CHARACTER: case FmtPart::CHARACTER:
log_assert(part.sig.size() % 8 == 0); log_assert(part.sig.size() % 8 == 0);
YS_FALLTHROUGH YS_FALLTHROUGH
@ -202,6 +213,11 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
fmt += part.signed_ ? 's' : 'u'; fmt += part.signed_ ? 's' : 'u';
} else if (part.type == FmtPart::CHARACTER) { } else if (part.type == FmtPart::CHARACTER) {
fmt += 'c'; fmt += 'c';
} else if (part.type == FmtPart::TIME) {
if (part.realtime)
fmt += 'r';
else
fmt += 't';
} else log_abort(); } else log_abort();
fmt += '}'; fmt += '}';
break; break;
@ -339,6 +355,15 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
part.sig.extend_u0((part.sig.size() + 7) / 8 * 8); part.sig.extend_u0((part.sig.size() + 7) / 8 * 8);
// %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog // %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog
part.padding = ' '; part.padding = ' ';
} else if (fmt[i] == 't' || fmt[i] == 'T') {
if (arg->type == VerilogFmtArg::TIME) {
part.type = FmtPart::TIME;
part.realtime = arg->realtime;
if (!has_width && !has_leading_zero)
part.width = 20;
} else {
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1);
}
} else { } else {
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1); log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1);
} }
@ -458,6 +483,28 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
} }
break; break;
} }
case FmtPart::TIME: {
VerilogFmtArg arg;
arg.type = VerilogFmtArg::TIME;
if (part.realtime)
arg.realtime = true;
args.push_back(arg);
fmt.str += '%';
if (part.plus)
fmt.str += '+';
if (part.justify == FmtPart::LEFT)
fmt.str += '-';
log_assert(part.padding == ' ' || part.padding == '0');
if (part.padding == '0' && part.width > 0)
fmt.str += '0';
fmt.str += std::to_string(part.width);
fmt.str += 't';
break;
}
default: log_abort();
} }
} }
@ -522,6 +569,25 @@ void Fmt::emit_cxxrtl(std::ostream &f, std::function<void(const RTLIL::SigSpec &
f << ')'; f << ')';
break; 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.lzero;
f << ", " << part.plus;
f << ')';
break;
}
default: log_abort();
} }
} }
} }
@ -636,6 +702,12 @@ std::string Fmt::render() const
str += std::string(part.width - buf.size(), part.padding); str += std::string(part.width - buf.size(), part.padding);
break; break;
} }
case FmtPart::TIME: {
// We only render() during initial, so time is always zero.
str += "0";
break;
}
} }
} }

View File

@ -30,6 +30,7 @@ struct VerilogFmtArg {
enum { enum {
STRING = 0, STRING = 0,
INTEGER = 1, INTEGER = 1,
TIME = 2,
} type; } type;
// All types // All types
@ -42,6 +43,9 @@ struct VerilogFmtArg {
// INTEGER type // INTEGER type
RTLIL::SigSpec sig; RTLIL::SigSpec sig;
bool signed_ = false; bool signed_ = false;
// TIME type
bool realtime = false;
}; };
// RTLIL format part, such as the substitutions in: // RTLIL format part, such as the substitutions in:
@ -51,24 +55,31 @@ struct FmtPart {
STRING = 0, STRING = 0,
INTEGER = 1, INTEGER = 1,
CHARACTER = 2, CHARACTER = 2,
TIME = 3,
} type; } type;
// STRING type // STRING type
std::string str; std::string str;
// INTEGER/CHARACTER type // INTEGER/CHARACTER types
RTLIL::SigSpec sig; RTLIL::SigSpec sig;
// INTEGER/CHARACTER/TIME types
enum { enum {
RIGHT = 0, RIGHT = 0,
LEFT = 1, LEFT = 1,
} justify = RIGHT; } justify = RIGHT;
char padding = '\0'; char padding = '\0';
size_t width = 0; size_t width = 0;
// INTEGER type // INTEGER type
unsigned base = 10; unsigned base = 10;
bool signed_ = false; bool signed_ = false;
bool lzero = false; bool lzero = false;
bool plus = false; bool plus = false;
// TIME type
bool realtime = false;
}; };
struct Fmt { struct Fmt {

View File

@ -202,34 +202,44 @@ module always_full(input clk, output reg fin);
if (counter == 176) $display(":%020b:", 16'shaaaa); if (counter == 176) $display(":%020b:", 16'shaaaa);
if (counter == 177) $display(":%-020b:", 16'shaaaa); if (counter == 177) $display(":%-020b:", 16'shaaaa);
if (counter == 178) $display("===> %%s"); if (counter == 178) $display("==> time %%t");
if (counter == 179) $display(":%10s:", "foo"); if (counter == 179) $display(":%t:", $time);
if (counter == 180) $display(":%010s:", "foo"); if (counter == 180) $display(":%-t:", $time);
if (counter == 181) $display(":%-10s:", "foo"); if (counter == 181) $display(":%0t:", $time);
if (counter == 182) $display(":%-010s:", "foo"); if (counter == 182) $display(":%-0t:", $time);
if (counter == 183) $display(":%10t:", $time);
if (counter == 184) $display(":%-10t:", $time);
if (counter == 185) $display(":%015t:", $time);
if (counter == 186) $display(":%-015t:", $time);
if (counter == 183) $display("===> %%c"); if (counter == 187) $display("===> %%s");
if (counter == 184) $display(":%10c:", "foo"); if (counter == 188) $display(":%10s:", "foo");
if (counter == 185) $display(":%010c:", "foo"); if (counter == 189) $display(":%010s:", "foo");
if (counter == 186) $display(":%-10c:", "foo"); if (counter == 190) $display(":%-10s:", "foo");
if (counter == 187) $display(":%-010c:", "foo"); if (counter == 191) $display(":%-010s:", "foo");
if (counter == 188) $display("==> aliases"); if (counter == 192) $display("===> %%c");
if (counter == 189) $display(":%x:", 16'shaa); if (counter == 193) $display(":%10c:", "foo");
if (counter == 190) $display(":%X:", 16'shaa); if (counter == 194) $display(":%010c:", "foo");
if (counter == 191) $display(":%H:", 16'shaa); if (counter == 195) $display(":%-10c:", "foo");
if (counter == 192) $display(":%O:", 16'shaa); if (counter == 196) $display(":%-010c:", "foo");
if (counter == 193) $display(":%B:", 16'shaa);
if (counter == 194) $display("==> default base"); if (counter == 197) $display("==> aliases");
if (counter == 195) $displayh(16'haa); if (counter == 198) $display(":%x:", 16'shaa);
if (counter == 196) $displayo(16'haa); if (counter == 199) $display(":%X:", 16'shaa);
if (counter == 197) $displayb(16'haa); if (counter == 200) $display(":%H:", 16'shaa);
if (counter == 201) $display(":%O:", 16'shaa);
if (counter == 202) $display(":%B:", 16'shaa);
if (counter == 198) $display("==> write/format"); if (counter == 203) $display("==> default base");
if (counter == 199) $display("%d", 1, "%d", 1); if (counter == 204) $displayh(16'haa);
if (counter == 205) $displayo(16'haa);
if (counter == 206) $displayb(16'haa);
if (counter == 200) begin if (counter == 207) $display("==> write/format");
if (counter == 208) $display("%d", 1, "%d", 1);
if (counter == 209) begin
$display("<<<END>>>"); $display("<<<END>>>");
fin <= 1; fin <= 1;
end end