From 25a4cd7020c100838e359b393ffb545532e69101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Thu, 16 Jun 2022 06:04:04 +0200 Subject: memory_libmap: Fix params emitted for unused ports for consistency. --- passes/memory/memory_libmap.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'passes/memory') diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index 898e0af85..d77e4be30 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -1706,10 +1706,11 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector &cells, cons if (pdef.wrbe_separate) { cell->setPort(stringf("\\PORT_%s_WR_EN", name), State::S0); cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren); - cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren)); + if (cfg.def->width_mode != WidthMode::Single) + cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren)); } else { cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren); - if (cfg.def->byte != 0) + if (cfg.def->byte != 0 && cfg.def->width_mode != WidthMode::Single) cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren)); } } -- cgit v1.2.3 From d69091806ad29c3720e478d965354f44bd266d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jun 2022 01:20:33 +0200 Subject: memory_libmap: Fix wrprio handling. --- passes/memory/memory_libmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes/memory') diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index d77e4be30..9e147b0bf 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -837,7 +837,7 @@ void MemMapping::handle_priority() { if (!port2.priority_mask[p1idx]) continue; for (auto &cfg: cfgs) { - auto &p1cfg = cfg.rd_ports[p1idx]; + auto &p1cfg = cfg.wr_ports[p1idx]; auto &p2cfg = cfg.wr_ports[p2idx]; bool found = false; for (auto &pgi: p2cfg.def->wrprio) { -- cgit v1.2.3 From 01daa077a2837830914f3d99f351918d690b9093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jun 2022 14:11:04 +0200 Subject: memory_map: Use const drivers instead of FFs for ROMs. --- passes/memory/memory_map.cc | 111 +++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 52 deletions(-) (limited to 'passes/memory') diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index ca1ca483d..21c7a761e 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -191,6 +191,10 @@ struct MemoryMapWorker data_reg_out[idx] = static_cells_map[addr]; count_static++; } + else if (mem.wr_ports.empty()) + { + data_reg_out[idx] = init_data.extract(i*mem.width, mem.width); + } else { RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff)); @@ -266,69 +270,72 @@ struct MemoryMapWorker log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux); - for (int i = 0; i < mem.size; i++) + if (!mem.wr_ports.empty()) { - int addr = i + mem.start_offset; - int idx = addr & ((1 << abits) - 1); - if (static_cells_map.count(addr) > 0) - continue; - - RTLIL::SigSpec sig = data_reg_out[idx]; - - for (int j = 0; j < GetSize(mem.wr_ports); j++) + for (int i = 0; i < mem.size; i++) { - auto &port = mem.wr_ports[j]; - RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2); - RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr))); + int addr = i + mem.start_offset; + int idx = addr & ((1 << abits) - 1); + if (static_cells_map.count(addr) > 0) + continue; - int sub = addr & ((1 << port.wide_log2) - 1); + RTLIL::SigSpec sig = data_reg_out[idx]; - int wr_offset = 0; - while (wr_offset < mem.width) + for (int j = 0; j < GetSize(mem.wr_ports); j++) { - int wr_width = 1; - RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1); - - while (wr_offset + wr_width < mem.width) { - RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1); - if (next_wr_bit != wr_bit) - break; - wr_width++; - } + auto &port = mem.wr_ports[j]; + RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2); + RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr))); - RTLIL::Wire *w = w_seladdr; + int sub = addr & ((1 << port.wide_log2) - 1); - if (wr_bit != State::S1) + int wr_offset = 0; + while (wr_offset < mem.width) { - RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and)); - c->parameters[ID::A_SIGNED] = RTLIL::Const(0); - c->parameters[ID::B_SIGNED] = RTLIL::Const(0); - c->parameters[ID::A_WIDTH] = RTLIL::Const(1); - c->parameters[ID::B_WIDTH] = RTLIL::Const(1); - c->parameters[ID::Y_WIDTH] = RTLIL::Const(1); - c->setPort(ID::A, w); - c->setPort(ID::B, wr_bit); - - w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y")); - c->setPort(ID::Y, RTLIL::SigSpec(w)); + int wr_width = 1; + RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1); + + while (wr_offset + wr_width < mem.width) { + RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1); + if (next_wr_bit != wr_bit) + break; + wr_width++; + } + + RTLIL::Wire *w = w_seladdr; + + if (wr_bit != State::S1) + { + RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and)); + c->parameters[ID::A_SIGNED] = RTLIL::Const(0); + c->parameters[ID::B_SIGNED] = RTLIL::Const(0); + c->parameters[ID::A_WIDTH] = RTLIL::Const(1); + c->parameters[ID::B_WIDTH] = RTLIL::Const(1); + c->parameters[ID::Y_WIDTH] = RTLIL::Const(1); + c->setPort(ID::A, w); + c->setPort(ID::B, wr_bit); + + w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y")); + c->setPort(ID::Y, RTLIL::SigSpec(w)); + } + + RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux)); + c->parameters[ID::WIDTH] = wr_width; + c->setPort(ID::A, sig.extract(wr_offset, wr_width)); + c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width)); + c->setPort(ID::S, RTLIL::SigSpec(w)); + + w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width); + c->setPort(ID::Y, w); + + sig.replace(wr_offset, w); + wr_offset += wr_width; + count_wrmux++; } - - RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux)); - c->parameters[ID::WIDTH] = wr_width; - c->setPort(ID::A, sig.extract(wr_offset, wr_width)); - c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width)); - c->setPort(ID::S, RTLIL::SigSpec(w)); - - w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width); - c->setPort(ID::Y, w); - - sig.replace(wr_offset, w); - wr_offset += wr_width; - count_wrmux++; } - } - module->connect(RTLIL::SigSig(data_reg_in[idx], sig)); + module->connect(RTLIL::SigSig(data_reg_in[idx], sig)); + } } log(" write interface: %d write mux blocks.\n", count_wrmux); -- cgit v1.2.3 From ab3a9325c33b5b1b9de6971b6931ee12c3e3871c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jun 2022 15:29:37 +0200 Subject: memory_map: Add -rom-only option. --- passes/memory/memory_map.cc | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'passes/memory') diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 21c7a761e..ccfb8c94f 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -30,6 +30,7 @@ PRIVATE_NAMESPACE_BEGIN struct MemoryMapWorker { bool attr_icase = false; + bool rom_only = false; dict> attributes; RTLIL::Design *design; @@ -107,11 +108,8 @@ struct MemoryMapWorker SigSpec init_data = mem.get_init_data(); - // delete unused memory cell - if (mem.rd_ports.empty()) { - mem.remove(); + if (!mem.wr_ports.empty() && rom_only) return; - } // check if attributes allow us to infer FFRAM for this memory for (const auto &attr : attributes) { @@ -143,6 +141,12 @@ struct MemoryMapWorker } } + // delete unused memory cell + if (mem.rd_ports.empty()) { + mem.remove(); + return; + } + // all write ports must share the same clock RTLIL::SigSpec refclock; bool refclock_pol = false; @@ -373,10 +377,14 @@ struct MemoryMapPass : public Pass { log(" -iattr\n"); log(" for -attr, ignore case of .\n"); log("\n"); + log(" -rom-only\n"); + log(" only perform conversion for ROMs (memories with no write ports).\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool attr_icase = false; + bool rom_only = false; dict> attributes; log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n"); @@ -413,6 +421,11 @@ struct MemoryMapPass : public Pass { attr_icase = true; continue; } + if (args[argidx] == "-rom-only") + { + rom_only = true; + continue; + } break; } extra_args(args, argidx, design); @@ -421,6 +434,7 @@ struct MemoryMapPass : public Pass { MemoryMapWorker worker(design, mod); worker.attr_icase = attr_icase; worker.attributes = attributes; + worker.rom_only = rom_only; worker.run(); } } -- cgit v1.2.3 From d78d807a7fa1747b40da8bac9e278183cf86d3cc Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 27 Jun 2022 15:47:55 +0200 Subject: memory_map: -keepdc option for formal Use it when invoking memory_map -rom-only from write_{smt2,btor}. --- passes/memory/memory_map.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'passes/memory') diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index ccfb8c94f..5ec717733 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -31,6 +31,7 @@ struct MemoryMapWorker { bool attr_icase = false; bool rom_only = false; + bool keepdc = false; dict> attributes; RTLIL::Design *design; @@ -190,14 +191,15 @@ struct MemoryMapWorker { int addr = i + mem.start_offset; int idx = addr & ((1 << abits) - 1); + SigSpec w_init = init_data.extract(i*mem.width, mem.width); if (static_cells_map.count(addr) > 0) { data_reg_out[idx] = static_cells_map[addr]; count_static++; } - else if (mem.wr_ports.empty()) + else if (mem.wr_ports.empty() && (!keepdc || w_init.is_fully_def())) { - data_reg_out[idx] = init_data.extract(i*mem.width, mem.width); + data_reg_out[idx] = w_init; } else { @@ -220,7 +222,6 @@ struct MemoryMapWorker w_out_name = genid(mem.memid, "", addr, "$q"); RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width); - SigSpec w_init = init_data.extract(i*mem.width, mem.width); if (!w_init.is_fully_undef()) w_out->attributes[ID::init] = w_init.as_const(); @@ -380,11 +381,15 @@ struct MemoryMapPass : public Pass { log(" -rom-only\n"); log(" only perform conversion for ROMs (memories with no write ports).\n"); log("\n"); + log(" -keepdc\n"); + log(" when mapping ROMs, keep x-bits shared across read ports.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool attr_icase = false; bool rom_only = false; + bool keepdc = false; dict> attributes; log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n"); @@ -426,6 +431,11 @@ struct MemoryMapPass : public Pass { rom_only = true; continue; } + if (args[argidx] == "-keepdc") + { + keepdc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -435,6 +445,7 @@ struct MemoryMapPass : public Pass { worker.attr_icase = attr_icase; worker.attributes = attributes; worker.rom_only = rom_only; + worker.keepdc = keepdc; worker.run(); } } -- cgit v1.2.3 From a6b440b5c9c4fb0472c01aec84961c3f1b40c954 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 28 Jun 2022 19:05:35 +0200 Subject: memory_map: avoid undriven unused FF inputs for -keepdc --- passes/memory/memory_map.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes/memory') diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 5ec717733..fd5b1f1ad 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -228,6 +228,9 @@ struct MemoryMapWorker data_reg_out[idx] = w_out; c->setPort(ID::Q, w_out); + + if (mem.wr_ports.empty()) + module->connect(RTLIL::SigSig(w_in, w_out)); } } -- cgit v1.2.3 From a2f9ebe43a287233917947851e0d0dff803a4675 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 16:07:28 +0200 Subject: memory_map: Add -formal option This maps memories for a global clock based formal verification flow. This implies -keepdc, uses $ff cells for ROMs and sets hdlname attributes. --- passes/memory/memory_map.cc | 84 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 17 deletions(-) (limited to 'passes/memory') diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index fd5b1f1ad..e2f74c2e1 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -32,6 +32,7 @@ struct MemoryMapWorker bool attr_icase = false; bool rom_only = false; bool keepdc = false; + bool formal = false; dict> attributes; RTLIL::Design *design; @@ -151,6 +152,8 @@ struct MemoryMapWorker // all write ports must share the same clock RTLIL::SigSpec refclock; bool refclock_pol = false; + bool async_wr = false; + bool static_only = true; for (int i = 0; i < GetSize(mem.wr_ports); i++) { auto &port = mem.wr_ports[i]; if (port.en.is_fully_const() && !port.en.as_bool()) { @@ -164,10 +167,20 @@ struct MemoryMapWorker static_ports.insert(i); continue; } - log("Not mapping memory %s in module %s (write port %d has no clock).\n", - mem.memid.c_str(), module->name.c_str(), i); - return; + static_only = false; + if (GetSize(refclock) != 0) + log("Not mapping memory %s in module %s (mixed clocked and async write ports).\n", + mem.memid.c_str(), module->name.c_str()); + if (!formal) + log("Not mapping memory %s in module %s (write port %d has no clock).\n", + mem.memid.c_str(), module->name.c_str(), i); + async_wr = true; + continue; } + static_only = false; + if (async_wr) + log("Not mapping memory %s in module %s (mixed clocked and async write ports).\n", + mem.memid.c_str(), module->name.c_str()); if (refclock.size() == 0) { refclock = port.clk; refclock_pol = port.clk_polarity; @@ -185,6 +198,8 @@ struct MemoryMapWorker std::vector data_reg_in(1 << abits); std::vector data_reg_out(1 << abits); + std::vector &data_read = async_wr ? data_reg_in : data_reg_out; + int count_static = 0; for (int i = 0; i < mem.size; i++) @@ -194,24 +209,36 @@ struct MemoryMapWorker SigSpec w_init = init_data.extract(i*mem.width, mem.width); if (static_cells_map.count(addr) > 0) { - data_reg_out[idx] = static_cells_map[addr]; + data_read[idx] = static_cells_map[addr]; count_static++; } - else if (mem.wr_ports.empty() && (!keepdc || w_init.is_fully_def())) + else if (static_only && (!keepdc || w_init.is_fully_def())) { - data_reg_out[idx] = w_init; + data_read[idx] = w_init; } else { - RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff)); - c->parameters[ID::WIDTH] = mem.width; - if (GetSize(refclock) != 0) { + RTLIL::Cell *c; + auto ff_id = genid(mem.memid, "", addr); + + if (static_only) { + // non-static part is a ROM, we only reach this with keepdc + if (formal) { + c = module->addCell(ff_id, ID($ff)); + } else { + c = module->addCell(ff_id, ID($dff)); + c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1); + c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0)); + } + } else if (async_wr) { + log_assert(formal); // General async write not implemented yet, checked against above + c = module->addCell(ff_id, ID($ff)); + } else { + c = module->addCell(ff_id, ID($dff)); c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol); c->setPort(ID::CLK, refclock); - } else { - c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1); - c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0)); } + c->parameters[ID::WIDTH] = mem.width; RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", addr, "$d"), mem.width); data_reg_in[idx] = w_in; @@ -223,18 +250,27 @@ struct MemoryMapWorker RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width); + if (formal && mem.packed && mem.cell->name.c_str()[0] == '\\') { + auto hdlname = mem.cell->get_hdlname_attribute(); + if (hdlname.empty()) + hdlname.push_back(mem.cell->name.c_str() + 1); + hdlname.push_back(stringf("[%d]", addr)); + w_out->set_hdlname_attribute(hdlname); + } + if (!w_init.is_fully_undef()) w_out->attributes[ID::init] = w_init.as_const(); data_reg_out[idx] = w_out; c->setPort(ID::Q, w_out); - if (mem.wr_ports.empty()) + if (static_only) module->connect(RTLIL::SigSig(w_in, w_out)); } } - log(" created %d $dff cells and %d static cells of width %d.\n", mem.size-count_static, count_static, mem.width); + log(" created %d %s cells and %d static cells of width %d.\n", + mem.size-count_static, formal && (static_only || async_wr) ? "$ff" : "$dff", count_static, mem.width); int count_dff = 0, count_mux = 0, count_wrmux = 0; @@ -272,13 +308,13 @@ struct MemoryMapWorker } for (int j = 0; j < (1 << abits); j++) - if (data_reg_out[j] != SigSpec()) - module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j])); + if (data_read[j] != SigSpec()) + module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_read[j])); } log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux); - if (!mem.wr_ports.empty()) + if (!static_only) { for (int i = 0; i < mem.size; i++) { @@ -387,12 +423,19 @@ struct MemoryMapPass : public Pass { log(" -keepdc\n"); log(" when mapping ROMs, keep x-bits shared across read ports.\n"); log("\n"); + log(" -formal\n"); + log(" map memories for a global clock based formal verification flow.\n"); + log(" This implies -keepdc, uses $ff cells for ROMs and sets hdlname\n"); + log(" attributes. It also has limited support for async write ports\n"); + log(" as generated by clk2fflogic.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool attr_icase = false; bool rom_only = false; bool keepdc = false; + bool formal = false; dict> attributes; log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n"); @@ -439,6 +482,12 @@ struct MemoryMapPass : public Pass { keepdc = true; continue; } + if (args[argidx] == "-formal") + { + formal = true; + keepdc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -449,6 +498,7 @@ struct MemoryMapPass : public Pass { worker.attributes = attributes; worker.rom_only = rom_only; worker.keepdc = keepdc; + worker.formal = formal; worker.run(); } } -- cgit v1.2.3