1
- import enum
2
- from collections import OrderedDict
3
-
4
1
from amaranth import *
2
+ from amaranth .lib import enum , wiring
3
+ from amaranth .lib .wiring import In , Out
5
4
6
5
7
6
__all__ = ["Source" , "EventMap" , "Monitor" ]
8
7
9
8
10
- class Source (Record ):
9
+ class Source (wiring . Interface ):
11
10
class Trigger (enum .Enum ):
12
11
"""Event trigger mode."""
13
12
LEVEL = "level"
14
13
RISE = "rise"
15
14
FALL = "fall"
16
15
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
+
17
87
"""Event source interface.
18
88
19
89
Parameters
20
90
----------
21
- trigger : :class:`Trigger`
91
+ trigger : :class:`Source. Trigger`
22
92
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` .
25
95
26
96
Attributes
27
97
----------
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`.
32
104
"""
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 )
45
107
46
- @property
47
- def event_map (self ):
48
- """Event map.
108
+ self ._map = None
49
109
50
- Return value
51
- ------------
52
- A :class:`EventMap` describing subordinate event sources.
110
+ @ property
111
+ def trigger ( self ):
112
+ return self . signature . trigger
53
113
54
- Exceptions
55
- ----------
56
- Raises :exn:`NotImplementedError` if the source does not have an event map.
57
- """
114
+ @property
115
+ def event_map (self ):
58
116
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" )
61
118
return self ._map
62
119
63
120
@event_map .setter
64
121
def event_map (self , event_map ):
65
122
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} " )
68
124
event_map .freeze ()
69
125
self ._map = event_map
70
126
71
- # FIXME: get rid of this
72
- __hash__ = object . __hash__
127
+ def __repr__ ( self ):
128
+ return f"event.Source( { self . signature !r } )"
73
129
74
130
75
131
class EventMap :
@@ -80,7 +136,7 @@ class EventMap:
80
136
increment, starting at 0.
81
137
"""
82
138
def __init__ (self ):
83
- self ._sources = OrderedDict ()
139
+ self ._sources = dict ()
84
140
self ._frozen = False
85
141
86
142
@property
@@ -117,8 +173,8 @@ def add(self, src):
117
173
if not isinstance (src , Source ):
118
174
raise TypeError ("Event source must be an instance of event.Source, not {!r}"
119
175
.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
122
178
123
179
def index (self , src ):
124
180
"""Get the index corresponding to an event source.
@@ -139,7 +195,8 @@ def index(self, src):
139
195
if not isinstance (src , Source ):
140
196
raise TypeError ("Event source must be an instance of event.Source, not {!r}"
141
197
.format (src ))
142
- return self ._sources [src ]
198
+ _ , index = self ._sources [id (src )]
199
+ return index
143
200
144
201
def sources (self ):
145
202
"""Iterate event sources.
@@ -148,8 +205,7 @@ def sources(self):
148
205
------------
149
206
A tuple ``src, index`` corresponding to an event source and its index.
150
207
"""
151
- for src , index in self ._sources .items ():
152
- yield src , index
208
+ yield from self ._sources .values ()
153
209
154
210
155
211
class Monitor (Elaboratable ):
@@ -160,7 +216,7 @@ class Monitor(Elaboratable):
160
216
Parameters
161
217
----------
162
218
event_map : :class:`EventMap`
163
- Event map .
219
+ A collection of event sources .
164
220
trigger : :class:`Source.Trigger`
165
221
Trigger mode. See :class:`Source`.
166
222
@@ -176,7 +232,7 @@ class Monitor(Elaboratable):
176
232
Clear selected pending events.
177
233
"""
178
234
def __init__ (self , event_map , * , trigger = "level" ):
179
- self .src = Source (trigger = trigger )
235
+ self .src = Source (trigger = trigger , path = ( "src" ,) )
180
236
self .src .event_map = event_map
181
237
182
238
self .enable = Signal (event_map .size )
0 commit comments