Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / memory_pipe_experiment / l1_cache_memory.py
1 from nmigen import Elaboratable, Signal, Module, Mux, Repl, Array
2 from nmigen.hdl.mem import ReadPort, WritePort, Memory
3 from .config import MemoryPipeConfig
4
5
6 class L1CacheMemory(Elaboratable):
7 """ The data memory for the L1 cache.
8
9 It is conceptually organized into `config.l1_way_count` ways,
10 where each way has `config.l1_sets_count` sets,
11 where each set is a single cache line of `config.bytes_per_cache_line`
12 bytes. None of the dimensions must be powers of 2, but must all be at
13 least 1.
14
15 The memory has a single R/W port that can read or write
16 (but not both) an entire cache line each cycle.
17 When writing, writing to each byte can individually be enabled by setting
18 the corresponding bit in `write_byte_en`.
19
20 The results of reading are available after the next clock edge.
21
22 The address is divided into `set_index` and `way_index`.
23
24 Parameters:
25
26 config: MemoryPipeConfig
27 The configuration.
28
29 Attributes:
30
31 config: MemoryPipeConfig
32 The configuration.
33 set_index: Signal(range(config.l1_set_count))
34 The input index of the set to read/write.
35 way_index: Signal(range(config.l1_way_count))
36 The input index of the way to read/write.
37 write_byte_en: Signal(config.bytes_per_cache_line)
38 The per-byte write enable inputs.
39 write_enable: Signal()
40 The overall write enable input.
41 Set to 1 to write and to 0 to read.
42 read_data: Signal(config.bits_per_cache_line)
43 The read data output.
44 write_data: Signal(config.bits_per_cache_line)
45 The write data input.
46
47 """
48
49 def __init__(self, config: MemoryPipeConfig):
50 self.config = config
51 self.set_index = Signal(range(config.l1_set_count), reset_less=True)
52 self.way_index = Signal(range(config.l1_way_count),
53 reset_less=True)
54 self.write_byte_en = Signal(config.bytes_per_cache_line,
55 reset_less=True)
56 self.write_enable = Signal(reset_less=True)
57 self.read_data = Signal(config.bits_per_cache_line,
58 reset_less=True)
59 self.write_data = Signal(config.bits_per_cache_line,
60 reset_less=True)
61
62 def elaborate(self, platform):
63 m = Module()
64 read_data_signals = []
65 for way in range(self.config.l1_way_count):
66 way_memory_name = f"way_memory_{way}"
67 way_memory = Memory(width=self.config.bits_per_cache_line,
68 depth=self.config.l1_set_count,
69 name=way_memory_name)
70 write_port = WritePort(way_memory, granularity=8)
71 setattr(m.submodules, way_memory_name + '_write_port', write_port)
72 m.d.comb += write_port.addr.eq(self.set_index)
73 m.d.comb += write_port.data.eq(self.write_data)
74 way_enable = Signal(name=f"way_enable_{way}", reset_less=True)
75 m.d.comb += way_enable.eq(way == self.way_index)
76 way_write_enable = self.write_enable & way_enable
77 way_read_enable = ~self.write_enable & way_enable
78 m.d.comb += write_port.en.eq(
79 Repl(way_write_enable,
80 self.config.bytes_per_cache_line
81 ) & self.write_byte_en)
82 read_port = ReadPort(way_memory, transparent=False)
83 setattr(m.submodules, way_memory_name + '_read_port', read_port)
84 m.d.comb += read_port.addr.eq(self.set_index)
85 m.d.comb += read_port.en.eq(way_read_enable)
86 read_data_signals.append(read_port.data)
87
88 last_way_index = Signal.like(self.way_index)
89 m.d.sync += last_way_index.eq(self.way_index)
90 read_data = Array(read_data_signals)
91 m.d.comb += self.read_data.eq(read_data[last_way_index])
92 return m