diff options
author | Clifford Wolf <clifford@clifford.at> | 2015-09-25 12:23:11 +0200 |
---|---|---|
committer | Clifford Wolf <clifford@clifford.at> | 2015-09-25 12:23:11 +0200 |
commit | 924d9d6e86a5e9a2294479345daac1c03d78008a (patch) | |
tree | 04d28a2068b32c44c0aca2b8b815f6fc51cec427 | |
parent | ec92c8965960fa814c3663e987bc2a7eb80965e5 (diff) | |
download | yosys-924d9d6e86a5e9a2294479345daac1c03d78008a.tar.gz yosys-924d9d6e86a5e9a2294479345daac1c03d78008a.tar.bz2 yosys-924d9d6e86a5e9a2294479345daac1c03d78008a.zip |
Added read-enable to memory model
-rw-r--r-- | frontends/ast/genrtlil.cc | 1 | ||||
-rw-r--r-- | frontends/verific/verific.cc | 3 | ||||
-rw-r--r-- | kernel/celltypes.h | 6 | ||||
-rw-r--r-- | kernel/rtlil.cc | 2 | ||||
-rw-r--r-- | manual/CHAPTER_CellLib.tex | 8 | ||||
-rw-r--r-- | passes/memory/memory_bram.cc | 20 | ||||
-rw-r--r-- | passes/memory/memory_collect.cc | 37 | ||||
-rw-r--r-- | passes/memory/memory_dff.cc | 52 | ||||
-rw-r--r-- | passes/memory/memory_map.cc | 33 | ||||
-rw-r--r-- | passes/memory/memory_unpack.cc | 1 | ||||
-rw-r--r-- | techlibs/common/simlib.v | 9 | ||||
-rw-r--r-- | techlibs/ice40/brams.txt | 4 | ||||
-rw-r--r-- | techlibs/ice40/brams_map.v | 10 | ||||
-rw-r--r-- | techlibs/xilinx/brams.txt | 14 | ||||
-rw-r--r-- | techlibs/xilinx/brams_map.v | 24 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 4 | ||||
-rw-r--r-- | tests/techmap/mem_simple_4x1_map.v | 9 |
17 files changed, 159 insertions, 78 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index a2655e9a5..c322faf7b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -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)); diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 897a7f328..793c06844 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -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; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index f36833446..40fdca36e 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -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}); } diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8ff521952..7090fe913 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -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")); diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 9f9ec2e2b..c648eb1fe 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -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. diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index f638b5bb7..3e83a6d9b 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -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"); diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index 91b5759eb..abd4b1242 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -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); diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 5584f27c3..3373369f6 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -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"); diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 524fa8d2b..0b8ccb363 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -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); } } diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc index a497362bf..60724da77 100644 --- a/passes/memory/memory_unpack.cc +++ b/passes/memory/memory_unpack.cc @@ -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)); } diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 2a56b3a1e..a2dc466d4 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -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 diff --git a/techlibs/ice40/brams.txt b/techlibs/ice40/brams.txt index 05131b227..03d596111 100644 --- a/techlibs/ice40/brams.txt +++ b/techlibs/ice40/brams.txt @@ -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 diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v index f3674b4ed..a82161c99 100644 --- a/techlibs/ice40/brams_map.v +++ b/techlibs/ice40/brams_map.v @@ -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), diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/brams.txt index 894e714c6..f1161114e 100644 --- a/techlibs/xilinx/brams.txt +++ b/techlibs/xilinx/brams.txt @@ -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 diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/brams_map.v index cbfd4e1eb..7ea49158d 100644 --- a/techlibs/xilinx/brams_map.v +++ b/techlibs/xilinx/brams_map.v @@ -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), diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b3d4c214f..ee67beba7 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -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"); diff --git a/tests/techmap/mem_simple_4x1_map.v b/tests/techmap/mem_simple_4x1_map.v index 868f5d00c..762e2938e 100644 --- a/tests/techmap/mem_simple_4x1_map.v +++ b/tests/techmap/mem_simple_4x1_map.v @@ -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; |