arm_dcc/
lib.rs

1//! [Debug Communication Channel][dcc] (DCC) API
2//!
3//! [dcc]: https://developer.arm.com/products/software-development-tools/compilers/arm-compiler-5/docs/dui0471/latest/debug-communications-channel
4//!
5//! # Example
6//!
7//! ## Device side
8//!
9//! ``` no_run
10//! use arm_dcc::dprintln;
11//!
12//! fn main() {
13//!     dprintln!("Hello, world!");
14//! }
15//! ```
16//!
17//! ## Host side
18//!
19//! ``` text
20//! $ # XSDB = Xilinx System Debugger
21//! $ xsdb
22//!
23//! xsdb% # connect
24//! xsdb% conn
25//!
26//! xsdb% # select a Cortex-R core
27//! xsdb% targets -set 0
28//!
29//! xsdb% # hold the processor in reset state
30//! xsdb% rst -processor
31//!
32//! xsdb% # load program
33//! xsdb% dow hello.elf
34//!
35//! xsdb% # open a file
36//! xsdb% set f [open dcc.log w]
37//!
38//! xsdb% # redirect DCC output to file handle `f`
39//! xsdb% readjtaguart -start -handle $f
40//!
41//! xsdb% # start program execution
42//! xsdb% con
43//! ```
44//!
45//! ``` text
46//! $ # on another terminal
47//! $ tail -f dcc.log
48//! Hello, world!
49//! ```
50//!
51//! # Supported Rust version
52//!
53//! - Rust >=1.59
54//!
55//! # Optional features
56//!
57//! ## `nop`
58//!
59//! Turns `dcc::write` into a "no-operation" (not the instruction). This is useful when the DCC is
60//! disabled as `dcc::write` blocks forever in that case.
61
62#![deny(missing_docs)]
63#![no_std]
64
65use core::fmt;
66
67/// Macro for printing to the DCC
68#[macro_export]
69macro_rules! dprint {
70    ($s:expr) => {
71        $crate::write_str($s)
72    };
73    ($($tt:tt)*) => {
74        $crate::write_fmt(format_args!($($tt)*))
75    };
76}
77
78/// Macro for printing to the DCC, with a newline.
79#[macro_export]
80macro_rules! dprintln {
81    () => {
82        $crate::write_str("\n")
83    };
84    ($s:expr) => {
85        $crate::write_str(concat!($s, "\n"))
86    };
87    ($s:expr, $($tt:tt)*) => {
88        $crate::write_fmt(format_args!(concat!($s, "\n"), $($tt)*))
89    };
90}
91
92/// Proxy struct that implements the `fmt::Write`
93///
94/// The main use case for this is using the `write!` macro
95pub struct Writer;
96
97impl fmt::Write for Writer {
98    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
99        write_str(s);
100        Ok(())
101    }
102}
103
104/// Writes a single word to the DCC
105///
106/// **NOTE:** This operation is blocking
107#[allow(unused_variables)]
108#[inline(always)]
109pub fn write(word: u32) {
110    match () {
111        #[cfg(not(target_arch = "arm"))]
112        () => unimplemented!(),
113        #[cfg(all(target_arch = "arm", feature = "nop"))]
114        () => {}
115        #[cfg(all(target_arch = "arm", not(feature = "nop")))]
116        () => {
117            const W: u32 = 1 << 29;
118
119            unsafe {
120                let mut r: u32;
121                loop {
122                    // busy wait until we can send data
123                    core::arch::asm!("MRC p14, 0, {}, c0, c1, 0", out(reg) r);
124                    if r & W == 0 {
125                        break;
126                    }
127                }
128                core::arch::asm!("MCR p14, 0, {}, c0, c5, 0", in(reg) word);
129            }
130        }
131    }
132}
133
134/// Writes the bytes to the DCC
135///
136/// NOTE: each byte will be word-extended before being `write`-n to the DCC
137pub fn write_all(bytes: &[u8]) {
138    bytes.iter().for_each(|byte| write(u32::from(*byte)))
139}
140
141#[doc(hidden)]
142pub fn write_fmt(args: fmt::Arguments) {
143    use core::fmt::Write;
144
145    Writer.write_fmt(args).ok();
146}
147
148/// Writes the string to the DCC
149pub fn write_str(string: &str) {
150    write_all(string.as_bytes())
151}
152
153#[cfg(target_arch = "arm")]
154core::arch::global_asm!(
155    r#"
156    // Routine for putting data in the DCC register
157    .section .text.__dcc_write
158    .global __dcc_write
159__dcc_write:
1601:  mrc     p14, 0, r1, c0, c1, 0
161    tst     r1, #536870912      /* 0x20000000 */
162    bne     1b
163    mcr     p14, 0, r0, c0, c5, 0
164    bx      lr
165    "#
166);