From c0b68f4848f709034d68dbfa8697abe76b67a69e Mon Sep 17 00:00:00 2001 From: luke whittlesey Date: Thu, 7 May 2015 13:03:09 -0400 Subject: [PATCH 1/3] Added support for $mem cells in the verilog backend. --- backends/verilog/verilog_backend.cc | 121 +++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index c6d595c3..f39b1de4 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -788,8 +788,127 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type == "$mem") + { + std::ostringstream os; + RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string(); + std::string mem_id = id( cell->parameters["\\MEMID"].decode_string() ); + int abits = cell->parameters["\\ABITS"].as_int(); + int size = cell->parameters["\\SIZE"].as_int(); + int width = cell->parameters["\\WIDTH"].as_int(); + int offset = cell->parameters["\\OFFSET"].as_int(); + bool use_init = !(RTLIL::SigSpec( cell->parameters["\\INIT"] ).is_fully_undef()); + + // for memory block make something like: + // reg [7:0] memid [3:0]; + // initial begin + // memid[0] <= ... + // end + int mem_val; + RTLIL::Memory memory; + memory.name = memid; + memory.width = width; + memory.start_offset = offset; + memory.size = size; + dump_memory(os, indent.c_str(), &memory); + if (use_init) + { + os << stringf("%s" "initial begin\n", indent.c_str()); + for (int i=0; iparameters["\\INIT"].extract(i*width, width).as_int(); + os << stringf("%s" " %s[%d] <= %d'd%d;\n", indent.c_str(), mem_id.c_str(), i, width, mem_val); + } + os << stringf("%s" "end\n", indent.c_str()); + } + + + int nread_ports = cell->parameters["\\RD_PORTS"].as_int(); + RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr; + bool use_rd_clk, rd_clk_posedge; + // read ports + for (int i=0; i < nread_ports; i++) + { + sig_rd_clk = cell->getPort("\\RD_CLK").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(); + rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool(); + if (use_rd_clk) + { + // for clocked read ports make something like: + // always @(posedge clk) + // r_data <= array_reg[r_addr]; + os << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg"); + dump_sigspec(os, sig_rd_clk); + os << stringf(")\n"); + os << stringf("%s" " ", indent.c_str()); + dump_sigspec(os, sig_rd_data); + os << stringf(" <= %s[", mem_id.c_str()); + dump_sigspec(os, sig_rd_addr); + os << stringf("];\n"); + }else{ + // for non-clocked read-ports make something like: + // assign r_data = array_reg[r_addr]; + os << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(os, sig_rd_data); + os << stringf(" = %s[", mem_id.c_str()); + dump_sigspec(os, sig_rd_addr); + os << stringf("];\n"); + } + } + + 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, temp_wire; + bool wr_clk_posedge, use_wen; + // write ports + for (int i=0; i < nwrite_ports; i++) + { + // for write-ports make something like: + // always @(posedge clk) + // if (wr_en) + // memid[w_addr] <= w_data; + sig_wr_clk = cell->getPort("\\WR_CLK").extract(i); + 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(); + use_wen = !(sig_wr_en.is_fully_const() && (sig_wr_en.as_int() == ((1 << width) - 1))); + // if we're using wen, make sure every bit is the same wire, otherwise this verilog description won't be correct + // question: when would WR_EN have different wires for each bit? + if (sig_wr_en_bit.size() != 1) + return false; + if (use_wen) + { + for(int j=0; jname == sig_wr_en_bit.as_chunk().wire->name)) ) + return false; + } + } + os << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg"); + dump_sigspec(os, sig_wr_clk); + os << stringf(")\n"); + if (use_wen) + { + os << stringf("%s" " if (", indent.c_str()); + dump_sigspec(os, sig_wr_en_bit); + os << stringf(")\n "); + } + os << stringf("%s" " %s[", indent.c_str(), mem_id.c_str()); + dump_sigspec(os, sig_wr_addr); + os << stringf("] <= "); + dump_sigspec(os, sig_wr_data); + os << stringf(";\n"); + } + f << os.str(); + return true; + } + // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_ - // FIXME: $sr, $dlatch, $memrd, $memwr, $mem, $fsm + // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm return false; } From 2c1e15029786fe8a118343b7a81f681450a8ce93 Mon Sep 17 00:00:00 2001 From: luke whittlesey Date: Fri, 8 May 2015 15:29:51 -0400 Subject: [PATCH 2/3] Verilog backend for $mem cells should now be able to handle different write-enable bits and RD_TRANSPARENT parameter settings. --- backends/verilog/verilog_backend.cc | 155 +++++++++++++++++++--------- 1 file changed, 105 insertions(+), 50 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index f39b1de4..a7457d91 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -29,10 +29,12 @@ #include "kernel/register.h" #include "kernel/celltypes.h" #include "kernel/log.h" +#include "kernel/sigtools.h" #include #include #include #include +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -151,6 +153,17 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) return true; } +bool bit_check_equal(SigMap &sigmap, RTLIL::SigSpec &a, RTLIL::SigSpec &b) +{ + if (a.is_fully_const() && b.is_fully_const()){ + return (a.as_bool() == b.as_bool()); + }else if (!a.is_fully_const() && !b.is_fully_const()){ + return (sigmap(a) == sigmap(b)); + }else{ + return false; + } +} + void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) { if (width < 0) @@ -790,7 +803,6 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) if (cell->type == "$mem") { - std::ostringstream os; RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string(); std::string mem_id = id( cell->parameters["\\MEMID"].decode_string() ); int abits = cell->parameters["\\ABITS"].as_int(); @@ -810,22 +822,22 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) memory.width = width; memory.start_offset = offset; memory.size = size; - dump_memory(os, indent.c_str(), &memory); + dump_memory(f, indent.c_str(), &memory); if (use_init) { - os << stringf("%s" "initial begin\n", indent.c_str()); + f << stringf("%s" "initial begin\n", indent.c_str()); for (int i=0; iparameters["\\INIT"].extract(i*width, width).as_int(); - os << stringf("%s" " %s[%d] <= %d'd%d;\n", indent.c_str(), mem_id.c_str(), i, width, mem_val); + f << stringf("%s" " %s[%d] <= %d'd%d;\n", indent.c_str(), mem_id.c_str(), i, width, mem_val); } - os << stringf("%s" "end\n", indent.c_str()); + f << stringf("%s" "end\n", indent.c_str()); } - int nread_ports = cell->parameters["\\RD_PORTS"].as_int(); RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr; - bool use_rd_clk, rd_clk_posedge; + bool use_rd_clk, rd_clk_posedge, rd_transparent; + RTLIL::IdString new_id; // read ports for (int i=0; i < nread_ports; i++) { @@ -834,33 +846,58 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits); use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool(); rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool(); - if (use_rd_clk) + rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool(); + if (use_rd_clk && !rd_transparent) { // for clocked read ports make something like: // always @(posedge clk) // r_data <= array_reg[r_addr]; - os << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg"); - dump_sigspec(os, sig_rd_clk); - os << stringf(")\n"); - os << stringf("%s" " ", indent.c_str()); - dump_sigspec(os, sig_rd_data); - os << stringf(" <= %s[", mem_id.c_str()); - dump_sigspec(os, sig_rd_addr); - os << stringf("];\n"); + f << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg"); + dump_sigspec(f, sig_rd_clk); + f << stringf(")\n"); + f << stringf("%s" " ", indent.c_str()); + dump_sigspec(f, sig_rd_data); + f << stringf(" <= %s[", mem_id.c_str()); + dump_sigspec(f, sig_rd_addr); + f << stringf("];\n"); }else{ - // for non-clocked read-ports make something like: - // assign r_data = array_reg[r_addr]; - os << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(os, sig_rd_data); - os << stringf(" = %s[", mem_id.c_str()); - dump_sigspec(os, sig_rd_addr); - os << stringf("];\n"); + if (rd_transparent){ + // for rd-transparent read-ports make something like: + // reg [..] new-id; + // always @(posedge clk) + // new-id <= r_addr; + // assign r_data = array_reg[new-id]; + new_id = RTLIL::IdString(stringf("$%d", (int)time(NULL))); + reset_auto_counter_id(new_id, true); + f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_addr.size() - 1, id(new_id).c_str()); + f << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg"); + dump_sigspec(f, sig_rd_clk); + f << stringf(")\n"); + f << stringf("%s" " %s <= ", indent.c_str(), id(new_id).c_str()); + dump_sigspec(f, sig_rd_addr); + f << stringf(";\n"); + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, sig_rd_data); + f << stringf(" = %s[%s];\n", mem_id.c_str(), id(new_id).c_str()); + }else{ + // for non-clocked read-ports make something like: + // assign r_data = array_reg[r_addr]; + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, sig_rd_data); + f << stringf(" = %s[", mem_id.c_str()); + dump_sigspec(f, sig_rd_addr); + f << stringf("];\n"); + } } } 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, temp_wire; - bool wr_clk_posedge, use_wen; + RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit, last_bit, current_bit; + bool wr_clk_posedge; //, use_wen; //, use_individual_wen_bits; + std::vector lof_wen; + std::map wen_to_width; + SigMap sigmap(active_module); + int n, wen_width; // write ports for (int i=0; i < nwrite_ports; i++) { @@ -874,36 +911,54 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) 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(); - use_wen = !(sig_wr_en.is_fully_const() && (sig_wr_en.as_int() == ((1 << width) - 1))); - // if we're using wen, make sure every bit is the same wire, otherwise this verilog description won't be correct - // question: when would WR_EN have different wires for each bit? - if (sig_wr_en_bit.size() != 1) - return false; - if (use_wen) + // group the wen bits + last_bit = sig_wr_en.extract(0); + lof_wen.push_back(last_bit); + wen_to_width[last_bit] = 0; + for(int j=0; jname == sig_wr_en_bit.as_chunk().wire->name)) ) - return false; + current_bit = sig_wr_en.extract(j); + if ( bit_check_equal(sigmap, current_bit, last_bit) ){ + wen_to_width[lof_wen.back()] += 1; + }else{ + lof_wen.push_back(current_bit); + wen_to_width[current_bit] = 1; } + last_bit = current_bit; } - os << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg"); - dump_sigspec(os, sig_wr_clk); - os << stringf(")\n"); - if (use_wen) - { - os << stringf("%s" " if (", indent.c_str()); - dump_sigspec(os, sig_wr_en_bit); - os << stringf(")\n "); + // 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.is_fully_zero()) + { + f << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg"); + dump_sigspec(f, sig_wr_clk); + f << stringf(")\n"); + //if (wen_bit.is_wire()) // why doesn't wen_bit.is_wire() work here? + if (!wen_bit.has_const()) + { + f << stringf("%s" " if (", indent.c_str()); + dump_sigspec(f, wen_bit); + f << stringf(")\n "); + } + f << stringf("%s" " %s[", indent.c_str(), mem_id.c_str()); + dump_sigspec(f, sig_wr_addr); + if (wen_width == width) + f << stringf("] <= "); + else + f << stringf("][%d:%d] <= ", n+wen_width-1, n); + dump_sigspec(f, sig_wr_data.extract(n, wen_width)); + f << stringf(";\n"); + } + n += wen_width; } - os << stringf("%s" " %s[", indent.c_str(), mem_id.c_str()); - dump_sigspec(os, sig_wr_addr); - os << stringf("] <= "); - dump_sigspec(os, sig_wr_data); - os << stringf(";\n"); } - f << os.str(); + return true; } From 6de8fea2c77abb936ba2356bf5c1425a15f5edd7 Mon Sep 17 00:00:00 2001 From: luke whittlesey Date: Sun, 10 May 2015 11:33:24 -0400 Subject: [PATCH 3/3] Made changes recommended by Clifford Wolf ... Removed bit_check_equal(), used RTLIL::SigBit for individual bits, used dict<> instead of std::map, and used RTLIL::SigSpec instead of std::vector. --- backends/verilog/verilog_backend.cc | 33 ++++++++++------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index a7457d91..8b8c3d7b 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -153,17 +153,6 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) return true; } -bool bit_check_equal(SigMap &sigmap, RTLIL::SigSpec &a, RTLIL::SigSpec &b) -{ - if (a.is_fully_const() && b.is_fully_const()){ - return (a.as_bool() == b.as_bool()); - }else if (!a.is_fully_const() && !b.is_fully_const()){ - return (sigmap(a) == sigmap(b)); - }else{ - return false; - } -} - void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) { if (width < 0) @@ -892,10 +881,11 @@ 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, last_bit, current_bit; - bool wr_clk_posedge; //, use_wen; //, use_individual_wen_bits; - std::vector lof_wen; - std::map wen_to_width; + RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit; + RTLIL::SigBit last_bit, current_bit; + bool wr_clk_posedge; + RTLIL::SigSpec lof_wen; + dict wen_to_width; SigMap sigmap(active_module); int n, wen_width; // write ports @@ -913,15 +903,15 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool(); // group the wen bits last_bit = sig_wr_en.extract(0); - lof_wen.push_back(last_bit); + lof_wen.append_bit(last_bit); wen_to_width[last_bit] = 0; for(int j=0; j