Added TRANSPARENT parameter to $memrd (and RD_TRANSPARENT to $mem)
authorClifford Wolf <clifford@clifford.at>
Mon, 3 Feb 2014 12:01:45 +0000 (13:01 +0100)
committerClifford Wolf <clifford@clifford.at>
Mon, 3 Feb 2014 12:01:45 +0000 (13:01 +0100)
backends/btor/btor.cc
backends/btor/verilog2btor.sh
frontends/ast/genrtlil.cc
kernel/rtlil.cc
manual/CHAPTER_CellLib.tex
passes/memory/memory_collect.cc
passes/memory/memory_dff.cc
passes/memory/memory_map.cc
passes/memory/memory_unpack.cc
techlibs/common/simlib.v
tests/simple/memory.v

index b8ff7bb36d26d451d27e60fe1ec064a9c233f13a..c69d9899bf70ecd24afb99f943b0d86ce648a682 100644 (file)
@@ -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);
index a2f9ebc7ef8ab93a667e28564d4046693a7f17e9..06a32c81dad0550ea51d110b6859e116521b74d8 100755 (executable)
@@ -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;
index 99d8566dca1e7fc240cf8b74e0e4e53894719283..591d027cbb5ef991540c7e2aa564b7609045521c 100644 (file)
@@ -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);
                }
index 1d1448d45f9ae1e8446175931e5be2221ff51e9b..2ab3320bdf04fd17e543659c6bf25dd6e1eebdc6 100644 (file)
@@ -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"));
index b848a2b60a46cc0539cff3ea7cb6683c31ae77d8..c8c2b6c6c6217c4aaa296c034d84e949ca1fa7eb 100644 (file)
@@ -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.
 
index ad4df228e9a6cc1d0e26880e247d6f6cdd22b4e2..40504d7814e6a878e17ee5b2000cbc8d8941be3d 100644 (file)
@@ -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;
index 6ba9bf23b9dcaa17c3353e1f254189b1caca12e8..2502a8b61548e00b3603f28762781b1addf0036c 100644 (file)
@@ -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;
  
index 9f2b6994ca6c144cdff4ca8894e7a813a4f4607c..e0e3802d1e2dc9b0d785a7c1a33584d8525ec6a7 100644 (file)
@@ -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++)
index 060d8e671a6e105b7465f18381c6289425573f05..782c0cd798074bb87fb74a26590fb645ca361918 100644 (file)
@@ -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);
index c0c564fc7073651fe54b8637683989e41c32268e..87e83bd1581f50b74e5f1793b17f423fb5981500 100644 (file)
@@ -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
index eaeee01dd39cfc4bfd687cad507550f65e463e00..927ee0438933124780a1d8d3b72ce955def7311c 100644 (file)
@@ -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
+