diff options
author | Clifford Wolf <clifford@clifford.at> | 2014-02-03 13:01:45 +0100 |
---|---|---|
committer | Clifford Wolf <clifford@clifford.at> | 2014-02-03 13:01:45 +0100 |
commit | a6750b375301f2c2ebb51a2496cdf2c820b2546b (patch) | |
tree | e3a91710abab3a7a89858426b0d17601946d8fec | |
parent | de9226a64f96a3731008218727d6b3897c58f593 (diff) | |
download | yosys-a6750b375301f2c2ebb51a2496cdf2c820b2546b.tar.gz yosys-a6750b375301f2c2ebb51a2496cdf2c820b2546b.tar.bz2 yosys-a6750b375301f2c2ebb51a2496cdf2c820b2546b.zip |
Added TRANSPARENT parameter to $memrd (and RD_TRANSPARENT to $mem)
-rw-r--r-- | backends/btor/btor.cc | 4 | ||||
-rwxr-xr-x | backends/btor/verilog2btor.sh | 3 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 1 | ||||
-rw-r--r-- | kernel/rtlil.cc | 2 | ||||
-rw-r--r-- | manual/CHAPTER_CellLib.tex | 7 | ||||
-rw-r--r-- | passes/memory/memory_collect.cc | 9 | ||||
-rw-r--r-- | passes/memory/memory_dff.cc | 67 | ||||
-rw-r--r-- | passes/memory/memory_map.cc | 71 | ||||
-rw-r--r-- | passes/memory/memory_unpack.cc | 1 | ||||
-rw-r--r-- | techlibs/common/simlib.v | 60 | ||||
-rw-r--r-- | tests/simple/memory.v | 39 |
11 files changed, 186 insertions, 78 deletions
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index b8ff7bb36..c69d9899b 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -716,6 +716,8 @@ struct BtorDumper else if(cell->type == "$memrd") { log("writing memrd cell\n"); + if (cell->parameters.at("\\CLK_ENABLE").as_bool() == true) + log_error("The btor backen does not support $memrd cells with built-in registers. Run memory_dff with -wr_only.\n"); str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string(); int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str()))); int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int(); @@ -729,6 +731,8 @@ struct BtorDumper else if(cell->type == "$memwr") { log("writing memwr cell\n"); + if (cell->parameters.at("\\CLK_ENABLE").as_bool() == false) + log_error("The btor backen does not support $memwr cells without built-in registers. Run memory_dff (but with -wr_only).\n"); int clk = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLK")), 1); bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool(); int enable = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\EN")), 1); diff --git a/backends/btor/verilog2btor.sh b/backends/btor/verilog2btor.sh index a2f9ebc7e..06a32c81d 100755 --- a/backends/btor/verilog2btor.sh +++ b/backends/btor/verilog2btor.sh @@ -25,7 +25,8 @@ proc; opt; opt_const -mux_undef; opt; rename -hide;;; techmap -share_map pmux2mux.v;; -memory -nomap;; +memory_dff -wr_only +memory_collect;; flatten;; memory_unpack; splitnets -driver; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 99d8566dc..591d027cb 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1245,6 +1245,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); + cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); return RTLIL::SigSpec(wire); } diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1d1448d45..2ab3320bd 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -556,6 +556,7 @@ namespace { param("\\MEMID"); param("\\CLK_ENABLE"); param("\\CLK_POLARITY"); + param("\\TRANSPARENT"); port("\\CLK", 1); port("\\ADDR", param("\\ABITS")); port("\\DATA", param("\\WIDTH")); @@ -582,6 +583,7 @@ namespace { param("\\OFFSET"); param("\\RD_CLK_ENABLE"); param("\\RD_CLK_POLARITY"); + param("\\RD_TRANSPARENT"); param("\\WR_CLK_ENABLE"); param("\\WR_CLK_POLARITY"); port("\\RD_CLK", param("\\RD_PORTS")); diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index b848a2b60..c8c2b6c6c 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -250,6 +250,10 @@ the \B{CLK} input is not used. \item \B{CLK\_POLARITY} \\ Clock is active on the positive edge if this parameter has the value {\tt 1'b1} and on the negative edge if this parameter is {\tt 1'b0}. + +\item \B{TRANSPARENT} \\ +If this parameter is set to {\tt 1'b1}, a read and write to the same address in the same cycle will +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} @@ -308,6 +312,9 @@ This parameter is \B{RD\_PORTS} bits wide, containing a clock enable bit for eac \item \B{RD\_CLK\_POLARITY} \\ This parameter is \B{RD\_PORTS} bits wide, containing a clock polarity bit for each read port. +\item \B{RD\_TRANSPARENT} \\ +This parameter is \B{RD\_PORTS} bits wide, containing a transparent bit for each read port. + \item \B{WR\_PORTS} \\ The number of write ports on this memory cell. diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index ad4df228e..40504d781 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -54,6 +54,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) RTLIL::SigSpec sig_rd_clk; RTLIL::SigSpec sig_rd_clk_enable; RTLIL::SigSpec sig_rd_clk_polarity; + RTLIL::SigSpec sig_rd_transparent; RTLIL::SigSpec sig_rd_addr; RTLIL::SigSpec sig_rd_data; @@ -105,18 +106,21 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) RTLIL::SigSpec clk = cell->connections["\\CLK"]; RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); + RTLIL::SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]); RTLIL::SigSpec addr = cell->connections["\\ADDR"]; RTLIL::SigSpec data = cell->connections["\\DATA"]; clk.extend(1, false); clk_enable.extend(1, false); clk_polarity.extend(1, false); + transparent.extend(1, false); addr.extend(addr_bits, false); data.extend(memory->width, false); sig_rd_clk.append(clk); sig_rd_clk_enable.append(clk_enable); sig_rd_clk_polarity.append(clk_polarity); + sig_rd_transparent.append(transparent); sig_rd_addr.append(addr); sig_rd_data.append(data); } @@ -147,7 +151,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) 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_POLARITY"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0); + mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.chunks[0].data : RTLIL::Const(0, 0); mem->connections["\\WR_CLK"] = sig_wr_clk; mem->connections["\\WR_ADDR"] = sig_wr_addr; @@ -165,7 +169,8 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) mem->parameters["\\RD_PORTS"] = RTLIL::Const(rd_ports); mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0); - mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0); + mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.chunks[0].data : RTLIL::Const(0, 0); + mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.chunks[0].data : RTLIL::Const(0, 0); mem->connections["\\RD_CLK"] = sig_rd_clk; mem->connections["\\RD_ADDR"] = sig_rd_addr; diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 6ba9bf23b..2502a8b61 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -113,14 +113,6 @@ static void handle_wr_cell(RTLIL::Module *module, RTLIL::Cell *cell) } } -#if 1 -static void handle_rd_cell(RTLIL::Module*, RTLIL::Cell*) -{ - // merging dffs into read ports isn't neccessary for memory_map. - // we'd loose the information if the register is on the address or - // data port and wouldn't get any benefits. -} -#else static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig) { normalize_sig(module, sig); @@ -149,43 +141,46 @@ static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell) bool clk_polarity = 0; - RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx); - RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"]; - if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity)) - { - cell->connections["\\CLK"] = clk_addr; - cell->connections["\\ADDR"] = sig_addr; - cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); - cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); - log("merged address $dff to cell.\n"); - return; - } - RTLIL::SigSpec clk_data = RTLIL::SigSpec(RTLIL::State::Sx); RTLIL::SigSpec sig_data = cell->connections["\\DATA"]; - if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true)) + if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true) && + clk_data != RTLIL::SigSpec(RTLIL::State::Sx)) { disconnect_dff(module, sig_data); cell->connections["\\CLK"] = clk_data; cell->connections["\\DATA"] = sig_data; cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); + cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); log("merged data $dff to cell.\n"); return; } + RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx); + RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"]; + if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity) && + clk_addr != RTLIL::SigSpec(RTLIL::State::Sx)) + { + cell->connections["\\CLK"] = clk_addr; + cell->connections["\\ADDR"] = sig_addr; + cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); + cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); + cell->parameters["\\TRANSPARENT"] = RTLIL::Const(1); + log("merged address $dff to cell.\n"); + return; + } + log("no (compatible) $dff found.\n"); } -#endif -static void handle_module(RTLIL::Design *design, RTLIL::Module *module) +static void handle_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_wr_only) { for (auto &cell_it : module->cells) { if (!design->selected(module, cell_it.second)) continue; if (cell_it.second->type == "$memwr" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool()) handle_wr_cell(module, cell_it.second); - if (cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool()) + if (!flag_wr_only && cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool()) handle_rd_cell(module, cell_it.second); } } @@ -196,19 +191,35 @@ struct MemoryDffPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" memory_dff [selection]\n"); + log(" memory_dff [options] [selection]\n"); log("\n"); log("This pass detects DFFs at memory ports and merges them into the memory port.\n"); log("I.e. it consumes an asynchronous memory port and the flip-flops at its\n"); log("interface and yields a synchronous memory port.\n"); log("\n"); + log(" -wr_only\n"); + log(" do not merge registers on read ports\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + bool flag_wr_only = false; + log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n"); - extra_args(args, 1, design); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-wr_only") { + flag_wr_only = true; + continue; + } + break; + } + extra_args(args, argidx, design); + for (auto &mod_it : design->modules) if (design->selected(mod_it.second)) - handle_module(design, mod_it.second); + handle_module(design, mod_it.second, flag_wr_only); } } MemoryDffPass; diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 9f2b6994c..e0e3802d1 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -162,44 +162,47 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1) { -#if 1 - RTLIL::Cell *c = new RTLIL::Cell; - c->name = genid(cell->name, "$rdreg", i); - c->type = "$dff"; - c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits); - c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); - c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); - c->connections["\\D"] = rd_addr; - module->cells[c->name] = c; - count_dff++; + if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1) + { + RTLIL::Cell *c = new RTLIL::Cell; + c->name = genid(cell->name, "$rdreg", i); + c->type = "$dff"; + c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits); + c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); + c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); + c->connections["\\D"] = rd_addr; + module->cells[c->name] = c; + count_dff++; - RTLIL::Wire *w = new RTLIL::Wire; - w->name = genid(cell->name, "$rdreg", i, "$q"); - w->width = mem_abits; - module->wires[w->name] = w; + RTLIL::Wire *w = new RTLIL::Wire; + w->name = genid(cell->name, "$rdreg", i, "$q"); + w->width = mem_abits; + module->wires[w->name] = w; - c->connections["\\Q"] = RTLIL::SigSpec(w); - rd_addr = RTLIL::SigSpec(w); -#else - RTLIL::Cell *c = new RTLIL::Cell; - c->name = genid(cell->name, "$rdreg", i); - c->type = "$dff"; - c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"]; - c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); - c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); - c->connections["\\Q"] = rd_signals.back(); - module->cells[c->name] = c; - count_dff++; + c->connections["\\Q"] = RTLIL::SigSpec(w); + rd_addr = RTLIL::SigSpec(w); + } + else + { + RTLIL::Cell *c = new RTLIL::Cell; + c->name = genid(cell->name, "$rdreg", i); + c->type = "$dff"; + c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"]; + c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); + c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); + c->connections["\\Q"] = rd_signals.back(); + module->cells[c->name] = c; + count_dff++; - RTLIL::Wire *w = new RTLIL::Wire; - w->name = genid(cell->name, "$rdreg", i, "$d"); - w->width = mem_width; - module->wires[w->name] = w; + RTLIL::Wire *w = new RTLIL::Wire; + w->name = genid(cell->name, "$rdreg", i, "$d"); + w->width = mem_width; + module->wires[w->name] = w; - rd_signals.clear(); - rd_signals.push_back(RTLIL::SigSpec(w)); - c->connections["\\D"] = rd_signals.back(); -#endif + rd_signals.clear(); + rd_signals.push_back(RTLIL::SigSpec(w)); + c->connections["\\D"] = rd_signals.back(); + } } for (int j = 0; j < mem_abits; j++) diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc index 060d8e671..782c0cd79 100644 --- a/passes/memory/memory_unpack.cc +++ b/passes/memory/memory_unpack.cc @@ -55,6 +55,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory) cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH"); cell->parameters["\\CLK_ENABLE"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_ENABLE")).extract(i, 1).as_const(); cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_POLARITY")).extract(i, 1).as_const(); + cell->parameters["\\TRANSPARENT"] = RTLIL::SigSpec(memory->parameters.at("\\RD_TRANSPARENT")).extract(i, 1).as_const(); cell->connections["\\CLK"] = memory->connections.at("\\RD_CLK").extract(i, 1); cell->connections["\\ADDR"] = memory->connections.at("\\RD_ADDR").extract(i*abits, abits); cell->connections["\\DATA"] = memory->connections.at("\\RD_DATA").extract(i*mem->width, mem->width); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index c0c564fc7..87e83bd15 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1220,6 +1220,7 @@ parameter WIDTH = 8; parameter RD_PORTS = 1; parameter RD_CLK_ENABLE = 1'b1; parameter RD_CLK_POLARITY = 1'b1; +parameter RD_TRANSPARENT = 1'b1; parameter WR_PORTS = 1; parameter WR_CLK_ENABLE = 1'b1; @@ -1242,37 +1243,70 @@ generate for (i = 0; i < RD_PORTS; i = i+1) begin:rd if (RD_CLK_ENABLE[i] == 0) begin:rd_noclk always @(RD_ADDR or update_async_rd) - RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ]; + RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; end else - if (RD_CLK_POLARITY[i] == 1) begin:rd_posclk - always @(posedge RD_CLK[i]) - RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ]; - end else begin:rd_negclk - always @(negedge RD_CLK[i]) - RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ]; + if (RD_TRANSPARENT[i] == 1) begin:rd_transparent + reg [ABITS-1:0] addr_buf; + if (RD_CLK_POLARITY[i] == 1) begin:rd_trans_posclk + always @(posedge RD_CLK[i]) + addr_buf <= RD_ADDR[ i*ABITS +: ABITS ]; + end else begin:rd_trans_negclk + always @(negedge RD_CLK[i]) + addr_buf <= RD_ADDR[ i*ABITS +: ABITS ]; + end + always @(addr_buf or update_async_rd) + RD_DATA[ i*WIDTH +: WIDTH ] <= data[ addr_buf - OFFSET ]; + end else begin:rd_notransparent + if (RD_CLK_POLARITY[i] == 1) begin:rd_notrans_posclk + always @(posedge RD_CLK[i]) + RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; + end else begin:rd_notrans_negclk + always @(negedge RD_CLK[i]) + RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; + end end end for (i = 0; i < WR_PORTS; i = i+1) begin:wr + integer k; + reg found_collision; if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk always @(WR_ADDR or WR_DATA or WR_EN) begin if (WR_EN[i]) begin - data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ]; - update_async_rd <= 1; update_async_rd <= 0; + 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; + end end end end else if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk always @(posedge WR_CLK[i]) if (WR_EN[i]) begin - data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ]; - update_async_rd <= 1; update_async_rd <= 0; + 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; + end end end else begin:rd_negclk always @(negedge WR_CLK[i]) if (WR_EN[i]) begin - data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ]; - update_async_rd <= 1; update_async_rd <= 0; + 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; + end end end end diff --git a/tests/simple/memory.v b/tests/simple/memory.v index eaeee01dd..927ee0438 100644 --- a/tests/simple/memory.v +++ b/tests/simple/memory.v @@ -75,3 +75,42 @@ assign y4 = mem2[addr][bit]; endmodule +// ---------------------------------------------------------- + +module test03(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data); + +input clk, wr_enable; +input [3:0] wr_addr, wr_data, rd_addr; +output reg [3:0] rd_data; + +reg [3:0] memory [0:15]; + +always @(posedge clk) begin + if (wr_enable) + memory[wr_addr] <= wr_data; + rd_data <= memory[rd_addr]; +end + +endmodule + +// ---------------------------------------------------------- + +module test04(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data); + +input clk, wr_enable; +input [3:0] wr_addr, wr_data, rd_addr; +output [3:0] rd_data; + +reg rd_addr_buf; +reg [3:0] memory [0:15]; + +always @(posedge clk) begin + if (wr_enable) + memory[wr_addr] <= wr_data; + rd_addr_buf <= rd_addr; +end + +assign rd_data = memory[rd_addr_buf]; + +endmodule + |