summaryrefslogtreecommitdiff
path: root/backends/verilog/verilog_backend.cc
diff options
context:
space:
mode:
Diffstat (limited to 'backends/verilog/verilog_backend.cc')
-rw-r--r--backends/verilog/verilog_backend.cc170
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 &reg_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 &current_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;