Added read-enable to memory model
authorClifford Wolf <clifford@clifford.at>
Fri, 25 Sep 2015 10:23:11 +0000 (12:23 +0200)
committerClifford Wolf <clifford@clifford.at>
Fri, 25 Sep 2015 10:23:11 +0000 (12:23 +0200)
17 files changed:
frontends/ast/genrtlil.cc
frontends/verific/verific.cc
kernel/celltypes.h
kernel/rtlil.cc
manual/CHAPTER_CellLib.tex
passes/memory/memory_bram.cc
passes/memory/memory_collect.cc
passes/memory/memory_dff.cc
passes/memory/memory_map.cc
passes/memory/memory_unpack.cc
techlibs/common/simlib.v
techlibs/ice40/brams.txt
techlibs/ice40/brams_map.v
techlibs/xilinx/brams.txt
techlibs/xilinx/brams_map.v
techlibs/xilinx/synth_xilinx.cc
tests/techmap/mem_simple_4x1_map.v

index a2655e9a58a5628d8d772b885a34c135720afeaf..c322faf7bcf3432762241fce55b0409242e3215e 100644 (file)
@@ -1220,6 +1220,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
                        id2ast->meminfo(mem_width, mem_size, addr_bits);
 
                        cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+                       cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1));
                        cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
                        cell->setPort("\\DATA", RTLIL::SigSpec(wire));
 
index 897a7f328410e8c62f68a546050b13ca7a175942..793c068444e963e4498ec24bd2720c8e6fb33bb8 100644 (file)
@@ -692,7 +692,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
                        cell->parameters["\\TRANSPARENT"] = false;
                        cell->parameters["\\ABITS"] = GetSize(addr);
                        cell->parameters["\\WIDTH"] = GetSize(data);
-                       cell->setPort("\\CLK", RTLIL::State::S0);
+                       cell->setPort("\\CLK", RTLIL::State::Sx);
+                       cell->setPort("\\EN", RTLIL::State::Sx);
                        cell->setPort("\\ADDR", addr);
                        cell->setPort("\\DATA", data);
                        continue;
index f3683344656eeed44f762f805ab3dddeb5abca2b..40fdca36eef0bde52eb40ed8013408a510e1e6f6 100644 (file)
@@ -122,7 +122,7 @@ struct CellTypes
        void setup_internals_mem()
        {
                IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN";
-               IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA";
+               IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA", RD_EN = "\\RD_EN";
                IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN";
                IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA";
                IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT";
@@ -135,10 +135,10 @@ struct CellTypes
                setup_type("$dlatch", {EN, D}, {Q});
                setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q});
 
-               setup_type("$memrd", {CLK, ADDR}, {DATA});
+               setup_type("$memrd", {CLK, EN, ADDR}, {DATA});
                setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>());
                setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>());
