1- import enum
2- from collections import OrderedDict
3-
41from amaranth import *
2+ from amaranth .lib import enum , wiring
3+ from amaranth .lib .wiring import In , Out
54
65
76__all__ = ["Source" , "EventMap" , "Monitor" ]
87
98
10- class Source (Record ):
9+ class Source (wiring . Interface ):
1110 class Trigger (enum .Enum ):
1211 """Event trigger mode."""
1312 LEVEL = "level"
1413 RISE = "rise"
1514 FALL = "fall"
1615
16+ class Signature (wiring .Signature ):
17+ """Event source signature.
18+
19+ Parameters
20+ ----------
21+ trigger : :class:`Source.Trigger`
22+ Trigger mode. An event can be edge- or level-triggered by the input line.
23+
24+ Interface attributes
25+ --------------------
26+ i : Signal()
27+ Input line. Sampled in order to detect an event.
28+ trg : Signal()
29+ Event trigger. Asserted when an event occurs, according to the trigger mode.
30+
31+ Raises
32+ ------
33+ See :meth:`Source.Signature.check_parameters`.
34+ """
35+ def __init__ (self , * , trigger = "level" ):
36+ self .check_parameters (trigger = trigger )
37+
38+ self ._trigger = Source .Trigger (trigger )
39+
40+ members = {
41+ "i" : In (1 ),
42+ "trg" : Out (1 ),
43+ }
44+ super ().__init__ (members )
45+
46+ @property
47+ def trigger (self ):
48+ return self ._trigger
49+
50+ def check_parameters (cls , * , trigger ):
51+ """Validate signature parameters.
52+
53+ Raises
54+ ------
55+ :exc:`ValueError`
56+ If ``trigger`` is not a member of :class:`Source.Trigger`.
57+ """
58+ # TODO(py3.9): Remove this. Python 3.8 and below use cls.__name__ in the error message
59+ # instead of cls.__qualname__.
60+ # Source.Trigger(trigger)
61+ try :
62+ Source .Trigger (trigger )
63+ except ValueError as e :
64+ raise ValueError (f"{ trigger !r} is not a valid Source.Trigger" ) from e
65+
66+ def create (self , * , path = ()):
67+ """Create a compatible interface.
68+
69+ See :meth:`wiring.Signature.create` for details.
70+
71+ Returns
72+ -------
73+ A :class:`Source` object using this signature.
74+ """
75+ return Source (trigger = self .trigger , path = path )
76+
77+ def __eq__ (self , other ):
78+ """Compare signatures.
79+
80+ Two signatures are equal if they have the same trigger mode.
81+ """
82+ return isinstance (other , Source .Signature ) and self .trigger == other .trigger
83+
84+ def __repr__ (self ):
85+ return f"event.Source.Signature({ self .members !r} )"
86+
1787 """Event source interface.
1888
1989 Parameters
2090 ----------
21- trigger : :class:`Trigger`
91+ trigger : :class:`Source. Trigger`
2292 Trigger mode. An event can be edge- or level-triggered by the input line.
23- name: str
24- Name of the underlying record .
93+ path : iter(:class:` str`)
94+ Path to this event source interface. Optional. See :class:`wiring.Interface` .
2595
2696 Attributes
2797 ----------
28- i : Signal()
29- Input line. Sampled in order to detect an event.
30- trg : Signal()
31- Event trigger. Asserted when an event occurs, according to the trigger mode.
98+ event_map : :class:`EventMap`
99+ A collection of event sources.
100+
101+ Raises
102+ ------
103+ See :meth:`Source.Signature.check_parameters`.
32104 """
33- def __init__ (self , * , trigger = "level" , name = None , src_loc_at = 0 ):
34- choices = ("level" , "rise" , "fall" )
35- if not isinstance (trigger , Source .Trigger ) and trigger not in choices :
36- raise ValueError ("Invalid trigger mode {!r}; must be one of {}"
37- .format (trigger , ", " .join (choices )))
38- self .trigger = Source .Trigger (trigger )
39- self ._map = None
40-
41- super ().__init__ ([
42- ("i" , 1 ),
43- ("trg" , 1 ),
44- ], name = name , src_loc_at = 1 + src_loc_at )
105+ def __init__ (self , * , trigger = "level" , path = ()):
106+ super ().__init__ (Source .Signature (trigger = trigger ), path = path )
45107
46- @property
47- def event_map (self ):
48- """Event map.
108+ self ._map = None
49109
50- Return value
51- ------------
52- A :class:`EventMap` describing subordinate event sources.
110+ @ property
111+ def trigger ( self ):
112+ return self . signature . trigger
53113
54- Exceptions
55- ----------
56- Raises :exn:`NotImplementedError` if the source does not have an event map.
57- """
114+ @property
115+ def event_map (self ):
58116 if self ._map is None :
59- raise NotImplementedError ("Event source {!r} does not have an event map"
60- .format (self ))
117+ raise NotImplementedError (f"{ self !r} does not have an event map" )
61118 return self ._map
62119
63120 @event_map .setter
64121 def event_map (self , event_map ):
65122 if not isinstance (event_map , EventMap ):
66- raise TypeError ("Event map must be an instance of EventMap, not {!r}"
67- .format (event_map ))
123+ raise TypeError (f"Event map must be an instance of EventMap, not { event_map !r} " )
68124 event_map .freeze ()
69125 self ._map = event_map
70126
71- # FIXME: get rid of this
72- __hash__ = object . __hash__
127+ def __repr__ ( self ):
128+ return f"event.Source( { self . signature !r } )"
73129
74130
75131class EventMap :
@@ -80,7 +136,7 @@ class EventMap:
80136 increment, starting at 0.
81137 """
82138 def __init__ (self ):
83- self ._sources = OrderedDict ()
139+ self ._sources = dict ()
84140 self ._frozen = False
85141
86142 @property
@@ -117,8 +173,8 @@ def add(self, src):
117173 if not isinstance (src , Source ):
118174 raise TypeError ("Event source must be an instance of event.Source, not {!r}"
119175 .format (src ))
120- if src not in self ._sources :
121- self ._sources [src ] = self .size
176+ if id ( src ) not in self ._sources :
177+ self ._sources [id ( src ) ] = src , self .size
122178
123179 def index (self , src ):
124180 """Get the index corresponding to an event source.
@@ -139,7 +195,8 @@ def index(self, src):
139195 if not isinstance (src , Source ):
140196 raise TypeError ("Event source must be an instance of event.Source, not {!r}"
141197 .format (src ))
142- return self ._sources [src ]
198+ _ , index = self ._sources [id (src )]
199+ return index
143200
144201 def sources (self ):
145202 """Iterate event sources.
@@ -148,8 +205,7 @@ def sources(self):
148205 ------------
149206 A tuple ``src, index`` corresponding to an event source and its index.
150207 """
151- for src , index in self ._sources .items ():
152- yield src , index
208+ yield from self ._sources .values ()
153209
154210
155211class Monitor (Elaboratable ):
@@ -160,7 +216,7 @@ class Monitor(Elaboratable):
160216 Parameters
161217 ----------
162218 event_map : :class:`EventMap`
163- Event map .
219+ A collection of event sources .
164220 trigger : :class:`Source.Trigger`
165221 Trigger mode. See :class:`Source`.
166222
@@ -176,7 +232,7 @@ class Monitor(Elaboratable):
176232 Clear selected pending events.
177233 """
178234 def __init__ (self , event_map , * , trigger = "level" ):
179- self .src = Source (trigger = trigger )
235+ self .src = Source (trigger = trigger , path = ( "src" ,) )
180236 self .src .event_map = event_map
181237
182238 self .enable = Signal (event_map .size )
0 commit comments