From bf80dd9bb96464f13b386c7fe17821803a62b4a2 Mon Sep 17 00:00:00 2001 From: Daniel Benusovich Date: Mon, 11 Mar 2019 21:05:17 -0700 Subject: [PATCH] Add logic to TLB to correctly utilize Cam, RegisterFile, and PermissionValidator submodules. Needs lots of work. --- TLB/src/TLB.py | 155 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 46 deletions(-) diff --git a/TLB/src/TLB.py b/TLB/src/TLB.py index dc151ce2..5299caec 100644 --- a/TLB/src/TLB.py +++ b/TLB/src/TLB.py @@ -2,69 +2,132 @@ from nmigen import Memory, Module, Signal from nmigen.cli import main from PermissionValidator import PermissionValidator +from Cam import Cam +from RegisterFile import RegisterFile # The expected form of the data is # Item (Bits) # Tag (N - 79) / ASID (78 - 64) / PTE (63 - 0) class TLB(): - def __init__(self): + def __init__(self, asid_size, vma_size, pte_size): + """ Arguments + * asid_size: Address Space IDentifier (ASID) typically 15 bits + * vma_size: Virtual Memory Address (VMA) typically 36 bits + * pte_size: Page Table Entry (PTE) typically 64 bits + + Notes: + These arguments should represent the largest possible size + defined by the MODE settings. See + Volume II: RISC-V Privileged Architectures V1.10 Page 57 + """ + + # Internal + self.state = 0 + # L1 Cache Modules + L1_size = 8 + bits_for_LRU = 8 # Just a placeholder for not. Arbitrary 8! + self.cam_L1 = Cam(vma_size, cam_size) + self.reg_file = RegisterFile(pte_size + bits_for_LRU, cam_size) + + # Permission Validator + self.perm_validator = PermissionValidator(asid_size + pte_size) + # Inputs self.super = Signal(1) # Supervisor Mode self.super_access = Signal(1) # Supervisor Access - self.command = Signal(2) # 00=None, 01=Search, 10=Write PTE, 11=Reset + self.command = Signal(2) # 00=None, 01=Search, 10=Write PTE, 11=None self.xwr = Signal(3) # Execute, Write, Read self.mode = Signal(4) # 4 bits for access to Sv48 on Rv64 - self.asid = Signal(15) # Address Space IDentifier (ASID) - self.vma = Signal(36) # Virtual Memory Address (VMA) - self.pte_in = Signal(64) # To be saved Page Table Entry (PTE) + self.asid = Signal(asid_size) # Address Space IDentifier (ASID) + self.vma = Signal(vma_size) # Virtual Memory Address (VMA) + self.pte_in = Signal(pte_size) # To be saved Page Table Entry (PTE) # Outputs self.hit = Signal(1) # Denotes if the VMA had a mapped PTE - self.valid = Signal(1) # Denotes if the permissions are correct - self.pteOut = Signal(64) # PTE that was mapped to by the VMA - - # Cam simulations - mem_l1 = Memory(113, 32) # L1 TLB cache - read_port_l1 = mem_l1.read_port - write_port_l1 = mem_l1.write_port - - mem_l2 = Memory(113, 128) # L2 TLB cache - read_port_l2 = mem_l2.read_port - write_port_l2 = mem_l2.write_port + self.perm_valid = Signal(1) # Denotes if the permissions are correct + self.pte_out = Signal(pte_size) # PTE that was mapped to by the VMA def elaborate(self, platform): m = Module() - m.d.submodules.perm_valid = perm_valid = PermissionValidator(113) - m.d.sync += [ - Case(self.command, { - # Search for PTE - 1: [ - # Check first entry in set - # TODO make module? - read_port_l1.addr.eq(vma[0,2]), - If(read_port_l1.data[0] == 1, - perm_valid.data.eq(read_port_l1.data), - perm_valid.xwr.eq(self.xwr), - perm_valid.super.eq(self.super), - perm_valid.super_access.eq(self.super_access), - perm_valid.asid.eq(self.asid), - self.valid,eq(perm_valid.valid) - ), - If(self.valid == 0, - read_port_l1.addr.eq(vma[0,2] + 1), - If(read_port_l1.data[0] == 1, - perm_valid.data.eq(read_port_l1.data), - perm_valid.xwr.eq(self.xwr), - perm_valid.super.eq(self.super), - perm_valid.super_access.eq(self.super_access), - perm_valid.asid.eq(self.asid), - self.valid,eq(perm_valid.valid) - ) - ) - ] - }) - ] + + # Add submodules + m.d.submodules.perm_valididator += self.perm_validator + m.d.submodules.cam_L1 += self.cam_L1 + m.d.sumbmodules.reg_file += self.reg_file + + # When MODE specifies translation + # TODO add in different bit length handling ie prefix 0s + with m.If(self.mode != 0): + m.d.comb += [ + self.cam_L1.enable.eq(1), + self.reg_file.enable.eq(1) + ] + with m.Switch(self.command): + # Search + with m.Case("01"): + m.d.comb += [ + self.cam_L1.write_enable.eq(0), + self.cam_L1.data_in.eq(self.vma) + ] + # Write + with m.Case("10"): + # LRU logic should go in here + # Or take in address for writing? + # Add hardware option/software option + # SO MANY CHOICES + m.d.comb += [ + self.cam_L1.write_enable.eq(1), + self.cam_L1.data_in.eq(self.vma) + ] + # Match found in L1 CAM + with m.If(self.cam_L1.single_match + | self.cam_L1.multiple_match): + # Register file shortcut variables + reg_addrress = self.cam_L1.match_address + reg_data = self.reg_file.register_array[reg_addrress] + # Set all permission validator fields + m.d.comb += [ + self.hit.eq(1), + # Set permission validator data to the correct + # register file data according to CAM match + # address + self.perm_validator.data.eq(reg_data), + # Execute, Read, Write + self.perm_validator.xwr.eq(self.xwr), + # Supervisor Mode + self.perm_validator.super.eq(self.super), + # Supverisor Access + self.perm_validator.super_access.eq(self.super_access), + # Address Space IDentifier (ASID) + self.perm_validator.asid.eq(self.asid), + # Output result of permission validation + self.perm_valid.eq(self.perm_validator.valid) + ] + # Do not output PTE if permissions fail + with m.If(self.perm_validator.valid): + m.d.comb += [ + self.pte_out.eq(reg_data) + ] + with m.Else(): + m.d.comb += [ + self.pte_out.eq(0) + ] + with m.Else(): + m.d.comb += [ + self.hit.eq(0), + self.perm_valid.eq(0), + self.pte_out.eq(0) + ] + # When disabled + with m.Else(): + m.d.comb += [ + self.cam_L1.enable.eq(0), + self.reg_file.enable.eq(0), + self.hit.eq(0), + self.valid.eq(0), + self.pte_out.eq(0) + ] return m thing = TLB() -- 2.30.2