mirror of https://github.com/YosysHQ/yosys.git
$mem cell in verilog backend : grouped writes by clock
This commit is contained in:
parent
a8fe040906
commit
2f90499e3d
|
@ -38,7 +38,7 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
bool norename, noattr, attr2comment, noexpr, nomem;
|
bool norename, noattr, attr2comment, noexpr;
|
||||||
int auto_name_counter, auto_name_offset, auto_name_digits;
|
int auto_name_counter, auto_name_offset, auto_name_digits;
|
||||||
std::map<RTLIL::IdString, int> auto_name_map;
|
std::map<RTLIL::IdString, int> auto_name_map;
|
||||||
std::set<RTLIL::IdString> reg_wires, reg_ct;
|
std::set<RTLIL::IdString> reg_wires, reg_ct;
|
||||||
|
@ -791,7 +791,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->type == "$mem" && nomem == false)
|
if (cell->type == "$mem")
|
||||||
{
|
{
|
||||||
RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
|
RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
|
||||||
std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
|
std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
|
||||||
|
@ -818,6 +818,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
f << stringf("%s" "end\n", indent.c_str());
|
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();
|
int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
|
||||||
RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr;
|
RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr;
|
||||||
bool use_rd_clk, rd_clk_posedge, rd_transparent;
|
bool use_rd_clk, rd_clk_posedge, rd_transparent;
|
||||||
|
@ -830,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();
|
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_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
|
||||||
rd_transparent = cell->parameters["\\RD_TRANSPARENT"].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)
|
if (use_rd_clk && !rd_transparent)
|
||||||
{
|
{
|
||||||
// for clocked read ports make something like:
|
// for clocked read ports make something like:
|
||||||
|
@ -838,16 +852,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
// temp_id <= array_reg[r_addr];
|
// temp_id <= array_reg[r_addr];
|
||||||
// assign r_data = temp_id;
|
// assign r_data = temp_id;
|
||||||
std::string temp_id = next_auto_id();
|
std::string temp_id = next_auto_id();
|
||||||
f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_data.size() - 1, temp_id.c_str());
|
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.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);
|
std::ostringstream os;
|
||||||
f << stringf(")\n");
|
dump_sigspec(os, sig_rd_addr);
|
||||||
f << stringf("%s" " %s <= %s[", indent.c_str(), temp_id.c_str(), mem_id.c_str());
|
std::string line = stringf("%s <= %s[%s];\n", temp_id.c_str(), mem_id.c_str(), os.str().c_str());
|
||||||
dump_sigspec(f, sig_rd_addr);
|
clk_to_lof_body[clk_domain_str].push_back(line);
|
||||||
f << stringf("];\n");
|
}
|
||||||
f << stringf("%s" "assign ", indent.c_str());
|
{
|
||||||
dump_sigspec(f, sig_rd_data);
|
std::ostringstream os;
|
||||||
f << stringf(" = %s;\n", temp_id.c_str());
|
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 {
|
} else {
|
||||||
if (rd_transparent) {
|
if (rd_transparent) {
|
||||||
// for rd-transparent read-ports make something like:
|
// for rd-transparent read-ports make something like:
|
||||||
|
@ -856,24 +873,27 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
// temp_id <= r_addr;
|
// temp_id <= r_addr;
|
||||||
// assign r_data = array_reg[temp_id];
|
// assign r_data = array_reg[temp_id];
|
||||||
std::string temp_id = next_auto_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());
|
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", 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);
|
std::ostringstream os;
|
||||||
f << stringf(")\n");
|
dump_sigspec(os, sig_rd_addr);
|
||||||
f << stringf("%s" " %s <= ", indent.c_str(), temp_id.c_str());
|
std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
|
||||||
dump_sigspec(f, sig_rd_addr);
|
clk_to_lof_body[clk_domain_str].push_back(line);
|
||||||
f << stringf(";\n");
|
}
|
||||||
f << stringf("%s" "assign ", indent.c_str());
|
{
|
||||||
dump_sigspec(f, sig_rd_data);
|
std::ostringstream os;
|
||||||
f << stringf(" = %s[%s];\n", mem_id.c_str(), temp_id.c_str());
|
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 {
|
} else {
|
||||||
// for non-clocked read-ports make something like:
|
// for non-clocked read-ports make something like:
|
||||||
// assign r_data = array_reg[r_addr];
|
// assign r_data = array_reg[r_addr];
|
||||||
f << stringf("%s" "assign ", indent.c_str());
|
std::ostringstream os, os2;
|
||||||
dump_sigspec(f, sig_rd_data);
|
dump_sigspec(os, sig_rd_data);
|
||||||
f << stringf(" = %s[", mem_id.c_str());
|
dump_sigspec(os2, sig_rd_addr);
|
||||||
dump_sigspec(f, sig_rd_addr);
|
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
|
||||||
f << stringf("];\n");
|
clk_to_lof_body[""].push_back(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,16 +909,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
// write ports
|
// write ports
|
||||||
for (int i=0; i < nwrite_ports; i++)
|
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_clk = cell->getPort("\\WR_CLK").extract(i);
|
||||||
sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
|
sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
|
||||||
sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
|
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 = cell->getPort("\\WR_EN").extract(i*width, width);
|
||||||
sig_wr_en_bit = sig_wr_en.extract(0);
|
sig_wr_en_bit = sig_wr_en.extract(0);
|
||||||
wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
|
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
|
// group the wen bits
|
||||||
last_bit = sig_wr_en.extract(0);
|
last_bit = sig_wr_en.extract(0);
|
||||||
lof_wen = RTLIL::SigSpec(last_bit);
|
lof_wen = RTLIL::SigSpec(last_bit);
|
||||||
|
@ -916,35 +939,75 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
}
|
}
|
||||||
// make something like:
|
// make something like:
|
||||||
// always @(posedge clk)
|
// always @(posedge clk)
|
||||||
// if (wr_en_bit)
|
// if (wr_en_bit) memid[w_addr][??] <= w_data[??];
|
||||||
// memid[w_addr][??] <= w_data[??];
|
|
||||||
// ...
|
// ...
|
||||||
n = 0;
|
n = 0;
|
||||||
for (auto &wen_bit : lof_wen) {
|
for (auto &wen_bit : lof_wen) {
|
||||||
wen_width = wen_to_width[wen_bit];
|
wen_width = wen_to_width[wen_bit];
|
||||||
if (!(wen_bit == RTLIL::SigBit(false)))
|
if (!(wen_bit == RTLIL::SigBit(false)))
|
||||||
{
|
{
|
||||||
f << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg");
|
std::ostringstream os;
|
||||||
dump_sigspec(f, sig_wr_clk);
|
|
||||||
f << stringf(")\n");
|
|
||||||
if (!(wen_bit == RTLIL::SigBit(true)))
|
if (!(wen_bit == RTLIL::SigBit(true)))
|
||||||
{
|
{
|
||||||
f << stringf("%s" " if (", indent.c_str());
|
os << stringf("if (");
|
||||||
dump_sigspec(f, wen_bit);
|
dump_sigspec(os, wen_bit);
|
||||||
f << stringf(")\n ");
|
os << stringf(") ");
|
||||||
}
|
}
|
||||||
f << stringf("%s" " %s[", indent.c_str(), mem_id.c_str());
|
os << stringf("%s[", mem_id.c_str());
|
||||||
dump_sigspec(f, sig_wr_addr);
|
dump_sigspec(os, sig_wr_addr);
|
||||||
if (wen_width == width)
|
if (wen_width == width)
|
||||||
f << stringf("] <= ");
|
os << stringf("] <= ");
|
||||||
else
|
else
|
||||||
f << stringf("][%d:%d] <= ", n+wen_width-1, n);
|
os << stringf("][%d:%d] <= ", n+wen_width-1, n);
|
||||||
dump_sigspec(f, sig_wr_data.extract(n, wen_width));
|
dump_sigspec(os, sig_wr_data.extract(n, wen_width));
|
||||||
f << stringf(";\n");
|
os << stringf(";\n");
|
||||||
|
clk_to_lof_body[clk_domain_str].push_back(os.str());
|
||||||
}
|
}
|
||||||
n += wen_width;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1285,10 +1348,6 @@ struct VerilogBackend : public Backend {
|
||||||
log(" only write selected modules. modules must be selected entirely or\n");
|
log(" only write selected modules. modules must be selected entirely or\n");
|
||||||
log(" not at all.\n");
|
log(" not at all.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -nomem\n");
|
|
||||||
log(" do not create verilog code for $mem cells. This is only used for\n");
|
|
||||||
log(" testing.\n");
|
|
||||||
log("\n");
|
|
||||||
}
|
}
|
||||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
|
@ -1298,7 +1357,6 @@ struct VerilogBackend : public Backend {
|
||||||
noattr = false;
|
noattr = false;
|
||||||
attr2comment = false;
|
attr2comment = false;
|
||||||
noexpr = false;
|
noexpr = false;
|
||||||
nomem = false;
|
|
||||||
|
|
||||||
bool blackboxes = false;
|
bool blackboxes = false;
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
@ -1356,10 +1414,6 @@ struct VerilogBackend : public Backend {
|
||||||
selected = true;
|
selected = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-nomem") {
|
|
||||||
nomem = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(f, filename, args, argidx);
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
../../yosys -qq -p "proc; opt; memory -nomap -bram temp/brams_${2}.txt; opt -fast -full; write_verilog temp/synth_${1}_${2}_stage0.v" \
|
../../yosys -qq -p "proc; opt; memory -nomap -bram temp/brams_${2}.txt; opt -fast -full" \
|
||||||
-l temp/synth_${1}_${2}_stage0.log temp/brams_${1}.v
|
-l temp/synth_${1}_${2}.log -o temp/synth_${1}_${2}.v temp/brams_${1}.v
|
||||||
../../yosys -qq -p "proc; opt; memory -nomap; opt -fast -full; write_verilog -nomem temp/synth_${1}_${2}.v" \
|
|
||||||
-l temp/synth_${1}_${2}.log temp/synth_${1}_${2}_stage0.v
|
|
||||||
iverilog -Dvcd_file=\"temp/tb_${1}_${2}.vcd\" -DSIMLIB_MEMDELAY=1ns -o temp/tb_${1}_${2}.tb temp/brams_${1}_tb.v \
|
iverilog -Dvcd_file=\"temp/tb_${1}_${2}.vcd\" -DSIMLIB_MEMDELAY=1ns -o temp/tb_${1}_${2}.tb temp/brams_${1}_tb.v \
|
||||||
temp/brams_${1}_ref.v temp/synth_${1}_${2}.v temp/brams_${2}.v ../../techlibs/common/simlib.v
|
temp/brams_${1}_ref.v temp/synth_${1}_${2}.v temp/brams_${2}.v ../../techlibs/common/simlib.v
|
||||||
temp/tb_${1}_${2}.tb > temp/tb_${1}_${2}.txt
|
temp/tb_${1}_${2}.tb > temp/tb_${1}_${2}.txt
|
||||||
|
|
Loading…
Reference in New Issue