diff options
Diffstat (limited to 'backends/verilog/verilog_backend.cc')
-rw-r--r-- | backends/verilog/verilog_backend.cc | 223 |
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; |