aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelina Koƛcielnicka <mwk@0x04.net>2021-05-25 02:56:35 +0200
committerMarcelina Koƛcielnicka <mwk@0x04.net>2021-05-25 12:25:58 +0200
commit4858721637fc5d6ae6d7e0fb0489e0cec8bb388b (patch)
tree0284071263a51eeac0cb1d8ecd111fcf6b2ed2bd
parente0736c1622c60980ddf9b989e9c3e2acc4403135 (diff)
downloadyosys-4858721637fc5d6ae6d7e0fb0489e0cec8bb388b.tar.gz
yosys-4858721637fc5d6ae6d7e0fb0489e0cec8bb388b.tar.bz2
yosys-4858721637fc5d6ae6d7e0fb0489e0cec8bb388b.zip
kernel/mem: Add emulate_priority helper.
-rw-r--r--kernel/mem.cc38
-rw-r--r--kernel/mem.h6
2 files changed, 44 insertions, 0 deletions
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<std::pair<SigBit, SigBit>, 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<SigBit, SigBit> 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) {}
};