diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 436bb2b22..d160ec034 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -791,14 +791,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } - if (cell->type == "$mem" && false) // FIXME! + if (cell->type == "$mem") { 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: @@ -807,12 +806,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // memid[0] <= ... // end int mem_val; - RTLIL::Memory memory; - memory.name = memid; - memory.width = width; - memory.start_offset = offset; - memory.size = size; - dump_memory(f, indent.c_str(), &memory); + 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) { f << stringf("%s" "initial begin\n", indent.c_str()); @@ -824,6 +818,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf("%s" "end\n", indent.c_str()); } + // create a map : "edge clk" -> expressions within that clock domain + dict> clk_to_lof_body; + clk_to_lof_body[""] = std::vector(); + std::string clk_domain_str; + // create a list of reg declarations + std::vector lof_reg_declarations; + 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, rd_transparent; @@ -836,6 +837,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool(); rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool(); rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool(); + { + std::ostringstream os; + dump_sigspec(os, sig_rd_clk); + clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str()); + if( clk_to_lof_body.count(clk_domain_str) == 0 ) + clk_to_lof_body[clk_domain_str] = std::vector(); + } if (use_rd_clk && !rd_transparent) { // for clocked read ports make something like: @@ -844,16 +852,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // temp_id <= array_reg[r_addr]; // assign r_data = temp_id; std::string temp_id = next_auto_id(); - f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_addr.size() - 1, temp_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 <= %s[", indent.c_str(), temp_id.c_str(), mem_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;\n", temp_id.c_str()); + lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) ); + { + std::ostringstream os; + 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); + } + { + std::ostringstream os; + dump_sigspec(os, sig_rd_data); + std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str()); + clk_to_lof_body[""].push_back(line); + } } else { if (rd_transparent) { // for rd-transparent read-ports make something like: @@ -862,31 +873,34 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // temp_id <= r_addr; // assign r_data = array_reg[temp_id]; std::string temp_id = next_auto_id(); - f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_addr.size() - 1, temp_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(), temp_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(), temp_id.c_str()); + lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr.size() - 1, temp_id.c_str()) ); + { + std::ostringstream os; + dump_sigspec(os, sig_rd_addr); + std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str()); + clk_to_lof_body[clk_domain_str].push_back(line); + } + { + std::ostringstream os; + dump_sigspec(os, sig_rd_data); + std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str()); + clk_to_lof_body[clk_domain_str].push_back(line); + } } 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"); + std::ostringstream os, os2; + dump_sigspec(os, sig_rd_data); + dump_sigspec(os2, sig_rd_addr); + std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str()); + clk_to_lof_body[""].push_back(line); } } } 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, current_bit; + RTLIL::SigBit last_bit; bool wr_clk_posedge; RTLIL::SigSpec lof_wen; dict wen_to_width; @@ -895,24 +909,26 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // 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(); + { + std::ostringstream os; + dump_sigspec(os, sig_wr_clk); + clk_domain_str = stringf("%sedge %s", wr_clk_posedge ? "pos" : "neg", os.str().c_str()); + if( clk_to_lof_body.count(clk_domain_str) == 0 ) + clk_to_lof_body[clk_domain_str] = std::vector(); + } // 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 (int j=0; j lof_lines = pair.second; + if( clk_domain != "") + { + f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str()); + for(auto &line : lof_lines) + f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str()); + f << stringf("%s" "end\n", indent.c_str()); + } + else + { + // the non-clocked assignments + for(auto &line : lof_lines) + f << stringf("%s" "%s", indent.c_str(), line.c_str()); + } + } return true; }