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