-               setup_type("$mem", {RD_CLK, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
+               setup_type("$mem", {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
 
                setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT});
        }
index 8ff52195207b02ac52c9103826c6e6928083ce19..7090fe913eb5cf7aafc8b27bf0cccf49446b9c79 100644 (file)
@@ -947,6 +947,7 @@ namespace {
                                param_bool("\\CLK_POLARITY");
                                param_bool("\\TRANSPARENT");
                                port("\\CLK", 1);
+                               port("\\EN", 1);
                                port("\\ADDR", param("\\ABITS"));
                                port("\\DATA", param("\\WIDTH"));
                                check_expected();
@@ -986,6 +987,7 @@ namespace {
                                param_bits("\\WR_CLK_ENABLE", std::max(1, param("\\WR_PORTS")));
                                param_bits("\\WR_CLK_POLARITY", std::max(1, param("\\WR_PORTS")));
                                port("\\RD_CLK", param("\\RD_PORTS"));
+                               port("\\RD_EN", param("\\RD_PORTS"));
                                port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS"));
                                port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH"));
                                port("\\WR_CLK", param("\\WR_PORTS"));
index 9f9ec2e2b522350d055b0bb1bcc01d040aa0f0b9..c648eb1febea9483a9b54df0064702cf5285b801 100644 (file)
@@ -220,8 +220,9 @@ cell is created. Having individual cells for read and write ports has the advant
 consolidated using resource sharing passes. In some cases this drastically reduces the number of required
 ports on the memory cell.
 
-The {\tt \$memrd} cells have a clock input \B{CLK}, an address input \B{ADDR} and a data output
-\B{DATA}. They also have the following parameters:
+The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an
+address input \B{ADDR}, and a data output \B{DATA}. They also have the
+following parameters:
 
 \begin{itemize}
 \item \B{MEMID} \\
@@ -322,6 +323,9 @@ The {\tt \$mem} cell has the following ports:
 \item \B{RD\_CLK} \\
 This input is \B{RD\_PORTS} bits wide, containing all clock signals for the read ports.
 
+\item \B{RD\_EN} \\
+This input is \B{RD\_PORTS} bits wide, containing all enable signals for the read ports.
+
 \item \B{RD\_ADDR} \\
 This input is \B{RD\_PORTS}*\B{ABITS} bits wide, containing all address signals for the read ports.
 
index f638b5bb799120888278e4ab7401169d97d9cd58..3e83a6d9bde0c9bd745a2742dbcd8697532467c5 100644 (file)
@@ -112,15 +112,15 @@ struct rules_t
                                if (ports[i] != other.ports[i])
                                        log_error("Bram %s variants %d and %d have different number of %c-ports.\n", log_id(name), variant, other.variant, 'A'+i);
                                if (wrmode[i] != other.wrmode[i])
-                                       variant_params[stringf("\\CFG_WRMODE_%c", 'A' + i)] = wrmode[1];
+                                       variant_params[stringf("\\CFG_WRMODE_%c", 'A' + i)] = wrmode[i];
                                if (enable[i] != other.enable[i])
-                                       variant_params[stringf("\\CFG_ENABLE_%c", 'A' + i)] = enable[1];
+                                       variant_params[stringf("\\CFG_ENABLE_%c", 'A' + i)] = enable[i];
                                if (transp[i] != other.transp[i])
-                                       variant_params[stringf("\\CFG_TRANSP_%c", 'A' + i)] = transp[1];
+                                       variant_params[stringf("\\CFG_TRANSP_%c", 'A' + i)] = transp[i];
                                if (clocks[i] != other.clocks[i])
-                                       variant_params[stringf("\\CFG_CLOCKS_%c", 'A' + i)] = clocks[1];
+                                       variant_params[stringf("\\CFG_CLOCKS_%c", 'A' + i)] = clocks[i];
                                if (clkpol[i] != other.clkpol[i])
-                                       variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[1];
+                                       variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[i];
                        }
                }
        };
@@ -429,6 +429,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
        rd_clkpol.extend_u0(rd_ports);
        rd_transp.extend_u0(rd_ports);
 
+       SigSpec rd_en = cell->getPort("\\RD_EN");
        SigSpec rd_clk = cell->getPort("\\RD_CLK");
        SigSpec rd_data = cell->getPort("\\RD_DATA");
        SigSpec rd_addr = cell->getPort("\\RD_ADDR");
@@ -688,6 +689,10 @@ grow_read_ports:;
                                        log("        Bram port %c%d.%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
                                        goto skip_bram_rport;
                                }
