diff options
Diffstat (limited to 'backends/verilog/verilog_backend.cc')
-rw-r--r-- | backends/verilog/verilog_backend.cc | 170 |
1 files changed, 109 insertions, 61 deletions
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 10f10e3c..52cf861d 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -19,11 +19,6 @@ * * A simple and straightforward Verilog backend. * - * Note that RTLIL processes can't always be mapped easily to a Verilog - * process. Therefore this frontend should only be used to export a - * Verilog netlist (i.e. after the "proc" pass has converted all processes - * to logic networks and registers). - * */ #include "kernel/register.h" @@ -38,7 +33,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool norename, noattr, attr2comment, noexpr; +bool norename, noattr, attr2comment, noexpr, nodec, nostr, defparam; int auto_name_counter, auto_name_offset, auto_name_digits; std::map<RTLIL::IdString, int> auto_name_map; std::set<RTLIL::IdString> reg_wires, reg_ct; @@ -146,6 +141,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) if (sig.size() != chunk.wire->width) { if (sig.size() == 1) reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset); + else if (chunk.wire->upto) + reg_name += stringf("[%d:%d]", (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset, + (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); else reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1, chunk.wire->start_offset + chunk.offset); @@ -158,8 +156,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o { if (width < 0) width = data.bits.size() - offset; + if (nostr) + goto dump_bits; if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { - if (width == 32 && !no_decimal) { + if (width == 32 && !no_decimal && !nodec) { int32_t val = 0; for (int i = offset+width-1; i >= offset; i--) { log_assert(i < (int)data.bits.size()); @@ -169,9 +169,9 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o val |= 1 << (i - offset); } if (set_signed && val < 0) - f << stringf("-32'sd %u", -val); + f << stringf("-32'sd%u", -val); else - f << stringf("32'%sd %u", set_signed ? "s" : "", val); + f << stringf("32'%sd%u", set_signed ? "s" : "", val); } else { dump_bits: f << stringf("%d'%sb", width, set_signed ? "s" : ""); @@ -827,12 +827,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) std::vector<std::string> lof_reg_declarations; int nread_ports = cell->parameters["\\RD_PORTS"].as_int(); - RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr; + RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr; bool use_rd_clk, rd_clk_posedge, rd_transparent; // read ports for (int i=0; i < nread_ports; i++) { sig_rd_clk = cell->getPort("\\RD_CLK").extract(i); + sig_rd_en = cell->getPort("\\RD_EN").extract(i); sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width); sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits); use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool(); @@ -850,15 +851,22 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // for clocked read ports make something like: // reg [..] temp_id; // always @(posedge clk) - // temp_id <= array_reg[r_addr]; + // if (rd_en) temp_id <= array_reg[r_addr]; // assign r_data = temp_id; std::string temp_id = next_auto_id(); lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) ); { std::ostringstream os; + if (sig_rd_en != RTLIL::SigBit(true)) + { + os << stringf("if ("); + dump_sigspec(os, sig_rd_en); + os << stringf(") "); + } + os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str()); dump_sigspec(os, sig_rd_addr); - std::string line = stringf("%s <= %s[%s];\n", temp_id.c_str(), mem_id.c_str(), os.str().c_str()); - clk_to_lof_body[clk_domain_str].push_back(line); + os << stringf("];\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); } { std::ostringstream os; @@ -900,13 +908,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) } int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int(); - RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit; - RTLIL::SigBit last_bit; + RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en; bool wr_clk_posedge; - RTLIL::SigSpec lof_wen; - dict<RTLIL::SigSpec, int> wen_to_width; SigMap sigmap(active_module); - int n, wen_width; // write ports for (int i=0; i < nwrite_ports; i++) { @@ -914,7 +918,6 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width); sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits); sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width); - sig_wr_en_bit = sig_wr_en.extract(0); wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool(); { std::ostringstream os; @@ -923,48 +926,37 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) if( clk_to_lof_body.count(clk_domain_str) == 0 ) clk_to_lof_body[clk_domain_str] = std::vector<std::string>(); } - // group the wen bits - last_bit = sig_wr_en.extract(0); - lof_wen = RTLIL::SigSpec(last_bit); - wen_to_width.clear(); - wen_to_width[last_bit] = 0; - for (auto ¤t_bit : sig_wr_en.bits()) - { - if (sigmap(current_bit) == sigmap(last_bit)){ - wen_to_width[current_bit] += 1; - } else { - lof_wen.append_bit(current_bit); - wen_to_width[current_bit] = 1; - } - last_bit = current_bit; - } // make something like: // always @(posedge clk) // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; // ... - n = 0; - for (auto &wen_bit : lof_wen) { - wen_width = wen_to_width[wen_bit]; - if (!(wen_bit == RTLIL::SigBit(false))) + for (int i = 0; i < GetSize(sig_wr_en); i++) + { + int start_i = i, width = 1; + SigBit wen_bit = sig_wr_en[i]; + + while (i+1 < GetSize(sig_wr_en) && sigmap(sig_wr_en[i+1]) == sigmap(wen_bit)) + i++, width++; + + if (wen_bit == State::S0) + continue; + + std::ostringstream os; + if (wen_bit != State::S1) { - std::ostringstream os; - if (!(wen_bit == RTLIL::SigBit(true))) - { - os << stringf("if ("); - dump_sigspec(os, wen_bit); - os << stringf(") "); - } - os << stringf("%s[", mem_id.c_str()); - dump_sigspec(os, sig_wr_addr); - if (wen_width == width) - os << stringf("] <= "); - else - os << stringf("][%d:%d] <= ", n+wen_width-1, n); - dump_sigspec(os, sig_wr_data.extract(n, wen_width)); - os << stringf(";\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); + os << stringf("if ("); + dump_sigspec(os, wen_bit); + os << stringf(") "); } - n += wen_width; + os << stringf("%s[", mem_id.c_str()); + dump_sigspec(os, sig_wr_addr); + if (width == GetSize(sig_wr_en)) + os << stringf("] <= "); + else + os << stringf("][%d:%d] <= ", i, start_i); + dump_sigspec(os, sig_wr_data.extract(start_i, width)); + os << stringf(";\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); } } // Output Verilog that looks something like this: @@ -1029,7 +1021,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_attributes(f, indent, cell->attributes); f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); - if (cell->parameters.size() > 0) { + if (!defparam && cell->parameters.size() > 0) { f << stringf(" #("); for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { if (it != cell->parameters.begin()) @@ -1079,6 +1071,16 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf(")"); } f << stringf("\n%s" ");\n", indent.c_str()); + + if (defparam && cell->parameters.size() > 0) { + for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { + f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); + bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; + dump_const(f, it->second, -1, 0, false, is_signed); + f << stringf(";\n"); + } + } + } void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) @@ -1135,11 +1137,15 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_sigspec(f, sw->signal); f << stringf(")\n"); + bool got_default = false; for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { - f << stringf("%s ", indent.c_str()); - if ((*it)->compare.size() == 0) - f << stringf("default"); - else { + if ((*it)->compare.size() == 0) { + if (got_default) + continue; + f << stringf("%s default", indent.c_str()); + got_default = true; + } else { + f << stringf("%s ", indent.c_str()); for (size_t i = 0; i < (*it)->compare.size(); i++) { if (i > 0) f << stringf(", "); @@ -1244,6 +1250,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) reset_auto_counter(module); active_module = module; + if (!module->processes.empty()) + log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n" + "can't always be mapped directly to Verilog always blocks. Unintended\n" + "changes in simulation behavior are possible! Use \"proc\" to convert\n" + "processes to logic networks and registers.", log_id(module)); + f << stringf("\n"); for (auto it = module->processes.begin(); it != module->processes.end(); ++it) dump_process(f, indent + " ", it->second, true); @@ -1340,6 +1352,21 @@ struct VerilogBackend : public Backend { log(" without this option all internal cells are converted to Verilog\n"); log(" expressions.\n"); log("\n"); + log(" -nodec\n"); + log(" 32-bit constant values are by default dumped as decimal numbers,\n"); + log(" not bit pattern. This option decativates this feature and instead\n"); + log(" will write out all constants in binary.\n"); + log("\n"); + log(" -nostr\n"); + log(" Parameters and attributes that are specified as strings in the\n"); + log(" original input will be output as strings by this back-end. This\n"); + log(" decativates this feature and instead will write string constants\n"); + log(" as binary numbers.\n"); + log("\n"); + log(" -defparam\n"); + log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n"); + log(" cell parameters.\n"); + log("\n"); log(" -blackboxes\n"); log(" usually modules with the 'blackbox' attribute are ignored. with\n"); log(" this option set only the modules with the 'blackbox' attribute\n"); @@ -1349,15 +1376,24 @@ struct VerilogBackend : public Backend { log(" only write selected modules. modules must be selected entirely or\n"); log(" not at all.\n"); log("\n"); + log("Note that RTLIL processes can't always be mapped directly to Verilog\n"); + log("always blocks. This frontend should only be used to export an RTLIL\n"); + log("netlist, i.e. after the \"proc\" pass has been used to convert all\n"); + log("processes to logic networks and registers. A warning is generated when\n"); + log("this command is called on a design with RTLIL processes.\n"); + log("\n"); } virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing Verilog backend.\n"); + log_header(design, "Executing Verilog backend.\n"); norename = false; noattr = false; attr2comment = false; noexpr = false; + nodec = false; + nostr = false; + defparam = false; bool blackboxes = false; bool selected = false; @@ -1407,6 +1443,18 @@ struct VerilogBackend : public Backend { noexpr = true; continue; } + if (arg == "-nodec") { + nodec = true; + continue; + } + if (arg == "-nostr") { + nostr = true; + continue; + } + if (arg == "-defparam") { + defparam = true; + continue; + } if (arg == "-blackboxes") { blackboxes = true; continue; |