1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2016-2019 Tim 'mithro' Ansell <me@mith.ro>
6 The event manager provides a systematic way to generate standard interrupt
10 from functools
import reduce
11 from operator
import or_
14 from migen
.util
.misc
import xdir
15 from migen
.fhdl
.tracer
import get_obj_var_name
17 from litex
.soc
.interconnect
.csr
import *
20 class _EventSource(DUID
):
21 """Base class for EventSources.
25 trigger : Signal(), in
26 Signal which interfaces with the user design.
28 status : Signal(), out
29 Contains the current level of the trigger signal.
30 This value ends up in the ``status`` register.
32 pending : Signal(), out
33 A trigger event has occurred and not yet cleared.
34 This value ends up in the ``pending`` register.
37 Clear after a trigger event.
38 Ignored by some event sources.
41 A short name for this EventSource, usable as a Python identifier
44 A formatted description of this EventSource, including when
45 it will fire and how it behaves.
48 def __init__(self
, name
=None, description
=None):
50 self
.status
= Signal()
51 self
.pending
= Signal()
52 self
.trigger
= Signal()
54 self
.name
= get_obj_var_name(name
)
55 self
.description
= description
58 class EventSourcePulse(Module
, _EventSource
):
59 """EventSource which triggers on a pulse.
61 The event stays asserted after the ``trigger`` signal goes low, and until
62 software acknowledges it.
64 An example use is to pulse ``trigger`` high for 1 cycle after the reception
65 of a character in a UART.
68 def __init__(self
, name
=None, description
=None):
69 _EventSource
.__init
__(self
, name
, description
)
70 self
.comb
+= self
.status
.eq(0)
72 If(self
.clear
, self
.pending
.eq(0)),
73 If(self
.trigger
, self
.pending
.eq(1))
77 class EventSourceProcess(Module
, _EventSource
):
78 """EventSource which triggers on a falling edge.
80 The purpose of this event source is to monitor the status of processes and
81 generate an interrupt on their completion.
83 def __init__(self
, name
=None, description
=None):
84 _EventSource
.__init
__(self
, name
, description
)
85 self
.comb
+= self
.status
.eq(self
.trigger
)
86 old_trigger
= Signal()
88 If(self
.clear
, self
.pending
.eq(0)),
89 old_trigger
.eq(self
.trigger
),
90 If(~self
.trigger
& old_trigger
, self
.pending
.eq(1))
94 class EventSourceLevel(Module
, _EventSource
):
95 """EventSource which trigger contains the instantaneous state of the event.
97 It must be set and released by the user design. For example, a DMA
98 controller with several slots can use this event source to signal that one
99 or more slots require CPU attention.
101 def __init__(self
, name
=None, description
=None):
102 _EventSource
.__init
__(self
, name
, description
)
104 self
.status
.eq(self
.trigger
),
105 self
.pending
.eq(self
.trigger
)
109 class EventManager(Module
, AutoCSR
):
110 """Provide an IRQ and CSR registers for a set of event sources.
112 Each event source is assigned one bit in each of those registers.
117 A signal which is driven high whenever there is a pending and unmasked
119 It is typically connected to an interrupt line of a CPU.
121 status : CSR(n), read-only
122 Contains the current level of the trigger line of
123 ``EventSourceProcess`` and ``EventSourceLevel`` sources.
124 It is always 0 for ``EventSourcePulse``
126 pending : CSR(n), read-write
127 Contains the currently asserted events. Writing 1 to the bit assigned
128 to an event clears it.
130 enable : CSR(n), read-write
131 Defines which asserted events will cause the ``irq`` line to be
138 def do_finalize(self
):
139 sources_u
= [v
for k
, v
in xdir(self
, True) if isinstance(v
, _EventSource
)]
140 sources
= sorted(sources_u
, key
=lambda x
: x
.duid
)
143 self
.pending
= CSR(n
)
144 self
.enable
= CSRStorage(n
)
146 for i
, source
in enumerate(sources
):
148 self
.status
.w
[i
].eq(source
.status
),
149 If(self
.pending
.re
& self
.pending
.r
[i
], source
.clear
.eq(1)),
150 self
.pending
.w
[i
].eq(source
.pending
)
153 irqs
= [self
.pending
.w
[i
] & self
.enable
.storage
[i
] for i
in range(n
)]
154 self
.comb
+= self
.irq
.eq(reduce(or_
, irqs
))
156 def __setattr__(self
, name
, value
):
157 object.__setattr
__(self
, name
, value
)
158 if isinstance(value
, _EventSource
):
161 self
.submodules
+= value
164 class SharedIRQ(Module
):
165 """Allow an IRQ signal to be shared between multiple EventManager objects."""
167 def __init__(self
, *event_managers
):
169 self
.comb
+= self
.irq
.eq(reduce(or_
, [ev
.irq
for ev
in event_managers
]))