aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backends/verilog/verilog_backend.cc164
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 &current_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 &reg : 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;
}