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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
//! Module for interacting with the embedded Trace Memory Controller (TMC)
//!
//! The embedded trace memory controller exposes a means of buffering and storing trace data in
//! on-device SRAM for extraction either via the TPIU or via the debug interface.

use crate::{
    architecture::arm::{
        component::DebugComponentInterface, memory::CoresightComponent, ArmError, ArmProbeInterface,
    },
    memory_mapped_bitfield_register, Error,
};

const REGISTER_OFFSET_RSZ: u32 = 0x04;
const REGISTER_OFFSET_RRD: u32 = 0x10;
const REGISTER_OFFSET_CTL: u32 = 0x20;
const REGISTER_OFFSET_CBUFLVL: u32 = 0x30;

#[repr(u8)]
pub enum Mode {
    /// Trace memory is used as a circular buffer. When the buffer fills, incoming trace data will
    /// overwrite older trace memory until the trace is stopped.
    Circular = 0b00,

    /// The trace memory is used as a FIFO that can be manually read through the RRD register. When
    /// the buffer fills, the incoming trace stream is stalled.
    Software = 0b01,

    /// Trace memory is used as a FIFO that is drained through hardware to the TPIU. Trace data
    /// is captured until the buffer fills, at which point the incoming trace stream is stalled.
    /// Whenever the buffer is non-empty, trace data is drained to the TPIU.
    Hardware = 0b10,
}

/// The embedded trace memory controller.
pub struct TraceMemoryController<'a> {
    component: &'a CoresightComponent,
    interface: &'a mut dyn ArmProbeInterface,
}

impl<'a> TraceMemoryController<'a> {
    /// Construct a new embedded trace fifo controller.
    pub fn new(
        interface: &'a mut dyn ArmProbeInterface,
        component: &'a CoresightComponent,
    ) -> Self {
        Self {
            component,
            interface,
        }
    }

    /// Configure the FIFO operational mode.
    ///
    /// # Args
    /// * `mode` - The desired operational mode of the FIFO.
    pub fn set_mode(&mut self, mode: Mode) -> Result<(), Error> {
        let mut mode_reg = EtfMode::load(self.component, self.interface)?;
        mode_reg.set_mode(mode as _);
        mode_reg.store(self.component, self.interface)?;
        Ok(())
    }

    /// Enable trace captures using the FIFO.
    pub fn enable_capture(&mut self) -> Result<(), Error> {
        self.component
            .write_reg(self.interface, REGISTER_OFFSET_CTL, 1)?;
        Ok(())
    }

    /// Disable trace captures using the FIFO.
    pub fn disable_capture(&mut self) -> Result<(), Error> {
        self.component
            .write_reg(self.interface, REGISTER_OFFSET_CTL, 0)?;
        Ok(())
    }

    /// Attempt to read a value out of the FIFO
    pub fn read(&mut self) -> Result<Option<u32>, ArmError> {
        // Read the RRD register.
        match self
            .component
            .read_reg(self.interface, REGISTER_OFFSET_RRD)?
        {
            // The register has a sentinel value to indicate no more data is available in the FIFO.
            0xFFFF_FFFF => Ok(None),

            value => Ok(Some(value)),
        }
    }

    /// Check if the FIFO is full.
    pub fn full(&mut self) -> Result<bool, Error> {
        let status = Status::load(self.component, self.interface)?;
        Ok(status.full())
    }

    /// Check if the FIFO is empty.
    pub fn empty(&mut self) -> Result<bool, Error> {
        let status = Status::load(self.component, self.interface)?;
        Ok(status.empty())
    }

    /// Check if the ET capture has stopped and all internal pipelines and buffers have been
    /// drained.
    pub fn ready(&mut self) -> Result<bool, Error> {
        let status = Status::load(self.component, self.interface)?;
        Ok(status.ready())
    }

    /// Check if the ETF has triggered.
    ///
    /// # Note
    /// This will only be set when operating in circular buffer modes.
    pub fn triggered(&mut self) -> Result<bool, Error> {
        let status = Status::load(self.component, self.interface)?;
        Ok(status.trigd())
    }

    /// Get the current number of bytes within the FIFO.
    ///
    /// # Note
    /// This will always return zero if the capture is disabled.
    pub fn fill_level(&mut self) -> Result<u32, Error> {
        let level = self
            .component
            .read_reg(self.interface, REGISTER_OFFSET_CBUFLVL)?;
        Ok(level * core::mem::size_of::<u32>() as u32)
    }