+                               if (rd_en[cell_port_i] != State::S1 && pi.enable == 0) {
+                                       log("        Bram port %c%d.%d has no read enable input.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+                                       goto skip_bram_rport;
+                               }
                        skip_bram_rport_clkcheck:
                                if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
                                        if (match.make_transp && wr_ports <= 1) {
@@ -713,6 +718,7 @@ grow_read_ports:;
                                clock_polarities[pi.clkpol] = clkdom.second;
                                read_transp[pi.transp] = transp;
                                pi.sig_clock = clkdom.first;
+                               pi.sig_en = rd_en[cell_port_i];
                                pi.effective_clkpol = clkdom.second;
                        }
 
@@ -886,6 +892,8 @@ grow_read_ports:;
 
                                        if (pi.make_outreg) {
                                                SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
+                                               if (!pi.sig_en.empty())
+                                                       bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
                                                module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
                                                bram_dout = bram_dout_q;
                                        }
@@ -1126,7 +1134,7 @@ struct MemoryBramPass : public Pass {
                log("      groups 2           # number of port groups\n");
                log("      ports  1 1         # number of ports in each group\n");
                log("      wrmode 1 0         # set to '1' if this groups is write ports\n");
-               log("      enable 4 0         # number of enable bits (for write ports)\n");
+               log("      enable 4 1         # number of enable bits\n");
                log("      transp 0 2         # transparent (for read ports)\n");
                log("      clocks 1 2         # clock configuration\n");
                log("      clkpol 2 2         # clock polarity configuration\n");
index 91b5759ebeccef61284f45e4eff975db7295ed0a..abd4b1242cfa32d50165f3130d21870a4643ae9a 100644 (file)
@@ -57,6 +57,7 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
        SigSpec sig_rd_transparent;
        SigSpec sig_rd_addr;
        SigSpec sig_rd_data;
+       SigSpec sig_rd_en;
 
        std::vector<Cell*> memcells;
 
@@ -139,22 +140,27 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
                        SigSpec transparent = SigSpec(cell->parameters["\\TRANSPARENT"]);
                        SigSpec addr = sigmap(cell->getPort("\\ADDR"));
                        SigSpec data = sigmap(cell->getPort("\\DATA"));
+                       SigSpec en = sigmap(cell->getPort("\\EN"));
 
-                       clk.extend_u0(1, false);
-                       clk_enable.extend_u0(1, false);
-                       clk_polarity.extend_u0(1, false);
-                       transparent.extend_u0(1, false);
-                       addr.extend_u0(addr_bits, false);
-                       data.extend_u0(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);
-
-                       rd_ports++;
+                       if (!en.is_fully_zero())
+                       {
+                               clk.extend_u0(1, false);
+                               clk_enable.extend_u0(1, false);
+                               clk_polarity.extend_u0(1, false);
+                               transparent.extend_u0(1, false);
+                               addr.extend_u0(addr_bits, false);
+                               data.extend_u0(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);
+                               sig_rd_en.append(en);
+
+                               rd_ports++;
+                       }
                        continue;
                }
        }
@@ -203,6 +209,7 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
        mem->setPort("\\RD_CLK", sig_rd_clk);
        mem->setPort("\\RD_ADDR", sig_rd_addr);
        mem->setPort("\\RD_DATA", sig_rd_data);
+       mem->setPort("\\RD_EN", sig_rd_en);
 
        for (auto c : memcells)
                module->remove(c);
index 5584f27c3393a5c8c0d17259004899668eb6aa80..3373369f6ef141c47981b1350ca7bb70de8015fd 100644 (file)
@@ -31,6 +31,7 @@ struct MemoryDffWorker
        vector<Cell*> dff_cells;
        dict<SigBit, SigBit> invbits;
        dict<SigBit, int> sigbit_users_count;
+       dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
 
        MemoryDffWorker(Module *module) : module(module), sigmap(module) { }
 
@@ -150,16 +151,44 @@ struct MemoryDffWorker
                        if (sigbit_users_count[bit] > 1)
                                goto skip_ff_after_read_merging;
 
