From 08e3850f1cb5abcab4ed4f2390a723f54912432c Mon Sep 17 00:00:00 2001 From: Daniel Benusovich Date: Sun, 31 Mar 2019 23:08:57 -0700 Subject: [PATCH] Add SetAssociativeCache source with read logic --- TLB/src/SetAssociativeCache.py | 111 +++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 TLB/src/SetAssociativeCache.py diff --git a/TLB/src/SetAssociativeCache.py b/TLB/src/SetAssociativeCache.py new file mode 100644 index 00000000..a32cf785 --- /dev/null +++ b/TLB/src/SetAssociativeCache.py @@ -0,0 +1,111 @@ +from nmigen import Array, Memory, Module, Signal +from nmigen.cli import main + +from AddressEncoder import AddressEncoder + +class SetAssociativeCache(): + """ Set Associative Cache Memory + + The purpose of this module is to generate a memory cache given the + constraints passed in. This will create a n-way set associative cache. + It is expected for the SV TLB that the VMA will provide the set number + while the ASID provides the tag (still to be decided). + + """ + def __init__(self, tag_size, data_size, set_count, way_count): + """ Arguments + """ + # Internal + # Memory + # Plus one for valid bit. Valid bit will be the LSB in the memory + memory_array = Array(Memory(tag_size + data_size + 1, entry_count)) + self.read_port_array = Array() + self.write_port_array = Array() + for i in range(way_count): + self.read_port_array.append(memory_array[i].read_port()) + self.write_port_array.append(memory_array[i].write_port()) + self.way_count = way_count + self.tag_size = tag_size + self.data_size = data_size + # Encoder + self.encoder = AddressEncoder(max=way_count) + + # Input + self.enable = Signal(1) + self.command = Signal(2) # 00=None, 01=Read, 10=Write + self.set = Signal(max=set_count) + self.tag = Signal(tag_size) + self.data_i = Signal(data_size + tag_size) + + # Output + self.hit = Signal(1) + self.multiple_hit = Signal(1) # Oh no + self.data_o = Signal(data_size) + + def elaborate(self, platform=None): + m = Module() + m.submodules += self.read_port_array + m.submodules += self.write_port_array + + with m.If(self.enable): + with m.Switch(self.command): + # Search all sets at a particular tag + with m.Case("01"): + # Vector to store valid results + valid_vector = [] + # Loop through memory setting what set to read + for i in range(self.way_count): + n.d.comb += [ + self.write_port_array[i].en.eq(0), + self.read_port_array[i].addr.eq(self.set) + ] + # Pull out Valid bit from data + data = self.read_port_array[i].data; + valid_bit = data[0]; + # Validate given tag vs stored tag + tag_start = 1 + self.data_size + tag_end = 1 + self.data_size + self.tag_size; + tag = data[tag_start:tag_end] + tag_valid = self.tag == tag + # An entry is only valid if the tags match AND + # is marked as a valid entry + valid_vector.append(tag_valid & valid_bit) + + # Pass encoder the valid vector + self.encoder.i.eq(Cat(*valid_vector)) + # Only one entry should be marked + # This is due to already verifying the tags + # matched and the valid bit is high + with m.If(self.encoder.single_match): + # Pull out data from the read port + read_port = self.read_port_array[self.encoder.o] + data_start = 1 + data_end = 1 + self.data_size + data = read_port.data[data_start:data_end] + m.d.comb += [ + self.hit.eq(1), + self.multiple_hit.eq(0), + self.data_o.eq(data) + ] + # Oh no! Seal the gates! Multiple tags matched?!? kasd;ljkafdsj;k + with m.Elif(self.encoder.multiple_match): + m.d.comb += [ + self.hit.eq(0), + self.multiple_hit.eq(1), + self.data_o.eq(0) + ] + # No tag matches means no data + with m.Else(): + m.d.comb += [ + self.hit.eq(0), + self.multiple_hit.eq(0), + self.data_o.eq(0) + ] + # TODO + # Write to a given tag + # with m.Case("10"): + # Search for available space + # What to do when there is no space + # Maybe catch multiple tags write here? + # TODO + return m \ No newline at end of file -- 2.30.2