    /// Configure the capture stop-on-flush semantics.
    ///
    /// # Args
    /// * `stop` - Specified true if the capture should stop on flush events.
    pub fn stop_on_flush(&mut self, stop: bool) -> Result<(), Error> {
        let mut ffcr = FormatFlushControl::load(self.component, self.interface)?;
        ffcr.set_stoponfl(stop);
        ffcr.store(self.component, self.interface)?;
        Ok(())
    }

    /// Generate a manual flush event.
    pub fn manual_flush(&mut self) -> Result<(), Error> {
        let mut ffcr = FormatFlushControl::load(self.component, self.interface)?;
        ffcr.set_flushman(true);
        ffcr.store(self.component, self.interface)?;
        Ok(())
    }

    /// Get the size of the FIFO in bytes.
    pub fn fifo_size(&mut self) -> Result<u32, ArmError> {
        let size_words = self
            .component
            .read_reg(self.interface, REGISTER_OFFSET_RSZ)?;
        Ok(size_words * core::mem::size_of::<u32>() as u32)
    }
}

memory_mapped_bitfield_register! {
    pub struct FormatFlushControl(u32);
    0x304, "ETF_FFCR",
    impl From;

    pub drainbuf, set_drainbuf: 14;
    pub stpontrgev, set_stpontrgev: 13;
    pub stoponfl, set_stoponfl: 12;
    pub trigonfl, set_trigonfl: 10;
    pub trgontrgev, set_trgontrgev: 9;
    pub flushman, set_flushman: 6;
    pub fontrgev, set_fontrgev: 5;
    pub fonflin, set_flonflin: 4;
    pub enti, set_enti: 1;
    pub enft, set_enft: 0;
}

impl DebugComponentInterface for FormatFlushControl {}

memory_mapped_bitfield_register! {
    pub struct Status(u32);
    0xC, "ETF_STS",
    impl From;

    pub empty, _: 4;
    pub ftempty, _: 3;
    pub ready, _: 2;
    pub trigd, _: 1;
    pub full, _: 0;
}

impl DebugComponentInterface for Status {}

memory_mapped_bitfield_register! {
    pub struct EtfMode(u32);
    0x28, "ETF_MODE",
    impl From;

    // The Mode register configures the operational mode of the FIFO.
    pub u8, mode, set_mode: 1, 0;
}

impl DebugComponentInterface for EtfMode {}

/// Trace ID (a.k.a. ATID or trace source ID)
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Id(u8);
impl From<u8> for Id {
    fn from(id: u8) -> Self {
        Self(id)
    }
}
impl From<Id> for u8 {
    fn from(id: Id) -> Self {
        id.0
    }
}

/// Formatted frame demultiplexer.
/// Takes a reference to a 16 byte frame from the ETB/ETF or TPIU and
/// reads source ID and bytes from it.
#[derive(Copy, Clone, Debug)]
pub struct Frame<'a> {
    data: &'a [u8],
    idx: usize,
    id: Id,
}

impl<'a> Frame<'a> {
    pub fn new(data: &'a [u8], id: Id) -> Self {
        assert!(data.len() == 16);
        Self { data, id, idx: 0 }
    }

    pub fn id(&self) -> Id {
        self.id
    }

    pub fn rewind(&mut self) {
        self.idx = 0;
    }
}

impl<'a> Iterator for &mut Frame<'a> {
    type Item = (Id, u8);

    fn next(&mut self) -> Option<Self::Item> {
        // DDI0314H_coresight_components_trm (ARM DDI 0314H) 9.6.1,
        // US20050039078A1,
        // and others
        if self.idx >= 15 {
            return None;
        }
        let byte = self.data[self.idx];
        let lsb = (self.data[15] >> (self.idx >> 1)) & 1;
        let ret = if self.idx & 1 != 0 {
            // Odd indices of the frame always contain data associated with the previous ID.
            Some((self.id, byte))
        } else if byte & 1 == 0 {
            // Even bytes utilize the LSbit to indicate if they contain an ID or data. For a cleared LSbit, data is
            // contained and the correct LSbit is stored at the end of the frame.
            Some((self.id, byte | lsb))
        } else {
            // Even bytes may also contain a new ID to swap to. In this case, the LSbit contained at the end of the
            // frame is used to indicate if the following data uses the new or old ID.
            let new_id = (byte >> 1).into();
            let next_id = if lsb == 1 { self.id } else { new_id };
            self.id = new_id;
            if self.idx >= 14 {
                None
            } else {
                self.idx += 1;
                Some((next_id, self.data[self.idx]))
            }
        };
        self.idx += 1;
        ret
    }
}