1 from nmigen
import Elaboratable
, Signal
, Module
, Mux
, Repl
, Array
2 from nmigen
.hdl
.mem
import ReadPort
, WritePort
, Memory
3 from .config
import MemoryPipeConfig
6 class L1CacheMemory(Elaboratable
):
7 """ The data memory for the L1 cache.
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
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`.
20 The results of reading are available after the next clock edge.
22 The address is divided into `set_index` and `way_index`.
26 config: MemoryPipeConfig
31 config: MemoryPipeConfig
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)
44 write_data: Signal(config.bits_per_cache_line)
49 def __init__(self
, config
: MemoryPipeConfig
):
51 self
.set_index
= Signal(range(config
.l1_set_count
), reset_less
=True)
52 self
.way_index
= Signal(range(config
.l1_way_count
),
54 self
.write_byte_en
= Signal(config
.bytes_per_cache_line
,
56 self
.write_enable
= Signal(reset_less
=True)
57 self
.read_data
= Signal(config
.bits_per_cache_line
,
59 self
.write_data
= Signal(config
.bits_per_cache_line
,
62 def elaborate(self
, platform
):
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
,
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
)
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
])