1
1
from collections import defaultdict
2
2
from amaranth import *
3
3
from amaranth .lib import enum , wiring
4
- from amaranth .lib .wiring import In , Out
4
+ from amaranth .lib .wiring import In , Out , flipped
5
5
from amaranth .utils import log2_int
6
6
7
7
from ..memory import MemoryMap
@@ -198,6 +198,7 @@ def __init__(self, *, addr_width, data_width):
198
198
199
199
self ._addr_width = addr_width
200
200
self ._data_width = data_width
201
+ self ._memory_map = None
201
202
202
203
members = {
203
204
"addr" : Out (self .addr_width ),
@@ -216,6 +217,27 @@ def addr_width(self):
216
217
def data_width (self ):
217
218
return self ._data_width
218
219
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
+
219
241
@classmethod
220
242
def check_parameters (cls , * , addr_width , data_width ):
221
243
"""Validate signature parameters.
@@ -241,7 +263,9 @@ def create(self, *, path=()):
241
263
-------
242
264
An :class:`Interface` object using this signature.
243
265
"""
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 )
245
269
246
270
def __eq__ (self , other ):
247
271
"""Compare signatures.
@@ -280,22 +304,19 @@ class Interface(wiring.Interface):
280
304
Address width. See :class:`Signature`.
281
305
data_width : :class:`int`
282
306
Data width. See :class:`Signature`.
307
+ memory_map: :class:`MemoryMap`
308
+ Memory map of the bus. Optional. See :class:`Signature`.
283
309
path : iter(:class:`str`)
284
310
Path to this CSR interface. Optional. See :class:`wiring.Interface`.
285
311
286
- Attributes
287
- ----------
288
- memory_map : :class:`MemoryMap`
289
- Map of the bus.
290
-
291
312
Raises
292
313
------
293
314
See :meth:`Signature.check_parameters`.
294
315
"""
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 )
299
320
300
321
@property
301
322
def addr_width (self ):
@@ -307,28 +328,13 @@ def data_width(self):
307
328
308
329
@property
309
330
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
326
332
327
333
def __repr__ (self ):
328
334
return f"csr.Interface({ self .signature !r} )"
329
335
330
336
331
- class Multiplexer (Elaboratable ):
337
+ class Multiplexer (wiring . Component ):
332
338
class _Shadow :
333
339
class Chunk :
334
340
"""The interface between a CSR multiplexer and a shadow register chunk."""
@@ -555,44 +561,42 @@ def chunks(self):
555
561
CSR bus providing access to registers.
556
562
"""
557
563
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__ ()
563
572
564
573
@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
572
576
573
577
def align_to (self , alignment ):
574
578
"""Align the implicit address of the next register.
575
579
576
580
See :meth:`MemoryMap.align_to` for details.
577
581
"""
578
- return self ._map .align_to (alignment )
582
+ return self .bus . memory_map .align_to (alignment )
579
583
580
- def add (self , element , * , name , addr = None , alignment = None ):
584
+ def add (self , elem , * , name , addr = None , alignment = None ):
581
585
"""Add a register.
582
586
583
587
See :meth:`MemoryMap.add_resource` for details.
584
588
"""
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} " )
587
591
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 )
591
595
592
596
def elaborate (self , platform ):
593
597
m = Module ()
594
598
595
- for elem , _ , (elem_start , elem_end ) in self ._map .resources ():
599
+ for elem , _ , (elem_start , elem_end ) in self .bus . memory_map .resources ():
596
600
elem_range = range (elem_start , elem_end )
597
601
if elem .access .readable ():
598
602
self ._r_shadow .add (elem_range )
@@ -619,7 +623,7 @@ def elaborate(self, platform):
619
623
with m .Switch (self .bus .addr ):
620
624
for elem_range in r_chunk .elements ():
621
625
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 )
623
627
elem_offset = chunk_addr - elem_range .start
624
628
elem_slice = elem .r_data .word_select (elem_offset , self .bus .data_width )
625
629
@@ -644,7 +648,7 @@ def elaborate(self, platform):
644
648
with m .Switch (self .bus .addr ):
645
649
for elem_range in w_chunk .elements ():
646
650
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 )
648
652
elem_offset = chunk_addr - elem_range .start
649
653
elem_slice = elem .w_data .word_select (elem_offset , self .bus .data_width )
650
654
@@ -666,7 +670,7 @@ def elaborate(self, platform):
666
670
return m
667
671
668
672
669
- class Decoder (Elaboratable ):
673
+ class Decoder (wiring . Component ):
670
674
"""CSR bus decoder.
671
675
672
676
An address decoder for subordinate CSR buses.
@@ -700,39 +704,42 @@ class Decoder(Elaboratable):
700
704
CSR bus providing access to subordinate buses.
701
705
"""
702
706
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__ ()
707
714
708
715
@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
716
718
717
719
def align_to (self , alignment ):
718
720
"""Align the implicit address of the next window.
719
721
720
722
See :meth:`MemoryMap.align_to` for details.
721
723
"""
722
- return self ._map .align_to (alignment )
724
+ return self .bus . memory_map .align_to (alignment )
723
725
724
726
def add (self , sub_bus , * , addr = None ):
725
727
"""Add a window to a subordinate bus.
726
728
727
729
See :meth:`MemoryMap.add_resource` for details.
728
730
"""
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 :
732
739
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 } " )
734
741
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 )
736
743
737
744
def elaborate (self , platform ):
738
745
m = Module ()
@@ -741,7 +748,7 @@ def elaborate(self, platform):
741
748
r_data_fanin = 0
742
749
743
750
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 ():
745
752
assert sub_ratio == 1
746
753
747
754
sub_bus = self ._subs [sub_map ]
0 commit comments