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["\\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["\\ABITS"] = RTLIL::Const(addr_bits);
|
||||
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;
|
||||
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;
|
||||
current_ast_mod->children.push_back(wire_en);
|
||||
current_scope[wire_en->str] = wire_en;
|
||||
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++)
|
||||
x_bits_addr.push_back(RTLIL::State::Sx);
|
||||
for (int i = 0; i < mem_width; i++)
|
||||
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));
|
||||
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));
|
||||
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;
|
||||
|
||||
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->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;
|
||||
|
||||
newNode = new AstNode(AST_BLOCK);
|
||||
|
|
|
@ -619,7 +619,7 @@ namespace {
|
|||
param_bool("\\CLK_POLARITY");
|
||||
param("\\PRIORITY");
|
||||
port("\\CLK", 1);
|
||||
port("\\EN", 1);
|
||||
port("\\EN", param("\\WIDTH"));
|
||||
port("\\ADDR", param("\\ABITS"));
|
||||
port("\\DATA", param("\\WIDTH"));
|
||||
check_expected();
|
||||
|
@ -639,7 +639,7 @@ namespace {
|
|||
port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS"));
|
||||
port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH"));
|
||||
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_DATA", param("\\WR_PORTS") * param("\\WIDTH"));
|
||||
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.
|
||||
\end{itemize}
|
||||
|
||||
The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN}, an address input \B{ADDR}
|
||||
and a data input \B{DATA}. They also have the following parameters:
|
||||
The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN} (one
|
||||
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}
|
||||
\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.
|
||||
|
||||
\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} \\
|
||||
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);
|
||||
addr.extend(addr_bits, false);
|
||||
data.extend(memory->width, false);
|
||||
en.extend(1, false);
|
||||
en.extend(memory->width, false);
|
||||
|
||||
sig_wr_clk.append(clk);
|
||||
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_addr.width == wr_ports * addr_bits);
|
||||
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_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::State refclock_pol = RTLIL::State::Sx;
|
||||
for (int i = 0; i < clocks.width; i++) {
|
||||
RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i, 1);
|
||||
if (wr_en.is_fully_const() && wr_en.as_int() == 0) {
|
||||
RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i * mem_width, mem_width);
|
||||
if (wr_en.is_fully_const() && !wr_en.as_bool()) {
|
||||
static_ports.insert(i);
|
||||
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_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;
|
||||
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;
|
||||
count_wrmux++;
|
||||
|
||||
RTLIL::Wire *w = new RTLIL::Wire;
|
||||
w->name = genid(cell->name, "$wreq", i, "", j, "$y");
|
||||
module->wires[w->name] = w;
|
||||
c->connections["\\Y"] = RTLIL::SigSpec(w);
|
||||
RTLIL::Wire *w_seladdr = new RTLIL::Wire;
|
||||
w_seladdr->name = genid(cell->name, "$wreq", i, "", j, "$y");
|
||||
module->wires[w_seladdr->name] = w_seladdr;
|
||||
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->name = genid(cell->name, "$wren", i, "", j);
|
||||
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"] = RTLIL::SigSpec(w);
|
||||
c->connections["\\B"] = wr_en;
|
||||
c->name = genid(cell->name, "$wrmux", i, "", j, "", wr_offset);
|
||||
c->type = "$mux";
|
||||
c->parameters["\\WIDTH"] = wr_width;
|
||||
c->connections["\\A"] = sig.extract(wr_offset, wr_width);
|
||||
c->connections["\\B"] = wr_data.extract(wr_offset, wr_width);
|
||||
c->connections["\\S"] = RTLIL::SigSpec(w);
|
||||
module->cells[c->name] = c;
|
||||
|
||||
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;
|
||||
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));
|
||||
|
|
|
@ -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["\\PRIORITY"] = i;
|
||||
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["\\DATA"] = memory->connections.at("\\WR_DATA").extract(i*mem->width, mem->width);
|
||||
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) :
|
||||
design(design), module(module), assign_map(module)
|
||||
{
|
||||
|
@ -179,6 +239,20 @@ struct OptReduceWorker
|
|||
total_count = 0;
|
||||
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)
|
||||
{
|
||||
did_something = false;
|
||||
|
@ -213,6 +287,12 @@ struct OptReduceWorker
|
|||
RTLIL::Cell *cell = cell_it.second;
|
||||
if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1264,7 +1264,8 @@ parameter WIDTH = 8;
|
|||
parameter CLK_ENABLE = 0;
|
||||
parameter CLK_POLARITY = 0;
|
||||
|
||||
input CLK, EN;
|
||||
input CLK;
|
||||
input [WIDTH-1:0] EN;
|
||||
input [ABITS-1:0] ADDR;
|
||||
input [WIDTH-1:0] DATA;
|
||||
|
||||
|
@ -1300,7 +1301,8 @@ input [RD_PORTS-1:0] RD_CLK;
|
|||
input [RD_PORTS*ABITS-1:0] RD_ADDR;
|
||||
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*WIDTH-1:0] WR_DATA;
|
||||
|
||||
|
@ -1338,46 +1340,69 @@ generate
|
|||
end
|
||||
|
||||
for (i = 0; i < WR_PORTS; i = i+1) begin:wr
|
||||
integer k;
|
||||
reg found_collision;
|
||||
integer k, n;
|
||||
reg found_collision, run_update;
|
||||
if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk
|
||||
always @(WR_ADDR or WR_DATA or WR_EN) begin
|
||||
if (WR_EN[i]) begin
|
||||
found_collision = 0;
|
||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||
if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||
found_collision = 1;
|
||||
if (!found_collision) begin
|
||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
|
||||
update_async_rd <= 1; update_async_rd <= 0;
|
||||
run_update = 0;
|
||||
for (n = 0; n < WIDTH; n = n+1) begin
|
||||
if (WR_EN[i][n]) begin
|
||||
found_collision = 0;
|
||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||
if (WR_EN[k][n] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||
found_collision = 1;
|
||||
if (!found_collision) begin
|
||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ][n] <= WR_DATA[ i*WIDTH +: WIDTH ][n];
|
||||
run_update = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (run_update) begin
|
||||
update_async_rd <= 1;
|
||||
update_async_rd <= 0;
|
||||
end
|
||||
end
|
||||
end else
|
||||
if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk
|
||||
always @(posedge WR_CLK[i])
|
||||
if (WR_EN[i]) begin
|
||||
found_collision = 0;
|
||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||
if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||
found_collision = 1;
|
||||
if (!found_collision) begin
|
||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
|
||||
update_async_rd <= 1; update_async_rd <= 0;
|
||||
always @(posedge WR_CLK[i]) begin
|
||||
run_update = 0;
|
||||
for (n = 0; n < WIDTH; n = n+1) begin
|
||||
if (WR_EN[i][n]) begin
|
||||
found_collision = 0;
|
||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||
if (WR_EN[k][n] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||
found_collision = 1;
|
||||
if (!found_collision) begin
|
||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ][n] <= WR_DATA[ i*WIDTH +: WIDTH ][n];
|
||||
run_update = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (run_update) begin
|
||||
update_async_rd <= 1;
|
||||
update_async_rd <= 0;
|
||||
end
|
||||
end
|
||||
end else begin:rd_negclk
|
||||
always @(negedge WR_CLK[i])
|
||||
if (WR_EN[i]) begin
|
||||
found_collision = 0;
|
||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||
if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||
found_collision = 1;
|
||||
if (!found_collision) begin
|
||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ];
|
||||
update_async_rd <= 1; update_async_rd <= 0;
|
||||
always @(negedge WR_CLK[i]) begin
|
||||
run_update = 0;
|
||||
for (n = 0; n < WIDTH; n = n+1) begin
|
||||
if (WR_EN[i][n]) begin
|
||||
found_collision = 0;
|
||||
for (k = i+1; k < WR_PORTS; k = k+1)
|
||||
if (WR_EN[k][n] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ])
|
||||
found_collision = 1;
|
||||
if (!found_collision) begin
|
||||
data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ][n] <= WR_DATA[ i*WIDTH +: WIDTH ][n];
|
||||
run_update = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (run_update) begin
|
||||
update_async_rd <= 1;
|
||||
update_async_rd <= 0;
|
||||
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;
|
||||
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*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_WR_CLK_ = 0;
|
||||
|
||||
parameter _TECHMAP_BITS_CONNMAP_ = 0;
|
||||
parameter _TECHMAP_CONNMAP_WR_EN_ = 0;
|
||||
|
||||
reg _TECHMAP_FAIL_;
|
||||
integer k;
|
||||
initial begin
|
||||
_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)
|
||||
_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
|
||||
if (_TECHMAP_CONNMAP_RD_CLK_ != _TECHMAP_CONNMAP_WR_CLK_)
|
||||
_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]),
|
||||
.WR_ADDR(WR_ADDR),
|
||||
.WR_DATA(WR_DATA[i]),
|
||||
.WR_EN(WR_EN)
|
||||
.WR_EN(WR_EN[0])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
|
Loading…
Reference in New Issue