3384c88502d469b5edc111ea0e1c8c2e84dced3d
1 from nmigen
import Signal
, Module
, Cat
, Const
, Elaboratable
3 from TLB
.ariane
.ptw
import TLBUpdate
, PTE
7 def __init__(self
, asid_width
):
8 self
.asid
= Signal(asid_width
,name
="ent_asid")
9 # SV48 defines four levels of page tables
10 self
.vpn0
= Signal(9,name
="ent_vpn0")
11 self
.vpn1
= Signal(9,name
="ent_vpn1")
12 self
.vpn2
= Signal(9,name
="ent_vpn2")
13 self
.vpn3
= Signal(9,name
="ent_vpn3")
14 self
.is_2M
= Signal(name
="ent_is_2M")
15 self
.is_1G
= Signal(name
="ent_is_1G")
16 self
.is_512G
= Signal(name
="ent_is_512G")
17 self
.valid
= Signal(name
="ent_valid")
20 return Cat(*self
.ports())
23 return self
.flatten().eq(x
.flatten())
26 return [self
.asid
, self
.vpn0
, self
.vpn1
, self
.vpn2
,
27 self
.is_2M
, self
.is_1G
, self
.valid
]
30 class TLBContent(Elaboratable
):
31 def __init__(self
, pte_width
, asid_width
):
32 self
.asid_width
= asid_width
33 self
.pte_width
= pte_width
34 self
.flush_i
= Signal() # Flush signal
36 self
.update_i
= TLBUpdate(asid_width
)
41 self
.replace_en_i
= Signal() # replace the following entry,
42 # set by replacement strategy
44 self
.lu_asid_i
= Signal(asid_width
)
45 self
.lu_content_o
= Signal(pte_width
)
46 self
.lu_is_512G_o
= Signal()
47 self
.lu_is_2M_o
= Signal()
48 self
.lu_is_1G_o
= Signal()
49 self
.lu_hit_o
= Signal()
51 def elaborate(self
, platform
):
54 tags
= TLBEntry(self
.asid_width
)
57 content
= Signal(self
.pte_width
)
59 m
.d
.comb
+= [self
.lu_hit_o
.eq(0),
60 self
.lu_is_512G_o
.eq(0),
61 self
.lu_is_2M_o
.eq(0),
62 self
.lu_is_1G_o
.eq(0)]
64 # temporaries for lookup
65 asid_ok
= Signal(reset_less
=True)
66 # tags_ok = Signal(reset_less=True)
68 vpn3_ok
= Signal(reset_less
=True)
69 vpn2_ok
= Signal(reset_less
=True)
70 vpn1_ok
= Signal(reset_less
=True)
71 vpn0_ok
= Signal(reset_less
=True)
73 #tags_2M = Signal(reset_less=True)
74 vpn0_or_2M
= Signal(reset_less
=True)
77 #compare asid and vpn*
78 asid_ok
.eq(tags
.asid
== self
.lu_asid_i
),
79 vpn3_ok
.eq(tags
.vpn3
== self
.vpn3
),
80 vpn2_ok
.eq(tags
.vpn2
== self
.vpn2
),
81 vpn1_ok
.eq(tags
.vpn1
== self
.vpn1
),
82 vpn0_ok
.eq(tags
.vpn0
== self
.vpn0
),
83 vpn0_or_2M
.eq(tags
.is_2M | vpn0_ok
)
87 with m
.If(asid_ok
& tags
.valid
):
88 # first level, only vpn3 needs to match
89 with m
.If (tags
.is_512G
& vpn3_ok
):
90 m
.d
.comb
+= [ self
.lu_content_o
.eq(content
),
91 self
.lu_is_512G_o
.eq(1),
94 # second level , second level vpn2 and vpn3 need to match
95 with m
.Elif (tags
.is_1G
& vpn2_ok
& vpn3_ok
):
96 m
.d
.comb
+= [ self
.lu_content_o
.eq(content
),
97 self
.lu_is_1G_o
.eq(1),
100 # not a giga page hit nor a tera page hit so check further
101 with m
.Elif(vpn1_ok
):
102 # this could be a 2 mega page hit or a 4 kB hit
104 with m
.If(vpn0_or_2M
):
105 m
.d
.comb
+= [ self
.lu_content_o
.eq(content
),
106 self
.lu_is_2M_o
.eq(tags
.is_2M
),
114 replace_valid
= Signal(reset_less
=True)
115 m
.d
.comb
+= replace_valid
.eq(self
.update_i
.valid
& self
.replace_en_i
)
118 with m
.If (self
.flush_i
):
119 # invalidate (flush) conditions: all if zero or just this ASID
120 with m
.If (self
.lu_asid_i
== Const(0, self
.asid_width
) |
121 (self
.lu_asid_i
== tags
.asid
)):
122 m
.d
.sync
+= tags
.valid
.eq(0)
125 with m
.Elif(replace_valid
):
126 m
.d
.sync
+= [ # update tag array
127 tags
.asid
.eq(self
.update_i
.asid
),
128 tags
.vpn3
.eq(self
.update_i
.vpn
[27:36]),
129 tags
.vpn2
.eq(self
.update_i
.vpn
[18:27]),
130 tags
.vpn1
.eq(self
.update_i
.vpn
[9:18]),
131 tags
.vpn0
.eq(self
.update_i
.vpn
[0:9]),
132 tags
.is_512G
.eq(self
.update_i
.is_512G
),
133 tags
.is_1G
.eq(self
.update_i
.is_1G
),
134 tags
.is_2M
.eq(self
.update_i
.is_2M
),
136 # and content as well
137 content
.eq(self
.update_i
.content
.flatten())
142 return [self
.flush_i
,
144 self
.lu_is_2M_o
, self
.lu_is_1G_o
,self
.lu_is_512G_o
, self
.lu_hit_o
,
145 ] + self
.update_i
.content
.ports() + self
.update_i
.ports()