From 1b6d1e941950576f16140e43a53c1694cddb1092 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Thu, 19 Oct 2023 19:12:36 +0200 Subject: [PATCH 1/4] memory_libmap: look for ram_style attributes on surrounding signals --- kernel/constids.inc | 1 + kernel/mem.cc | 6 +++ passes/memory/memory_libmap.cc | 44 ++++++++++++++++--- tests/memlib/generate.py | 22 ++++++++++ tests/verific/rom_case.ys | 78 ++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 tests/verific/rom_case.ys diff --git a/kernel/constids.inc b/kernel/constids.inc index 93101282a..480e2afc6 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -140,6 +140,7 @@ X(nomem2reg) X(nomeminit) X(nosync) X(nowrshmsk) +X(no_ram) X(no_rw_check) X(O) X(OFFSET) diff --git a/kernel/mem.cc b/kernel/mem.cc index 269a476a1..40345b81d 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -148,6 +148,8 @@ void Mem::emit() { for (int j = 0; j < (1 << wr_ports[i].wide_log2); j++) wr_port_xlat.push_back(i); for (auto &port : rd_ports) { + for (auto attr: port.attributes) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -210,6 +212,8 @@ void Mem::emit() { cell->setPort(ID::RD_ADDR, rd_addr); cell->setPort(ID::RD_DATA, rd_data); for (auto &port : wr_ports) { + for (auto attr: port.attributes) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -246,6 +250,8 @@ void Mem::emit() { cell->setPort(ID::WR_ADDR, wr_addr); cell->setPort(ID::WR_DATA, wr_data); for (auto &init : inits) { + for (auto attr: init.attributes) + cell->attributes.insert(attr); if (init.cell) { module->remove(init.cell); init.cell = nullptr; diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index f8b0eec1d..e39a518b7 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -481,18 +481,49 @@ void MemMapping::dump_config(MemConfig &cfg) { } } +std::pair search_for_attribute(Mem mem, IdString attr) { + if (mem.has_attribute(attr)) + return std::make_pair(true, mem.attributes.at(attr)); + for (auto &port: mem.rd_ports){ + if (port.has_attribute(attr)) + return std::make_pair(true, port.attributes.at(attr)); + log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (SigBit bit: port.data) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (SigBit bit: port.addr) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + } + for (auto &port: mem.wr_ports){ + if (port.has_attribute(attr)) + return std::make_pair(true, port.attributes.at(attr)); + log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (SigBit bit: port.data) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + for (SigBit bit: port.addr) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + } + return std::make_pair(false, Const()); +} + // Go through memory attributes to determine user-requested mapping style. void MemMapping::determine_style() { kind = RamKind::Auto; style = ""; - if (mem.get_bool_attribute(ID::lram)) { + auto find_attr = search_for_attribute(mem, ID::lram); + if (find_attr.first && find_attr.second.as_bool()) { kind = RamKind::Huge; log("found attribute 'lram' on memory %s.%s, forced mapping to huge RAM\n", log_id(mem.module->name), log_id(mem.memid)); return; } for (auto attr: {ID::ram_block, ID::rom_block, ID::ram_style, ID::rom_style, ID::ramstyle, ID::romstyle, ID::syn_ramstyle, ID::syn_romstyle}) { - if (mem.has_attribute(attr)) { - Const val = mem.attributes.at(attr); + find_attr = search_for_attribute(mem, attr); + if (find_attr.first) { + Const val = find_attr.second; if (val == 1) { kind = RamKind::NotLogic; log("found attribute '%s = 1' on memory %s.%s, disabled mapping to FF\n", log_id(attr), log_id(mem.module->name), log_id(mem.memid)); @@ -526,8 +557,11 @@ void MemMapping::determine_style() { return; } } - if (mem.get_bool_attribute(ID::logic_block)) - kind = RamKind::Logic; + for (auto attr: {ID::logic_block, ID::no_ram}){ + find_attr = search_for_attribute(mem, attr); + if (find_attr.first && find_attr.second.as_bool()) + kind = RamKind::Logic; + } } // Determine whether the memory can be mapped entirely to soft logic. diff --git a/tests/memlib/generate.py b/tests/memlib/generate.py index f40210501..46eff6b43 100644 --- a/tests/memlib/generate.py +++ b/tests/memlib/generate.py @@ -1513,6 +1513,28 @@ end""" ["block_sp_full"], defs, {"RAM_BLOCK_SP": 1, "$*": add_logic} )) + +ROM_CASE = """ +module rom(input clk, input [2:0] addr, {attr}output reg [7:0] data); + +always @(posedge clk) begin + case (addr) + 3'b000: data <= 8'h12; + 3'b001: data <= 8'hAB; + 3'b010: data <= 8'h42; + 3'b011: data <= 8'h23; + 3'b100: data <= 8'h66; + 3'b101: data <= 8'hC0; + 3'b110: data <= 8'h3F; + 3'b111: data <= 8'h95; + endcase +end + +endmodule +""" + +TESTS.append(Test("rom_case", ROM_CASE.format(attr=""), ["block_sdp"], [], {"RAM_BLOCK_SDP" : 0})) +TESTS.append(Test("rom_case_block", ROM_CASE.format(attr="(* rom_style = \"block\" *) "), ["block_sdp"], [], {"RAM_BLOCK_SDP" : 1})) with open("run-test.mk", "w") as mf: mf.write("ifneq ($(strip $(SEED)),)\n") diff --git a/tests/verific/rom_case.ys b/tests/verific/rom_case.ys new file mode 100644 index 000000000..171c16db7 --- /dev/null +++ b/tests/verific/rom_case.ys @@ -0,0 +1,78 @@ +verific -sv < data <= X"12"; + when "001" => data <= X"AB"; + when "010" => data <= X"42"; + when "011" => data <= X"23"; + when "100" => data <= X"66"; + when "101" => data <= X"C0"; + when "110" => data <= X"3F"; + when others => data <= X"95"; + end case; + end if; + end process p_rom; + +end architecture rtl; +EOF +hierarchy -top rom +proc +opt +opt -full +memory -nomap +dump +memory_libmap -lib ../memlib/memlib_block_sdp.txt +memory_map +stat +select -assert-count 1 t:RAM_BLOCK_SDP \ No newline at end of file From 833b67af80a748b7c1f8a775c5721b2815151f34 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Fri, 20 Oct 2023 18:31:41 +0200 Subject: [PATCH 2/4] verific: import attributes on ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Miodrag Milanović --- frontends/verific/verific.cc | 7 ++++++- tests/verific/memory_semantics.ys | 4 ++-- tests/verific/rom_case.ys | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 115a42e33..5ac8f8b39 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1345,7 +1345,12 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); wire->upto = portbus->IsUp(); import_attributes(wire->attributes, portbus, nl); - + SetIter si ; + Port *port ; + FOREACH_PORT_OF_PORTBUS(portbus, si, port) { + import_attributes(wire->attributes, port->GetNet(), nl); + break; + } bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN; if (portbus_input) wire->port_input = true; diff --git a/tests/verific/memory_semantics.ys b/tests/verific/memory_semantics.ys index 92f4fd2dc..adcd3a4ca 100644 --- a/tests/verific/memory_semantics.ys +++ b/tests/verific/memory_semantics.ys @@ -26,9 +26,9 @@ reg [DEPTH_LOG2-1:0] counter = 0; reg done = 1'b0; always @(posedge clk) begin if (!done) - counter = counter + 1; + counter = counter + 1'b1; if (counter == 0) - done = 1; + done = 1'b1; end wire [WIDTH-1:0] old_data = PRIME1 * counter; diff --git a/tests/verific/rom_case.ys b/tests/verific/rom_case.ys index 171c16db7..253cc0766 100644 --- a/tests/verific/rom_case.ys +++ b/tests/verific/rom_case.ys @@ -30,7 +30,7 @@ select -assert-count 1 t:RAM_BLOCK_SDP design -reset -verific -vhdl << +verific -vhdl < Date: Tue, 24 Oct 2023 13:55:45 +0200 Subject: [PATCH 3/4] memory_libmap: update search order for attributes --- passes/memory/memory_libmap.cc | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index e39a518b7..ec181a142 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -482,31 +482,40 @@ void MemMapping::dump_config(MemConfig &cfg) { } std::pair search_for_attribute(Mem mem, IdString attr) { + // priority of attributes: + // 1. attributes on memory itself + // 2. attributes on a read or write port + // 3. attributes on data signal of a read or write port + // 4. attributes on address signal of a read or write port + if (mem.has_attribute(attr)) return std::make_pair(true, mem.attributes.at(attr)); - for (auto &port: mem.rd_ports){ + + for (auto &port: mem.rd_ports) if (port.has_attribute(attr)) return std::make_pair(true, port.attributes.at(attr)); - log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (auto &port: mem.wr_ports) + if (port.has_attribute(attr)) + return std::make_pair(true, port.attributes.at(attr)); + + for (auto &port: mem.rd_ports) for (SigBit bit: port.data) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); - log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); - for (SigBit bit: port.addr) - if (bit.is_wire() && bit.wire->has_attribute(attr)) - return std::make_pair(true, bit.wire->attributes.at(attr)); - } - for (auto &port: mem.wr_ports){ - if (port.has_attribute(attr)) - return std::make_pair(true, port.attributes.at(attr)); - log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (auto &port: mem.wr_ports) for (SigBit bit: port.data) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); + + for (auto &port: mem.rd_ports) for (SigBit bit: port.addr) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); - } + for (auto &port: mem.wr_ports) + for (SigBit bit: port.addr) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + return std::make_pair(false, Const()); } From f9ab6e147a2c70eb826119235ee34fbe713624d8 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 30 Oct 2023 16:30:34 +0100 Subject: [PATCH 4/4] mem: only import attributes from ports if the memory doesn't have them yet --- kernel/mem.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/mem.cc b/kernel/mem.cc index 40345b81d..01c866770 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -149,7 +149,8 @@ void Mem::emit() { wr_port_xlat.push_back(i); for (auto &port : rd_ports) { for (auto attr: port.attributes) - cell->attributes.insert(attr); + if (!cell->has_attribute(attr.first)) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -213,7 +214,8 @@ void Mem::emit() { cell->setPort(ID::RD_DATA, rd_data); for (auto &port : wr_ports) { for (auto attr: port.attributes) - cell->attributes.insert(attr); + if (!cell->has_attribute(attr.first)) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -251,7 +253,8 @@ void Mem::emit() { cell->setPort(ID::WR_DATA, wr_data); for (auto &init : inits) { for (auto attr: init.attributes) - cell->attributes.insert(attr); + if (!cell->has_attribute(attr.first)) + cell->attributes.insert(attr); if (init.cell) { module->remove(init.cell); init.cell = nullptr;