From 4858721637fc5d6ae6d7e0fb0489e0cec8bb388b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 25 May 2021 02:56:35 +0200 Subject: kernel/mem: Add emulate_priority helper. --- kernel/mem.cc | 38 ++++++++++++++++++++++++++++++++++++++ kernel/mem.h | 6 ++++++ 2 files changed, 44 insertions(+) diff --git a/kernel/mem.cc b/kernel/mem.cc index f2c8dd953..649515e0c 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -599,3 +599,41 @@ void Mem::narrow() { std::swap(rd_ports, new_rd_ports); std::swap(wr_ports, new_wr_ports); } + +void Mem::emulate_priority(int idx1, int idx2) +{ + auto &port1 = wr_ports[idx1]; + auto &port2 = wr_ports[idx2]; + if (!port2.priority_mask[idx1]) + return; + int min_wide_log2 = std::min(port1.wide_log2, port2.wide_log2); + int max_wide_log2 = std::max(port1.wide_log2, port2.wide_log2); + bool wide1 = port1.wide_log2 > port2.wide_log2; + for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) { + SigSpec addr1 = port1.addr; + SigSpec addr2 = port2.addr; + for (int j = min_wide_log2; j < max_wide_log2; j++) + if (wide1) + addr1[j] = State(sub >> j & 1); + else + addr2[j] = State(sub >> j & 1); + SigSpec addr_eq = module->Eq(NEW_ID, addr1, addr2); + int ewidth = width << min_wide_log2; + int sub1 = wide1 ? sub : 0; + int sub2 = wide1 ? 0 : sub; + dict, SigBit> cache; + for (int pos = 0; pos < ewidth; pos++) { + SigBit &en1 = port1.en[pos + sub1 * width]; + SigBit &en2 = port2.en[pos + sub2 * width]; + std::pair key(en1, en2); + if (cache.count(key)) { + en1 = cache[key]; + } else { + SigBit active2 = module->And(NEW_ID, addr_eq, en2); + SigBit nactive2 = module->Not(NEW_ID, active2); + en1 = cache[key] = module->And(NEW_ID, en1, nactive2); + } + } + } + port2.priority_mask[idx1] = false; +} diff --git a/kernel/mem.h b/kernel/mem.h index 214086ac4..08befebdb 100644 --- a/kernel/mem.h +++ b/kernel/mem.h @@ -77,6 +77,12 @@ struct Mem { Cell *extract_rdff(int idx, FfInitVals *initvals); void narrow(); + // If write port idx2 currently has priority over write port idx1, + // inserts extra logic on idx1's enable signal to disable writes + // when idx2 is writing to the same address, then removes the priority + // from the priority mask. + void emulate_priority(int idx1, int idx2); + Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {} }; -- cgit v1.2.3