litex/
event_manager.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! LiteX Event Manager
//!
//! Documentation on the different LiteX event source, which all
//! behave differently, can be found in the LiteX repository under
//! [`litex/soc/interconnect/csr_eventmanager.py`](https://github.com/enjoy-digital/litex/blob/master/litex/soc/interconnect/csr_eventmanager.py).

use crate::litex_registers::{Read, ReadWrite, UIntLike};
use core::marker::PhantomData;

/// LiteX event manager abstraction
///
/// A LiteX event manager combines and manages event sources of a
/// LiteX core / peripheral. The event manager itself is connected to
/// an interrupt source in the CPU.
///
/// This is an abstraction over an instance of a LiteX EventManager,
/// which is exposed to the operating system using three configuration
/// status registers (LiteX CSRs), as part of the core's /
/// peripheral's configuration status registers bank.
pub struct LiteXEventManager<'a, T, S, P, E>
where
    T: UIntLike,
    S: Read<T>,
    P: ReadWrite<T>,
    E: ReadWrite<T>,
{
    status: &'a S,
    pending: &'a P,
    enable: &'a E,
    _base_type: PhantomData<T>,
}

impl<'a, T, S, P, E> LiteXEventManager<'a, T, S, P, E>
where
    T: UIntLike,
    S: Read<T>,
    P: ReadWrite<T>,
    E: ReadWrite<T>,
{
    pub const fn new(status: &'a S, pending: &'a P, enable: &'a E) -> Self {
        LiteXEventManager {
            status,
            pending,
            enable,
            _base_type: PhantomData,
        }
    }

    /// Disable / suppress all event sources connected to the LiteX
    /// event manager.
    ///
    /// This will prevent any of the event sources from asserting the
    /// event manager's CPU interrupt.
    pub fn disable_all(&self) {
        self.enable.set(T::zero());
    }

    /// Enable all event sources connected to the LiteX
    /// event manager.
    ///
    /// This will make any asserted (pending) event source assert the
    /// event manager's CPU interrupt.
    pub fn enable_all(&self) {
        self.enable.set(T::max());
    }

    /// Disable / suppress an event source connected to the LiteX
    /// event manager.
    ///
    /// This will prevent the specific event source from asserting the
    /// event manager's CPU interrupt.
    ///
    /// The event is addressed by its index in the event manager's
    /// registers (starting at 0).
    pub fn disable_event(&self, index: usize) {
        self.enable.set(self.enable.get() & !(T::one() << index));
    }

    /// Enable an event source connected to the LiteX event manager
    ///
    /// This will assert the event manager's CPU interrupt if this or
    /// any other event source is asserted (pending).
    ///
    /// The event is addressed by its index in the event manager's
    /// registers (starting at 0).
    pub fn enable_event(&self, index: usize) {
        self.enable.set(self.enable.get() | (T::one() << index));
    }

    /// Check whether an event is enabled.
    ///
    /// This checks whether an event source may assert the event
    /// manager's CPU interrupt.
    ///
    /// The event is addressed by its index in the event manager's
    /// registers (starting at 0).
    pub fn event_enabled(&self, index: usize) -> bool {
        self.enable.get() & (T::one() << index) != T::zero()
    }

    /// Get all enabled events.
    ///
    /// The enabled events are encoded as bits in the returned integer
    /// type, starting from the least significant bit for the first
    /// event source (index 0), where a `1` means enabled and `0`
    /// means disabled (suppressed).
    pub fn events_enabled(&self) -> T {
        self.enable.get()
    }

    /// Get the input signal to an event source.
    ///
    /// This returns whether an event source input is currently
    /// asserted. This is independent of whether the event is actually
    /// enabled or pending.
    ///
    /// The event source is addressed by its index in the event
    /// manager's registers (starting at 0).
    pub fn event_source_input(&self, index: usize) -> bool {
        self.status.get() & (T::one() << index) != T::zero()
    }

    /// Check whether any event source is pending.
    ///
    /// This returns whether any event source is claiming to be
    /// pending. This is irrespective of whether an event source has a
    /// specific input or is enabled.
    ///
    /// An example for an event source which can be pending
    /// irrespective of the current input is an "EventSourceProcess",
    /// which triggers on a falling edge of the input and stays
    /// pending until cleared.
    pub fn any_event_pending(&self) -> bool {
        self.pending.get() != T::zero()
    }

    /// Check whether an event source is pending.
    ///
    /// This returns whether an event source is claiming to be
    /// pending. This is irrespective of whether an event source has a
    /// specific input or is enabled.
    ///
    /// An example for an event source which can be pending
    /// irrespective of the current input is an "EventSourceProcess",
    /// which triggers on a falling edge of the input and stays
    /// pending until cleared.
    ///
    /// The event source is addressed by its index in the event
    /// manager's registers (starting at 0).
    pub fn event_pending(&self, index: usize) -> bool {
        self.pending.get() & (T::one() << index) != T::zero()
    }

    /// Get all pending events.
    ///
    /// The pending events are encoded as bits in the returned integer
    /// type, starting from the least significant bit for the first
    /// event source (index 0), where a `1` means that the event
    /// source is pending.
    pub fn events_pending(&self) -> T {
        self.pending.get()
    }

    /// Check whether an event source is asserting the event manager's
    /// CPU interrupt (both enabled and pending).
    ///
    ///
    /// The event source is addressed by its index in the event
    /// manager's registers (starting at 0).
    pub fn event_asserted(&self, index: usize) -> bool {
        self.event_enabled(index) && self.event_pending(index)
    }

    /// Get the next asserted event, starting from 0.
    ///
    /// If an asserted event was found, its index is returned. Otherwise, None
    /// is returned.
    ///
    /// This method works by ANDing the enabled and pending bits and using the
    /// trailing_zeros intrinsic (of which there may be an optimized version
    /// with special instructions). Thus this is faster than a naive, loop-based
    /// version.
    pub fn next_asserted(&self) -> Option<usize> {
        let ev_bits = core::mem::size_of::<T>() * 8;
        let enabled = self.events_enabled();
        let pending = self.events_pending();
        let asserted = enabled & pending;

        // If there are no interrupts pending (asserted == 0), T::trailing_zeros
        // will return the number of bits in T, in which case we need to return
        // None.
        let trailing_zeros = T::trailing_zeros(asserted) as usize;
        if trailing_zeros == ev_bits {
            None
        } else {
            Some(trailing_zeros)
        }
    }

    /// Clear a pending event source.
    ///
    /// This operation may have side effects in the device (for
    /// instance, acknowledge the reception of a UART data word).
    ///
    /// It is not guaranteed that the event source will be no longer
    /// pending after clearing (for instance when used with FIFOs and
    /// pending data, or with an "EventSourceLevel" which can only be
    /// cleared by driving the input signal low).
    pub fn clear_event(&self, index: usize) {
        self.pending.set(T::one() << index);
    }

    /// Clear all pending event sources.
    ///
    /// This operation may have side effects in the device (for
    /// instance, acknowledge the reception of a UART data word).
    ///
    /// It is not guaranteed that the event sources will be no longer
    /// pending after clearing (for instance when used with FIFOs and
    /// pending data, or with an "EventSourceLevel" which can only be
    /// cleared by driving the input signal low).
    pub fn clear_all(&self) {
        self.pending.set(T::max());
    }
}