-from nmigen import Signal, Module, Cat, Const
+# based on ariane plru, from tlb.sv
+
+from nmigen import Signal, Module, Cat, Const, Repl
from nmigen.hdl.ir import Elaboratable
-from math import log2
+from nmigen.cli import rtlil
+from nmigen.utils import log2_int
class PLRU(Elaboratable):
... ... ... ...
"""
- def __init__(self, entries):
- self.entries = entries
- self.lu_hit = Signal(entries)
- self.replace_en_o = Signal(entries)
- self.lu_access_i = Signal()
- # Tree (bit per entry)
- self.TLBSZ = 2*(self.entries-1)
- self.plru_tree = Signal(self.TLBSZ)
- self.plru_tree_o = Signal(self.TLBSZ)
+ def __init__(self, BITS):
+ self.BITS = BITS
+ self.acc_en = Signal(BITS)
+ self.lru_o = Signal(BITS)
+ self.acc_i = Signal()
def elaborate(self, platform=None):
m = Module()
+ # Tree (bit per entry)
+ TLBSZ = 2*(self.BITS-1)
+ plru_tree = Signal(TLBSZ)
+
# Just predefine which nodes will be set/cleared
# E.g. for a TLB with 8 entries, the for-loop is semantically
# equivalent to the following pseudo-code:
# unique case (1'b1)
- # lu_hit[7]: plru_tree[0, 2, 6] = {1, 1, 1};
- # lu_hit[6]: plru_tree[0, 2, 6] = {1, 1, 0};
- # lu_hit[5]: plru_tree[0, 2, 5] = {1, 0, 1};
- # lu_hit[4]: plru_tree[0, 2, 5] = {1, 0, 0};
- # lu_hit[3]: plru_tree[0, 1, 4] = {0, 1, 1};
- # lu_hit[2]: plru_tree[0, 1, 4] = {0, 1, 0};
- # lu_hit[1]: plru_tree[0, 1, 3] = {0, 0, 1};
- # lu_hit[0]: plru_tree[0, 1, 3] = {0, 0, 0};
+ # acc_en[7]: plru_tree[0, 2, 6] = {1, 1, 1};
+ # acc_en[6]: plru_tree[0, 2, 6] = {1, 1, 0};
+ # acc_en[5]: plru_tree[0, 2, 5] = {1, 0, 1};
+ # acc_en[4]: plru_tree[0, 2, 5] = {1, 0, 0};
+ # acc_en[3]: plru_tree[0, 1, 4] = {0, 1, 1};
+ # acc_en[2]: plru_tree[0, 1, 4] = {0, 1, 0};
+ # acc_en[1]: plru_tree[0, 1, 3] = {0, 0, 1};
+ # acc_en[0]: plru_tree[0, 1, 3] = {0, 0, 0};
# default: begin /* No hit */ end
# endcase
- LOG_TLB = int(log2(self.entries))
- print(LOG_TLB)
- for i in range(self.entries):
+
+ LOG_TLB = log2_int(self.BITS)
+ hit = Signal(self.BITS)
+ m.d.comb += hit.eq(Repl(self.acc_i, self.BITS) & self.acc_en)
+
+ for i in range(self.BITS):
# we got a hit so update the pointer as it was least recently used
- hit = Signal(reset_less=True)
- m.d.comb += hit.eq(self.lu_hit[i] & self.lu_access_i)
- with m.If(hit):
+ with m.If(hit[i]):
# Set the nodes to the values we would expect
for lvl in range(LOG_TLB):
idx_base = (1 << lvl)-1
# lvl0 <=> MSB, lvl1 <=> MSB-1, ...
shift = LOG_TLB - lvl
- new_idx = Const(~((i >> (shift-1)) & 1), (1, False))
+ new_idx = Const(~((i >> (shift-1)) & 1), 1)
plru_idx = idx_base + (i >> shift)
print("plru", i, lvl, hex(idx_base),
plru_idx, shift, new_idx)
- m.d.comb += self.plru_tree_o[plru_idx].eq(new_idx)
+ m.d.sync += plru_tree[plru_idx].eq(new_idx)
# Decode tree to write enable signals
# Next for-loop basically creates the following logic for e.g.
# the corresponding bit of the entry's index, this is
# the next entry to replace.
replace = []
- for i in range(self.entries):
+ for i in range(self.BITS):
en = []
for lvl in range(LOG_TLB):
idx_base = (1 << lvl)-1
plru_idx = idx_base + (i >> shift)
plru = Signal(reset_less=True,
name="plru-%d-%d-%d" % (i, lvl, plru_idx))
- m.d.comb += plru.eq(self.plru_tree[plru_idx])
- # en &= plru_tree_q[idx_base + (i>>shift)] == new_idx;
+ m.d.comb += plru.eq(plru_tree[plru_idx])
if new_idx:
- en.append(~plru) # yes inverted (using bool())
+ en.append(~plru) # yes inverted (using bool() below)
else:
- en.append(plru) # yes inverted (using bool())
- print("plru", i, en)
+ en.append(plru) # yes inverted (using bool() below)
+ print("plru replace", i, en)
# boolean logic manipulation:
# plru0 & plru1 & plru2 == ~(~plru0 | ~plru1 | ~plru2)
replace.append(~Cat(*en).bool())
- m.d.comb += self.replace_en_o.eq(Cat(*replace))
+ m.d.comb += self.lru_o.eq(Cat(*replace))
return m
def ports(self):
- return [self.entries, self.lu_hit, self.replace_en_o,
- self.lu_access_i, self.plru_tree, self.plru_tree_o]
+ return [self.acc_en, self.lru_o, self.acc_i]
+
+
+if __name__ == '__main__':
+ dut = PLRU(4)
+ vl = rtlil.convert(dut, ports=dut.ports())
+ with open("test_plru.il", "w") as f:
+ f.write(vl)
+