| /* |
| * yosys -- Yosys Open SYnthesis Suite |
| * |
| * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| * |
| */ |
| |
| #include "kernel/yosys.h" |
| #include "kernel/sigtools.h" |
| |
| USING_YOSYS_NAMESPACE |
| PRIVATE_NAMESPACE_BEGIN |
| |
| struct MemoryNordffPass : public Pass { |
| MemoryNordffPass() : Pass("memory_nordff", "extract read port FFs from memories") { } |
| void help() YS_OVERRIDE |
| { |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| log("\n"); |
| log(" memory_nordff [options] [selection]\n"); |
| log("\n"); |
| log("This pass extracts FFs from memory read ports. This results in a netlist\n"); |
| log("similar to what one would get from calling memory_dff with -nordff.\n"); |
| log("\n"); |
| } |
| void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE |
| { |
| log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from $mem).\n"); |
| |
| size_t argidx; |
| for (argidx = 1; argidx < args.size(); argidx++) { |
| // if (args[argidx] == "-nordff" || args[argidx] == "-wr_only") { |
| // flag_wr_only = true; |
| // continue; |
| // } |
| break; |
| } |
| extra_args(args, argidx, design); |
| |
| for (auto module : design->selected_modules()) |
| for (auto cell : vector<Cell*>(module->selected_cells())) |
| { |
| if (cell->type != "$mem") |
| continue; |
| |
| int rd_ports = cell->getParam("\\RD_PORTS").as_int(); |
| int abits = cell->getParam("\\ABITS").as_int(); |
| int width = cell->getParam("\\WIDTH").as_int(); |
| |
| SigSpec rd_addr = cell->getPort("\\RD_ADDR"); |
| SigSpec rd_data = cell->getPort("\\RD_DATA"); |
| SigSpec rd_clk = cell->getPort("\\RD_CLK"); |
| SigSpec rd_en = cell->getPort("\\RD_EN"); |
| Const rd_clk_enable = cell->getParam("\\RD_CLK_ENABLE"); |
| Const rd_clk_polarity = cell->getParam("\\RD_CLK_POLARITY"); |
| |
| for (int i = 0; i < rd_ports; i++) |
| { |
| bool clk_enable = rd_clk_enable[i] == State::S1; |
| |
| if (clk_enable) |
| { |
| bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1; |
| bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1; |
| |
| SigSpec clk = cell->getPort("\\RD_CLK")[i] ; |
| SigSpec en = cell->getPort("\\RD_EN")[i]; |
| Cell *c; |
| |
| if (transparent) |
| { |
| SigSpec sig_q = module->addWire(NEW_ID, abits); |
| SigSpec sig_d = rd_addr.extract(abits * i, abits); |
| rd_addr.replace(abits * i, sig_q); |
| if (en != State::S1) |
| sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); |
| c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); |
| } |
| else |
| { |
| SigSpec sig_d = module->addWire(NEW_ID, width); |
| SigSpec sig_q = rd_data.extract(width * i, width); |
| rd_data.replace(width *i, sig_d); |
| if (en != State::S1) |
| sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); |
| c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); |
| } |
| |
| log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data", |
| i, log_id(module), log_id(cell), log_id(c)); |
| } |
| |
| rd_en[i] = State::S1; |
| rd_clk[i] = State::S0; |
| rd_clk_enable[i] = State::S0; |
| rd_clk_polarity[i] = State::S1; |
| } |
| |
| cell->setPort("\\RD_ADDR", rd_addr); |
| cell->setPort("\\RD_DATA", rd_data); |
| cell->setPort("\\RD_CLK", rd_clk); |
| cell->setPort("\\RD_EN", rd_en); |
| cell->setParam("\\RD_CLK_ENABLE", rd_clk_enable); |
| cell->setParam("\\RD_CLK_POLARITY", rd_clk_polarity); |
| } |
| } |
| } MemoryNordffPass; |
| |
| PRIVATE_NAMESPACE_END |