Skip to content

Commit 9ffaf94

Browse files
committed
Migrate elaboratables to lib.wiring components.
As a consequence of this change, memory maps are now assigned to {wishbone,csr}.Signature instead of {wishbone,csr}.Interface. Likewise, event maps are now assigned to event.Source.Signature instead of event.Source.
1 parent b11abe2 commit 9ffaf94

File tree

9 files changed

+447
-282
lines changed

9 files changed

+447
-282
lines changed

amaranth_soc/csr/bus.py

Lines changed: 76 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from collections import defaultdict
22
from amaranth import *
33
from amaranth.lib import enum, wiring
4-
from amaranth.lib.wiring import In, Out
4+
from amaranth.lib.wiring import In, Out, flipped
55
from amaranth.utils import log2_int
66

77
from ..memory import MemoryMap
@@ -198,6 +198,7 @@ def __init__(self, *, addr_width, data_width):
198198

199199
self._addr_width = addr_width
200200
self._data_width = data_width
201+
self._memory_map = None
201202

202203
members = {
203204
"addr": Out(self.addr_width),
@@ -216,6 +217,27 @@ def addr_width(self):
216217
def data_width(self):
217218
return self._data_width
218219

220+
@property
221+
def memory_map(self):
222+
if self._memory_map is None:
223+
raise AttributeError(f"{self!r} does not have a memory map")
224+
return self._memory_map
225+
226+
@memory_map.setter
227+
def memory_map(self, memory_map):
228+
if self.frozen:
229+
raise ValueError(f"Signature has been frozen. Cannot set its memory map")
230+
if memory_map is not None:
231+
if not isinstance(memory_map, MemoryMap):
232+
raise TypeError(f"Memory map must be an instance of MemoryMap, not {memory_map!r}")
233+
if memory_map.addr_width != self.addr_width:
234+
raise ValueError(f"Memory map has address width {memory_map.addr_width}, which is not "
235+
f"the same as bus interface address width {self.addr_width}")
236+
if memory_map.data_width != self.data_width:
237+
raise ValueError(f"Memory map has data width {memory_map.data_width}, which is not the "
238+
f"same as bus interface data width {self.data_width}")
239+
self._memory_map = memory_map
240+
219241
@classmethod
220242
def check_parameters(cls, *, addr_width, data_width):
221243
"""Validate signature parameters.
@@ -241,7 +263,9 @@ def create(self, *, path=()):
241263
-------
242264
An :class:`Interface` object using this signature.
243265
"""
244-
return Interface(addr_width=self.addr_width, data_width=self.data_width, path=path)
266+
return Interface(addr_width=self.addr_width, data_width=self.data_width,
267+
memory_map=self._memory_map, # if None, do not raise an exception
268+
path=path)
245269

246270
def __eq__(self, other):
247271
"""Compare signatures.
@@ -280,22 +304,19 @@ class Interface(wiring.Interface):
280304
Address width. See :class:`Signature`.
281305
data_width : :class:`int`
282306
Data width. See :class:`Signature`.
307+
memory_map: :class:`MemoryMap`
308+
Memory map of the bus. Optional. See :class:`Signature`.
283309
path : iter(:class:`str`)
284310
Path to this CSR interface. Optional. See :class:`wiring.Interface`.
285311
286-
Attributes
287-
----------
288-
memory_map : :class:`MemoryMap`
289-
Map of the bus.
290-
291312
Raises
292313
------
293314
See :meth:`Signature.check_parameters`.
294315
"""
295-
def __init__(self, *, addr_width, data_width, path=()):
296-
super().__init__(Signature(addr_width=addr_width, data_width=data_width), path=path)
297-
298-
self._map = None
316+
def __init__(self, *, addr_width, data_width, memory_map=None, path=()):
317+
sig = Signature(addr_width=addr_width, data_width=data_width)
318+
sig.memory_map = memory_map
319+
super().__init__(sig, path=path)
299320

300321
@property
301322
def addr_width(self):
@@ -307,28 +328,13 @@ def data_width(self):
307328

308329
@property
309330
def memory_map(self):
310-
if self._map is None:
311-
raise NotImplementedError(f"{self!r} does not have a memory map")
312-
return self._map
313-
314-
@memory_map.setter
315-
def memory_map(self, memory_map):
316-
if not isinstance(memory_map, MemoryMap):
317-
raise TypeError(f"Memory map must be an instance of MemoryMap, not {memory_map!r}")
318-
if memory_map.addr_width != self.addr_width:
319-
raise ValueError(f"Memory map has address width {memory_map.addr_width}, which is not "
320-
f"the same as bus interface address width {self.addr_width}")
321-
if memory_map.data_width != self.data_width:
322-
raise ValueError(f"Memory map has data width {memory_map.data_width}, which is not the "
323-
f"same as bus interface data width {self.data_width}")
324-
memory_map.freeze()
325-
self._map = memory_map
331+
return self.signature.memory_map
326332

327333
def __repr__(self):
328334
return f"csr.Interface({self.signature!r})"
329335

330336

331-
class Multiplexer(Elaboratable):
337+
class Multiplexer(wiring.Component):
332338
class _Shadow:
333339
class Chunk:
334340
"""The interface between a CSR multiplexer and a shadow register chunk."""
@@ -555,44 +561,42 @@ def chunks(self):
555561
CSR bus providing access to registers.
556562
"""
557563
def __init__(self, *, addr_width, data_width, alignment=0, name=None, shadow_overlaps=None):
558-
self._map = MemoryMap(addr_width=addr_width, data_width=data_width, alignment=alignment,
559-
name=name)
560-
self._bus = None
561-
self._r_shadow = Multiplexer._Shadow(data_width, shadow_overlaps, name="r_shadow")
562-
self._w_shadow = Multiplexer._Shadow(data_width, shadow_overlaps, name="w_shadow")
564+
bus_signature = Signature(addr_width=addr_width, data_width=data_width)
565+
bus_signature.memory_map = MemoryMap(addr_width=addr_width, data_width=data_width,
566+
alignment=alignment, name=name)
567+
568+
self._signature = wiring.Signature({"bus": In(bus_signature)})
569+
self._r_shadow = Multiplexer._Shadow(data_width, shadow_overlaps, name="r_shadow")
570+
self._w_shadow = Multiplexer._Shadow(data_width, shadow_overlaps, name="w_shadow")
571+
super().__init__()
563572

564573
@property
565-
def bus(self):
566-
if self._bus is None:
567-
self._map.freeze()
568-
self._bus = Interface(addr_width=self._map.addr_width, data_width=self._map.data_width,
569-
path=("csr",))
570-
self._bus.memory_map = self._map
571-
return self._bus
574+
def signature(self):
575+
return self._signature
572576

573577
def align_to(self, alignment):
574578
"""Align the implicit address of the next register.
575579
576580
See :meth:`MemoryMap.align_to` for details.
577581
"""
578-
return self._map.align_to(alignment)
582+
return self.bus.memory_map.align_to(alignment)
579583

580-
def add(self, element, *, name, addr=None, alignment=None):
584+
def add(self, elem, *, name, addr=None, alignment=None):
581585
"""Add a register.
582586
583587
See :meth:`MemoryMap.add_resource` for details.
584588
"""
585-
if not isinstance(element, Element):
586-
raise TypeError(f"Element must be an instance of csr.Element, not {element!r}")
589+
if not isinstance(elem, Element):
590+
raise TypeError(f"Element must be an instance of csr.Element, not {elem!r}")
587591

588-
size = (element.width + self._map.data_width - 1) // self._map.data_width
589-
return self._map.add_resource(element, size=size, addr=addr, alignment=alignment,
590-
name=name)
592+
size = (elem.width + self.bus.memory_map.data_width - 1) // self.bus.memory_map.data_width
593+
return self.bus.memory_map.add_resource(elem, size=size, addr=addr, alignment=alignment,
594+
name=name)
591595

592596
def elaborate(self, platform):
593597
m = Module()
594598

595-
for elem, _, (elem_start, elem_end) in self._map.resources():
599+
for elem, _, (elem_start, elem_end) in self.bus.memory_map.resources():
596600
elem_range = range(elem_start, elem_end)
597601
if elem.access.readable():
598602
self._r_shadow.add(elem_range)
@@ -619,7 +623,7 @@ def elaborate(self, platform):
619623
with m.Switch(self.bus.addr):
620624
for elem_range in r_chunk.elements():
621625
chunk_addr = self._r_shadow.encode_offset(chunk_offset, elem_range)
622-
elem = self._map.decode_address(elem_range.start)
626+
elem = self.bus.memory_map.decode_address(elem_range.start)
623627
elem_offset = chunk_addr - elem_range.start
624628
elem_slice = elem.r_data.word_select(elem_offset, self.bus.data_width)
625629

@@ -644,7 +648,7 @@ def elaborate(self, platform):
644648
with m.Switch(self.bus.addr):
645649
for elem_range in w_chunk.elements():
646650
chunk_addr = self._w_shadow.encode_offset(chunk_offset, elem_range)
647-
elem = self._map.decode_address(elem_range.start)
651+
elem = self.bus.memory_map.decode_address(elem_range.start)
648652
elem_offset = chunk_addr - elem_range.start
649653
elem_slice = elem.w_data.word_select(elem_offset, self.bus.data_width)
650654

@@ -666,7 +670,7 @@ def elaborate(self, platform):
666670
return m
667671

668672

669-
class Decoder(Elaboratable):
673+
class Decoder(wiring.Component):
670674
"""CSR bus decoder.
671675
672676
An address decoder for subordinate CSR buses.
@@ -700,39 +704,42 @@ class Decoder(Elaboratable):
700704
CSR bus providing access to subordinate buses.
701705
"""
702706
def __init__(self, *, addr_width, data_width, alignment=0, name=None):
703-
self._map = MemoryMap(addr_width=addr_width, data_width=data_width, alignment=alignment,
704-
name=name)
705-
self._bus = None
706-
self._subs = dict()
707+
bus_signature = Signature(addr_width=addr_width, data_width=data_width)
708+
bus_signature.memory_map = MemoryMap(addr_width=addr_width, data_width=data_width,
709+
alignment=alignment, name=name)
710+
711+
self._signature = wiring.Signature({"bus": In(bus_signature)})
712+
self._subs = dict()
713+
super().__init__()
707714

708715
@property
709-
def bus(self):
710-
if self._bus is None:
711-
self._map.freeze()
712-
self._bus = Interface(addr_width=self._map.addr_width, data_width=self._map.data_width,
713-
path=("csr",))
714-
self._bus.memory_map = self._map
715-
return self._bus
716+
def signature(self):
717+
return self._signature
716718

717719
def align_to(self, alignment):
718720
"""Align the implicit address of the next window.
719721
720722
See :meth:`MemoryMap.align_to` for details.
721723
"""
722-
return self._map.align_to(alignment)
724+
return self.bus.memory_map.align_to(alignment)
723725

724726
def add(self, sub_bus, *, addr=None):
725727
"""Add a window to a subordinate bus.
726728
727729
See :meth:`MemoryMap.add_resource` for details.
728730
"""
729-
if not isinstance(sub_bus, Interface):
730-
raise TypeError(f"Subordinate bus must be an instance of csr.Interface, not {sub_bus!r}")
731-
if sub_bus.data_width != self._map.data_width:
731+
if isinstance(sub_bus, wiring.FlippedInterface):
732+
sub_bus_unflipped = flipped(sub_bus)
733+
else:
734+
sub_bus_unflipped = sub_bus
735+
if not isinstance(sub_bus_unflipped, Interface):
736+
raise TypeError(f"Subordinate bus must be an instance of csr.Interface, not "
737+
f"{sub_bus_unflipped!r}")
738+
if sub_bus.data_width != self.bus.data_width:
732739
raise ValueError(f"Subordinate bus has data width {sub_bus.data_width}, which is not "
733-
f"the same as decoder data width {self._map.data_width}")
740+
f"the same as decoder data width {self.bus.data_width}")
734741
self._subs[sub_bus.memory_map] = sub_bus
735-
return self._map.add_window(sub_bus.memory_map, addr=addr)
742+
return self.bus.memory_map.add_window(sub_bus.memory_map, addr=addr)
736743

737744
def elaborate(self, platform):
738745
m = Module()
@@ -741,7 +748,7 @@ def elaborate(self, platform):
741748
r_data_fanin = 0
742749

743750
with m.Switch(self.bus.addr):
744-
for sub_map, (sub_pat, sub_ratio) in self._map.window_patterns():
751+
for sub_map, (sub_pat, sub_ratio) in self.bus.memory_map.window_patterns():
745752
assert sub_ratio == 1
746753

747754
sub_bus = self._subs[sub_map]

amaranth_soc/csr/event.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from math import ceil
33

44
from amaranth import *
5+
from amaranth.lib import wiring
6+
from amaranth.lib.wiring import In, Out, flipped, connect
57
from amaranth.utils import log2_int
68

79
from . import Element, Multiplexer
@@ -11,7 +13,7 @@
1113
__all__ = ["EventMonitor"]
1214

1315

14-
class EventMonitor(Elaboratable):
16+
class EventMonitor(wiring.Component):
1517
"""Event monitor.
1618
1719
A monitor for subordinate event sources, with a CSR bus interface.
@@ -35,6 +37,14 @@ class EventMonitor(Elaboratable):
3537
CSR address alignment. See :class:`..memory.MemoryMap`.
3638
name : str
3739
Window name. Optional. See :class:`..memory.MemoryMap`.
40+
41+
Attributes
42+
----------
43+
src : :class:`..event.Source`
44+
Event source. Its input line is asserted by the monitor when a subordinate event is enabled
45+
and pending.
46+
bus : :class:`..csr.Interface`
47+
CSR bus interface.
3848
"""
3949
def __init__(self, event_map, *, trigger="level", data_width, alignment=0, name=None):
4050
if not isinstance(data_width, int) or data_width <= 0:
@@ -53,32 +63,24 @@ def __init__(self, event_map, *, trigger="level", data_width, alignment=0, name=
5363
self._mux.add(self._enable, name="enable")
5464
self._mux.add(self._pending, name="pending")
5565

56-
@property
57-
def src(self):
58-
"""Event source.
59-
60-
Return value
61-
------------
62-
An :class:`..event.Source`. Its input line is asserted by the monitor when a subordinate
63-
event is enabled and pending.
64-
"""
65-
return self._monitor.src
66+
self._signature = wiring.Signature({
67+
"src": Out(self._monitor.src.signature),
68+
"bus": In(self._mux.bus.signature),
69+
})
70+
super().__init__()
6671

6772
@property
68-
def bus(self):
69-
"""CSR bus interface.
70-
71-
Return value
72-
------------
73-
A :class:`..csr.Interface` providing access to registers.
74-
"""
75-
return self._mux.bus
73+
def signature(self):
74+
return self._signature
7675

7776
def elaborate(self, platform):
7877
m = Module()
7978
m.submodules.monitor = self._monitor
8079
m.submodules.mux = self._mux
8180

81+
connect(m, flipped(self.src), self._monitor.src)
82+
connect(m, self.bus, self._mux.bus)
83+
8284
with m.If(self._enable.w_stb):
8385
m.d.sync += self._monitor.enable.eq(self._enable.w_data)
8486
m.d.comb += self._enable.r_data.eq(self._monitor.enable)

0 commit comments

Comments
 (0)