diff options
Diffstat (limited to 'passes/memory/memory_collect.cc')
-rw-r--r-- | passes/memory/memory_collect.cc | 130 |
1 files changed, 83 insertions, 47 deletions
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index 9c670f00f..96d0ada03 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -17,13 +17,13 @@ * */ -#include "kernel/register.h" -#include "kernel/log.h" -#include <sstream> -#include <algorithm> -#include <stdlib.h> +#include "kernel/yosys.h" +#include "kernel/sigtools.h" -static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b) +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b) { if (a->type == "$memrd" && b->type == "$memrd") return a->name < b->name; @@ -32,14 +32,15 @@ static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b) return a->parameters.at("\\PRIORITY").as_int() < b->parameters.at("\\PRIORITY").as_int(); } -static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) +void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) { - log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n", + log("Collecting $memrd, $memwr and $meminit 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++; + + Const init_data(State::Sx, memory->size * memory->width); + SigMap sigmap(module); int wr_ports = 0; RTLIL::SigSpec sig_wr_clk; @@ -57,37 +58,64 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) RTLIL::SigSpec sig_rd_addr; RTLIL::SigSpec sig_rd_data; - std::vector<RTLIL::Cell*> del_cells; std::vector<RTLIL::Cell*> memcells; for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if ((cell->type == "$memwr" || cell->type == "$memrd") && memory->name == cell->parameters["\\MEMID"].decode_string()) + if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) { + addr_bits = std::max(addr_bits, cell->getParam("\\ABITS").as_int()); memcells.push_back(cell); + } + } + + if (memcells.empty()) { + log(" no cells found. removing memory.\n"); + return; } std::sort(memcells.begin(), memcells.end(), memcells_cmp); for (auto cell : memcells) { - if (cell->type == "$memwr" && memory->name == cell->parameters["\\MEMID"].decode_string()) + log(" %s (%s)\n", log_id(cell), log_id(cell->type)); + + if (cell->type == "$meminit") { - wr_ports++; - del_cells.push_back(cell); - - RTLIL::SigSpec clk = cell->getPort("\\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->getPort("\\ADDR"); - RTLIL::SigSpec data = cell->getPort("\\DATA"); - RTLIL::SigSpec en = cell->getPort("\\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(memory->width, false); + SigSpec addr = sigmap(cell->getPort("\\ADDR")); + SigSpec data = sigmap(cell->getPort("\\DATA")); + + if (!addr.is_fully_const()) + log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell)); + if (!data.is_fully_const()) + log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell)); + + int offset = (addr.as_int() - memory->start_offset) * memory->width; + + if (offset < 0 || offset + GetSize(data) > GetSize(init_data)) + log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr), log_id(cell)); + + for (int i = 0; i < GetSize(data); i++) + if (0 <= i+offset && i+offset < GetSize(init_data)) + init_data.bits[i+offset] = data[i].data; + + continue; + } + + if (cell->type == "$memwr") + { + SigSpec clk = sigmap(cell->getPort("\\CLK")); + SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); + SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); + 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); + addr.extend_u0(addr_bits, false); + data.extend_u0(memory->width, false); + en.extend_u0(memory->width, false); sig_wr_clk.append(clk); sig_wr_clk_enable.append(clk_enable); @@ -95,26 +123,26 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) sig_wr_addr.append(addr); sig_wr_data.append(data); sig_wr_en.append(en); + + wr_ports++; + continue; } - if (cell->type == "$memrd" && memory->name == cell->parameters["\\MEMID"].decode_string()) + if (cell->type == "$memrd") { - rd_ports++; - del_cells.push_back(cell); - - RTLIL::SigSpec clk = cell->getPort("\\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->getPort("\\ADDR"); - RTLIL::SigSpec data = cell->getPort("\\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); + SigSpec clk = sigmap(cell->getPort("\\CLK")); + SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); + SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); + SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]); + SigSpec addr = sigmap(cell->getPort("\\ADDR")); + SigSpec data = sigmap(cell->getPort("\\DATA")); + + 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); @@ -122,6 +150,9 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) sig_rd_transparent.append(transparent); sig_rd_addr.append(addr); sig_rd_data.append(data); + + rd_ports++; + continue; } } @@ -135,6 +166,10 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) mem->parameters["\\SIZE"] = RTLIL::Const(memory->size); mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + while (GetSize(init_data) > 1 && init_data.bits.back() == State::Sx && init_data.bits[GetSize(init_data)-2] == State::Sx) + init_data.bits.pop_back(); + mem->parameters["\\INIT"] = init_data; + log_assert(sig_wr_clk.size() == wr_ports); log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const()); log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const()); @@ -166,7 +201,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) mem->setPort("\\RD_ADDR", sig_rd_addr); mem->setPort("\\RD_DATA", sig_rd_data); - for (auto c : del_cells) + for (auto c : memcells) module->remove(c); } @@ -205,3 +240,4 @@ struct MemoryCollectPass : public Pass { } } MemoryCollectPass; +PRIVATE_NAMESPACE_END |