# based on ariane plru, from tlb.sv
-from nmigen import Signal, Module, Cat, Const, Repl
+# old PLRU API, once all users have migrated to new API in plru2.py, then
+# plru2.py will be renamed to plru.py, replacing this file.
+
+from nmigen import Signal, Module, Cat, Const, Repl, Array
from nmigen.hdl.ir import Elaboratable
from nmigen.cli import rtlil
from nmigen.utils import log2_int
+from nmigen.lib.coding import Decoder
+from warnings import warn
class PLRU(Elaboratable):
- """ PLRU - Pseudo Least Recently Used Replacement
+ r""" PLRU - Pseudo Least Recently Used Replacement
PLRU-tree indexing:
lvl0 0
"""
def __init__(self, BITS):
+ warn("nmutil.plru.PLRU is deprecated due to having a broken API, use "
+ "nmutil.plru2.PLRU instead", DeprecationWarning, stacklevel=2)
self.BITS = BITS
- self.acc_en = Signal(BITS)
- self.acc_i = Signal()
+ self.acc_i = Signal(BITS)
+ self.acc_en = Signal()
self.lru_o = Signal(BITS)
+ self._plru_tree = Signal(self.TLBSZ)
+ """ exposed only for testing """
+
+ @property
+ def TLBSZ(self):
+ return 2 * (self.BITS - 1)
+
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
# default: begin /* No hit */ end
# endcase
- LOG_TLB = log2_int(self.BITS)
+ LOG_TLB = log2_int(self.BITS, False)
hit = Signal(self.BITS, reset_less=True)
- m.d.comb += hit.eq(Repl(self.acc_i, self.BITS) & self.acc_en)
+ m.d.comb += hit.eq(Repl(self.acc_en, self.BITS) & self.acc_i)
for i in range(self.BITS):
# we got a hit so update the pointer as it was least recently used
shift = LOG_TLB - lvl
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.sync += plru_tree[plru_idx].eq(new_idx)
+ # print("plru", i, lvl, hex(idx_base),
+ # plru_idx, shift, new_idx)
+ m.d.sync += self._plru_tree[plru_idx].eq(new_idx)
# Decode tree to write enable signals
# Next for-loop basically creates the following logic for e.g.
new_idx = (i >> (shift-1)) & 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(plru_tree[plru_idx])
+ name="plru-%d-%d-%d-%d" %
+ (i, lvl, plru_idx, new_idx))
+ m.d.comb += plru.eq(self._plru_tree[plru_idx])
if new_idx:
en.append(~plru) # yes inverted (using bool() below)
else:
en.append(plru) # yes inverted (using bool() below)
- print("plru replace", i, en)
+ #print("plru", i, en)
# boolean logic manipulation:
# plru0 & plru1 & plru2 == ~(~plru0 | ~plru1 | ~plru2)
replace.append(~Cat(*en).bool())
return [self.acc_en, self.lru_o, self.acc_i]
+class PLRUs(Elaboratable):
+ def __init__(self, n_plrus, n_bits):
+ warn("nmutil.plru.PLRUs is deprecated due to having a broken API, use "
+ "nmutil.plru2.PLRUs instead", DeprecationWarning, stacklevel=2)
+ self.n_plrus = n_plrus
+ self.n_bits = n_bits
+ self.valid = Signal()
+ self.way = Signal(n_bits)
+ self.index = Signal(n_plrus.bit_length())
+ self.isel = Signal(n_plrus.bit_length())
+ self.o_index = Signal(n_bits)
+
+ def elaborate(self, platform):
+ """Generate TLB PLRUs
+ """
+ m = Module()
+ comb = m.d.comb
+
+ if self.n_plrus == 0:
+ return m
+
+ # Binary-to-Unary one-hot, enabled by valid
+ m.submodules.te = te = Decoder(self.n_plrus)
+ comb += te.n.eq(~self.valid)
+ comb += te.i.eq(self.index)
+
+ out = Array(Signal(self.n_bits, name="plru_out%d" % x)
+ for x in range(self.n_plrus))
+
+ for i in range(self.n_plrus):
+ # PLRU interface
+ m.submodules["plru_%d" % i] = plru = PLRU(self.n_bits)
+
+ comb += plru.acc_en.eq(te.o[i])
+ comb += plru.acc_i.eq(self.way)
+ comb += out[i].eq(plru.lru_o)
+
+ # select output based on index
+ comb += self.o_index.eq(out[self.isel])
+
+ return m
+
+ def ports(self):
+ return [self.valid, self.way, self.index, self.isel, self.o_index]
+
+
if __name__ == '__main__':
- dut = PLRU(4)
+ dut = PLRU(3)
vl = rtlil.convert(dut, ports=dut.ports())
with open("test_plru.il", "w") as f:
f.write(vl)
+ dut = PLRUs(4, 2)
+ vl = rtlil.convert(dut, ports=dut.ports())
+ with open("test_plrus.il", "w") as f:
+ f.write(vl)