1 from nmigen
import Signal
, Module
, Cat
, Const
, Elaboratable
4 from ptw
import TLBUpdate
, PTE
, ASID_WIDTH
6 class PLRU(Elaboratable
):
7 """ PLRU - Pseudo Least Recently Used Replacement
19 def __init__(self
, entries
):
20 self
.entries
= entries
21 self
.lu_hit
= Signal(entries
)
22 self
.replace_en_o
= Signal(entries
)
23 self
.lu_access_i
= Signal()
24 # Tree (bit per entry)
25 self
.TLBSZ
= 2*(self
.entries
-1)
26 self
.plru_tree
= Signal(self
.TLBSZ
)
27 self
.plru_tree_o
= Signal(self
.TLBSZ
)
29 def elaborate(self
, platform
):
32 # Just predefine which nodes will be set/cleared
33 # E.g. for a TLB with 8 entries, the for-loop is semantically
34 # equivalent to the following pseudo-code:
36 # lu_hit[7]: plru_tree[0, 2, 6] = {1, 1, 1};
37 # lu_hit[6]: plru_tree[0, 2, 6] = {1, 1, 0};
38 # lu_hit[5]: plru_tree[0, 2, 5] = {1, 0, 1};
39 # lu_hit[4]: plru_tree[0, 2, 5] = {1, 0, 0};
40 # lu_hit[3]: plru_tree[0, 1, 4] = {0, 1, 1};
41 # lu_hit[2]: plru_tree[0, 1, 4] = {0, 1, 0};
42 # lu_hit[1]: plru_tree[0, 1, 3] = {0, 0, 1};
43 # lu_hit[0]: plru_tree[0, 1, 3] = {0, 0, 0};
44 # default: begin /* No hit */ end
46 LOG_TLB
= int(log2(self
.entries
))
48 for i
in range(self
.entries
):
49 # we got a hit so update the pointer as it was least recently used
50 hit
= Signal(reset_less
=True)
51 m
.d
.comb
+= hit
.eq(self
.lu_hit
[i
] & self
.lu_access_i
)
53 # Set the nodes to the values we would expect
54 for lvl
in range(LOG_TLB
):
56 # lvl0 <=> MSB, lvl1 <=> MSB-1, ...
57 shift
= LOG_TLB
- lvl
;
58 new_idx
= Const(~
((i
>> (shift
-1)) & 1), (1, False))
59 plru_idx
= idx_base
+ (i
>> shift
)
60 print ("plru", i
, lvl
, hex(idx_base
),
61 plru_idx
, shift
, new_idx
)
62 m
.d
.comb
+= self
.plru_tree_o
[plru_idx
].eq(new_idx
)
64 # Decode tree to write enable signals
65 # Next for-loop basically creates the following logic for e.g.
66 # an 8 entry TLB (note: pseudo-code obviously):
67 # replace_en[7] = &plru_tree[ 6, 2, 0]; #plru_tree[0,2,6]=={1,1,1}
68 # replace_en[6] = &plru_tree[~6, 2, 0]; #plru_tree[0,2,6]=={1,1,0}
69 # replace_en[5] = &plru_tree[ 5,~2, 0]; #plru_tree[0,2,5]=={1,0,1}
70 # replace_en[4] = &plru_tree[~5,~2, 0]; #plru_tree[0,2,5]=={1,0,0}
71 # replace_en[3] = &plru_tree[ 4, 1,~0]; #plru_tree[0,1,4]=={0,1,1}
72 # replace_en[2] = &plru_tree[~4, 1,~0]; #plru_tree[0,1,4]=={0,1,0}
73 # replace_en[1] = &plru_tree[ 3,~1,~0]; #plru_tree[0,1,3]=={0,0,1}
74 # replace_en[0] = &plru_tree[~3,~1,~0]; #plru_tree[0,1,3]=={0,0,0}
75 # For each entry traverse the tree. If every tree-node matches
76 # the corresponding bit of the entry's index, this is
77 # the next entry to replace.
79 for i
in range(self
.entries
):
81 for lvl
in range(LOG_TLB
):
83 # lvl0 <=> MSB, lvl1 <=> MSB-1, ...
84 shift
= LOG_TLB
- lvl
;
85 new_idx
= (i
>> (shift
-1)) & 1;
86 plru_idx
= idx_base
+ (i
>>shift
)
87 plru
= Signal(reset_less
=True,
88 name
="plru-%d-%d-%d" % (i
, lvl
, plru_idx
))
89 m
.d
.comb
+= plru
.eq(self
.plru_tree
[plru_idx
])
90 # en &= plru_tree_q[idx_base + (i>>shift)] == new_idx;
92 en
.append(~plru
) # yes inverted (using bool())
94 en
.append(plru
) # yes inverted (using bool())
96 # boolean logic manipulation:
97 # plru0 & plru1 & plru2 == ~(~plru0 | ~plru1 | ~plru2)
98 replace
.append(~
Cat(*en
).bool())
99 m
.d
.comb
+= self
.replace_en_o
.eq(Cat(*replace
))