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 x_bits_addr, x_bits_data; + std::vector 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; + + 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)); 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 sig_a = assign_map(cell->connections["\\A"]).to_sigbit_vector(); + std::vector sig_b = assign_map(cell->connections["\\B"]).to_sigbit_vector(); + std::vector sig_y = assign_map(cell->connections["\\Y"]).to_sigbit_vector(); + + std::vector new_sig_y; + RTLIL::SigSig old_sig_conn; + + std::vector> consolidated_in_tuples; + std::map, RTLIL::SigBit> consolidated_in_tuples_map; + + for (int i = 0; i < int(sig_y.size()); i++) + { + std::vector 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