mirror of https://github.com/YosysHQ/yosys.git
Merged new $mem/$memwr WR_EN interface
This commit is contained in:
commit
02346cd1d5
|
@ -1287,9 +1287,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
cell->connections["\\DATA"] = children[1]->genWidthRTLIL(current_module->memories[str]->width);
|
cell->connections["\\DATA"] = children[1]->genWidthRTLIL(current_module->memories[str]->width);
|
||||||
cell->connections["\\EN"] = children[2]->genRTLIL();
|
cell->connections["\\EN"] = children[2]->genRTLIL();
|
||||||
|
|
||||||
if (cell->connections["\\EN"].width > 1)
|
|
||||||
cell->connections["\\EN"] = uniop2rtlil(this, "$reduce_bool", 1, cell->connections["\\EN"], false);
|
|
||||||
|
|
||||||
cell->parameters["\\MEMID"] = RTLIL::Const(str);
|
cell->parameters["\\MEMID"] = RTLIL::Const(str);
|
||||||
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
|
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
|
||||||
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
|
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
|
||||||
|
|
|
@ -1177,17 +1177,19 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
current_scope[wire_data->str] = wire_data;
|
current_scope[wire_data->str] = wire_data;
|
||||||
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
|
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
|
||||||
|
|
||||||
AstNode *wire_en = new AstNode(AST_WIRE);
|
AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||||
wire_en->str = id_en;
|
wire_en->str = id_en;
|
||||||
current_ast_mod->children.push_back(wire_en);
|
current_ast_mod->children.push_back(wire_en);
|
||||||
current_scope[wire_en->str] = wire_en;
|
current_scope[wire_en->str] = wire_en;
|
||||||
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
||||||
|
|
||||||
std::vector<RTLIL::State> x_bits_addr, x_bits_data;
|
std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
|
||||||
for (int i = 0; i < addr_bits; i++)
|
for (int i = 0; i < addr_bits; i++)
|
||||||
x_bits_addr.push_back(RTLIL::State::Sx);
|
x_bits_addr.push_back(RTLIL::State::Sx);
|
||||||
for (int i = 0; i < mem_width; i++)
|
for (int i = 0; i < mem_width; i++)
|
||||||
x_bits_data.push_back(RTLIL::State::Sx);
|
x_bits_data.push_back(RTLIL::State::Sx);
|
||||||
|
for (int i = 0; i < mem_width; i++)
|
||||||
|
set_bits_en.push_back(RTLIL::State::S1);
|
||||||
|
|
||||||
AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false));
|
AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false));
|
||||||
assign_addr->children[0]->str = id_addr;
|
assign_addr->children[0]->str = id_addr;
|
||||||
|
@ -1195,7 +1197,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
|
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
|
||||||
assign_data->children[0]->str = id_data;
|
assign_data->children[0]->str = id_data;
|
||||||
|
|
||||||
AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1));
|
AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
|
||||||
assign_en->children[0]->str = id_en;
|
assign_en->children[0]->str = id_en;
|
||||||
|
|
||||||
AstNode *default_signals = new AstNode(AST_BLOCK);
|
AstNode *default_signals = new AstNode(AST_BLOCK);
|
||||||
|
@ -1210,7 +1212,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
|
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
|
||||||
assign_data->children[0]->str = id_data;
|
assign_data->children[0]->str = id_data;
|
||||||
|
|
||||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
|
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
|
||||||
assign_en->children[0]->str = id_en;
|
assign_en->children[0]->str = id_en;
|
||||||
|
|
||||||
newNode = new AstNode(AST_BLOCK);
|
newNode = new AstNode(AST_BLOCK);
|
||||||
|
|
|
@ -619,7 +619,7 @@ namespace {
|
||||||
param_bool("\\CLK_POLARITY");
|
param_bool("\\CLK_POLARITY");
|
||||||
param("\\PRIORITY");
|
param("\\PRIORITY");
|
||||||
port("\\CLK", 1);
|
port("\\CLK", 1);
|
||||||
port("\\EN", 1);
|
port("\\EN", param("\\WIDTH"));
|
||||||
port("\\ADDR", param("\\ABITS"));
|
port("\\ADDR", param("\\ABITS"));
|
||||||
port("\\DATA", param("\\WIDTH"));
|
port("\\DATA", param("\\WIDTH"));
|
||||||
check_expected();
|
check_expected();
|
||||||
|
@ -639,7 +639,7 @@ namespace {
|
||||||
port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS"));
|
port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS"));
|
||||||
port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH"));
|
port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH"));
|
||||||
port("\\WR_CLK", param("\\WR_PORTS"));
|
port("\\WR_CLK", param("\\WR_PORTS"));
|
||||||
port("\\WR_EN", param("\\WR_PORTS"));
|
port("\\WR_EN", param("\\WR_PORTS") * param("\\WIDTH"));
|
||||||
port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS"));
|
port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS"));
|
||||||
port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH"));
|
port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH"));
|
||||||
check_expected();
|
check_expected();
|
||||||
|
|
|
@ -256,8 +256,9 @@ If this parameter is set to {\tt 1'b1}, a read and write to the same address in
|
||||||
return the new value. Otherwise the old value is returned.
|
return the new value. Otherwise the old value is returned.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN}, an address input \B{ADDR}
|
The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN} (one
|
||||||
and a data input \B{DATA}. They also have the following parameters:
|
enable bit for each data bit), an address input \B{ADDR} and a data input
|
||||||
|
\B{DATA}. They also have the following parameters:
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \B{MEMID} \\
|
\item \B{MEMID} \\
|
||||||
|
@ -341,7 +342,7 @@ This input is \B{RD\_PORTS}*\B{WIDTH} bits wide, containing all data signals for
|
||||||
This input is \B{WR\_PORTS} bits wide, containing all clock signals for the write ports.
|
This input is \B{WR\_PORTS} bits wide, containing all clock signals for the write ports.
|
||||||
|
|
||||||
\item \B{WR\_EN} \\
|
\item \B{WR\_EN} \\
|
||||||
This input is \B{WR\_PORTS} bits wide, containing all enable signals for the write ports.
|
This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all enable signals for the write ports.
|
||||||
|
|
||||||
\item \B{WR\_ADDR} \\
|
\item \B{WR\_ADDR} \\
|
||||||
This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals for the write ports.
|
This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals for the write ports.
|
||||||
|
|
|
@ -88,7 +88,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
|
||||||
clk_polarity.extend(1, false);
|
clk_polarity.extend(1, false);
|
||||||
addr.extend(addr_bits, false);
|
addr.extend(addr_bits, false);
|
||||||
data.extend(memory->width, false);
|
data.extend(memory->width, false);
|
||||||
en.extend(1, false);
|
en.extend(memory->width, false);
|
||||||
|
|
||||||
sig_wr_clk.append(clk);
|
sig_wr_clk.append(clk);
|
||||||
sig_wr_clk_enable.append(clk_enable);
|
sig_wr_clk_enable.append(clk_enable);
|
||||||
|
@ -147,7 +147,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
|
||||||
assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const());
|
assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const());
|
||||||
assert(sig_wr_addr.width == wr_ports * addr_bits);
|
assert(sig_wr_addr.width == wr_ports * addr_bits);
|
||||||
assert(sig_wr_data.width == wr_ports * memory->width);
|
assert(sig_wr_data.width == wr_ports * memory->width);
|
||||||
assert(sig_wr_en.width == wr_ports);
|
assert(sig_wr_en.width == wr_ports * memory->width);
|
||||||
|
|
||||||
mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports);
|
mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports);
|
||||||
mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
|
mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
|
||||||
|
|
|
@ -69,8 +69,8 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
|
||||||
RTLIL::SigSpec refclock;
|
RTLIL::SigSpec refclock;
|
||||||
RTLIL::State refclock_pol = RTLIL::State::Sx;
|
RTLIL::State refclock_pol = RTLIL::State::Sx;
|
||||||
for (int i = 0; i < clocks.width; i++) {
|
for (int i = 0; i < clocks.width; i++) {
|
||||||
RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i, 1);
|
RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i * mem_width, mem_width);
|
||||||
if (wr_en.is_fully_const() && wr_en.as_int() == 0) {
|
if (wr_en.is_fully_const() && !wr_en.as_bool()) {
|
||||||
static_ports.insert(i);
|
static_ports.insert(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
|
||||||
{
|
{
|
||||||
RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(j*mem_abits, mem_abits);
|
RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(j*mem_abits, mem_abits);
|
||||||
RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(j*mem_width, mem_width);
|
RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(j*mem_width, mem_width);
|
||||||
RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j, 1);
|
RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j*mem_width, mem_width);
|
||||||
|
|
||||||
RTLIL::Cell *c = new RTLIL::Cell;
|
RTLIL::Cell *c = new RTLIL::Cell;
|
||||||
c->name = genid(cell->name, "$wreq", i, "", j);
|
c->name = genid(cell->name, "$wreq", i, "", j);
|
||||||
|
@ -271,46 +271,64 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
|
||||||
module->cells[c->name] = c;
|
module->cells[c->name] = c;
|
||||||
count_wrmux++;
|
count_wrmux++;
|
||||||
|
|
||||||
RTLIL::Wire *w = new RTLIL::Wire;
|
RTLIL::Wire *w_seladdr = new RTLIL::Wire;
|
||||||
w->name = genid(cell->name, "$wreq", i, "", j, "$y");
|
w_seladdr->name = genid(cell->name, "$wreq", i, "", j, "$y");
|
||||||
module->wires[w->name] = w;
|
module->wires[w_seladdr->name] = w_seladdr;
|
||||||
c->connections["\\Y"] = RTLIL::SigSpec(w);
|
c->connections["\\Y"] = w_seladdr;
|
||||||
|
|
||||||
if (wr_en != RTLIL::SigSpec(1, 1))
|
int wr_offset = 0;
|
||||||
|
while (wr_offset < wr_en.width)
|
||||||
{
|
{
|
||||||
|
int wr_width = 1;
|
||||||
|
RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1);
|
||||||
|
|
||||||
|
while (wr_offset + wr_width < wr_en.width) {
|
||||||
|
RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1);
|
||||||
|
if (next_wr_bit != wr_bit)
|
||||||
|
break;
|
||||||
|
wr_width++;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTLIL::Wire *w = w_seladdr;
|
||||||
|
|
||||||
|
if (wr_bit != RTLIL::SigSpec(1, 1))
|
||||||
|
{
|
||||||
|
c = new RTLIL::Cell;
|
||||||
|
c->name = genid(cell->name, "$wren", i, "", j, "", wr_offset);
|
||||||
|
c->type = "$and";
|
||||||
|
c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
|
||||||
|
c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
|
||||||
|
c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
|
||||||
|
c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
|
||||||
|
c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
|
||||||
|
c->connections["\\A"] = w;
|
||||||
|
c->connections["\\B"] = wr_bit;
|
||||||
|
module->cells[c->name] = c;
|
||||||
|
|
||||||
|
w = new RTLIL::Wire;
|
||||||
|
w->name = genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y");
|
||||||
|
module->wires[w->name] = w;
|
||||||
|
c->connections["\\Y"] = RTLIL::SigSpec(w);
|
||||||
|
}
|
||||||
|
|
||||||
c = new RTLIL::Cell;
|
c = new RTLIL::Cell;
|
||||||
c->name = genid(cell->name, "$wren", i, "", j);
|
c->name = genid(cell->name, "$wrmux", i, "", j, "", wr_offset);
|
||||||
c->type = "$and";
|
c->type = "$mux";
|
||||||
c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
|
c->parameters["\\WIDTH"] = wr_width;
|
||||||
c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
|
c->connections["\\A"] = sig.extract(wr_offset, wr_width);
|
||||||
c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
|
c->connections["\\B"] = wr_data.extract(wr_offset, wr_width);
|
||||||
c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
|
c->connections["\\S"] = RTLIL::SigSpec(w);
|
||||||
c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
|
|
||||||
c->connections["\\A"] = RTLIL::SigSpec(w);
|
|
||||||
c->connections["\\B"] = wr_en;
|
|
||||||
module->cells[c->name] = c;
|
module->cells[c->name] = c;
|
||||||
|
|
||||||
w = new RTLIL::Wire;
|
w = new RTLIL::Wire;
|
||||||
w->name = genid(cell->name, "$wren", i, "", j, "$y");
|
w->name = genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y");
|
||||||
|
w->width = wr_width;
|
||||||
module->wires[w->name] = w;
|
module->wires[w->name] = w;
|
||||||
c->connections["\\Y"] = RTLIL::SigSpec(w);
|
c->connections["\\Y"] = w;
|
||||||
|
|
||||||
|
sig.replace(wr_offset, w);
|
||||||
|
wr_offset += wr_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = new RTLIL::Cell;
|
|
||||||
c->name = genid(cell->name, "$wrmux", i, "", j);
|
|
||||||
c->type = "$mux";
|
|
||||||
c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
|
|
||||||
c->connections["\\A"] = sig;
|
|
||||||
c->connections["\\B"] = wr_data;
|
|
||||||
c->connections["\\S"] = RTLIL::SigSpec(w);
|
|
||||||
module->cells[c->name] = c;
|
|
||||||
|
|
||||||
w = new RTLIL::Wire;
|
|
||||||
w->name = genid(cell->name, "$wrmux", i, "", j, "$y");
|
|
||||||
w->width = mem_width;
|
|
||||||
module->wires[w->name] = w;
|
|
||||||
c->connections["\\Y"] = RTLIL::SigSpec(w);
|
|
||||||
sig = RTLIL::SigSpec(w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
|
module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
|
||||||
|
|
|
@ -74,7 +74,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
|
||||||
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_POLARITY")).extract(i, 1).as_const();
|
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_POLARITY")).extract(i, 1).as_const();
|
||||||
cell->parameters["\\PRIORITY"] = i;
|
cell->parameters["\\PRIORITY"] = i;
|
||||||
cell->connections["\\CLK"] = memory->connections.at("\\WR_CLK").extract(i, 1);
|
cell->connections["\\CLK"] = memory->connections.at("\\WR_CLK").extract(i, 1);
|
||||||
cell->connections["\\EN"] = memory->connections.at("\\WR_EN").extract(i, 1);
|
cell->connections["\\EN"] = memory->connections.at("\\WR_EN").extract(i*mem->width, mem->width);
|
||||||
cell->connections["\\ADDR"] = memory->connections.at("\\WR_ADDR").extract(i*abits, abits);
|
cell->connections["\\ADDR"] = memory->connections.at("\\WR_ADDR").extract(i*abits, abits);
|
||||||
cell->connections["\\DATA"] = memory->connections.at("\\WR_DATA").extract(i*mem->width, mem->width);
|
cell->connections["\\DATA"] = memory->connections.at("\\WR_DATA").extract(i*mem->width, mem->width);
|
||||||
module->add(cell);
|
module->add(cell);
|
||||||
|
|
|
@ -171,6 +171,66 @@ struct OptReduceWorker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void opt_mux_bits(RTLIL::Cell *cell)
|
||||||
|
{
|
||||||
|
std::vector<RTLIL::SigBit> sig_a = assign_map(cell->connections["\\A"]).to_sigbit_vector();
|
||||||
|
std::vector<RTLIL::SigBit> sig_b = assign_map(cell->connections["\\B"]).to_sigbit_vector();
|
||||||
|
std::vector<RTLIL::SigBit> sig_y = assign_map(cell->connections["\\Y"]).to_sigbit_vector();
|
||||||
|
|
||||||
|
std::vector<RTLIL::SigBit> new_sig_y;
|
||||||
|
RTLIL::SigSig old_sig_conn;
|
||||||
|
|
||||||
|
std::vector<std::vector<RTLIL::SigBit>> consolidated_in_tuples;
|
||||||
|
std::map<std::vector<RTLIL::SigBit>, RTLIL::SigBit> consolidated_in_tuples_map;
|
||||||
|
|
||||||
|
for (int i = 0; i < int(sig_y.size()); i++)
|
||||||
|
{
|
||||||
|
std::vector<RTLIL::SigBit> in_tuple;
|
||||||
|
in_tuple.push_back(sig_a.at(i));
|
||||||
|
for (int j = i; j < int(sig_b.size()); j += int(sig_a.size()))
|
||||||
|
in_tuple.push_back(sig_b.at(j));
|
||||||
|
|
||||||
|
if (consolidated_in_tuples_map.count(in_tuple))
|
||||||
|
{
|
||||||
|
old_sig_conn.first.append_bit(sig_y.at(i));
|
||||||
|
old_sig_conn.second.append_bit(consolidated_in_tuples_map.at(in_tuple));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consolidated_in_tuples_map[in_tuple] = sig_y.at(i);
|
||||||
|
consolidated_in_tuples.push_back(in_tuple);
|
||||||
|
new_sig_y.push_back(sig_y.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_sig_y.size() != sig_y.size())
|
||||||
|
{
|
||||||
|
log(" Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str());
|
||||||
|
log(" Old inputs: A=%s, B=%s\n", log_signal(cell->connections["\\A"]), log_signal(cell->connections["\\B"]));
|
||||||
|
|
||||||
|
cell->connections["\\A"] = RTLIL::SigSpec();
|
||||||
|
for (auto &in_tuple : consolidated_in_tuples)
|
||||||
|
cell->connections["\\A"].append(in_tuple.at(0));
|
||||||
|
|
||||||
|
cell->connections["\\B"] = RTLIL::SigSpec();
|
||||||
|
for (int i = 1; i <= cell->connections["\\S"].width; i++)
|
||||||
|
for (auto &in_tuple : consolidated_in_tuples)
|
||||||
|
cell->connections["\\B"].append(in_tuple.at(i));
|
||||||
|
|
||||||
|
log(" New inputs: A=%s, B=%s\n", log_signal(cell->connections["\\A"]), log_signal(cell->connections["\\B"]));
|
||||||
|
|
||||||
|
cell->parameters["\\WIDTH"] = RTLIL::Const(new_sig_y.size());
|
||||||
|
cell->connections["\\Y"] = new_sig_y;
|
||||||
|
|
||||||
|
module->connections.push_back(old_sig_conn);
|
||||||
|
module->check();
|
||||||
|
|
||||||
|
did_something = true;
|
||||||
|
OPT_DID_SOMETHING = true;
|
||||||
|
total_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
|
OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
|
||||||
design(design), module(module), assign_map(module)
|
design(design), module(module), assign_map(module)
|
||||||
{
|
{
|
||||||
|
@ -179,6 +239,20 @@ struct OptReduceWorker
|
||||||
total_count = 0;
|
total_count = 0;
|
||||||
did_something = true;
|
did_something = true;
|
||||||
|
|
||||||
|
SigPool mem_wren_sigs;
|
||||||
|
for (auto &cell_it : module->cells) {
|
||||||
|
RTLIL::Cell *cell = cell_it.second;
|
||||||
|
if (cell->type == "$mem")
|
||||||
|
mem_wren_sigs.add(assign_map(cell->connections["\\WR_EN"]));
|
||||||
|
if (cell->type == "$memwr")
|
||||||
|
mem_wren_sigs.add(assign_map(cell->connections["\\EN"]));
|
||||||
|
}
|
||||||
|
for (auto &cell_it : module->cells) {
|
||||||
|
RTLIL::Cell *cell = cell_it.second;
|
||||||
|
if (cell->type == "$dff" && mem_wren_sigs.check_any(assign_map(cell->connections["\\Q"])))
|
||||||
|
mem_wren_sigs.add(assign_map(cell->connections["\\D"]));
|
||||||
|
}
|
||||||
|
|
||||||
while (did_something)
|
while (did_something)
|
||||||
{
|
{
|
||||||
did_something = false;
|
did_something = false;
|
||||||
|
@ -213,6 +287,12 @@ struct OptReduceWorker
|
||||||
RTLIL::Cell *cell = cell_it.second;
|
RTLIL::Cell *cell = cell_it.second;
|
||||||
if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
|
if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// this optimization is to aggressive for most coarse-grain applications.
|
||||||
|
// but we always want it for multiplexers driving write enable ports.
|
||||||
|
if (mem_wren_sigs.check_any(assign_map(cell->connections.at("\\Y"))))
|
||||||
|
opt_mux_bits(cell);
|
||||||
|
|
||||||
opt_mux(cell);
|
opt_mux(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1264,7 +1264,8 @@ parameter WIDTH = 8;
|
||||||
parameter CLK_ENABLE = 0;
|
parameter CLK_ENABLE = 0;
|
||||||
parameter CLK_POLARITY = 0;
|
parameter CLK_POLARITY = 0;
|
||||||
|
|
||||||
input CLK, EN;
|
input CLK;
|
||||||
|
input [WIDTH-1:0] EN;
|
||||||
input [ABITS-1:0] ADDR;
|
input [ABITS-1:0] ADDR;
|
||||||
input [WIDTH-1:0] DATA;
|
input [WIDTH-1:0] DATA;
|
||||||
|
|
||||||
|
@ -1300,7 +1301,8 @@ input [RD_PORTS-1:0] RD_CLK;
|
||||||
input [RD_PORTS*ABITS-1:0] RD_ADDR;
|
input [RD_PORTS*ABITS-1:0] RD_ADDR;
|
||||||
output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
|
output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
|
||||||
|
|
||||||
input [WR_PORTS-1:0] WR_CLK, WR_EN;
|
input [WR_PORTS-1:0] WR_CLK;
|
||||||
|
input [WR_PORTS*WIDTH-1:0] WR_EN;
|
||||||
input [WR_PORTS*ABITS-1:0] WR_ADDR;
|
input [WR_PORTS*ABITS-1:0] WR_ADDR;
|
||||||
input [WR_PORTS*WIDTH-1:0] WR_DATA;
|
input [WR_PORTS*WIDTH-1:0] WR_DATA;
|
||||||
|
|
||||||
|
@ -1338,46 +1340,69 @@ generate
|
||||||
end
|
end
|
||||||
|
|
||||||
for (i = 0; i < WR_PORTS; i = i+1) begin:wr
|
for (i = 0; i < WR_PORTS; i = i+1) begin:wr
|
||||||
integer k;
|
integer k, n;
|
||||||
reg found_collision;
|
reg found_collision, run_update;
|
||||||
if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk
|
if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk
|
||||||
always @(WR_ADDR or WR_DATA or WR_EN) begin
|
always @(WR_ADDR or WR_DATA or WR_EN) begin
|
||||||
if (WR_EN[i]) begin
|
run_update = 0;
|
||||||
found_collision = 0;
|
for (n = 0; n < WIDTH; n = n+1) begin
|
||||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
if (WR_EN[i][n]) begin
|
||||||
if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
found_collision = 0;
|
||||||
found_collision = 1;
|
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||||
if (!found_collision) begin
|
if (WR_EN[k][n] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
|
found_collision = 1;
|
||||||
update_async_rd <= 1; update_async_rd <= 0;
|
if (!found_collision) begin
|
||||||
|
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ][n] <= WR_DATA[ i*WIDTH +: WIDTH ][n];
|
||||||
|
run_update = 1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if (run_update) begin
|
||||||
|
update_async_rd <= 1;
|
||||||
|
update_async_rd <= 0;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end else
|
end else
|
||||||
if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk
|
if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk
|
||||||
always @(posedge WR_CLK[i])
|
always @(posedge WR_CLK[i]) begin
|
||||||
if (WR_EN[i]) begin
|
run_update = 0;
|
||||||
found_collision = 0;
|
for (n = 0; n < WIDTH; n = n+1) begin
|
||||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
if (WR_EN[i][n]) begin
|
||||||
if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
found_collision = 0;
|
||||||
found_collision = 1;
|
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||||
if (!found_collision) begin
|
if (WR_EN[k][n] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
|
found_collision = 1;
|
||||||
update_async_rd <= 1; update_async_rd <= 0;
|
if (!found_collision) begin
|
||||||
|
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ][n] <= WR_DATA[ i*WIDTH +: WIDTH ][n];
|
||||||
|
run_update = 1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if (run_update) begin
|
||||||
|
update_async_rd <= 1;
|
||||||
|
update_async_rd <= 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
end else begin:rd_negclk
|
end else begin:rd_negclk
|
||||||
always @(negedge WR_CLK[i])
|
always @(negedge WR_CLK[i]) begin
|
||||||
if (WR_EN[i]) begin
|
run_update = 0;
|
||||||
found_collision = 0;
|
for (n = 0; n < WIDTH; n = n+1) begin
|
||||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
if (WR_EN[i][n]) begin
|
||||||
if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
found_collision = 0;
|
||||||
found_collision = 1;
|
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||||
if (!found_collision) begin
|
if (WR_EN[k][n] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
|
found_collision = 1;
|
||||||
update_async_rd <= 1; update_async_rd <= 0;
|
if (!found_collision) begin
|
||||||
|
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ][n] <= WR_DATA[ i*WIDTH +: WIDTH ][n];
|
||||||
|
run_update = 1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if (run_update) begin
|
||||||
|
update_async_rd <= 1;
|
||||||
|
update_async_rd <= 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
|
||||||
input [RD_PORTS*ABITS-1:0] RD_ADDR;
|
input [RD_PORTS*ABITS-1:0] RD_ADDR;
|
||||||
output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
|
output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
|
||||||
|
|
||||||
input [WR_PORTS-1:0] WR_CLK, WR_EN;
|
input [WR_PORTS-1:0] WR_CLK;
|
||||||
|
input [WR_PORTS*WIDTH-1:0] WR_EN;
|
||||||
input [WR_PORTS*ABITS-1:0] WR_ADDR;
|
input [WR_PORTS*ABITS-1:0] WR_ADDR;
|
||||||
input [WR_PORTS*WIDTH-1:0] WR_DATA;
|
input [WR_PORTS*WIDTH-1:0] WR_DATA;
|
||||||
|
|
||||||
|
@ -28,7 +29,11 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
|
||||||
parameter _TECHMAP_CONNMAP_RD_CLK_ = 0;
|
parameter _TECHMAP_CONNMAP_RD_CLK_ = 0;
|
||||||
parameter _TECHMAP_CONNMAP_WR_CLK_ = 0;
|
parameter _TECHMAP_CONNMAP_WR_CLK_ = 0;
|
||||||
|
|
||||||
|
parameter _TECHMAP_BITS_CONNMAP_ = 0;
|
||||||
|
parameter _TECHMAP_CONNMAP_WR_EN_ = 0;
|
||||||
|
|
||||||
reg _TECHMAP_FAIL_;
|
reg _TECHMAP_FAIL_;
|
||||||
|
integer k;
|
||||||
initial begin
|
initial begin
|
||||||
_TECHMAP_FAIL_ <= 0;
|
_TECHMAP_FAIL_ <= 0;
|
||||||
|
|
||||||
|
@ -44,6 +49,12 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
|
||||||
if (!WR_CLK_ENABLE || !WR_CLK_POLARITY)
|
if (!WR_CLK_ENABLE || !WR_CLK_POLARITY)
|
||||||
_TECHMAP_FAIL_ <= 1;
|
_TECHMAP_FAIL_ <= 1;
|
||||||
|
|
||||||
|
// only one global write enable bit is supported
|
||||||
|
for (k = 1; k < WR_PORTS*WIDTH; k = k+1)
|
||||||
|
if (_TECHMAP_CONNMAP_WR_EN_[0 +: _TECHMAP_BITS_CONNMAP_] !=
|
||||||
|
_TECHMAP_CONNMAP_WR_EN_[k*_TECHMAP_BITS_CONNMAP_ +: _TECHMAP_BITS_CONNMAP_])
|
||||||
|
_TECHMAP_FAIL_ <= 1;
|
||||||
|
|
||||||
// read and write must be in same clock domain
|
// read and write must be in same clock domain
|
||||||
if (_TECHMAP_CONNMAP_RD_CLK_ != _TECHMAP_CONNMAP_WR_CLK_)
|
if (_TECHMAP_CONNMAP_RD_CLK_ != _TECHMAP_CONNMAP_WR_CLK_)
|
||||||
_TECHMAP_FAIL_ <= 1;
|
_TECHMAP_FAIL_ <= 1;
|
||||||
|
@ -65,7 +76,7 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
|
||||||
.RD_DATA(RD_DATA[i]),
|
.RD_DATA(RD_DATA[i]),
|
||||||
.WR_ADDR(WR_ADDR),
|
.WR_ADDR(WR_ADDR),
|
||||||
.WR_DATA(WR_DATA[i]),
|
.WR_DATA(WR_DATA[i]),
|
||||||
.WR_EN(WR_EN)
|
.WR_EN(WR_EN[0])
|
||||||
);
|
);
|
||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
Loading…
Reference in New Issue