c8b26031b636e4fb23b9378354e0400fee16f0a2
2 from nmigen
import Signal
, Module
, Cat
, Const
4 from ptw
import TLBUpdate
, PTE
, ASID_WIDTH
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 TLBSZ
= 2*(self
.entries
-1)
26 self
.plru_tree
= Signal(TLBSZ
)
28 def elaborate(self
, platform
):
31 # Just predefine which nodes will be set/cleared
32 # E.g. for a TLB with 8 entries, the for-loop is semantically
33 # equivalent to the following pseudo-code:
35 # lu_hit[7]: plru_tree[0, 2, 6] = {1, 1, 1};
36 # lu_hit[6]: plru_tree[0, 2, 6] = {1, 1, 0};
37 # lu_hit[5]: plru_tree[0, 2, 5] = {1, 0, 1};
38 # lu_hit[4]: plru_tree[0, 2, 5] = {1, 0, 0};
39 # lu_hit[3]: plru_tree[0, 1, 4] = {0, 1, 1};
40 # lu_hit[2]: plru_tree[0, 1, 4] = {0, 1, 0};
41 # lu_hit[1]: plru_tree[0, 1, 3] = {0, 0, 1};
42 # lu_hit[0]: plru_tree[0, 1, 3] = {0, 0, 0};
43 # default: begin /* No hit */ end
45 LOG_TLB
= int(log2(self
.entries
))
47 for i
in range(self
.entries
):
48 # we got a hit so update the pointer as it was least recently used
49 hit
= Signal(reset_less
=True)
50 m
.d
.comb
+= hit
.eq(self
.lu_hit
[i
] & self
.lu_access_i
)
52 # Set the nodes to the values we would expect
53 for lvl
in range(LOG_TLB
):
55 # lvl0 <=> MSB, lvl1 <=> MSB-1, ...
56 shift
= LOG_TLB
- lvl
;
57 new_idx
= Const(~
((i
>> (shift
-1)) & 1), (1, False))
58 plru_idx
= idx_base
+ (i
>> shift
)
59 print ("plru", i
, lvl
, hex(idx_base
),
60 plru_idx
, shift
, new_idx
)
61 m
.d
.sync
+= self
.plru_tree
[plru_idx
].eq(new_idx
)
63 # Decode tree to write enable signals
64 # Next for-loop basically creates the following logic for e.g.
65 # an 8 entry TLB (note: pseudo-code obviously):
66 # replace_en[7] = &plru_tree[ 6, 2, 0]; #plru_tree[0,2,6]=={1,1,1}
67 # replace_en[6] = &plru_tree[~6, 2, 0]; #plru_tree[0,2,6]=={1,1,0}
68 # replace_en[5] = &plru_tree[ 5,~2, 0]; #plru_tree[0,2,5]=={1,0,1}
69 # replace_en[4] = &plru_tree[~5,~2, 0]; #plru_tree[0,2,5]=={1,0,0}
70 # replace_en[3] = &plru_tree[ 4, 1,~0]; #plru_tree[0,1,4]=={0,1,1}
71 # replace_en[2] = &plru_tree[~4, 1,~0]; #plru_tree[0,1,4]=={0,1,0}
72 # replace_en[1] = &plru_tree[ 3,~1,~0]; #plru_tree[0,1,3]=={0,0,1}
73 # replace_en[0] = &plru_tree[~3,~1,~0]; #plru_tree[0,1,3]=={0,0,0}
74 # For each entry traverse the tree. If every tree-node matches
75 # the corresponding bit of the entry's index, this is
76 # the next entry to replace.
78 for i
in range(self
.entries
):
80 for lvl
in range(LOG_TLB
):
82 # lvl0 <=> MSB, lvl1 <=> MSB-1, ...
83 shift
= LOG_TLB
- lvl
;
84 new_idx
= (i
>> (shift
-1)) & 1;
85 plru_idx
= idx_base
+ (i
>>shift
)
86 plru
= Signal(reset_less
=True,
87 name
="plru-%d-%d-%d" % (i
, lvl
, plru_idx
))
88 m
.d
.comb
+= plru
.eq(self
.plru_tree
[plru_idx
])
89 # en &= plru_tree_q[idx_base + (i>>shift)] == new_idx;
91 en
.append(~plru
) # yes inverted (using bool())
93 en
.append(plru
) # yes inverted (using bool())
95 # boolean logic manipulation:
96 # plru0 & plru1 & plru2 == ~(~plru0 | ~plru1 | ~plru2)
97 replace
.append(~
Cat(*en
).bool())
98 m
.d
.comb
+= self
.replace_en_o
.eq(Cat(*replace
))