mirror of https://github.com/YosysHQ/yosys.git
fmt: %t/$time support
This commit is contained in:
parent
52dc397a50
commit
c382d7d3ac
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
kernel/fmt.h
13
kernel/fmt.h
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue