1use super::{Core, MemoryRegion, RawFlashAlgorithm, TargetDescriptionSource};
2use crate::flashing::FlashLoader;
3use crate::{
4 architecture::{
5 arm::{
6 ApV2Address, FullyQualifiedApAddress,
7 dp::DpAddress,
8 sequences::{ArmDebugSequence, DefaultArmSequence},
9 },
10 riscv::sequences::{DefaultRiscvSequence, RiscvDebugSequence},
11 xtensa::sequences::{DefaultXtensaSequence, XtensaDebugSequence},
12 },
13 rtt::ScanRegion,
14};
15use probe_rs_target::{
16 Architecture, Chip, ChipFamily, Jtag, MemoryAccess, MemoryRange as _, NvmRegion,
17};
18use std::sync::Arc;
19
20#[derive(Clone)]
22pub struct Target {
23 pub name: String,
25 pub cores: Vec<Core>,
27 pub flash_algorithms: Vec<RawFlashAlgorithm>,
29 pub memory_map: Vec<MemoryRegion>,
31 pub(crate) source: TargetDescriptionSource,
33 pub debug_sequence: DebugSequence,
35 pub rtt_scan_regions: ScanRegion,
40 pub jtag: Option<Jtag>,
46 pub default_format: Option<String>,
48}
49
50impl std::fmt::Debug for Target {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 write!(
53 f,
54 "Target {{
55 identifier: {:?},
56 flash_algorithms: {:?},
57 memory_map: {:?},
58 }}",
59 self.name, self.flash_algorithms, self.memory_map
60 )
61 }
62}
63
64impl Target {
65 pub(super) fn new(family: &ChipFamily, chip: &Chip) -> Target {
69 let mut memory_map = chip.memory_map.clone();
70 let mut flash_algorithms = Vec::new();
71 for algo_name in chip.flash_algorithms.iter() {
72 let Some(algo) = family.get_algorithm_for_chip(algo_name, chip) else {
73 unreachable!(
74 "The chip {chip_name} refers to a flash algorithm called {algo_name}, which is \
75 not defined in the family {family_name}. The flash algorithms should have been \
76 validated when the ChipFamily was loaded. This is a bug, please report it.",
77 chip_name = chip.name,
78 family_name = family.name,
79 );
80 };
81
82 let algo_range = &algo.flash_properties.address_range;
86 if !memory_map
87 .iter()
88 .any(|region| region.address_range().intersects_range(algo_range))
89 {
90 memory_map.push(MemoryRegion::Nvm(NvmRegion {
95 name: Some(format!("synthesized for {algo_name}")),
96 range: algo_range.clone(),
97 cores: if algo.cores.is_empty() {
98 chip.cores.iter().map(|core| core.name.clone()).collect()
99 } else {
100 algo.cores.clone()
101 },
102 is_alias: true,
103 access: Some(MemoryAccess {
104 read: false,
105 write: false,
106 execute: false,
107 boot: false,
108 }),
109 }));
110 }
111
112 flash_algorithms.push(algo);
113 }
114
115 let debug_sequence = crate::vendor::try_create_debug_sequence(chip).unwrap_or_else(|| {
116 match chip.cores[0].core_type.architecture() {
119 Architecture::Arm => DebugSequence::Arm(DefaultArmSequence::create()),
120 Architecture::Riscv => DebugSequence::Riscv(DefaultRiscvSequence::create()),
121 Architecture::Xtensa => DebugSequence::Xtensa(DefaultXtensaSequence::create()),
122 }
123 });
124
125 tracing::info!("Using sequence {:?}", debug_sequence);
126
127 let rtt_scan_regions = match &chip.rtt_scan_ranges {
128 Some(ranges) => ScanRegion::Ranges(ranges.clone()),
129 None => ScanRegion::Ram, };
131
132 Target {
133 name: chip.name.clone(),
134 cores: chip.cores.clone(),
135 flash_algorithms,
136 source: family.source.clone(),
137 memory_map,
138 debug_sequence,
139 rtt_scan_regions,
140 jtag: chip.jtag.clone(),
141 default_format: chip.default_binary_format.clone(),
142 }
143 }
144
145 pub fn architecture(&self) -> Architecture {
147 let target_arch = self.cores[0].core_type.architecture();
148
149 assert!(
151 self.cores
152 .iter()
153 .map(|core| core.core_type.architecture())
154 .all(|core_arch| core_arch == target_arch),
155 "Not all cores of the target are of the same architecture. Probe-rs doesn't support this (yet). If you see this, it is a bug. Please file an issue."
156 );
157
158 target_arch
159 }
160
161 pub fn default_core(&self) -> &Core {
166 &self.cores[0]
168 }
169
170 pub fn source(&self) -> &TargetDescriptionSource {
172 &self.source
173 }
174
175 pub fn flash_loader(&self) -> FlashLoader {
178 FlashLoader::new(self.memory_map.clone(), self.source.clone())
179 }
180
181 pub(crate) fn flash_algorithm_by_name(&self, name: &str) -> Option<&RawFlashAlgorithm> {
183 self.flash_algorithms.iter().find(|a| a.name == name)
184 }
185
186 pub fn core_index_by_name(&self, name: &str) -> Option<usize> {
188 self.cores.iter().position(|c| c.name == name)
189 }
190
191 pub fn core_index_by_address(&self, address: u64) -> Option<usize> {
193 let target_memory = self.memory_region_by_address(address)?;
194 let core_name = target_memory.cores().first()?;
195 self.core_index_by_name(core_name)
196 }
197
198 pub fn memory_region_by_address(&self, address: u64) -> Option<&MemoryRegion> {
200 self.memory_map
201 .iter()
202 .find(|region| region.contains(address))
203 }
204}
205
206#[derive(Debug, Clone)]
208pub enum TargetSelector {
209 Unspecified(String),
213 Specified(Target),
215 Auto,
219}
220
221impl From<&str> for TargetSelector {
222 fn from(value: &str) -> Self {
223 TargetSelector::Unspecified(value.into())
224 }
225}
226
227impl From<&String> for TargetSelector {
228 fn from(value: &String) -> Self {
229 TargetSelector::Unspecified(value.into())
230 }
231}
232
233impl From<String> for TargetSelector {
234 fn from(value: String) -> Self {
235 TargetSelector::Unspecified(value)
236 }
237}
238
239impl From<Option<&str>> for TargetSelector {
240 fn from(value: Option<&str>) -> Self {
241 match value {
242 Some(identifier) => identifier.into(),
243 None => TargetSelector::Auto,
244 }
245 }
246}
247
248impl From<()> for TargetSelector {
249 fn from(_value: ()) -> Self {
250 TargetSelector::Auto
251 }
252}
253
254impl From<Target> for TargetSelector {
255 fn from(target: Target) -> Self {
256 TargetSelector::Specified(target)
257 }
258}
259
260#[derive(Clone, Debug)]
263pub enum DebugSequence {
264 Arm(Arc<dyn ArmDebugSequence>),
266 Riscv(Arc<dyn RiscvDebugSequence>),
268 Xtensa(Arc<dyn XtensaDebugSequence>),
270}
271
272pub(crate) trait CoreExt {
273 fn memory_ap(&self) -> Option<FullyQualifiedApAddress>;
276}
277
278impl CoreExt for Core {
279 fn memory_ap(&self) -> Option<FullyQualifiedApAddress> {
280 match &self.core_access_options {
281 probe_rs_target::CoreAccessOptions::Arm(options) => {
282 let dp = match options.targetsel {
283 None => DpAddress::Default,
284 Some(x) => DpAddress::Multidrop(x),
285 };
286 Some(match &options.ap {
287 probe_rs_target::ApAddress::V1(ap) => {
288 FullyQualifiedApAddress::v1_with_dp(dp, *ap)
289 }
290 probe_rs_target::ApAddress::V2(ap) => {
291 FullyQualifiedApAddress::v2_with_dp(dp, ApV2Address::new(*ap))
292 }
293 })
294 }
295 probe_rs_target::CoreAccessOptions::Riscv(_) => None,
296 probe_rs_target::CoreAccessOptions::Xtensa(_) => None,
297 }
298 }
299}