start preliminary test of load/store dependency matrices
[soc.git] / src / TLB / TLB.py
1 """ TLB Module
2
3 The expected form of the data is:
4 * Item (Bits)
5 * Tag (N - 79) / ASID (78 - 64) / PTE (63 - 0)
6 """
7
8 from nmigen import Memory, Module, Signal, Cat
9 from nmigen.cli import main
10
11 from PermissionValidator import PermissionValidator
12 from Cam import Cam
13
14 class TLB():
15 def __init__(self, asid_size, vma_size, pte_size, L1_size):
16 """ Arguments
17 * asid_size: Address Space IDentifier (ASID) typically 15 bits
18 * vma_size: Virtual Memory Address (VMA) typically 36 bits
19 * pte_size: Page Table Entry (PTE) typically 64 bits
20
21 Notes:
22 These arguments should represent the largest possible size
23 defined by the MODE settings. See
24 Volume II: RISC-V Privileged Architectures V1.10 Page 57
25 """
26
27 # Internal
28 self.state = 0
29 # L1 Cache Modules
30 L1_size = 8 # XXX overridden incoming argument?
31 self.cam_L1 = Cam(vma_size, L1_size)
32 self.mem_L1 = Memory(asid_size + pte_size, L1_size)
33
34 # Permission Validator
35 self.perm_validator = PermissionValidator(asid_size, pte_size)
36
37 # Inputs
38 self.supermode = Signal(1) # Supervisor Mode
39 self.super_access = Signal(1) # Supervisor Access
40 self.command = Signal(2) # 00=None, 01=Search, 10=Write L1, 11=Write L2
41 self.xwr = Signal(3) # Execute, Write, Read
42 self.mode = Signal(4) # 4 bits for access to Sv48 on Rv64
43 self.address_L1 = Signal(max=L1_size)
44 self.asid = Signal(asid_size) # Address Space IDentifier (ASID)
45 self.vma = Signal(vma_size) # Virtual Memory Address (VMA)
46 self.pte_in = Signal(pte_size) # To be saved Page Table Entry (PTE)
47
48 # Outputs
49 self.hit = Signal(1) # Denotes if the VMA had a mapped PTE
50 self.perm_valid = Signal(1) # Denotes if the permissions are correct
51 self.pte_out = Signal(pte_size) # PTE that was mapped to by the VMA
52
53 def search(self, m, read_L1, write_L1):
54 """ searches the TLB
55 """
56 m.d.comb += [
57 write_L1.en.eq(0),
58 self.cam_L1.write_enable.eq(0),
59 self.cam_L1.data_in.eq(self.vma)
60 ]
61 # Match found in L1 CAM
62 match_found = Signal(reset_less=True)
63 m.d.comb += match_found.eq(self.cam_L1.single_match
64 | self.cam_L1.multiple_match)
65 with m.If(match_found):
66 # Memory shortcut variables
67 mem_address = self.cam_L1.match_address
68 # Memory Logic
69 m.d.comb += read_L1.addr.eq(mem_address)
70 # Permission Validator Logic
71 m.d.comb += [
72 self.hit.eq(1),
73 # Set permission validator data to the correct
74 # register file data according to CAM match
75 # address
76 self.perm_validator.data.eq(read_L1.data),
77 # Execute, Read, Write
78 self.perm_validator.xwr.eq(self.xwr),
79 # Supervisor Mode
80 self.perm_validator.super_mode.eq(self.supermode),
81 # Supverisor Access
82 self.perm_validator.super_access.eq(self.super_access),
83 # Address Space IDentifier (ASID)
84 self.perm_validator.asid.eq(self.asid),
85 # Output result of permission validation
86 self.perm_valid.eq(self.perm_validator.valid)
87 ]
88 # Only output PTE if permissions are valid
89 with m.If(self.perm_validator.valid):
90 # XXX TODO - dummy for now
91 reg_data = Signal.like(self.pte_out)
92 m.d.comb += [
93 self.pte_out.eq(reg_data)
94 ]
95 with m.Else():
96 m.d.comb += [
97 self.pte_out.eq(0)
98 ]
99 # Miss Logic
100 with m.Else():
101 m.d.comb += [
102 self.hit.eq(0),
103 self.perm_valid.eq(0),
104 self.pte_out.eq(0)
105 ]
106
107 def write_l1(self, m, read_L1, write_L1):
108 """ writes to the L1 cache
109 """
110 # Memory_L1 Logic
111 m.d.comb += [
112 write_L1.en.eq(1),
113 write_L1.addr.eq(self.address_L1),
114 # The Cat places arguments from LSB -> MSB
115 write_L1.data.eq(Cat(self.pte_in, self.asid))
116 ]
117 # CAM_L1 Logic
118 m.d.comb += [
119 self.cam_L1.write_enable.eq(1),
120 self.cam_L1.data_in.eq(self.vma),
121 ]
122
123 def elaborate(self, platform):
124 m = Module()
125 # Add submodules
126 # Submodules for L1 Cache
127 m.d.submodules.cam_L1 = self.cam_L1
128 m.d.sumbmodules.read_L1 = read_L1 = self.mem_L1.read_port()
129 m.d.sumbmodules.read_L1 = write_L1 = self.mem_L1.write_port()
130 # Permission Validator Submodule
131 m.d.submodules.perm_valididator = self.perm_validator
132
133 # When MODE specifies translation
134 # TODO add in different bit length handling ie prefix 0s
135 tlb_enable = Signal(reset_less=True)
136 m.d.comb += tlb_enable.eq(self.mode != 0)
137
138 with m.If(tlb_enable):
139 m.d.comb += [
140 self.cam_L1.enable.eq(1)
141 ]
142 with m.Switch(self.command):
143 # Search
144 with m.Case("01"):
145 self.search(m, read_L1, write_L1)
146
147 # Write L1
148 # Expected that the miss will be handled in software
149 with m.Case("10"):
150 self.write_l1(m, read_L1, write_L1)
151
152 # TODO
153 #with m.Case("11"):
154
155 # When disabled
156 with m.Else():
157 m.d.comb += [
158 self.cam_L1.enable.eq(0),
159 # XXX TODO - self.reg_file.enable.eq(0),
160 self.hit.eq(0),
161 self.perm_valid.eq(0), # XXX TODO, check this
162 self.pte_out.eq(0)
163 ]
164 return m
165
166
167 if __name__ == '__main__':
168 tlb = TLB(15, 36, 64, 4)
169 main(tlb, ports=[ tlb.supermode, tlb.super_access, tlb.command,
170 tlb.xwr, tlb.mode, tlb.address_L1, tlb.asid,
171 tlb.vma, tlb.pte_in,
172 tlb.hit, tlb.perm_valid, tlb.pte_out,
173 ] + tlb.cam_L1.ports())