Skip to main content

probe_rs_target/
chip.rs

1use std::collections::HashMap;
2
3use super::memory::MemoryRegion;
4use crate::{
5    CoreType,
6    serialize::{hex_option, hex_u_int},
7};
8use serde::{Deserialize, Serialize};
9
10/// Represents a DAP scan chain element.
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct ScanChainElement {
13    /// Unique name of the DAP
14    pub name: Option<String>,
15    /// Specifies the IR length of the DAP (default value: 4).
16    pub ir_len: Option<u8>,
17}
18
19impl ScanChainElement {
20    /// Returns the IR length, or 4 if not specified.
21    pub fn ir_len(&self) -> u8 {
22        self.ir_len.unwrap_or(4)
23    }
24}
25
26/// Configuration for JTAG tunneling.
27///
28/// This JTAG tunnel wraps JTAG IR and DR accesses as DR access to a specific instruction. For
29/// example, this can be used to access a Risc-V core in an FPGA using the same JTAG cable that
30/// configures the FPGA.
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
32pub struct RiscvJtagTunnel {
33    /// JTAG instruction used to tunnel
34    pub ir_id: u32,
35
36    /// Width of tunneled JTAG instruction register
37    pub ir_width: u32,
38}
39
40/// Configuration for JTAG probes.
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
42pub struct Jtag {
43    /// Describes the scan chain
44    ///
45    /// ref: `<https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/sdf_pg.html#sdf_element_scanchain>`
46    #[serde(default)]
47    pub scan_chain: Option<Vec<ScanChainElement>>,
48
49    /// When set to `true`, the scan chain described in `scan_chain` is used as-is, bypassing
50    /// the JTAG auto-detection (DR/IR scan). This is required for targets whose JTAG TAP does
51    /// not respond to the standard IDCODE scan (e.g., some RISC-V cores during early power-up).
52    ///
53    /// When `false` (the default), `scan_chain` is treated as a hint for IR-length disambiguation
54    /// during the normal auto-detection scan.
55    #[serde(default)]
56    pub force_scan_chain: bool,
57
58    /// Describes JTAG tunnel for Risc-V
59    #[serde(default)]
60    pub riscv_tunnel: Option<RiscvJtagTunnel>,
61}
62
63/// A single chip variant.
64///
65/// This describes an exact chip variant, including the cores, flash and memory size. For example,
66/// the `nRF52832` chip has two variants, `nRF52832_xxAA` and `nRF52832_xxBB`. For this case,
67/// the struct will correspond to one of the variants, e.g. `nRF52832_xxAA`.
68#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(deny_unknown_fields)]
70pub struct Chip {
71    /// This is the name of the chip in base form.
72    /// E.g. `nRF52832`.
73    pub name: String,
74    /// The `PART` register of the chip.
75    /// This value can be determined via the `cli info` command.
76    pub part: Option<u16>,
77    /// An URL to the SVD file for this chip.
78    pub svd: Option<String>,
79    /// Documentation URLs associated with this chip.
80    #[serde(default)]
81    pub documentation: HashMap<String, String>,
82    /// The package variants available for this chip.
83    ///
84    /// If empty, the chip is assumed to have only one package variant.
85    #[serde(default)]
86    pub package_variants: Vec<String>,
87    /// The cores available on the chip.
88    #[serde(default)]
89    pub cores: Vec<Core>,
90    /// The memory regions available on the chip.
91    pub memory_map: Vec<MemoryRegion>,
92    /// Names of all flash algorithms available for this chip.
93    ///
94    /// This can be used to look up the flash algorithm in the
95    /// [`ChipFamily::flash_algorithms`] field.
96    ///
97    /// [`ChipFamily::flash_algorithms`]: crate::ChipFamily::flash_algorithms
98    #[serde(default)]
99    pub flash_algorithms: Vec<String>,
100    /// Specific memory ranges to search for a dynamic RTT header for code
101    /// running on this chip.
102    ///
103    /// This need not be specified for most chips because the default is
104    /// to search all RAM regions specified in `memory_map`. However,
105    /// that behavior isn't appropriate for some chips, such as those which
106    /// have a very large amount of RAM that would be time-consuming to
107    /// scan exhaustively.
108    ///
109    /// If specified then this is a list of zero or more address ranges to
110    /// scan. Each address range must be enclosed in exactly one RAM region
111    /// from `memory_map`. An empty list disables automatic scanning
112    /// altogether, in which case RTT will be enabled only when using an
113    /// executable image that includes the `_SEGGER_RTT` symbol pointing
114    /// to the exact address of the RTT header.
115    pub rtt_scan_ranges: Option<Vec<std::ops::Range<u64>>>,
116    /// JTAG-specific options
117    #[serde(default)]
118    pub jtag: Option<Jtag>,
119    /// The default binary format for this chip
120    // TODO: rename to default_platform
121    #[serde(default)]
122    pub default_binary_format: Option<String>,
123}
124
125impl Chip {
126    /// Create a generic chip with the given name, a single core,
127    /// and no flash algorithm or memory map. Used to create
128    /// generic targets.
129    pub fn generic_arm(name: &str, core_type: CoreType) -> Self {
130        Chip {
131            name: name.to_string(),
132            part: None,
133            svd: None,
134            documentation: HashMap::new(),
135            package_variants: vec![],
136            cores: vec![Core {
137                name: "main".to_string(),
138                core_type,
139                core_access_options: CoreAccessOptions::Arm(ArmCoreAccessOptions::default()),
140            }],
141            memory_map: vec![],
142            flash_algorithms: vec![],
143            rtt_scan_ranges: None,
144            jtag: None,
145            default_binary_format: None,
146        }
147    }
148
149    /// Returns the package variants for this chip.
150    pub fn package_variants(&self) -> impl Iterator<Item = &String> {
151        std::slice::from_ref(&self.name)
152            .iter()
153            .chain(self.package_variants.iter())
154    }
155}
156
157/// An individual core inside a chip
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct Core {
160    /// The core name.
161    pub name: String,
162
163    /// The core type.
164    /// E.g. `M0` or `M4`.
165    #[serde(rename = "type")]
166    pub core_type: CoreType,
167
168    /// The AP number to access the core
169    pub core_access_options: CoreAccessOptions,
170}
171
172/// The data required to access a core
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub enum CoreAccessOptions {
175    /// ARM specific options
176    Arm(ArmCoreAccessOptions),
177    /// RISC-V specific options
178    Riscv(RiscvCoreAccessOptions),
179    /// Xtensa specific options
180    Xtensa(XtensaCoreAccessOptions),
181}
182
183/// An address for AP accesses
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub enum ApAddress {
186    /// References an address for an APv1 access, which is part of the ADIv5 specification.
187    #[serde(rename = "v1")]
188    V1(u8),
189    /// References an address for an APv2 access, which is part of the ADIv6 specification.
190    ///
191    /// # Note
192    /// This represents a base address within the root DP memory space.
193    #[serde(rename = "v2")]
194    #[serde(serialize_with = "hex_u_int")]
195    V2(u64),
196}
197
198impl Default for ApAddress {
199    fn default() -> Self {
200        ApAddress::V1(0)
201    }
202}
203
204/// The data required to access an ARM core
205#[derive(Debug, Clone, Serialize, Deserialize, Default)]
206#[serde(deny_unknown_fields)]
207pub struct ArmCoreAccessOptions {
208    /// The access port number to access the core
209    pub ap: ApAddress,
210    /// The TARGETSEL value used to access the core
211    #[serde(serialize_with = "hex_option")]
212    pub targetsel: Option<u32>,
213    /// The base address of the debug registers for the core.
214    /// Required for Cortex-A, optional for Cortex-M
215    #[serde(serialize_with = "hex_option")]
216    pub debug_base: Option<u64>,
217    /// The base address of the cross trigger interface (CTI) for the core.
218    /// Required in ARMv8-A
219    #[serde(serialize_with = "hex_option")]
220    pub cti_base: Option<u64>,
221
222    /// The JTAG TAP index of the core's debug module
223    pub jtag_tap: Option<usize>,
224}
225
226/// The data required to access a Risc-V core
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct RiscvCoreAccessOptions {
229    /// The hart id
230    pub hart_id: Option<u32>,
231
232    /// The JTAG TAP index of the core's debug module
233    pub jtag_tap: Option<usize>,
234
235    /// CoreSight/mem-AP to use as DTM. This is the method used for RP235x
236    #[serde(default)]
237    pub mem_ap: Option<ApAddress>,
238}
239
240/// The data required to access an Xtensa core
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct XtensaCoreAccessOptions {
243    /// The JTAG TAP index of the core's debug module
244    pub jtag_tap: Option<usize>,
245}