mirror of https://github.com/YosysHQ/yosys.git
ast: translate $display/$write tasks in always blocks to new $print cell.
This commit is contained in:
parent
9f8e039a4b
commit
d5c9953c09
|
@ -278,6 +278,8 @@ namespace AST
|
||||||
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
|
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
|
||||||
AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
|
AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
|
||||||
bool is_simple_const_expr();
|
bool is_simple_const_expr();
|
||||||
|
|
||||||
|
// helper for parsing format strings
|
||||||
Fmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0);
|
Fmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0);
|
||||||
|
|
||||||
bool is_recursive_function() const;
|
bool is_recursive_function() const;
|
||||||
|
|
|
@ -693,8 +693,80 @@ struct AST_INTERNAL::ProcessGenerator
|
||||||
ast->input_error("Found parameter declaration in block without label!\n");
|
ast->input_error("Found parameter declaration in block without label!\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NONE:
|
|
||||||
case AST_TCALL:
|
case AST_TCALL:
|
||||||
|
if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
|
||||||
|
ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") {
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++);
|
||||||
|
|
||||||
|
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($print));
|
||||||
|
cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", ast->filename.c_str(), ast->location.first_line, ast->location.first_column, ast->location.last_line, ast->location.last_column);
|
||||||
|
|
||||||
|
RTLIL::SigSpec triggers;
|
||||||
|
RTLIL::Const polarity;
|
||||||
|
for (auto sync : proc->syncs) {
|
||||||
|
if (sync->type == RTLIL::STp) {
|
||||||
|
triggers.append(sync->signal);
|
||||||
|
polarity.bits.push_back(RTLIL::S1);
|
||||||
|
} else if (sync->type == RTLIL::STn) {
|
||||||
|
triggers.append(sync->signal);
|
||||||
|
polarity.bits.push_back(RTLIL::S0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell->parameters[ID::TRG_WIDTH] = triggers.size();
|
||||||
|
cell->parameters[ID::TRG_ENABLE] = !triggers.empty();
|
||||||
|
cell->parameters[ID::TRG_POLARITY] = polarity;
|
||||||
|
cell->setPort(ID::TRG, triggers);
|
||||||
|
|
||||||
|
Wire *wire = current_module->addWire(sstr.str() + "_EN", 1);
|
||||||
|
wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", ast->filename.c_str(), ast->location.first_line, ast->location.first_column, ast->location.last_line, ast->location.last_column);
|
||||||
|
cell->setPort(ID::EN, wire);
|
||||||
|
|
||||||
|
proc->root_case.actions.push_back(SigSig(wire, false));
|
||||||
|
current_case->actions.push_back(SigSig(wire, true));
|
||||||
|
|
||||||
|
int default_base = 10;
|
||||||
|
if (ast->str.back() == 'b')
|
||||||
|
default_base = 2;
|
||||||
|
else if (ast->str.back() == 'o')
|
||||||
|
default_base = 8;
|
||||||
|
else if (ast->str.back() == 'h')
|
||||||
|
default_base = 16;
|
||||||
|
|
||||||
|
std::vector<VerilogFmtArg> args;
|
||||||
|
for (auto node : ast->children) {
|
||||||
|
int width;
|
||||||
|
bool is_signed;
|
||||||
|
node->detectSignWidth(width, is_signed, nullptr);
|
||||||
|
|
||||||
|
VerilogFmtArg arg = {};
|
||||||
|
arg.filename = node->filename;
|
||||||
|
arg.first_line = node->location.first_line;
|
||||||
|
if (node->type == AST_CONSTANT && node->is_string) {
|
||||||
|
arg.type = VerilogFmtArg::STRING;
|
||||||
|
arg.str = node->bitsAsConst().decode_string();
|
||||||
|
// and in case this will be used as an argument...
|
||||||
|
arg.sig = node->bitsAsConst();
|
||||||
|
arg.signed_ = false;
|
||||||
|
} else {
|
||||||
|
arg.type = VerilogFmtArg::INTEGER;
|
||||||
|
arg.sig = node->genRTLIL();
|
||||||
|
arg.signed_ = is_signed;
|
||||||
|
}
|
||||||
|
args.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fmt fmt = {};
|
||||||
|
fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name);
|
||||||
|
if (ast->str.substr(0, 8) == "$display")
|
||||||
|
fmt.append_string("\n");
|
||||||
|
fmt.emit_rtlil(cell);
|
||||||
|
} else if (!ast->str.empty()) {
|
||||||
|
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AST_NONE:
|
||||||
case AST_FOR:
|
case AST_FOR:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -951,29 +951,33 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
|
||||||
str = std::string();
|
str = std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((type == AST_TCALL) && (str.substr(0, 8) == "$display" || str.substr(0, 6) == "$write") && (!current_always || current_always->type != AST_INITIAL)) {
|
|
||||||
log_file_warning(filename, location.first_line, "System task `%s' outside initial block is unsupported.\n", str.c_str());
|
|
||||||
delete_children();
|
|
||||||
str = std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
// print messages if this a call to $display() or $write() family of functions
|
|
||||||
if ((type == AST_TCALL) &&
|
if ((type == AST_TCALL) &&
|
||||||
(str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" ||
|
(str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" ||
|
||||||
str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo"))
|
str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo"))
|
||||||
{
|
{
|
||||||
int default_base = 10;
|
if (!current_always) {
|
||||||
if (str.back() == 'b')
|
log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str());
|
||||||
default_base = 2;
|
} else if (current_always->type == AST_INITIAL) {
|
||||||
else if (str.back() == 'o')
|
int default_base = 10;
|
||||||
default_base = 8;
|
if (str.back() == 'b')
|
||||||
else if (str.back() == 'h')
|
default_base = 2;
|
||||||
default_base = 16;
|
else if (str.back() == 'o')
|
||||||
|
default_base = 8;
|
||||||
|
else if (str.back() == 'h')
|
||||||
|
default_base = 16;
|
||||||
|
|
||||||
Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base);
|
// when $display()/$write() functions are used in an initial block, print them during synthesis
|
||||||
if (str.substr(0, 8) == "$display")
|
Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base);
|
||||||
fmt.append_string("\n");
|
if (str.substr(0, 8) == "$display")
|
||||||
log("%s", fmt.render().c_str());
|
fmt.append_string("\n");
|
||||||
|
log("%s", fmt.render().c_str());
|
||||||
|
} else {
|
||||||
|
// when $display()/$write() functions are used in an always block, simplify the expressions and
|
||||||
|
// convert them to a special cell later in genrtlil
|
||||||
|
for (auto node : children)
|
||||||
|
while (node->simplify(true, false, stage, -1, false, false)) {}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
delete_children();
|
delete_children();
|
||||||
str = std::string();
|
str = std::string();
|
||||||
|
|
|
@ -22,6 +22,8 @@ X(always_ff)
|
||||||
X(always_latch)
|
X(always_latch)
|
||||||
X(anyconst)
|
X(anyconst)
|
||||||
X(anyseq)
|
X(anyseq)
|
||||||
|
X(ARGS)
|
||||||
|
X(ARGS_WIDTH)
|
||||||
X(ARST)
|
X(ARST)
|
||||||
X(ARST_POLARITY)
|
X(ARST_POLARITY)
|
||||||
X(ARST_VALUE)
|
X(ARST_VALUE)
|
||||||
|
@ -86,6 +88,7 @@ X(equiv_merged)
|
||||||
X(equiv_region)
|
X(equiv_region)
|
||||||
X(extract_order)
|
X(extract_order)
|
||||||
X(F)
|
X(F)
|
||||||
|
X(FORMAT)
|
||||||
X(force_downto)
|
X(force_downto)
|
||||||
X(force_upto)
|
X(force_upto)
|
||||||
X(fsm_encoding)
|
X(fsm_encoding)
|
||||||
|
@ -233,6 +236,10 @@ X(TRANS_NUM)
|
||||||
X(TRANSPARENCY_MASK)
|
X(TRANSPARENCY_MASK)
|
||||||
X(TRANSPARENT)
|
X(TRANSPARENT)
|
||||||
X(TRANS_TABLE)
|
X(TRANS_TABLE)
|
||||||
|
X(TRG)
|
||||||
|
X(TRG_ENABLE)
|
||||||
|
X(TRG_POLARITY)
|
||||||
|
X(TRG_WIDTH)
|
||||||
X(T_RISE_MAX)
|
X(T_RISE_MAX)
|
||||||
X(T_RISE_MIN)
|
X(T_RISE_MIN)
|
||||||
X(T_RISE_TYP)
|
X(T_RISE_TYP)
|
||||||
|
|
|
@ -1720,6 +1720,17 @@ namespace {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cell->type == ID($print)) {
|
||||||
|
param(ID(FORMAT));
|
||||||
|
param_bool(ID::TRG_ENABLE);
|
||||||
|
param(ID::TRG_POLARITY);
|
||||||
|
port(ID::EN, 1);
|
||||||
|
port(ID::TRG, param(ID::TRG_WIDTH));
|
||||||
|
port(ID::ARGS, param(ID::ARGS_WIDTH));
|
||||||
|
check_expected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cell->type == ID($_BUF_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
if (cell->type == ID($_BUF_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
||||||
if (cell->type == ID($_NOT_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
if (cell->type == ID($_NOT_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
||||||
if (cell->type == ID($_AND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; }
|
if (cell->type == ID($_AND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; }
|
||||||
|
|
Loading…
Reference in New Issue