1#[cfg(feature = "trace")]
22mod imp {
23 pub const SYNC0: u8 = 0xA5;
24 pub const SYNC1: u8 = 0x5A;
25 pub const PROTOCOL_VERSION: u8 = 1;
26 pub const NO_TASK: u32 = u32::MAX;
27 pub const MAX_PAYLOAD: usize = 32;
28 pub const FRAME_OVERHEAD: usize = 2 + 1 + 2 + 2 + 1 + 4 + 8 + 1 + 2;
29 pub const MAX_FRAME: usize = FRAME_OVERHEAD + MAX_PAYLOAD;
30
31 pub fn crc16(data: &[u8]) -> u16 {
32 let mut crc: u16 = 0xFFFF;
33 for &byte in data {
34 crc ^= (byte as u16) << 8;
35 for _ in 0..8 {
36 if crc & 0x8000 != 0 {
37 crc = (crc << 1) ^ 0x1021;
38 } else {
39 crc <<= 1;
40 }
41 }
42 }
43 crc
44 }
45
46 use core::sync::atomic::{AtomicU16, Ordering};
47 static SEQ: AtomicU16 = AtomicU16::new(0);
48
49 pub fn encode(
52 buf: &mut [u8; MAX_FRAME],
53 kind: u16,
54 core_id: u8,
55 task_id: u32,
56 timestamp: u64,
57 payload: &[u8],
58 ) -> usize {
59 debug_assert!(payload.len() <= MAX_PAYLOAD);
60 let seq = SEQ.fetch_add(1, Ordering::Relaxed);
61 buf[0] = SYNC0;
62 buf[1] = SYNC1;
63 buf[2] = PROTOCOL_VERSION;
64 buf[3..5].copy_from_slice(&seq.to_le_bytes());
65 buf[5..7].copy_from_slice(&kind.to_le_bytes());
66 buf[7] = core_id;
67 buf[8..12].copy_from_slice(&task_id.to_le_bytes());
68 buf[12..20].copy_from_slice(×tamp.to_le_bytes());
69 buf[20] = payload.len() as u8;
70 buf[21..21 + payload.len()].copy_from_slice(payload);
71 let crc_end = 21 + payload.len();
72 let crc = crc16(&buf[0..crc_end]);
73 buf[crc_end..crc_end + 2].copy_from_slice(&crc.to_le_bytes());
74 crc_end + 2
75 }
76
77 pub fn now_ts() -> u64 {
78 crate::port::board::now_us()
79 }
80
81 pub fn core_id() -> u8 {
82 crate::port::arch::hart_id() as u8
83 }
84}
85
86#[cfg(feature = "trace")]
87use imp::*;
88
89#[cfg(feature = "trace")]
94mod kind {
95 pub const STREAM_HEADER: u16 = 0x0701;
96 pub const TASK_CREATED: u16 = 0x0001;
97 pub const CONTEXT_SWITCH: u16 = 0x0009;
98 pub const IRQ_ENTER: u16 = 0x0301;
99 pub const IRQ_EXIT: u16 = 0x0302;
100 pub const MUTEX_LOCK_ACQUIRED: u16 = 0x0102;
101 pub const MUTEX_UNLOCK: u16 = 0x0104;
102 pub const PRIORITY_INHERIT: u16 = 0x0105;
103 pub const HARD_FAULT: u16 = 0x0601;
104 pub const STACK_OVERFLOW: u16 = 0x0605;
105}
106
107#[cfg(feature = "trace")]
110#[derive(Clone, Copy)]
111pub enum SwitchReason {
112 Preempted = 0,
113 TimerWake = 6,
114}
115
116#[cfg(feature = "trace")]
120static CACHED_CPU_HZ: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
121#[cfg(feature = "trace")]
122static CACHED_MAX_HARTS: core::sync::atomic::AtomicU8 = core::sync::atomic::AtomicU8::new(0);
123
124#[cfg(feature = "trace")]
128pub fn stream_header(cpu_hz: u32, max_harts: u8) {
129 use core::sync::atomic::Ordering;
130 CACHED_CPU_HZ.store(cpu_hz, Ordering::Relaxed);
131 CACHED_MAX_HARTS.store(max_harts, Ordering::Relaxed);
132 let mut payload = [0u8; 8];
133 payload[0] = 0; payload[1] = 1;
135 payload[2] = 0;
136 payload[3..7].copy_from_slice(&cpu_hz.to_le_bytes());
137 payload[7] = max_harts;
138 let mut buf = [0u8; MAX_FRAME];
139 let n = encode(&mut buf, kind::STREAM_HEADER, core_id(), NO_TASK, now_ts(), &payload);
140 crate::port::board::trace_write(&buf[..n]);
141}
142
143#[cfg(feature = "trace")]
150pub fn reannounce_stream_header() {
151 use core::sync::atomic::Ordering;
152 let cpu_hz = CACHED_CPU_HZ.load(Ordering::Relaxed);
153 if cpu_hz == 0 {
154 return;
155 }
156 stream_header(cpu_hz, CACHED_MAX_HARTS.load(Ordering::Relaxed));
157}
158
159#[cfg(feature = "trace")]
164pub fn task_created(task_id: u16, priority: u8, stack_size: u32) {
165 let mut payload = [0u8; 5];
166 payload[0] = priority;
167 payload[1..5].copy_from_slice(&stack_size.to_le_bytes());
168 let mut buf = [0u8; MAX_FRAME];
169 let n = encode(
170 &mut buf,
171 kind::TASK_CREATED,
172 core_id(),
173 task_id as u32,
174 now_ts(),
175 &payload,
176 );
177 crate::port::board::trace_write(&buf[..n]);
178}
179
180#[cfg(feature = "trace")]
184pub fn context_switch(prev_task: u16, next_task: u16, reason: SwitchReason) {
185 let mut payload = [0u8; 9];
186 payload[0..4].copy_from_slice(&(prev_task as u32).to_le_bytes());
187 payload[4..8].copy_from_slice(&(next_task as u32).to_le_bytes());
188 payload[8] = reason as u8;
189 let mut buf = [0u8; MAX_FRAME];
190 let n = encode(
191 &mut buf,
192 kind::CONTEXT_SWITCH,
193 core_id(),
194 next_task as u32,
195 now_ts(),
196 &payload,
197 );
198 crate::port::board::trace_write(&buf[..n]);
199}
200
201#[cfg(feature = "trace")]
203pub fn isr(irq: u32, entry: bool) {
204 let mut payload = [0u8; 4];
205 payload.copy_from_slice(&irq.to_le_bytes());
206 let mut buf = [0u8; MAX_FRAME];
207 let k = if entry { kind::IRQ_ENTER } else { kind::IRQ_EXIT };
208 let n = encode(&mut buf, k, core_id(), NO_TASK, now_ts(), &payload);
209 crate::port::board::trace_write(&buf[..n]);
210}
211
212#[cfg(feature = "trace")]
214pub fn mutex_lock_acquired(task_id: u16, mutex_id: u32) {
215 let mut payload = [0u8; 4];
216 payload.copy_from_slice(&mutex_id.to_le_bytes());
217 let mut buf = [0u8; MAX_FRAME];
218 let n = encode(
219 &mut buf,
220 kind::MUTEX_LOCK_ACQUIRED,
221 core_id(),
222 task_id as u32,
223 now_ts(),
224 &payload,
225 );
226 crate::port::board::trace_write(&buf[..n]);
227}
228
229#[cfg(feature = "trace")]
231pub fn mutex_unlock(task_id: u16, mutex_id: u32) {
232 let mut payload = [0u8; 4];
233 payload.copy_from_slice(&mutex_id.to_le_bytes());
234 let mut buf = [0u8; MAX_FRAME];
235 let n = encode(&mut buf, kind::MUTEX_UNLOCK, core_id(), task_id as u32, now_ts(), &payload);
236 crate::port::board::trace_write(&buf[..n]);
237}
238
239#[cfg(feature = "trace")]
242pub fn priority_inherit(task_id: u16, mutex_id: u32) {
243 let mut payload = [0u8; 4];
244 payload.copy_from_slice(&mutex_id.to_le_bytes());
245 let mut buf = [0u8; MAX_FRAME];
246 let n = encode(
247 &mut buf,
248 kind::PRIORITY_INHERIT,
249 core_id(),
250 task_id as u32,
251 now_ts(),
252 &payload,
253 );
254 crate::port::board::trace_write(&buf[..n]);
255}
256
257#[cfg(feature = "trace")]
261pub fn fault(task_id: u16, reason: u8, pc: u32) {
262 let mut payload = [0u8; 8];
263 payload[0..4].copy_from_slice(&(reason as u32).to_le_bytes());
264 payload[4..8].copy_from_slice(&pc.to_le_bytes());
265 let mut buf = [0u8; MAX_FRAME];
266 let k = if reason == 4 { kind::STACK_OVERFLOW } else { kind::HARD_FAULT };
267 let n = encode(&mut buf, k, core_id(), task_id as u32, now_ts(), &payload);
268 crate::port::board::trace_write(&buf[..n]);
269}
270
271#[cfg(feature = "trace")]
282pub fn reannounce_all_tasks() {
283 use crate::preempt::tcb;
284 use core::sync::atomic::Ordering;
285 for id in 0..tcb::MAX_PTASKS {
286 let Some(t) = tcb::get(id) else { continue };
287 if !t.used.load(Ordering::Acquire) {
288 continue;
289 }
290 let priority = t.base_priority.load(Ordering::Acquire);
291 let stack_size = t.stack_size.load(Ordering::Acquire) as u32;
292 task_created(id as u16, priority, stack_size);
293 }
294}