-               if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
+               if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data))
                {
-                       disconnect_dff(sig_data);
-                       cell->setPort("\\CLK", clk_data);
-                       cell->setPort("\\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;
+                       bool enable_invert = mux_cells_a.count(sig_data);
+                       Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data);
+                       SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"));
+
+                       sig_data = sigmap(mux->getPort("\\Y"));
+                       for (auto bit : sig_data)
+                               if (sigbit_users_count[bit] > 1)
+                                       goto skip_ff_after_read_merging;
+
+                       if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q)
+                       {
+                               disconnect_dff(sig_data);
+                               cell->setPort("\\CLK", clk_data);
+                               cell->setPort("\\EN", enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S"));
+                               cell->setPort("\\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 with rd enable to cell.\n");
+                               return;
+                       }
+               }
+               else
+               {
+                       if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
+                       {
+                               disconnect_dff(sig_data);
+                               cell->setPort("\\CLK", clk_data);
+                               cell->setPort("\\EN", State::S1);
+                               cell->setPort("\\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;
+                       }
                }
 
        skip_ff_after_read_merging:;
@@ -169,6 +198,7 @@ struct MemoryDffWorker
                                clk_addr != RTLIL::SigSpec(RTLIL::State::Sx))
                {
                        cell->setPort("\\CLK", clk_addr);
+                       cell->setPort("\\EN", State::S1);
                        cell->setPort("\\ADDR", sig_addr);
                        cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
                        cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
@@ -191,6 +221,10 @@ struct MemoryDffWorker
                for (auto cell : module->cells()) {
                        if (cell->type == "$dff")
                                dff_cells.push_back(cell);
+                       if (cell->type == "$mux") {
+                               mux_cells_a[sigmap(cell->getPort("\\A"))] = cell;
+                               mux_cells_b[sigmap(cell->getPort("\\B"))] = cell;
+                       }
                        if (cell->type == "$not" || cell->type == "$_NOT_" || (cell->type == "$logic_not" && GetSize(cell->getPort("\\A")) == 1)) {
                                SigSpec sig_a = cell->getPort("\\A");
                                SigSpec sig_y = cell->getPort("\\Y");
index 524fa8d2bca894075952a1e711b6adf78415182b..0b8ccb36379ec8a854d01000e170076fc9bf0e67 100644 (file)
@@ -200,34 +200,43 @@ struct MemoryMapWorker
 
                        if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
                        {
+                               RTLIL::Cell *dff_cell = nullptr;
+
                                if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
                                {
-                                       RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
-                                       c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
-                                       c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
-                                       c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
-                                       c->setPort("\\D", rd_addr);
+                                       dff_cell = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+                                       dff_cell->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
+                                       dff_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+                                       dff_cell->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+                                       dff_cell->setPort("\\D", rd_addr);
                                        count_dff++;
 
                                        RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits);
 
-                                       c->setPort("\\Q", RTLIL::SigSpec(w));
+                                       dff_cell->setPort("\\Q", RTLIL::SigSpec(w));
                                        rd_addr = RTLIL::SigSpec(w);
                                }
                                else
                                {
-                                       RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
-                                       c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
-                                       c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
-                                       c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
-                                       c->setPort("\\Q", rd_signals.back());
+                                       dff_cell = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+                                       dff_cell->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+                                       dff_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+                                       dff_cell->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+                                       dff_cell->setPort("\\Q", rd_signals.back());
                                        count_dff++;
 
                                        RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width);
 
                                        rd_signals.clear();
                                        rd_signals.push_back(RTLIL::SigSpec(w));
-                                       c->setPort("\\D", rd_signals.back());
+                                       dff_cell->setPort("\\D", rd_signals.back());
+                               }
+
+                               SigBit en_bit = cell->getPort("\\RD_EN").extract(i);
+                               if (en_bit != State::S1) {
+                                       SigSpec new_d = module->Mux(genid(cell->name, "$rdenmux", i),
+                                                       dff_cell->getPort("\\Q"), dff_cell->getPort("\\D"), en_bit);
+                                       dff_cell->setPort("\\D", new_d);
                                }
                        }
 
index a497362bf8e9246a839cb5dbb790c23cac5c619e..60724da77ad5c5287ee9531feb43fed8cdc44991 100644 (file)
@@ -57,6 +57,7 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
                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->setPort("\\CLK", memory->getPort("\\RD_CLK").extract(i, 1));
+               cell->setPort("\\EN", memory->getPort("\\RD_EN").extract(i, 1));
                cell->setPort("\\ADDR", memory->getPort("\\RD_ADDR").extract(i*abits, abits));
                cell->setPort("\\DATA", memory->getPort("\\RD_DATA").extract(i*mem->width, mem->width));
        }
