diff options
author | Clifford Wolf <clifford@clifford.at> | 2015-06-09 06:42:07 +0200 |
---|---|---|
committer | Clifford Wolf <clifford@clifford.at> | 2015-06-09 06:42:07 +0200 |
commit | c88be7bae5e06a605aea0cebc483bf5d02737bf1 (patch) | |
tree | 3fc31ae98de7ebc340ed85818b904432eedb8ed2 | |
parent | de4f4dad3c69561711e878dbcbf3019e1a44e907 (diff) | |
parent | 2f90499e3db061e07fbe6cc544d7f888db34eb6d (diff) | |
download | yosys-c88be7bae5e06a605aea0cebc483bf5d02737bf1.tar.gz yosys-c88be7bae5e06a605aea0cebc483bf5d02737bf1.tar.bz2 yosys-c88be7bae5e06a605aea0cebc483bf5d02737bf1.zip |
Merge branch 'verilog-backend-memV2' of github.com:wluker/yosys
-rw-r--r-- | backends/verilog/verilog_backend.cc | 164 |
1 files changed, 110 insertions, 54 deletions
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<std::string, std::vector<std::string>> clk_to_lof_body; + clk_to_lof_body[""] = std::vector<std::string>(); + std::string clk_domain_str; + // create a list of reg declarations + 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; 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<std::string>(); + } 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<RTLIL::SigSpec, int> 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<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 (int j=0; j<width; j++) + for (auto ¤t_bit : sig_wr_en.bits()) { - current_bit = sig_wr_en.extract(j); if (sigmap(current_bit) == sigmap(last_bit)){ wen_to_width[current_bit] += 1; } else { @@ -923,35 +939,75 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) } // make something like: // always @(posedge clk) - // if (wr_en_bit) - // memid[w_addr][??] <= w_data[??]; + // 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))) { - f << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg"); - dump_sigspec(f, sig_wr_clk); - f << stringf(")\n"); + std::ostringstream os; if (!(wen_bit == RTLIL::SigBit(true))) { - f << stringf("%s" " if (", indent.c_str()); - dump_sigspec(f, wen_bit); - f << stringf(")\n "); + os << stringf("if ("); + dump_sigspec(os, wen_bit); + os << stringf(") "); } - f << stringf("%s" " %s[", indent.c_str(), mem_id.c_str()); - dump_sigspec(f, sig_wr_addr); + os << stringf("%s[", mem_id.c_str()); + dump_sigspec(os, sig_wr_addr); if (wen_width == width) - f << stringf("] <= "); + os << stringf("] <= "); else - f << stringf("][%d:%d] <= ", n+wen_width-1, n); - dump_sigspec(f, sig_wr_data.extract(n, wen_width)); - f << stringf(";\n"); + 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()); } n += wen_width; } } + // Output verilog that looks something like this: + // reg [..] _3_; + // always @(posedge CLK2) begin + // _3_ <= memory[D1ADDR]; + // if (A1EN) + // memory[A1ADDR] <= A1DATA; + // if (A2EN) + // memory[A2ADDR] <= A2DATA; + // ... + // end + // always @(negedge CLK1) begin + // if (C1EN) + // memory[C1ADDR] <= C1DATA; + // end + // ... + // assign D1DATA = _3_; + // assign D2DATA <= memory[D2ADDR]; + + // the reg ... definitions + for(auto ® : lof_reg_declarations) + { + f << stringf("%s" "%s", indent.c_str(), reg.c_str()); + } + // the block of expressions by clock domain + for(auto &pair : clk_to_lof_body) + { + std::string clk_domain = pair.first; + std::vector<std::string> 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; } |