3 The expected form of the data is:
5 * Tag (N - 79) / ASID (78 - 64) / PTE (63 - 0)
8 from nmigen
import Memory
, Module
, Signal
, Cat
, Elaboratable
9 from nmigen
.cli
import main
11 from .PermissionValidator
import PermissionValidator
14 class TLB(Elaboratable
):
15 def __init__(self
, asid_size
, vma_size
, pte_size
, L1_size
):
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
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
30 self
.cam_L1
= Cam(vma_size
, L1_size
)
31 self
.mem_L1
= Memory(asid_size
+ pte_size
, L1_size
)
33 # Permission Validator
34 self
.perm_validator
= PermissionValidator(asid_size
, pte_size
)
37 self
.supermode
= Signal(1) # Supervisor Mode
38 self
.super_access
= Signal(1) # Supervisor Access
39 self
.command
= Signal(2) # 00=None, 01=Search, 10=Write L1, 11=Write L2
40 self
.xwr
= Signal(3) # Execute, Write, Read
41 self
.mode
= Signal(4) # 4 bits for access to Sv48 on Rv64
42 self
.address_L1
= Signal(max=L1_size
)
43 self
.asid
= Signal(asid_size
) # Address Space IDentifier (ASID)
44 self
.vma
= Signal(vma_size
) # Virtual Memory Address (VMA)
45 self
.pte_in
= Signal(pte_size
) # To be saved Page Table Entry (PTE)
48 self
.hit
= Signal(1) # Denotes if the VMA had a mapped PTE
49 self
.perm_valid
= Signal(1) # Denotes if the permissions are correct
50 self
.pte_out
= Signal(pte_size
) # PTE that was mapped to by the VMA
52 def search(self
, m
, read_L1
, write_L1
):
57 self
.cam_L1
.write_enable
.eq(0),
58 self
.cam_L1
.data_in
.eq(self
.vma
)
60 # Match found in L1 CAM
61 match_found
= Signal(reset_less
=True)
62 m
.d
.comb
+= match_found
.eq(self
.cam_L1
.single_match
63 | self
.cam_L1
.multiple_match
)
64 with m
.If(match_found
):
65 # Memory shortcut variables
66 mem_address
= self
.cam_L1
.match_address
68 m
.d
.comb
+= read_L1
.addr
.eq(mem_address
)
69 # Permission Validator Logic
72 # Set permission validator data to the correct
73 # register file data according to CAM match
75 self
.perm_validator
.data
.eq(read_L1
.data
),
76 # Execute, Read, Write
77 self
.perm_validator
.xwr
.eq(self
.xwr
),
79 self
.perm_validator
.super_mode
.eq(self
.supermode
),
81 self
.perm_validator
.super_access
.eq(self
.super_access
),
82 # Address Space IDentifier (ASID)
83 self
.perm_validator
.asid
.eq(self
.asid
),
84 # Output result of permission validation
85 self
.perm_valid
.eq(self
.perm_validator
.valid
)
87 # Only output PTE if permissions are valid
88 with m
.If(self
.perm_validator
.valid
):
89 # XXX TODO - dummy for now
90 reg_data
= Signal
.like(self
.pte_out
)
92 self
.pte_out
.eq(reg_data
)
102 self
.perm_valid
.eq(0),
106 def write_l1(self
, m
, read_L1
, write_L1
):
107 """ writes to the L1 cache
112 write_L1
.addr
.eq(self
.address_L1
),
113 # The Cat places arguments from LSB -> MSB
114 write_L1
.data
.eq(Cat(self
.pte_in
, self
.asid
))
118 self
.cam_L1
.write_enable
.eq(1),
119 self
.cam_L1
.data_in
.eq(self
.vma
), #data_in is sent to all entries
120 # self.cam_L1.address_in.eq(todo) # a CAM entry needs to be selected
124 def elaborate(self
, platform
):
127 # Submodules for L1 Cache
128 m
.submodules
.cam_L1
= self
.cam_L1
129 m
.submodules
.read_L1
= read_L1
= self
.mem_L1
.read_port()
130 m
.submodules
.write_L1
= write_L1
= self
.mem_L1
.write_port()
132 # Permission Validator Submodule
133 m
.submodules
.perm_valididator
= self
.perm_validator
135 # When MODE specifies translation
136 # TODO add in different bit length handling ie prefix 0s
137 tlb_enable
= Signal(reset_less
=True)
138 m
.d
.comb
+= tlb_enable
.eq(self
.mode
!= 0)
140 with m
.If(tlb_enable
):
142 self
.cam_L1
.enable
.eq(1)
144 with m
.Switch(self
.command
):
147 self
.search(m
, read_L1
, write_L1
)
150 # Expected that the miss will be handled in software
152 self
.write_l1(m
, read_L1
, write_L1
)
160 self
.cam_L1
.enable
.eq(0),
161 # XXX TODO - self.reg_file.enable.eq(0),
163 self
.perm_valid
.eq(0), # XXX TODO, check this
169 if __name__
== '__main__':
170 tlb
= TLB(15, 36, 64, 4)
171 main(tlb
, ports
=[ tlb
.supermode
, tlb
.super_access
, tlb
.command
,
172 tlb
.xwr
, tlb
.mode
, tlb
.address_L1
, tlb
.asid
,
174 tlb
.hit
, tlb
.perm_valid
, tlb
.pte_out
,
175 ] + tlb
.cam_L1
.ports())