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
)
9 # SV39 defines three levels of page tables
18 return Cat(*self
.ports())
21 return self
.flatten().eq(x
.flatten())
24 return [self
.asid
, self
.vpn0
, self
.vpn1
, self
.vpn2
,
25 self
.is_2M
, self
.is_1G
, self
.valid
]
27 class TLBContent(Elaboratable
):
28 def __init__(self
, pte_width
, asid_width
):
29 self
.asid_width
= asid_width
30 self
.pte_width
= pte_width
31 self
.flush_i
= Signal() # Flush signal
33 self
.update_i
= TLBUpdate(asid_width
)
37 self
.replace_en_i
= Signal() # replace the following entry,
38 # set by replacement strategy
40 self
.lu_asid_i
= Signal(asid_width
)
41 self
.lu_content_o
= Signal(pte_width
)
42 self
.lu_is_2M_o
= Signal()
43 self
.lu_is_1G_o
= Signal()
44 self
.lu_hit_o
= Signal()
46 def elaborate(self
, platform
):
49 tags
= TLBEntry(self
.asid_width
)
50 content
= Signal(self
.pte_width
)
52 m
.d
.comb
+= [self
.lu_hit_o
.eq(0),
53 self
.lu_is_2M_o
.eq(0),
54 self
.lu_is_1G_o
.eq(0)]
56 # temporaries for 1st level match
57 asid_ok
= Signal(reset_less
=True)
58 vpn2_ok
= Signal(reset_less
=True)
59 tags_ok
= Signal(reset_less
=True)
60 vpn2_hit
= Signal(reset_less
=True)
61 m
.d
.comb
+= [tags_ok
.eq(tags
.valid
),
62 asid_ok
.eq(tags
.asid
== self
.lu_asid_i
),
63 vpn2_ok
.eq(tags
.vpn2
== self
.vpn2
),
64 vpn2_hit
.eq(tags_ok
& asid_ok
& vpn2_ok
)]
65 # temporaries for 2nd level match
66 vpn1_ok
= Signal(reset_less
=True)
67 tags_2M
= Signal(reset_less
=True)
68 vpn0_ok
= Signal(reset_less
=True)
69 vpn0_or_2M
= Signal(reset_less
=True)
70 m
.d
.comb
+= [vpn1_ok
.eq(self
.vpn1
== tags
.vpn1
),
71 tags_2M
.eq(tags
.is_2M
),
72 vpn0_ok
.eq(self
.vpn0
== tags
.vpn0
),
73 vpn0_or_2M
.eq(tags_2M | vpn0_ok
)]
74 # first level match, this may be a giga page,
75 # check the ASID flags as well
78 with m
.If (tags
.is_1G
):
79 m
.d
.comb
+= [ self
.lu_content_o
.eq(content
),
80 self
.lu_is_1G_o
.eq(1),
83 # not a giga page hit so check further
85 # this could be a 2 mega page hit or a 4 kB hit
87 with m
.If(vpn0_or_2M
):
88 m
.d
.comb
+= [ self
.lu_content_o
.eq(content
),
89 self
.lu_is_2M_o
.eq(tags
.is_2M
),
97 replace_valid
= Signal(reset_less
=True)
98 m
.d
.comb
+= replace_valid
.eq(self
.update_i
.valid
& self
.replace_en_i
)
101 with m
.If (self
.flush_i
):
102 # invalidate (flush) conditions: all if zero or just this ASID
103 with m
.If (self
.lu_asid_i
== Const(0, self
.asid_width
) |
104 (self
.lu_asid_i
== tags
.asid
)):
105 m
.d
.sync
+= tags
.valid
.eq(0)
108 with m
.Elif(replace_valid
):
109 m
.d
.sync
+= [ # update tag array
110 tags
.asid
.eq(self
.update_i
.asid
),
111 tags
.vpn2
.eq(self
.update_i
.vpn
[18:27]),
112 tags
.vpn1
.eq(self
.update_i
.vpn
[9:18]),
113 tags
.vpn0
.eq(self
.update_i
.vpn
[0:9]),
114 tags
.is_1G
.eq(self
.update_i
.is_1G
),
115 tags
.is_2M
.eq(self
.update_i
.is_2M
),
117 # and content as well
118 content
.eq(self
.update_i
.content
.flatten())
123 return [self
.flush_i
,
125 self
.lu_is_2M_o
, self
.lu_is_1G_o
, self
.lu_hit_o
,
126 ] + self
.update_i
.content
.ports() + self
.update_i
.ports()