diff options
Diffstat (limited to 'passes/memory/memory_collect.cc')
-rw-r--r-- | passes/memory/memory_collect.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc new file mode 100644 index 000000000..b89b97695 --- /dev/null +++ b/passes/memory/memory_collect.cc @@ -0,0 +1,182 @@ +/* + * 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/register.h" +#include "kernel/log.h" +#include <sstream> +#include <stdlib.h> +#include <assert.h> + +static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) +{ + log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n", + memory->name.c_str(), module->name.c_str()); + + int addr_bits = 0; + while ((1 << addr_bits) < memory->size) + addr_bits++; + + int wr_ports = 0; + RTLIL::SigSpec sig_wr_clk; + RTLIL::SigSpec sig_wr_clk_enable; + RTLIL::SigSpec sig_wr_clk_polarity; + RTLIL::SigSpec sig_wr_addr; + RTLIL::SigSpec sig_wr_data; + RTLIL::SigSpec sig_wr_en; + + int rd_ports = 0; + RTLIL::SigSpec sig_rd_clk; + RTLIL::SigSpec sig_rd_clk_enable; + RTLIL::SigSpec sig_rd_clk_polarity; + RTLIL::SigSpec sig_rd_addr; + RTLIL::SigSpec sig_rd_data; + + std::vector<std::string> del_cell_ids; + + for (auto &cell_it : module->cells) + { + RTLIL::Cell *cell = cell_it.second; + + if (cell->type == "$memwr" && cell->parameters["\\MEMID"].str == memory->name) + { + wr_ports++; + del_cell_ids.push_back(cell->name); + + 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 addr = cell->connections["\\ADDR"]; + RTLIL::SigSpec data = cell->connections["\\DATA"]; + RTLIL::SigSpec en = cell->connections["\\EN"]; + + clk.extend(1, false); + clk_enable.extend(1, false); + clk_polarity.extend(1, false); + addr.extend(addr_bits, false); + data.extend(memory->width, false); + en.extend(1, false); + + sig_wr_clk.append(clk); + sig_wr_clk_enable.append(clk_enable); + sig_wr_clk_polarity.append(clk_polarity); + sig_wr_addr.append(addr); + sig_wr_data.append(data); + sig_wr_en.append(en); + } + + if (cell->type == "$memrd" && cell->parameters["\\MEMID"].str == memory->name) + { + rd_ports++; + del_cell_ids.push_back(cell->name); + + 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 addr = cell->connections["\\ADDR"]; + RTLIL::SigSpec data = cell->connections["\\DATA"]; + + clk.extend(1, false); + clk_enable.extend(1, false); + clk_polarity.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_addr.append(addr); + sig_rd_data.append(data); + } + } + + std::stringstream sstr; + sstr << "$mem$" << memory->name << "$" << (RTLIL::autoidx++); + + RTLIL::Cell *mem = new RTLIL::Cell; + mem->name = sstr.str(); + mem->type = "$mem"; + + mem->parameters["\\MEMID"] = RTLIL::Const(memory->name); + mem->parameters["\\WIDTH"] = RTLIL::Const(memory->width); + mem->parameters["\\OFFSET"] = RTLIL::Const(memory->start_offset); + mem->parameters["\\SIZE"] = RTLIL::Const(memory->size); + mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + + sig_wr_clk_enable.optimize(); + sig_wr_clk_polarity.optimize(); + + assert(sig_wr_clk.width == wr_ports); + assert(sig_wr_clk_enable.width == wr_ports && sig_wr_clk_enable.is_fully_const()); + assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const()); + assert(sig_wr_addr.width == wr_ports * addr_bits); + assert(sig_wr_data.width == wr_ports * memory->width); + assert(sig_wr_en.width == wr_ports); + + 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->connections["\\WR_CLK"] = sig_wr_clk; + mem->connections["\\WR_ADDR"] = sig_wr_addr; + mem->connections["\\WR_DATA"] = sig_wr_data; + mem->connections["\\WR_EN"] = sig_wr_en; + + sig_rd_clk_enable.optimize(); + sig_rd_clk_polarity.optimize(); + + assert(sig_rd_clk.width == rd_ports); + assert(sig_rd_clk_enable.width == rd_ports && sig_rd_clk_enable.is_fully_const()); + assert(sig_rd_clk_polarity.width == rd_ports && sig_rd_clk_polarity.is_fully_const()); + assert(sig_rd_addr.width == rd_ports * addr_bits); + assert(sig_rd_data.width == rd_ports * memory->width); + + 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->connections["\\RD_CLK"] = sig_rd_clk; + mem->connections["\\RD_ADDR"] = sig_rd_addr; + mem->connections["\\RD_DATA"] = sig_rd_data; + + for (auto &id : del_cell_ids) { + delete module->cells[id]; + module->cells.erase(id); + } + module->cells[mem->name] = mem; +} + +static void handle_module(RTLIL::Module *module) +{ + for (auto &mem_it : module->memories) { + handle_memory(module, mem_it.second); + delete mem_it.second; + } + module->memories.clear(); +} + +struct MemoryCollectPass : public Pass { + MemoryCollectPass() : Pass("memory_collect") { } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n"); + extra_args(args, 1, design); + for (auto &mod_it : design->modules) + handle_module(mod_it.second); + } +} MemoryCollectPass; + |