4ffd919eb3800750ffc2c23006342f16fae80071
[soc.git] / src / TLB / ariane / tlb_content.py
1 from nmigen import Signal, Module, Cat, Const, Elaboratable
2
3 from TLB.ariane.ptw import TLBUpdate, PTE
4
5
6 class TLBEntry:
7 def __init__(self, asid_width):
8 self.asid = Signal(asid_width)
9 # SV48 defines four levels of page tables
10 self.vpn0 = Signal(9)
11 self.vpn1 = Signal(9)
12 self.vpn2 = Signal(9)
13 self.vpn3 = Signal(9)
14 self.is_2M = Signal()
15 self.is_1G = Signal()
16 self.is_512G = Signal()
17 self.valid = Signal()
18
19 def flatten(self):
20 return Cat(*self.ports())
21
22 def eq(self, x):
23 return self.flatten().eq(x.flatten())
24
25 def ports(self):
26 return [self.asid, self.vpn0, self.vpn1, self.vpn2,
27 self.is_2M, self.is_1G, self.valid]
28
29 class TLBContent(Elaboratable):
30 def __init__(self, pte_width, asid_width):
31 self.asid_width = asid_width
32 self.pte_width = pte_width
33 self.flush_i = Signal() # Flush signal
34 # Update TLB
35 self.update_i = TLBUpdate(asid_width)
36 self.vpn2 = Signal(9)
37 self.vpn1 = Signal(9)
38 self.vpn0 = Signal(9)
39 self.replace_en_i = Signal() # replace the following entry,
40 # set by replacement strategy
41 # Lookup signals
42 self.lu_asid_i = Signal(asid_width)
43 self.lu_content_o = Signal(pte_width)
44 self.lu_is_512G_o = Signal()
45 self.lu_is_2M_o = Signal()
46 self.lu_is_1G_o = Signal()
47 self.lu_hit_o = Signal()
48
49 def elaborate(self, platform):
50 m = Module()
51
52 tags = TLBEntry(self.asid_width)
53 content = Signal(self.pte_width)
54
55 m.d.comb += [self.lu_hit_o.eq(0),
56 self.lu_is_2M_o.eq(0),
57 self.lu_is_1G_o.eq(0)]
58
59 # temporaries for 1st level match
60 asid_ok = Signal(reset_less=True)
61 vpn2_ok = Signal(reset_less=True)
62 tags_ok = Signal(reset_less=True)
63 vpn2_hit = Signal(reset_less=True)
64 m.d.comb += [tags_ok.eq(tags.valid),
65 asid_ok.eq(tags.asid == self.lu_asid_i),
66 vpn2_ok.eq(tags.vpn2 == self.vpn2),
67 vpn2_hit.eq(tags_ok & asid_ok & vpn2_ok)]
68 # temporaries for 2nd level match
69 vpn1_ok = Signal(reset_less=True)
70 tags_2M = Signal(reset_less=True)
71 vpn0_ok = Signal(reset_less=True)
72 vpn0_or_2M = Signal(reset_less=True)
73 m.d.comb += [vpn1_ok.eq(self.vpn1 == tags.vpn1),
74 tags_2M.eq(tags.is_2M),
75 vpn0_ok.eq(self.vpn0 == tags.vpn0),
76 vpn0_or_2M.eq(tags_2M | vpn0_ok)]
77 # TODO temporaries for 3rd level match
78
79 # first level match, this may be a giga page,
80 # check the ASID flags as well
81 with m.If(vpn2_hit):
82 # second level
83 with m.If (tags.is_1G):
84 m.d.comb += [ self.lu_content_o.eq(content),
85 self.lu_is_1G_o.eq(1),
86 self.lu_hit_o.eq(1),
87 ]
88 # not a giga page hit so check further
89 with m.Elif(vpn1_ok):
90 # this could be a 2 mega page hit or a 4 kB hit
91 # output accordingly
92 with m.If(vpn0_or_2M):
93 m.d.comb += [ self.lu_content_o.eq(content),
94 self.lu_is_2M_o.eq(tags.is_2M),
95 self.lu_hit_o.eq(1),
96 ]
97 # ------------------
98 # Update or Flush
99 # ------------------
100
101 # temporaries
102 replace_valid = Signal(reset_less=True)
103 m.d.comb += replace_valid.eq(self.update_i.valid & self.replace_en_i)
104
105 # flush
106 with m.If (self.flush_i):
107 # invalidate (flush) conditions: all if zero or just this ASID
108 with m.If (self.lu_asid_i == Const(0, self.asid_width) |
109 (self.lu_asid_i == tags.asid)):
110 m.d.sync += tags.valid.eq(0)
111
112 # normal replacement
113 with m.Elif(replace_valid):
114 m.d.sync += [ # update tag array
115 tags.asid.eq(self.update_i.asid),
116 tags.vpn2.eq(self.update_i.vpn[18:27]),
117 tags.vpn1.eq(self.update_i.vpn[9:18]),
118 tags.vpn0.eq(self.update_i.vpn[0:9]),
119 tags.is_512G.eq(self.update_i.is_512G),
120 tags.is_1G.eq(self.update_i.is_1G),
121 tags.is_2M.eq(self.update_i.is_2M),
122 tags.valid.eq(1),
123 # and content as well
124 content.eq(self.update_i.content.flatten())
125 ]
126 return m
127
128 def ports(self):
129 return [self.flush_i,
130 self.lu_asid_i,
131 self.lu_is_2M_o, self.lu_is_1G_o,self.lu_is_512G_o, self.lu_hit_o,
132 ] + self.update_i.content.ports() + self.update_i.ports()