class MMU:
- def __init__(self, INSTR_TLB_ENTRIES = 4,
- DATA_TLB_ENTRIES = 4,
- ASID_WIDTH = 1):
+ def __init__(self, instr_tlb_entries = 4,
+ data_tlb_entries = 4,
+ asid_width = 1):
+ self.instr_tlb_entries = instr_tlb_entries
+ self.data_tlb_entries = data_tlb_entries
+ self.asid_width = asid_width
+
self.flush_i = Signal()
self.enable_translation_i = Signal()
self.en_ld_st_translation_i = Signal() # enable VM translation for LD/ST
self.mxr_i = Signal()
# input logic flag_mprv_i,
self.satp_ppn_i = Signal(44)
- self.asid_i = Signal(ASID_WIDTH)
+ self.asid_i = Signal(self.asid_width)
self.flush_tlb_i = Signal()
# Performance counters
self.itlb_miss_o = Signal()
update_vaddr = Signal(39)
uaddr64 = Cat(update_vaddr, Const(0, 25)) # extend to 64bit with zeros
- update_ptw_itlb = TLBUpdate()
- update_ptw_dtlb = TLBUpdate()
+ update_ptw_itlb = TLBUpdate(self.asid_width)
+ update_ptw_dtlb = TLBUpdate(self.asid_width)
itlb_lu_access = Signal()
itlb_content = PTE()
]
# ITLB
- m.submodules.i_tlb = i_tlb = TLB()#INSTR_TLB_ENTRIES, ASID_WIDTH)
+ m.submodules.i_tlb = i_tlb = TLB(self.instr_tlb_entries,
+ self.asid_width)
m.d.comb += [i_tlb.flush_i.eq(self.flush_tlb_i),
i_tlb.update_i.eq(update_ptw_itlb),
i_tlb.lu_access_i.eq(itlb_lu_access),
]
# DTLB
- m.submodules.d_tlb = d_tlb = TLB() #DATA_TLB_ENTRIES, ASID_WIDTH)
+ m.submodules.d_tlb = d_tlb = TLB(self.data_tlb_entries,
+ self.asid_width)
m.d.comb += [d_tlb.flush_i.eq(self.flush_tlb_i),
d_tlb.update_i.eq(update_ptw_dtlb),
d_tlb.lu_access_i.eq(dtlb_lu_access),
]
# PTW
- m.submodules.ptw = ptw = PTW() #ASID_WIDTH)
+ m.submodules.ptw = ptw = PTW(self.asid_width)
m.d.comb += [ptw_active.eq(ptw.ptw_active_o),
walking_instr.eq(ptw.walking_instr_o),
ptw_error.eq(ptw.ptw_error_o),
class TLBUpdate:
- def __init__(self):
+ def __init__(self, asid_width):
self.valid = Signal() # valid flag
self.is_2M = Signal()
self.is_1G = Signal()
self.vpn = Signal(27)
- self.asid = Signal(ASID_WIDTH)
+ self.asid = Signal(asid_width)
self.content = PTE()
def flatten(self):
class PTW:
- def __init__(self):
+ def __init__(self, asid_width=8):
+ self.asid_width = asid_width
+
self.flush_i = Signal() # flush everything, we need to do this because
# actually everything we do is speculative at this stage
# e.g.: there could be a CSR instruction that changes everything
self.req_port_o = DCacheReqI()
# to TLBs, update logic
- self.itlb_update_o = TLBUpdate()
- self.dtlb_update_o = TLBUpdate()
+ self.itlb_update_o = TLBUpdate(asid_width)
+ self.dtlb_update_o = TLBUpdate(asid_width)
self.update_vaddr_o = Signal(39)
- self.asid_i = Signal(ASID_WIDTH)
+ self.asid_i = Signal(self.asid_width)
# from TLBs
# did we miss?
self.itlb_access_i = Signal()
# latched tag signal
tag_valid = Signal()
# register the ASID
- tlb_update_asid = Signal(ASID_WIDTH)
+ tlb_update_asid = Signal(self.asid_width)
# register VPN we need to walk, SV39 defines a 39 bit virtual addr
vaddr = Signal(64)
# 4 byte aligned physical pointer
TLB_ENTRIES = 8
class TLB:
- def __init__(self):
+ def __init__(self, tlb_entries=8, asid_width=8):
+ self.tlb_entries = tlb_entries
+ self.asid_width = asid_width
+
self.flush_i = Signal() # Flush signal
# Lookup signals
self.lu_access_i = Signal()
- self.lu_asid_i = Signal(ASID_WIDTH)
+ self.lu_asid_i = Signal(self.asid_width)
self.lu_vaddr_i = Signal(64)
self.lu_content_o = PTE()
self.lu_is_2M_o = Signal()
self.lu_hit_o = Signal()
# Update TLB
self.pte_width = len(self.lu_content_o.flatten())
- self.update_i = TLBUpdate()
+ self.update_i = TLBUpdate(asid_width)
def elaborate(self, platform):
m = Module()
]
tc = []
- for i in range(TLB_ENTRIES):
- tlc = TLBContent(self.pte_width, ASID_WIDTH)
+ for i in range(self.tlb_entries):
+ tlc = TLBContent(self.pte_width, self.asid_width)
setattr(m.submodules, "tc%d" % i, tlc)
tc.append(tlc)
# connect inputs
# use Encoder to select hit index
# XXX TODO: assert that there's only one valid entry (one lu_hit)
- hitsel = Encoder(TLB_ENTRIES)
+ hitsel = Encoder(self.tlb_entries)
m.submodules.hitsel = hitsel
hits = []
- for i in range(TLB_ENTRIES):
+ for i in range(self.tlb_entries):
hits.append(tc[i].lu_hit_o)
m.d.comb += hitsel.i.eq(Cat(*hits)) # (goes into plru as well)
idx = hitsel.o
# PLRU.
#--------------
- p = PLRU(TLB_ENTRIES)
+ p = PLRU(self.tlb_entries)
m.submodules.plru = p
# connect PLRU inputs/outputs
# XXX TODO: assert that there's only one valid entry (one replace_en)
en = []
- for i in range(TLB_ENTRIES):
+ for i in range(self.tlb_entries):
en.append(tc[i].replace_en_i)
m.d.comb += [Cat(*en).eq(p.replace_en_o), # output from PLRU into tags
p.lu_hit.eq(hitsel.i),
# Sanity checks
#--------------
- assert (TLB_ENTRIES % 2 == 0) and (TLB_ENTRIES > 1), \
+ assert (self.tlb_entries % 2 == 0) and (self.tlb_entries > 1), \
"TLB size must be a multiple of 2 and greater than 1"
- assert (ASID_WIDTH >= 1), \
+ assert (self.asid_width >= 1), \
"ASID width must be at least 1"
return m
"""
# Just for checking
- function int countSetBits(logic[TLB_ENTRIES-1:0] vector);
+ function int countSetBits(logic[self.tlb_entries-1:0] vector);
automatic int count = 0;
foreach (vector[idx]) begin
count += vector[idx];
self.pte_width = pte_width
self.flush_i = Signal() # Flush signal
# Update TLB
- self.update_i = TLBUpdate()
+ self.update_i = TLBUpdate(asid_width)
self.vpn2 = Signal(9)
self.vpn1 = Signal(9)
self.vpn0 = Signal(9)
self.replace_en_i = Signal() # replace the following entry,
# set by replacement strategy
# Lookup signals
- self.lu_asid_i = Signal(self.asid_width)
- self.lu_content_o = Signal(self.pte_width)
+ self.lu_asid_i = Signal(asid_width)
+ self.lu_content_o = Signal(pte_width)
self.lu_is_2M_o = Signal()
self.lu_is_1G_o = Signal()
self.lu_hit_o = Signal()
return [self.flush_i,
self.lu_asid_i,
self.lu_is_2M_o, self.lu_is_1G_o, self.lu_hit_o,
- ] + self.update_i.content.ports() + self.update_i.ports()
\ No newline at end of file
+ ] + self.update_i.content.ports() + self.update_i.ports()