summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2014-07-16 14:15:33 +0200
committerClifford Wolf <clifford@clifford.at>2014-07-16 14:15:33 +0200
commit02346cd1d5c8d88d067693b66e35893578de0991 (patch)
tree58c9ca907142980dd5db8cf8fdc9fc81dff0aac2
parent964a67ac4194bb85fb3cb7a90a62dc1e4a685ea4 (diff)
parent73a345294a0c4639b6339ee20e5ca942c963f2f4 (diff)
Merged new $mem/$memwr WR_EN interface
-rw-r--r--frontends/ast/genrtlil.cc3
-rw-r--r--frontends/ast/simplify.cc10
-rw-r--r--kernel/rtlil.cc4
-rw-r--r--manual/CHAPTER_CellLib.tex7
-rw-r--r--passes/memory/memory_collect.cc4
-rw-r--r--passes/memory/memory_map.cc88
-rw-r--r--passes/memory/memory_unpack.cc2
-rw-r--r--passes/opt/opt_reduce.cc80
-rw-r--r--techlibs/common/simlib.v85
-rw-r--r--tests/techmap/mem_simple_4x1_map.v15
10 files changed, 216 insertions, 82 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 787f4d2d..a2fdcf8b 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -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);
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index e547ede3..ba0dca13 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -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);
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 028cd6d8..c4c08d5b 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -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();
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index e7895521..f09c4929 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -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.
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 6fe5e162..028841f6 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -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);
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index e0e3802d..10ab6e2f 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -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;
- 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);
+ sig.replace(wr_offset, w);
+ wr_offset += wr_width;
+ }
}
module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 782c0cd7..bbd01583 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -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);
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index dfe21441..d5bcb7f0 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -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);
}
}
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index be9d24f1..9c774dea 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -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
diff --git a/tests/techmap/mem_simple_4x1_map.v b/tests/techmap/mem_simple_4x1_map.v
index 5f93914c..820f89de 100644
--- a/tests/techmap/mem_simple_4x1_map.v
+++ b/tests/techmap/mem_simple_4x1_map.v
@@ -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