11from collections import defaultdict
22from amaranth import *
33from amaranth .lib import enum , wiring
4- from amaranth .lib .wiring import In , Out
4+ from amaranth .lib .wiring import In , Out , flipped
55from amaranth .utils import log2_int
66
77from ..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 ]
0 commit comments