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.cc223
1 files changed, 197 insertions, 26 deletions
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index a617215f..44e4e5f9 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -33,13 +33,15 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool verbose, norename, noattr, attr2comment, noexpr, nodec, nostr, defparam;
+bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
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;
std::string auto_prefix;
RTLIL::Module *active_module;
+dict<RTLIL::SigBit, RTLIL::State> active_initdata;
+SigMap active_sigmap;
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
{
@@ -159,23 +161,73 @@ 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;
+ goto dump_hex;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
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());
if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
- goto dump_bits;
+ goto dump_hex;
if (data.bits[i] == RTLIL::S1)
val |= 1 << (i - offset);
}
- if (set_signed && val < 0)
+ if (decimal)
+ f << stringf("%d", val);
+ else if (set_signed && val < 0)
f << stringf("-32'sd%u", -val);
else
f << stringf("32'%sd%u", set_signed ? "s" : "", val);
} else {
- dump_bits:
+ dump_hex:
+ if (nohex)
+ goto dump_bin;
+ vector<char> bin_digits, hex_digits;
+ for (int i = offset; i < offset+width; i++) {
+ log_assert(i < (int)data.bits.size());
+ switch (data.bits[i]) {
+ case RTLIL::S0: bin_digits.push_back('0'); break;
+ case RTLIL::S1: bin_digits.push_back('1'); break;
+ case RTLIL::Sx: bin_digits.push_back('x'); break;
+ case RTLIL::Sz: bin_digits.push_back('z'); break;
+ case RTLIL::Sa: bin_digits.push_back('z'); break;
+ case RTLIL::Sm: log_error("Found marker state in final netlist.");
+ }
+ }
+ if (GetSize(bin_digits) == 0)
+ goto dump_bin;
+ while (GetSize(bin_digits) % 4 != 0)
+ if (bin_digits.back() == '1')
+ bin_digits.push_back('0');
+ else
+ bin_digits.push_back(bin_digits.back());
+ for (int i = 0; i < GetSize(bin_digits); i += 4)
+ {
+ char bit_3 = bin_digits[i+3];
+ char bit_2 = bin_digits[i+2];
+ char bit_1 = bin_digits[i+1];
+ char bit_0 = bin_digits[i+0];
+ if (bit_3 == 'x' || bit_2 == 'x' || bit_1 == 'x' || bit_0 == 'x') {
+ if (bit_3 != 'x' || bit_2 != 'x' || bit_1 != 'x' || bit_0 != 'x')
+ goto dump_bin;
+ hex_digits.push_back('x');
+ continue;
+ }
+ if (bit_3 == 'z' || bit_2 == 'z' || bit_1 == 'z' || bit_0 == 'z') {
+ if (bit_3 != 'z' || bit_2 != 'z' || bit_1 != 'z' || bit_0 != 'z')
+ goto dump_bin;
+ hex_digits.push_back('z');
+ continue;
+ }
+ int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0');
+ hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10);
+ }
+ f << stringf("%d'%sh", width, set_signed ? "s" : "");
+ for (int i = GetSize(hex_digits)-1; i >= 0; i--)
+ f << hex_digits[i];
+ }
+ if (0) {
+ dump_bin:
f << stringf("%d'%sb", width, set_signed ? "s" : "");
if (width == 0)
f << stringf("0");
@@ -214,6 +266,26 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
}
}
+void dump_reg_init(std::ostream &f, SigSpec sig)
+{
+ Const initval;
+ bool gotinit = false;
+
+ for (auto bit : active_sigmap(sig)) {
+ if (active_initdata.count(bit)) {
+ initval.bits.push_back(active_initdata.at(bit));
+ gotinit = true;
+ } else {
+ initval.bits.push_back(State::Sx);
+ }
+ }
+
+ if (gotinit) {
+ f << " = ";
+ dump_const(f, initval);
+ }
+}
+
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
{
if (chunk.wire == NULL) {
@@ -302,12 +374,12 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
if (wire->port_input && wire->port_output)
f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (reg_wires.count(wire->name)) {
- f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "reg%s %s", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (wire->attributes.count("\\init")) {
- f << stringf("%s" "initial %s = ", indent.c_str(), id(wire->name).c_str());
+ f << stringf(" = ");
dump_const(f, wire->attributes.at("\\init"));
- f << stringf(";\n");
}
+ f << stringf(";\n");
} else if (!wire->port_input && !wire->port_output)
f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
#endif
@@ -400,7 +472,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
f << stringf(" = ");
@@ -408,16 +480,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("~(");
dump_cell_expr_port(f, cell, "A", false);
f << stringf(" ");
- if (cell->type.in("$_AND_", "$_NAND_"))
+ if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
f << stringf("&");
- if (cell->type.in("$_OR_", "$_NOR_"))
+ if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_"))
f << stringf("|");
if (cell->type.in("$_XOR_", "$_XNOR_"))
f << stringf("^");
dump_attributes(f, "", cell->attributes, ' ');
f << stringf(" ");
+ if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
+ f << stringf("~(");
dump_cell_expr_port(f, cell, "B", false);
- if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
+ if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
f << stringf(")");
f << stringf(";\n");
return true;
@@ -474,8 +548,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
dump_attributes(f, indent, cell->attributes);
f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
@@ -514,8 +591,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
dump_attributes(f, indent, cell->attributes);
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
@@ -598,6 +678,23 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP
#undef HANDLE_BINOP
+ if (cell->type == "$shiftx")
+ {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf("[");
+ if (cell->getParam("\\B_SIGNED").as_bool())
+ f << stringf("$signed(");
+ dump_sigspec(f, cell->getPort("\\B"));
+ if (cell->getParam("\\B_SIGNED").as_bool())
+ f << stringf(")");
+ f << stringf(" +: %d", cell->getParam("\\Y_WIDTH").as_int());
+ f << stringf("];\n");
+ return true;
+ }
+
if (cell->type == "$mux")
{
f << stringf("%s" "assign ", indent.c_str());
@@ -698,8 +795,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str());
+ dump_reg_init(f, sig_q);
+ f << ";\n";
+ }
for (int i = 0; i < width; i++) {
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
@@ -754,8 +854,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
dump_sigspec(f, sig_clk);
@@ -794,6 +897,42 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type == "$dlatch")
+ {
+ RTLIL::SigSpec sig_en;
+ bool pol_en = false;
+
+ sig_en = cell->getPort("\\EN");
+ pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
+
+ std::string reg_name = cellname(cell);
+ bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
+
+ f << stringf("%s" "always @*\n", indent.c_str());
+
+ f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
+ dump_sigspec(f, sig_en);
+ f << stringf(")\n");
+
+ f << stringf("%s" " %s = ", indent.c_str(), reg_name.c_str());
+ dump_cell_expr_port(f, cell, "D", false);
+ f << stringf(";\n");
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Q"));
+ f << stringf(" = %s;\n", reg_name.c_str());
+ }
+
+ return true;
+ }
+
if (cell->type == "$mem")
{
RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
@@ -806,7 +945,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
// for memory block make something like:
// reg [7:0] memid [3:0];
// initial begin
- // memid[0] <= ...
+ // memid[0] = ...
// end
f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
if (use_init)
@@ -814,7 +953,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("%s" "initial begin\n", indent.c_str());
for (int i=0; i<size; i++)
{
- f << stringf("%s" " %s[%d] <= ", indent.c_str(), mem_id.c_str(), i);
+ f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
f << stringf(";\n");
}
@@ -912,7 +1051,7 @@ 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;
bool wr_clk_posedge;
- SigMap sigmap(active_module);
+
// write ports
for (int i=0; i < nwrite_ports; i++)
{
@@ -937,7 +1076,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
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))
+ while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
i++, width++;
if (wen_bit == State::S0)
@@ -1251,6 +1390,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
reg_wires.clear();
reset_auto_counter(module);
active_module = module;
+ active_sigmap.set(module);
+ active_initdata.clear();
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init")) {
+ SigSpec sig = active_sigmap(wire);
+ Const val = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
+ active_initdata[sig[i]] = val.bits.at(i);
+ }
if (!module->processes.empty())
log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
@@ -1327,11 +1476,13 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
f << stringf("%s" "endmodule\n", indent.c_str());
active_module = NULL;
+ active_sigmap.clear();
+ active_initdata.clear();
}
struct VerilogBackend : public Backend {
VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1362,6 +1513,14 @@ struct VerilogBackend : public Backend {
log(" not bit pattern. This option decativates this feature and instead\n");
log(" will write out all constants in binary.\n");
log("\n");
+ log(" -decimal\n");
+ log(" dump 32-bit constants in decimal and without size and radix\n");
+ log("\n");
+ log(" -nohex\n");
+ log(" constant values that are compatible with hex output are usually\n");
+ log(" dumped as hex values. This option decativates this feature and\n");
+ log(" instead 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");
@@ -1391,7 +1550,7 @@ struct VerilogBackend : public Backend {
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)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing Verilog backend.\n");
@@ -1401,8 +1560,10 @@ struct VerilogBackend : public Backend {
attr2comment = false;
noexpr = false;
nodec = false;
+ nohex = false;
nostr = false;
defparam = false;
+ decimal = false;
auto_prefix = "";
bool blackboxes = false;
@@ -1412,6 +1573,8 @@ struct VerilogBackend : public Backend {
reg_ct.insert("$dff");
reg_ct.insert("$adff");
+ reg_ct.insert("$dffe");
+ reg_ct.insert("$dlatch");
reg_ct.insert("$_DFF_N_");
reg_ct.insert("$_DFF_P_");
@@ -1461,6 +1624,10 @@ struct VerilogBackend : public Backend {
nodec = true;
continue;
}
+ if (arg == "-nohex") {
+ nohex = true;
+ continue;
+ }
if (arg == "-nostr") {
nostr = true;
continue;
@@ -1469,6 +1636,10 @@ struct VerilogBackend : public Backend {
defparam = true;
continue;
}
+ if (arg == "-decimal") {
+ decimal = true;
+ continue;
+ }
if (arg == "-blackboxes") {
blackboxes = true;
continue;