index 2a56b3a1e97918bcfdf8c52f37b30dfbcac407bb..a2dc466d4b72ccc475510b3e91196450fe55244b 100644 (file)
@@ -1494,7 +1494,7 @@ endmodule
 // --------------------------------------------------------
 `ifndef SIMLIB_NOMEM
 
-module \$memrd (CLK, ADDR, DATA);
+module \$memrd (CLK, EN, ADDR, DATA);
 
 parameter MEMID = "";
 parameter ABITS = 8;
@@ -1504,7 +1504,7 @@ parameter CLK_ENABLE = 0;
 parameter CLK_POLARITY = 0;
 parameter TRANSPARENT = 0;
 
-input CLK;
+input CLK, EN;
 input [ABITS-1:0] ADDR;
 output [WIDTH-1:0] DATA;
 
@@ -1568,7 +1568,7 @@ endmodule
 
 // --------------------------------------------------------
 
-module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
+module \$mem (RD_CLK, RD_EN, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
 
 parameter MEMID = "";
 parameter signed SIZE = 4;
@@ -1587,6 +1587,7 @@ parameter WR_CLK_ENABLE = 1'b1;
 parameter WR_CLK_POLARITY = 1'b1;
 
 input [RD_PORTS-1:0] RD_CLK;
+input [RD_PORTS-1:0] RD_EN;
 input [RD_PORTS*ABITS-1:0] RD_ADDR;
 output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
 
@@ -1626,7 +1627,7 @@ always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin
        #`SIMLIB_MEMDELAY;
 `endif
        for (i = 0; i < RD_PORTS; i = i+1) begin
-               if ((!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
+               if (!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i] && RD_EN[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
                        // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS],  memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
                        RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
                end
index 05131b227a45467c0db4c0a6cf7af13aa645048d..03d596111fc806a356dcbf5be8955d5506be3907 100644 (file)
@@ -5,7 +5,7 @@ bram $__ICE40_RAM4K_M0
   groups 2
   ports  1  1
   wrmode 0  1
-  enable 0 16
+  enable 1 16
   transp 0  0
   clocks 2  3
   clkpol 2  3
@@ -22,7 +22,7 @@ bram $__ICE40_RAM4K_M123
   groups 2
   ports  1 1
   wrmode 0 1
-  enable 0 1
+  enable 1 1
   transp 0 0
   clocks 2 3
   clkpol 2 3
index f3674b4ede9096b2ebca3bcc125bf55f38c8be25..a82161c990984bc1aa445ddac44158489a873be0 100644 (file)
@@ -168,7 +168,7 @@ module \$__ICE40_RAM4K (
 endmodule
 
 
-module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
        parameter [0:0] CLKPOL2 = 1;
        parameter [0:0] CLKPOL3 = 1;
 
@@ -179,6 +179,7 @@ module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
        input [7:0] A1ADDR;
        output [15:0] A1DATA;
+       input A1EN;
 
        input [7:0] B1ADDR;
        input [15:0] B1DATA;
@@ -213,7 +214,7 @@ module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
                .RADDR(A1ADDR_11),
                .RCLK(CLK2),
                .RCLKE(1'b1),
-               .RE(1'b1),
+               .RE(A1EN),
                .WDATA(B1DATA),
                .WADDR(B1ADDR_11),
                .MASK(~B1EN),
@@ -223,7 +224,7 @@ module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
        );
 endmodule
 
-module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
        parameter CFG_ABITS = 9;
        parameter CFG_DBITS = 8;
 
@@ -242,6 +243,7 @@ module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
        input [CFG_ABITS-1:0] A1ADDR;
        output [CFG_DBITS-1:0] A1DATA;
+       input A1EN;
 
        input [CFG_ABITS-1:0] B1ADDR;
        input [CFG_DBITS-1:0] B1DATA;
@@ -298,7 +300,7 @@ module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
                .RADDR(A1ADDR_11),
                .RCLK(CLK2),
                .RCLKE(1'b1),
-               .RE(1'b1),
+               .RE(A1EN),
                .WDATA(B1DATA_16),
                .WADDR(B1ADDR_11),
                .WCLK(CLK3),
index 894e714c643077ef49f03658526d6f1136105f59..f1161114e9bb0cf40cb4d09977a69c9be29b6f2e 100644 (file)
@@ -6,7 +6,7 @@ bram $__XILINX_RAMB36_SDP
   groups 2
   ports  1 1
   wrmode 0 1
-  enable 0 8
+  enable 1 8
   transp 0 0
   clocks 2 3
   clkpol 2 3
@@ -19,7 +19,7 @@ bram $__XILINX_RAMB18_SDP
   groups 2
   ports  1 1
   wrmode 0 1
-  enable 0 4
+  enable 1 4
   transp 0 0
   clocks 2 3
   clkpol 2 3
@@ -42,9 +42,9 @@ bram $__XILINX_RAMB36_TDP
   groups 2
   ports  1 1
   wrmode 0 1
-  enable 0 4   @a10d36
-  enable 0 2   @a11d18
-  enable 0 1   @a12d9 @a13d4 @a14d2 @a15d1
+  enable 1 4   @a10d36
+  enable 1 2   @a11d18
+  enable 1 1   @a12d9 @a13d4 @a14d2 @a15d1
   transp 0 0
   clocks 2 3
   clkpol 2 3
@@ -65,8 +65,8 @@ bram $__XILINX_RAMB18_TDP
   groups 2
   ports  1 1
   wrmode 0 1
-  enable 0 2   @a10d18
-  enable 0 1   @a11d9 @a12d4 @a13d2 @a14d1
+  enable 1 2   @a10d18
+  enable 1 1   @a11d9 @a12d4 @a13d2 @a14d1
   transp 0 0
   clocks 2 3
   clkpol 2 3
index cbfd4e1eb88e22cc2c5f576a571eee28f4ed6b33..7ea49158d27cbf83e99877432eb77539bcc392a4 100644 (file)
@@ -1,4 +1,4 @@
-module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
        parameter CLKPOL2 = 1;
        parameter CLKPOL3 = 1;
        parameter [36863:0] INIT = 36864'bx;
@@ -8,6 +8,7 @@ module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
        input [8:0] A1ADDR;
        output [71:0] A1DATA;
+       input A1EN;
 
        input [8:0] B1ADDR;
        input [71:0] B1DATA;
@@ -47,7 +48,7 @@ module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
                .ADDRARDADDR(A1ADDR_16),
                .CLKARDCLK(CLK2),
-               .ENARDEN(|1),
+               .ENARDEN(A1EN),
                .REGCEAREGCE(|1),
                .RSTRAMARSTRAM(|0),
                .RSTREGARSTREG(|0),
@@ -65,7 +66,7 @@ endmodule
 
 // ------------------------------------------------------------------------
 
-module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
        parameter CLKPOL2 = 1;
        parameter CLKPOL3 = 1;
        parameter [18431:0] INIT = 18432'bx;
@@ -75,6 +76,7 @@ module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
        input [8:0] A1ADDR;
        output [35:0] A1DATA;
+       input A1EN;
 
        input [8:0] B1ADDR;
        input [35:0] B1DATA;
@@ -111,7 +113,7 @@ module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
                .ADDRARDADDR(A1ADDR_14),
                .CLKARDCLK(CLK2),
-               .ENARDEN(|1),
+               .ENARDEN(A1EN),
                .REGCEAREGCE(|1),
                .RSTRAMARSTRAM(|0),
                .RSTREGARSTREG(|0),
@@ -129,7 +131,7 @@ endmodule
 
 // ------------------------------------------------------------------------
 
-module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
        parameter CFG_ABITS = 10;
        parameter CFG_DBITS = 36;
        parameter CFG_ENABLE_B = 4;
@@ -143,6 +145,7 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
        input [CFG_ABITS-1:0] A1ADDR;
        output [CFG_DBITS-1:0] A1DATA;
+       input A1EN;
 
        input [CFG_ABITS-1:0] B1ADDR;
        input [CFG_DBITS-1:0] B1DATA;
@@ -181,7 +184,7 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
                        .DOPADOP(DOP[3:0]),
                        .ADDRARDADDR(A1ADDR_16),
                        .CLKARDCLK(CLK2),
-                       .ENARDEN(|1),
+                       .ENARDEN(A1EN),
                        .REGCEAREGCE(|1),
                        .RSTRAMARSTRAM(|0),
                        .RSTREGARSTREG(|0),
@@ -219,7 +222,7 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
                        .DOPADOP(DOP[3:0]),
                        .ADDRARDADDR(A1ADDR_16),
                        .CLKARDCLK(CLK2),
-                       .ENARDEN(|1),
+                       .ENARDEN(A1EN),
                        .REGCEAREGCE(|1),
                        .RSTRAMARSTRAM(|0),
                        .RSTREGARSTREG(|0),
@@ -242,7 +245,7 @@ endmodule
 
 // ------------------------------------------------------------------------
 
-module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
        parameter CFG_ABITS = 10;
        parameter CFG_DBITS = 18;
        parameter CFG_ENABLE_B = 2;
@@ -256,6 +259,7 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
 
        input [CFG_ABITS-1:0] A1ADDR;
        output [CFG_DBITS-1:0] A1DATA;
+       input A1EN;
 
        input [CFG_ABITS-1:0] B1ADDR;
        input [CFG_DBITS-1:0] B1DATA;
@@ -294,7 +298,7 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
                        .DOPADOP(DOP),
                        .ADDRARDADDR(A1ADDR_14),
                        .CLKARDCLK(CLK2),
-                       .ENARDEN(|1),
+                       .ENARDEN(A1EN),
                        .REGCEAREGCE(|1),
                        .RSTRAMARSTRAM(|0),
                        .RSTREGARSTREG(|0),
@@ -332,7 +336,7 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
                        .DOPADOP(DOP),
                        .ADDRARDADDR(A1ADDR_14),
                        .CLKARDCLK(CLK2),
-                       .ENARDEN(|1),
+                       .ENARDEN(A1EN),
                        .REGCEAREGCE(|1),
                        .RSTRAMARSTRAM(|0),
                        .RSTREGARSTREG(|0),
index b3d4c214fd87c105f576a506c804368fa6bdecfc..ee67beba7ace028f7f2686ef55831673799fc1f9 100644 (file)
@@ -79,7 +79,6 @@ struct SynthXilinxPass : public Pass {
                log("\n");
                log("    coarse:\n");
                log("        synth -run coarse\n");
-               log("        dff2dffe\n");
                log("\n");
                log("    bram:\n");
                log("        memory_bram -rules +/xilinx/brams.txt\n");
@@ -92,6 +91,7 @@ struct SynthXilinxPass : public Pass {
                log("    fine:\n");
                log("        opt -fast -full\n");
                log("        memory_map\n");
+               log("        dff2dffe\n");
                log("        opt -full\n");
                log("        techmap -map +/techmap.v -map +/xilinx/arith_map.v\n");
                log("        opt -fast\n");
@@ -178,7 +178,6 @@ struct SynthXilinxPass : public Pass {
                if (check_label(active, run_from, run_to, "coarse"))
                {
                        Pass::call(design, "synth -run coarse");
-                       Pass::call(design, "dff2dffe");
                }
 
                if (check_label(active, run_from, run_to, "bram"))
@@ -197,6 +196,7 @@ struct SynthXilinxPass : public Pass {
                {
                        Pass::call(design, "opt -fast -full");
                        Pass::call(design, "memory_map");
+                       Pass::call(design, "dff2dffe");
                        Pass::call(design, "opt -full");
                        Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v");
                        Pass::call(design, "opt -fast");
index 868f5d00cdade2fee8011e8af4c1109948df74dc..762e2938e33c4d73691813ede4f50cfe7d2e84d1 100644 (file)
@@ -1,5 +1,5 @@
 
-module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
+module \$mem (RD_CLK, RD_EN, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
        parameter MEMID = "";
        parameter SIZE = 256;
        parameter OFFSET = 0;
@@ -17,6 +17,7 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
        parameter WR_CLK_POLARITY = 1'b1;
 
        input [RD_PORTS-1:0] RD_CLK;
+       input [RD_PORTS-1:0] RD_EN;
        input [RD_PORTS*ABITS-1:0] RD_ADDR;
        output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
 
@@ -30,6 +31,8 @@ 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_CONSTVAL_RD_EN_ = 0;
+
        parameter _TECHMAP_BITS_CONNMAP_ = 0;
        parameter _TECHMAP_CONNMAP_WR_EN_ = 0;
 
@@ -46,6 +49,10 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
                if (RD_PORTS > 1 || WR_PORTS > 1)
                        _TECHMAP_FAIL_ <= 1;
 
+               // read enable must be constant high
+               if (_TECHMAP_CONSTVAL_RD_EN_[0] !== 1'b1)
+                       _TECHMAP_FAIL_ <= 1;
+
                // we expect positive read clock and non-transparent reads
                if (RD_TRANSPARENT || !RD_CLK_ENABLE || !RD_CLK_POLARITY)
                        _TECHMAP_FAIL_ <= 1;