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