Skip to main content

probe_rs/architecture/arm/core/
armv7ar.rs

1//! Register types and the core interface for armv7-a and armv7-r
2
3use super::{
4    CortexARState,
5    instructions::aarch32::{
6        build_ldc, build_mcr, build_mov, build_mrc, build_mrs, build_mrs_spsr, build_msr,
7        build_stc, build_vmov, build_vmrs,
8    },
9    registers::{
10        aarch32::{
11            AARCH32_CORE_REGISTERS, AARCH32_WITH_FP_16_CORE_REGISTERS,
12            AARCH32_WITH_FP_32_CORE_REGISTERS,
13        },
14        cortex_m::{FP, PC, RA, SP, XPSR},
15    },
16};
17use crate::{
18    Architecture, CoreInformation, CoreInterface, CoreRegister, CoreStatus, CoreType, Endian,
19    HaltReason, InstructionSet, MemoryInterface,
20    architecture::arm::{
21        ArmError, DapAccess, FullyQualifiedApAddress,
22        ap::{ApRegister, BD0, BD1, BD2, BD3, TAR, TAR2},
23        core::armv7ar_debug_regs::*,
24        memory::ArmMemoryInterface,
25        sequences::ArmDebugSequence,
26    },
27    core::{
28        BreakpointCause, CoreRegisters, MemoryMappedRegister, RegisterId, RegisterValue,
29        VectorCatchCondition,
30    },
31    error::Error,
32    memory::{MemoryNotAlignedError, valid_32bit_address},
33    semihosting::{SemihostingCommand, decode_semihosting_syscall},
34};
35use std::{
36    mem::size_of,
37    sync::Arc,
38    time::{Duration, Instant},
39};
40use zerocopy::{FromBytes, IntoBytes};
41
42/// The maximum amount of time to wait for the core to respond
43const OPERATION_TIMEOUT: Duration = Duration::from_millis(250);
44
45/// Addresses for accessing debug registers when in banked mode
46struct BankedAccess<'a> {
47    /// Keep a reference to the `interface` to prevent anyone else
48    /// from changing the TAR while we're doing banked operations.
49    interface: &'a mut dyn DapAccess,
50    ap: FullyQualifiedApAddress,
51    dtrtx: u64,
52    itr: u64,
53    dscr: u64,
54    dtrrx: u64,
55}
56
57impl<'a> BankedAccess<'a> {
58    #[expect(dead_code)]
59    fn set_dtrrx(&mut self, value: u32) -> Result<(), ArmError> {
60        self.interface
61            .write_raw_ap_register(&self.ap, self.dtrrx, value)
62    }
63
64    fn set_dtrrx_repeated(&mut self, values: &[u32]) -> Result<(), ArmError> {
65        self.interface
66            .write_raw_ap_register_repeated(&self.ap, self.dtrrx, values)
67    }
68
69    fn dscr(&mut self) -> Result<Dbgdscr, ArmError> {
70        self.interface
71            .read_raw_ap_register(&self.ap, self.dscr)
72            .map(Dbgdscr::from)
73    }
74
75    fn set_dscr(&mut self, value: Dbgdscr) -> Result<(), ArmError> {
76        self.interface
77            .write_raw_ap_register(&self.ap, self.dscr, value.into())
78    }
79
80    fn set_itr(&mut self, value: u32) -> Result<(), ArmError> {
81        self.interface
82            .write_raw_ap_register(&self.ap, self.itr, value)
83    }
84
85    fn dtrtx(&mut self) -> Result<u32, ArmError> {
86        self.interface.read_raw_ap_register(&self.ap, self.dtrtx)
87    }
88
89    fn dtrtx_repeated(&mut self, buf: &mut [u32]) -> Result<(), ArmError> {
90        self.interface
91            .read_raw_ap_register_repeated(&self.ap, self.dtrtx, buf)?;
92        Ok(())
93    }
94
95    /// Operate the core in DCC Fast mode. For more information, see
96    /// ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
97    /// section C8.2.2.
98    ///
99    /// In this mode, writing to the ITR register does not immediately
100    /// trigger the instruction. Instead, it waits for a read from DTRTX
101    /// or a write to DTRRX. By placing an instruction with address-increment
102    /// in the pipeline this way, a load or store can be retriggered
103    /// repeatedly to quickly stream memory.
104    fn with_dcc_fast_mode<R>(
105        &mut self,
106        f: impl FnOnce(&mut Self) -> Result<R, ArmError>,
107    ) -> Result<R, ArmError> {
108        // Place DSCR in DCC Fast mode
109        let mut dscr = self.dscr()?;
110        dscr.set_extdccmode(2);
111        self.set_dscr(dscr)?;
112        let result = f(self);
113
114        // Return DSCR back to DCC Non Blocking mode
115        let mut dscr = self.dscr()?;
116        dscr.set_extdccmode(0);
117        self.set_dscr(dscr)?;
118
119        result
120    }
121}
122
123/// Errors for the ARMv7-A state machine
124#[derive(thiserror::Error, Debug)]
125pub enum Armv7arError {
126    /// Invalid register number
127    #[error("Register number {0} is not valid for ARMv7-A")]
128    InvalidRegisterNumber(u16),
129
130    /// Not halted
131    #[error("Core is running but operation requires it to be halted")]
132    NotHalted,
133
134    /// Data Abort occurred
135    #[error("A data abort occurred")]
136    DataAbort,
137}
138
139/// Interface for interacting with an ARMv7-A/R core
140pub struct Armv7ar<'probe> {
141    memory: Box<dyn ArmMemoryInterface + 'probe>,
142
143    state: &'probe mut CortexARState,
144
145    base_address: u64,
146
147    sequence: Arc<dyn ArmDebugSequence>,
148
149    num_breakpoints: Option<u32>,
150
151    itr_enabled: bool,
152
153    endianness: Option<Endian>,
154
155    core_type: CoreType,
156}
157
158impl<'probe> Armv7ar<'probe> {
159    pub(crate) fn new(
160        mut memory: Box<dyn ArmMemoryInterface + 'probe>,
161        state: &'probe mut CortexARState,
162        base_address: u64,
163        sequence: Arc<dyn ArmDebugSequence>,
164        core_type: CoreType,
165    ) -> Result<Self, Error> {
166        if !state.initialized() {
167            // determine current state
168            let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
169            let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
170
171            tracing::debug!("State when connecting: {:x?}", dbgdscr);
172
173            let core_state = if dbgdscr.halted() {
174                let reason = dbgdscr.halt_reason();
175
176                tracing::debug!("Core was halted when connecting, reason: {:?}", reason);
177
178                CoreStatus::Halted(reason)
179            } else {
180                CoreStatus::Running
181            };
182
183            state.current_state = core_state;
184        }
185
186        let mut core = Self {
187            memory,
188            state,
189            base_address,
190            sequence,
191            num_breakpoints: None,
192            itr_enabled: false,
193            endianness: None,
194            core_type,
195        };
196
197        if !core.state.initialized() {
198            core.reset_register_cache();
199            core.read_fp_reg_count()?;
200            core.state.initialize();
201        }
202
203        Ok(core)
204    }
205
206    fn read_fp_reg_count(&mut self) -> Result<(), Error> {
207        if self.state.fp_reg_count == 0 && matches!(self.state.current_state, CoreStatus::Halted(_))
208        {
209            self.prepare_r0_for_clobber()?;
210
211            // Check CP10/CP11 in CPACR which indicate whether the FPU is enabled;
212            // if it's disabled (both 0) then don't try to read MVFR0 as it would fault.
213            let instruction = build_mrc(15, 0, 0, 1, 0, 2);
214            self.execute_instruction(instruction)?;
215            let instruction = build_mcr(14, 0, 0, 0, 5, 0);
216            let cpacr = Cpacr(self.execute_instruction_with_result(instruction)?);
217            if cpacr.cp(10) == 0 || cpacr.cp(11) == 0 {
218                return Ok(());
219            }
220
221            // VMRS r0, MVFR0
222            let instruction = build_vmrs(0, 0b0111);
223            self.execute_instruction(instruction)?;
224
225            // Read from r0
226            let instruction = build_mcr(14, 0, 0, 0, 5, 0);
227            let vmrs = self.execute_instruction_with_result(instruction)?;
228
229            self.state.fp_reg_count = match vmrs & 0b111 {
230                0b001 => 16,
231                0b010 => 32,
232                _ => 0,
233            };
234        }
235
236        Ok(())
237    }
238
239    /// Execute an instruction
240    fn execute_instruction(&mut self, instruction: u32) -> Result<Dbgdscr, ArmError> {
241        if !self.state.current_state.is_halted() {
242            return Err(ArmError::CoreNotHalted);
243        }
244
245        // Enable ITR if needed
246        if !self.itr_enabled {
247            let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
248            let mut dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
249            dbgdscr.set_itren(true);
250
251            self.memory.write_word_32(address, dbgdscr.into())?;
252
253            self.itr_enabled = true;
254        }
255
256        execute_instruction(&mut *self.memory, self.base_address, instruction)
257    }
258
259    /// Execute an instruction on the CPU and return the result
260    fn execute_instruction_with_result(&mut self, instruction: u32) -> Result<u32, Error> {
261        // Run instruction
262        let mut dbgdscr = self.execute_instruction(instruction)?;
263
264        // Wait for TXfull
265        let start = Instant::now();
266        while !dbgdscr.txfull_l() {
267            let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
268            dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
269            // Check if we had any aborts, if so clear them and fail
270            check_and_clear_data_abort(&mut *self.memory, self.base_address, dbgdscr)?;
271            if start.elapsed() >= OPERATION_TIMEOUT {
272                return Err(Error::Timeout);
273            }
274        }
275
276        // Read result
277        let address = Dbgdtrtx::get_mmio_address_from_base(self.base_address)?;
278        let result = self.memory.read_word_32(address)?;
279
280        Ok(result)
281    }
282
283    fn execute_instruction_with_input(
284        &mut self,
285        instruction: u32,
286        value: u32,
287    ) -> Result<(), Error> {
288        // Move value
289        let address = Dbgdtrrx::get_mmio_address_from_base(self.base_address)?;
290        self.memory.write_word_32(address, value)?;
291
292        // Wait for RXfull
293        let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
294        let mut dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
295
296        let start = Instant::now();
297        while !dbgdscr.rxfull_l() {
298            dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
299            // Check if we had any aborts, if so clear them and fail
300            check_and_clear_data_abort(&mut *self.memory, self.base_address, dbgdscr)?;
301            if start.elapsed() >= OPERATION_TIMEOUT {
302                return Err(Error::Timeout);
303            }
304        }
305
306        // Run instruction
307        self.execute_instruction(instruction)?;
308
309        Ok(())
310    }
311
312    fn reset_register_cache(&mut self) {
313        self.state.register_cache = vec![None; 51];
314    }
315
316    /// Sync any updated registers back to the core
317    fn writeback_registers(&mut self) -> Result<(), Error> {
318        let writeback_iter = (17u16..=48).chain(15u16..=16).chain(0u16..=14);
319
320        for i in writeback_iter {
321            if let Some((val, writeback)) = self.state.register_cache[i as usize]
322                && writeback
323            {
324                match i {
325                    0..=14 => {
326                        let instruction = build_mrc(14, 0, i, 0, 5, 0);
327
328                        self.execute_instruction_with_input(instruction, val.try_into()?)?;
329                    }
330                    15 => {
331                        // Move val to r0
332                        let instruction = build_mrc(14, 0, 0, 0, 5, 0);
333
334                        self.execute_instruction_with_input(instruction, val.try_into()?)?;
335
336                        // Use `mov pc, r0` rather than `bx r0` because the `bx` instruction is
337                        // `UNPREDICTABLE` in the debug state (ARM Architecture Reference Manual,
338                        // ARMv7-A and ARMv7-R edition, C5.3: "Executing instructions in Debug state").
339                        let instruction = build_mov(15, 0);
340                        self.execute_instruction(instruction)?;
341                    }
342                    16 => {
343                        // msr cpsr_fsxc, r0
344                        let instruction = build_msr(0);
345                        self.execute_instruction_with_input(instruction, val.try_into()?)?;
346                    }
347                    17..=48 => {
348                        // Move value to r0, r1
349                        let value: u64 = val.try_into()?;
350                        let low_word = value as u32;
351                        let high_word = (value >> 32) as u32;
352
353                        let instruction = build_mrc(14, 0, 0, 0, 5, 0);
354                        self.execute_instruction_with_input(instruction, low_word)?;
355
356                        let instruction = build_mrc(14, 0, 1, 0, 5, 0);
357                        self.execute_instruction_with_input(instruction, high_word)?;
358
359                        // VMOV
360                        let instruction = build_vmov(0, 0, 1, i - 17);
361                        self.execute_instruction(instruction)?;
362                    }
363                    _ => {
364                        panic!("Logic missing for writeback of register {i}");
365                    }
366                }
367            }
368        }
369
370        self.reset_register_cache();
371
372        Ok(())
373    }
374
375    /// Save r0 if needed before it gets clobbered by instruction execution
376    fn prepare_r0_for_clobber(&mut self) -> Result<(), Error> {
377        self.prepare_for_clobber(0)
378    }
379
380    /// Save `r<n>` if needed before it gets clobbered by instruction execution
381    fn prepare_for_clobber(&mut self, reg: usize) -> Result<(), Error> {
382        if self.state.register_cache[reg].is_none() {
383            // cache reg since we're going to clobber it
384            let val: u32 = self.read_core_reg(RegisterId(reg as u16))?.try_into()?;
385
386            // Mark reg as needing writeback
387            self.state.register_cache[reg] = Some((val.into(), true));
388        }
389
390        Ok(())
391    }
392
393    fn set_r0(&mut self, value: u32) -> Result<(), Error> {
394        let instruction = build_mrc(14, 0, 0, 0, 5, 0);
395
396        self.execute_instruction_with_input(instruction, value)
397    }
398
399    fn set_core_status(&mut self, new_status: CoreStatus) {
400        super::update_core_status(&mut self.memory, &mut self.state.current_state, new_status);
401    }
402
403    pub(crate) fn halted_access<R>(
404        &mut self,
405        op: impl FnOnce(&mut Self) -> Result<R, Error>,
406    ) -> Result<R, Error> {
407        let was_running = !(self.state.current_state.is_halted() || self.status()?.is_halted());
408
409        if was_running {
410            self.halt(Duration::from_millis(100))?;
411        }
412
413        let result = op(self);
414
415        if was_running {
416            self.run()?
417        }
418
419        result
420    }
421
422    /// For greater performance, place DBGDTRTX, DBGDTRRX, DBGITR, and DBGDCSR
423    /// into the banked register window. This will allow us to directly access
424    /// these four values.
425    fn banked_access(&mut self) -> Result<BankedAccess<'_>, Error> {
426        let address = Dbgdtrrx::get_mmio_address_from_base(self.base_address)?;
427        let ap = self.memory.fully_qualified_address();
428        let is_64_bit = self.is_64_bit();
429        let interface = self.memory.get_arm_debug_interface()?;
430
431        if is_64_bit {
432            interface.write_raw_ap_register(&ap, TAR2::ADDRESS, (address >> 32) as u32)?;
433        }
434        interface.write_raw_ap_register(&ap, TAR::ADDRESS, address as u32)?;
435
436        Ok(BankedAccess {
437            interface,
438            ap,
439            dtrrx: BD0::ADDRESS,
440            itr: BD1::ADDRESS,
441            dscr: BD2::ADDRESS,
442            dtrtx: BD3::ADDRESS,
443        })
444    }
445}
446
447// These helper functions allow access to the ARMv7-A/R core from Sequences.
448// They are also used by the `CoreInterface` to avoid code duplication.
449
450/// Request the core to halt. Does not wait for the core to halt.
451pub(crate) fn request_halt(
452    memory: &mut dyn ArmMemoryInterface,
453    base_address: u64,
454) -> Result<(), ArmError> {
455    let address = Dbgdrcr::get_mmio_address_from_base(base_address)?;
456    let mut value = Dbgdrcr(0);
457    value.set_hrq(true);
458
459    memory.write_word_32(address, value.into())?;
460    Ok(())
461}
462
463/// Start the core running. This does not flush any state.
464pub(crate) fn run(memory: &mut dyn ArmMemoryInterface, base_address: u64) -> Result<(), ArmError> {
465    let address = Dbgdrcr::get_mmio_address_from_base(base_address)?;
466    let mut value = Dbgdrcr(0);
467    value.set_rrq(true);
468
469    memory.write_word_32(address, value.into())?;
470
471    // Wait for ack
472    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
473
474    let start = Instant::now();
475    loop {
476        let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
477        if dbgdscr.restarted() {
478            return Ok(());
479        }
480        if start.elapsed() > OPERATION_TIMEOUT {
481            return Err(ArmError::Timeout);
482        }
483    }
484}
485
486/// Wait for the core to be halted. If the core does not halt, then
487/// this will return `ArmError::Timeout`.
488pub(crate) fn wait_for_core_halted(
489    memory: &mut dyn ArmMemoryInterface,
490    base_address: u64,
491    timeout: Duration,
492) -> Result<(), ArmError> {
493    // Wait until halted state is active again.
494    let start = Instant::now();
495
496    while !core_halted(memory, base_address)? {
497        if start.elapsed() >= timeout {
498            return Err(ArmError::Timeout);
499        }
500        // Wait a bit before polling again.
501        std::thread::sleep(Duration::from_millis(1));
502    }
503
504    Ok(())
505}
506
507/// Return whether or not the core is halted.
508pub(crate) fn core_halted(
509    memory: &mut dyn ArmMemoryInterface,
510    base_address: u64,
511) -> Result<bool, ArmError> {
512    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
513    let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
514
515    Ok(dbgdscr.halted())
516}
517
518/// Set and enable a specific breakpoint. If the breakpoint is in use, it
519/// will be cleared.
520pub(crate) fn set_hw_breakpoint(
521    memory: &mut dyn ArmMemoryInterface,
522    base_address: u64,
523    bp_unit_index: usize,
524    addr: u32,
525) -> Result<(), ArmError> {
526    let bp_value_addr = Dbgbvr::get_mmio_address_from_base(base_address)?
527        + (bp_unit_index * size_of::<u32>()) as u64;
528    let bp_control_addr = Dbgbcr::get_mmio_address_from_base(base_address)?
529        + (bp_unit_index * size_of::<u32>()) as u64;
530    let mut bp_control = Dbgbcr(0);
531
532    // Breakpoint type - address match
533    bp_control.set_bt(0b0000);
534    // Match on all modes
535    bp_control.set_hmc(true);
536    bp_control.set_pmc(0b11);
537    // Match on all bytes
538    bp_control.set_bas(0b1111);
539    // Enable
540    bp_control.set_e(true);
541
542    memory.write_word_32(bp_value_addr, addr)?;
543    memory.write_word_32(bp_control_addr, bp_control.into())?;
544
545    Ok(())
546}
547
548/// If a specified breakpoint is set, disable it and clear it.
549pub(crate) fn clear_hw_breakpoint(
550    memory: &mut dyn ArmMemoryInterface,
551    base_address: u64,
552    bp_unit_index: usize,
553) -> Result<(), ArmError> {
554    let bp_value_addr = Dbgbvr::get_mmio_address_from_base(base_address)?
555        + (bp_unit_index * size_of::<u32>()) as u64;
556    let bp_control_addr = Dbgbcr::get_mmio_address_from_base(base_address)?
557        + (bp_unit_index * size_of::<u32>()) as u64;
558
559    memory.write_word_32(bp_value_addr, 0)?;
560    memory.write_word_32(bp_control_addr, 0)?;
561    Ok(())
562}
563
564/// Get a specific hardware breakpoint. If the breakpoint is not set, return `None`.
565pub(crate) fn get_hw_breakpoint(
566    memory: &mut dyn ArmMemoryInterface,
567    base_address: u64,
568    bp_unit_index: usize,
569) -> Result<Option<u32>, ArmError> {
570    let bp_value_addr = Dbgbvr::get_mmio_address_from_base(base_address)?
571        + (bp_unit_index * size_of::<u32>()) as u64;
572    let bp_value = memory.read_word_32(bp_value_addr)?;
573
574    let bp_control_addr = Dbgbcr::get_mmio_address_from_base(base_address)?
575        + (bp_unit_index * size_of::<u32>()) as u64;
576    let bp_control = Dbgbcr(memory.read_word_32(bp_control_addr)?);
577
578    Ok(if bp_control.e() { Some(bp_value) } else { None })
579}
580
581fn check_and_clear_data_abort(
582    memory: &mut dyn ArmMemoryInterface,
583    base_address: u64,
584    dbgdscr: Dbgdscr,
585) -> Result<(), ArmError> {
586    // Check if we had any aborts, if so clear them and fail
587    if dbgdscr.adabort_l() || dbgdscr.sdabort_l() || dbgdscr.und_l() {
588        let address = Dbgdrcr::get_mmio_address_from_base(base_address)?;
589        let mut dbgdrcr = Dbgdrcr(0);
590        dbgdrcr.set_cse(true);
591
592        memory.write_word_32(address, dbgdrcr.into())?;
593        return Err(ArmError::Armv7ar(
594            crate::architecture::arm::armv7ar::Armv7arError::DataAbort,
595        ));
596    }
597    Ok(())
598}
599
600/// Execute a single instruction.
601fn execute_instruction(
602    memory: &mut dyn ArmMemoryInterface,
603    base_address: u64,
604    instruction: u32,
605) -> Result<Dbgdscr, ArmError> {
606    // Run instruction
607    let address = Dbgitr::get_mmio_address_from_base(base_address)?;
608    memory.write_word_32(address, instruction)?;
609
610    // Wait for completion
611    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
612    let mut dbgdscr = Dbgdscr(memory.read_word_32(address)?);
613
614    let start = Instant::now();
615    while !dbgdscr.instrcoml_l() {
616        dbgdscr = Dbgdscr(memory.read_word_32(address)?);
617        // Check if we had any aborts, if so clear them and fail
618        check_and_clear_data_abort(memory, base_address, dbgdscr)?;
619        if start.elapsed() >= OPERATION_TIMEOUT {
620            return Err(ArmError::Timeout);
621        }
622    }
623
624    // Check if we had any aborts, if so clear them and fail
625    check_and_clear_data_abort(memory, base_address, dbgdscr)?;
626
627    Ok(dbgdscr)
628}
629
630/// Set the DBGDBGDTRRX register, which can be accessed with an
631/// `STC p14, c5, ..., #4` instruction.
632fn set_instruction_input(
633    memory: &mut dyn ArmMemoryInterface,
634    base_address: u64,
635    value: u32,
636) -> Result<(), ArmError> {
637    // Move value
638    let address = Dbgdtrrx::get_mmio_address_from_base(base_address)?;
639    memory.write_word_32(address, value)?;
640
641    // Wait for RXfull
642    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
643    let mut dbgdscr = Dbgdscr(memory.read_word_32(address)?);
644
645    let start = Instant::now();
646    while !dbgdscr.rxfull_l() {
647        dbgdscr = Dbgdscr(memory.read_word_32(address)?);
648        // Check if we had any aborts, if so clear them and fail
649        check_and_clear_data_abort(memory, base_address, dbgdscr)?;
650        if start.elapsed() >= OPERATION_TIMEOUT {
651            return Err(ArmError::Timeout);
652        }
653    }
654
655    Ok(())
656}
657
658/// Return the contents of DBGDTRTX, which is set as a result of an
659/// `LDC, p14, c5, ..., #4` instruction.
660fn get_instruction_result(
661    memory: &mut dyn ArmMemoryInterface,
662    base_address: u64,
663) -> Result<u32, ArmError> {
664    // Wait for TXfull
665    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
666    let start = Instant::now();
667    loop {
668        let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
669        if dbgdscr.txfull_l() {
670            break;
671        }
672        if start.elapsed() > OPERATION_TIMEOUT {
673            return Err(ArmError::Timeout);
674        }
675    }
676
677    // Read result
678    let address = Dbgdtrtx::get_mmio_address_from_base(base_address)?;
679    memory.read_word_32(address)
680}
681
682/// Write a 32-bit value to main memory. Assumes that the core is halted. Note that
683/// this clobbers $r0.
684pub(crate) fn write_word_32(
685    memory: &mut dyn ArmMemoryInterface,
686    base_address: u64,
687    address: u32,
688    data: u32,
689) -> Result<(), ArmError> {
690    // Load address into r0
691    set_instruction_input(memory, base_address, address)?;
692    execute_instruction(memory, base_address, build_mrc(14, 0, 0, 0, 5, 0))?;
693
694    // Store the value in the DBGDBGDTRRX register and store that value into RAM.
695    // STC p14, c5, [r0], #4
696    set_instruction_input(memory, base_address, data)?;
697    execute_instruction(memory, base_address, build_stc(14, 5, 0, 4))?;
698    Ok(())
699}
700
701/// Read a 32-bit value from main memory. Assumes that the core is halted. Note that
702/// this clobbers $r0.
703pub(crate) fn read_word_32(
704    memory: &mut dyn ArmMemoryInterface,
705    base_address: u64,
706    address: u32,
707) -> Result<u32, ArmError> {
708    // Load address into r0
709    set_instruction_input(memory, base_address, address)?;
710    execute_instruction(memory, base_address, build_mrc(14, 0, 0, 0, 5, 0))?;
711
712    // Execute the instruction and store the result in the DBGDTRTX register.
713    // LDC p14, c5, [r0], #4
714    execute_instruction(memory, base_address, build_ldc(14, 5, 0, 4))?;
715    get_instruction_result(memory, base_address)
716}
717
718impl CoreInterface for Armv7ar<'_> {
719    fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
720        wait_for_core_halted(&mut *self.memory, self.base_address, timeout).map_err(|e| e.into())
721    }
722
723    fn core_halted(&mut self) -> Result<bool, Error> {
724        core_halted(&mut *self.memory, self.base_address).map_err(|e| e.into())
725    }
726
727    fn status(&mut self) -> Result<crate::core::CoreStatus, Error> {
728        // determine current state
729        let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
730        let dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
731
732        if dbgdscr.halted() {
733            let mut reason = dbgdscr.halt_reason();
734
735            // Set the status so semihosting decoding can read registers
736            self.set_core_status(CoreStatus::Halted(reason));
737
738            self.read_fp_reg_count()?;
739
740            // Check for semihosting on SVC & HLT (UNDEF) vector catch
741            if let HaltReason::Exception = reason {
742                let lr: u32 = self.read_core_reg(RegisterId(14))?.try_into()?;
743
744                self.state.semihosting_command =
745                    check_for_semihosting(self.state.semihosting_command.take(), self, lr)?;
746                if let Some(command) = self.state.semihosting_command {
747                    reason = HaltReason::Breakpoint(BreakpointCause::Semihosting(command));
748                    self.set_core_status(CoreStatus::Halted(reason));
749                }
750            }
751
752            return Ok(CoreStatus::Halted(reason));
753        }
754        // Core is neither halted nor sleeping, so we assume it is running.
755        if self.state.current_state.is_halted() {
756            tracing::warn!("Core is running, but we expected it to be halted");
757        }
758
759        self.set_core_status(CoreStatus::Running);
760
761        Ok(CoreStatus::Running)
762    }
763
764    fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
765        if !matches!(self.state.current_state, CoreStatus::Halted(_)) {
766            request_halt(&mut *self.memory, self.base_address)?;
767            self.wait_for_core_halted(timeout)?;
768
769            // Reset our cached values
770            self.reset_register_cache();
771        }
772        // Update core status
773        let _ = self.status()?;
774
775        // try to read the program counter
776        let pc_value = self.read_core_reg(self.program_counter().into())?;
777
778        // get pc
779        Ok(CoreInformation {
780            pc: pc_value.try_into()?,
781        })
782    }
783
784    fn run(&mut self) -> Result<(), Error> {
785        if matches!(self.state.current_state, CoreStatus::Running) {
786            return Ok(());
787        }
788
789        if self.state.semihosting_command.is_some() {
790            // We're in an exception mode after vector catch (SVC mode for
791            // SVC vector catch, or Undefined mode for HLT/UNDEF vector catch).
792            // Need to:
793            // 1. Restore CPSR from SPSR (to return to original mode)
794            // 2. Set PC to LR (return address)
795
796            // Read LR (r14) - this is the banked LR for the current exception mode
797            let lr: u32 = self.read_core_reg(RegisterId(14))?.try_into()?;
798
799            // Save r0 in case it was modified by semihosting result
800            self.prepare_for_clobber(0)?;
801
802            // Read SPSR into r0: mrs r0, spsr
803            let mrs_spsr = build_mrs_spsr(0);
804            self.execute_instruction(mrs_spsr)?;
805
806            // Write r0 to CPSR: msr cpsr_fsxc, r0
807            let msr_cpsr = build_msr(0);
808            self.execute_instruction(msr_cpsr)?;
809
810            // Set PC to LR (return address)
811            self.write_core_reg(self.program_counter().into(), lr.into())?;
812
813            tracing::debug!(
814                "Semihosting resume: restoring CPSR from SPSR, setting PC to LR={:#x}",
815                lr
816            );
817        }
818
819        // Clear cached semihosting command
820        self.state.semihosting_command = None;
821
822        // set writeback values
823        self.writeback_registers()?;
824
825        // Disable ITRen before sending RRQ (per ARM C5.7)
826        if self.itr_enabled {
827            let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
828            let mut dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
829            dbgdscr.set_itren(false);
830            self.memory.write_word_32(address, dbgdscr.into())?;
831            self.itr_enabled = false;
832        }
833
834        run(&mut *self.memory, self.base_address)?;
835
836        // Recompute / verify current state
837        self.set_core_status(CoreStatus::Running);
838        let _ = self.status()?;
839
840        Ok(())
841    }
842
843    fn reset(&mut self) -> Result<(), Error> {
844        self.sequence.reset_system(
845            &mut *self.memory,
846            crate::CoreType::Armv7a,
847            Some(self.base_address),
848        )?;
849
850        // Reset our cached values
851        self.reset_register_cache();
852
853        // Recompute / verify current state
854        self.set_core_status(CoreStatus::Running);
855        let _ = self.status()?;
856
857        Ok(())
858    }
859
860    fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
861        self.sequence.reset_catch_set(
862            &mut *self.memory,
863            crate::CoreType::Armv7a,
864            Some(self.base_address),
865        )?;
866        self.sequence.reset_system(
867            &mut *self.memory,
868            crate::CoreType::Armv7a,
869            Some(self.base_address),
870        )?;
871
872        if !self.core_halted()? {
873            tracing::warn!("Core not halted after reset, platform-specific setup may be required");
874            tracing::warn!("Requesting halt anyway, but system may already be initialised");
875            let address = Dbgdrcr::get_mmio_address_from_base(self.base_address)?;
876            let mut value = Dbgdrcr(0);
877            value.set_hrq(true);
878            self.memory.write_word_32(address, value.into())?;
879        }
880
881        self.sequence.reset_catch_clear(
882            &mut *self.memory,
883            crate::CoreType::Armv7a,
884            Some(self.base_address),
885        )?;
886        self.wait_for_core_halted(timeout)?;
887
888        self.reset_register_cache();
889
890        // Clear any cached semihosting command from before reset
891        self.state.semihosting_command = None;
892
893        let _ = self.status()?;
894
895        // try to read the program counter
896        let pc_value = self.read_core_reg(self.program_counter().into())?;
897
898        // get pc
899        Ok(CoreInformation {
900            pc: pc_value.try_into()?,
901        })
902    }
903
904    fn step(&mut self) -> Result<CoreInformation, Error> {
905        // Save current breakpoint
906        let bp_unit_index = (self.available_breakpoint_units()? - 1) as usize;
907        let bp_value_addr = Dbgbvr::get_mmio_address_from_base(self.base_address)?
908            + (bp_unit_index * size_of::<u32>()) as u64;
909        let saved_bp_value = self.memory.read_word_32(bp_value_addr)?;
910
911        let bp_control_addr = Dbgbcr::get_mmio_address_from_base(self.base_address)?
912            + (bp_unit_index * size_of::<u32>()) as u64;
913        let saved_bp_control = self.memory.read_word_32(bp_control_addr)?;
914
915        // Set breakpoint for any change
916        let current_pc: u32 = self
917            .read_core_reg(self.program_counter().into())?
918            .try_into()?;
919        let mut bp_control = Dbgbcr(0);
920
921        // Breakpoint type - address mismatch
922        bp_control.set_bt(0b0100);
923        // Match on all modes
924        bp_control.set_hmc(true);
925        bp_control.set_pmc(0b11);
926        // Match on all bytes
927        bp_control.set_bas(0b1111);
928        // Enable
929        bp_control.set_e(true);
930
931        self.memory.write_word_32(bp_value_addr, current_pc)?;
932        self.memory
933            .write_word_32(bp_control_addr, bp_control.into())?;
934
935        // Resume
936        self.run()?;
937
938        // Wait for halt
939        self.wait_for_core_halted(Duration::from_millis(100))?;
940
941        // Reset breakpoint
942        self.memory.write_word_32(bp_value_addr, saved_bp_value)?;
943        self.memory
944            .write_word_32(bp_control_addr, saved_bp_control)?;
945
946        // try to read the program counter
947        let pc_value = self.read_core_reg(self.program_counter().into())?;
948
949        // get pc
950        Ok(CoreInformation {
951            pc: pc_value.try_into()?,
952        })
953    }
954
955    fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error> {
956        let reg_num = address.0;
957
958        // check cache
959        if (reg_num as usize) < self.state.register_cache.len()
960            && let Some(cached_result) = self.state.register_cache[reg_num as usize]
961        {
962            return Ok(cached_result.0);
963        }
964
965        // Generate instruction to extract register
966        let result: Result<RegisterValue, Error> = match reg_num {
967            0..=14 => {
968                // r0-r14, valid
969                // MCR p14, 0, <Rd>, c0, c5, 0 ; Write DBGDTRTXint Register
970                let instruction = build_mcr(14, 0, reg_num, 0, 5, 0);
971
972                let val = self.execute_instruction_with_result(instruction)?;
973
974                Ok(val.into())
975            }
976            15 => {
977                // PC, must access via r0
978                self.prepare_r0_for_clobber()?;
979
980                // MOV r0, PC
981                let instruction = build_mov(0, 15);
982                self.execute_instruction(instruction)?;
983
984                // Read from r0
985                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
986                let pra_plus_offset = self.execute_instruction_with_result(instruction)?;
987
988                // PC returned is PC + 8
989                Ok((pra_plus_offset - 8).into())
990            }
991            16 => {
992                // CPSR, must access via r0
993                self.prepare_r0_for_clobber()?;
994
995                // MRS r0, CPSR
996                let instruction = build_mrs(0);
997                self.execute_instruction(instruction)?;
998
999                // Read from r0
1000                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
1001                let cpsr = self.execute_instruction_with_result(instruction)?;
1002
1003                Ok(cpsr.into())
1004            }
1005            17..=48 => {
1006                // Access via r0, r1
1007                self.prepare_for_clobber(0)?;
1008                self.prepare_for_clobber(1)?;
1009
1010                // If FPEXC.EN = 0, then these registers aren't safe to access.  Read as zero
1011                let fpexc: u32 = self.read_core_reg(50.into())?.try_into()?;
1012                if (fpexc & (1 << 30)) == 0 {
1013                    // Disabled
1014                    return Ok(0u32.into());
1015                }
1016
1017                // VMOV r0, r1, <reg>
1018                let instruction = build_vmov(1, 0, 1, reg_num - 17);
1019                self.execute_instruction(instruction)?;
1020
1021                // Read from r0
1022                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
1023                let mut value = self.execute_instruction_with_result(instruction)? as u64;
1024
1025                // Read from r1
1026                let instruction = build_mcr(14, 0, 1, 0, 5, 0);
1027                value |= (self.execute_instruction_with_result(instruction)? as u64) << 32;
1028
1029                Ok(value.into())
1030            }
1031            49 => {
1032                // Access via r0
1033                self.prepare_for_clobber(0)?;
1034
1035                // If FPEXC.EN = 0, then these registers aren't safe to access.  Read as zero
1036                let fpexc: u32 = self.read_core_reg(50.into())?.try_into()?;
1037                if (fpexc & (1 << 30)) == 0 {
1038                    // Disabled
1039                    return Ok(0u32.into());
1040                }
1041
1042                // VMRS r0, FPSCR
1043                let instruction = build_vmrs(0, 1);
1044                self.execute_instruction(instruction)?;
1045
1046                // Read from r0
1047                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
1048                let value = self.execute_instruction_with_result(instruction)?;
1049
1050                Ok(value.into())
1051            }
1052            50 => {
1053                // Access via r0
1054                self.prepare_for_clobber(0)?;
1055
1056                // VMRS r0, FPEXC
1057                let instruction = build_vmrs(0, 0b1000);
1058                self.execute_instruction(instruction)?;
1059
1060                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
1061                let value = self.execute_instruction_with_result(instruction)?;
1062
1063                Ok(value.into())
1064            }
1065            _ => Err(Error::Arm(
1066                Armv7arError::InvalidRegisterNumber(reg_num).into(),
1067            )),
1068        };
1069
1070        if let Ok(value) = result {
1071            self.state.register_cache[reg_num as usize] = Some((value, false));
1072
1073            Ok(value)
1074        } else {
1075            Err(result.err().unwrap())
1076        }
1077    }
1078
1079    fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error> {
1080        let reg_num = address.0;
1081
1082        if (reg_num as usize) >= self.state.register_cache.len() {
1083            return Err(Error::Arm(
1084                Armv7arError::InvalidRegisterNumber(reg_num).into(),
1085            ));
1086        }
1087        self.state.register_cache[reg_num as usize] = Some((value, true));
1088
1089        Ok(())
1090    }
1091
1092    fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
1093        if self.num_breakpoints.is_none() {
1094            let address = Dbgdidr::get_mmio_address_from_base(self.base_address)?;
1095            let dbgdidr = Dbgdidr(self.memory.read_word_32(address)?);
1096
1097            self.num_breakpoints = Some(dbgdidr.brps() + 1);
1098        }
1099        Ok(self.num_breakpoints.unwrap())
1100    }
1101
1102    /// See docs on the [`CoreInterface::hw_breakpoints`] trait
1103    fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
1104        let mut breakpoints = vec![];
1105        let num_hw_breakpoints = self.available_breakpoint_units()? as usize;
1106
1107        for bp_unit_index in 0..num_hw_breakpoints {
1108            let bp_value_addr = Dbgbvr::get_mmio_address_from_base(self.base_address)?
1109                + (bp_unit_index * size_of::<u32>()) as u64;
1110            let bp_value = self.memory.read_word_32(bp_value_addr)?;
1111
1112            let bp_control_addr = Dbgbcr::get_mmio_address_from_base(self.base_address)?
1113                + (bp_unit_index * size_of::<u32>()) as u64;
1114            let bp_control = Dbgbcr(self.memory.read_word_32(bp_control_addr)?);
1115
1116            if bp_control.e() {
1117                breakpoints.push(Some(bp_value as u64));
1118            } else {
1119                breakpoints.push(None);
1120            }
1121        }
1122        Ok(breakpoints)
1123    }
1124
1125    fn enable_breakpoints(&mut self, _state: bool) -> Result<(), Error> {
1126        // Breakpoints are always on with v7-A
1127        Ok(())
1128    }
1129
1130    fn set_hw_breakpoint(&mut self, bp_unit_index: usize, addr: u64) -> Result<(), Error> {
1131        let addr = valid_32bit_address(addr)?;
1132        set_hw_breakpoint(&mut *self.memory, self.base_address, bp_unit_index, addr)?;
1133        Ok(())
1134    }
1135
1136    fn clear_hw_breakpoint(&mut self, bp_unit_index: usize) -> Result<(), Error> {
1137        clear_hw_breakpoint(&mut *self.memory, self.base_address, bp_unit_index)?;
1138        Ok(())
1139    }
1140
1141    fn registers(&self) -> &'static CoreRegisters {
1142        match self.state.fp_reg_count {
1143            16 => &AARCH32_WITH_FP_16_CORE_REGISTERS,
1144            32 => &AARCH32_WITH_FP_32_CORE_REGISTERS,
1145            _ => &AARCH32_CORE_REGISTERS,
1146        }
1147    }
1148
1149    fn program_counter(&self) -> &'static CoreRegister {
1150        &PC
1151    }
1152
1153    fn frame_pointer(&self) -> &'static CoreRegister {
1154        &FP
1155    }
1156
1157    fn stack_pointer(&self) -> &'static CoreRegister {
1158        &SP
1159    }
1160
1161    fn return_address(&self) -> &'static CoreRegister {
1162        &RA
1163    }
1164
1165    fn hw_breakpoints_enabled(&self) -> bool {
1166        true
1167    }
1168
1169    fn architecture(&self) -> Architecture {
1170        Architecture::Arm
1171    }
1172
1173    fn core_type(&self) -> CoreType {
1174        self.core_type
1175    }
1176
1177    fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
1178        let cpsr: u32 = self.read_core_reg(XPSR.id())?.try_into()?;
1179
1180        // CPSR bit 5 - T - Thumb mode
1181        match (cpsr >> 5) & 1 {
1182            1 => Ok(InstructionSet::Thumb2),
1183            _ => Ok(InstructionSet::A32),
1184        }
1185    }
1186
1187    fn endianness(&mut self) -> Result<Endian, Error> {
1188        if let Some(endianness) = self.endianness {
1189            return Ok(endianness);
1190        }
1191        self.halted_access(|core| {
1192            let endianness = {
1193                let psr = TryInto::<u32>::try_into(core.read_core_reg(XPSR.id())?).unwrap();
1194                if psr & 1 << 9 == 0 {
1195                    Endian::Little
1196                } else {
1197                    Endian::Big
1198                }
1199            };
1200            core.endianness = Some(endianness);
1201            Ok(endianness)
1202        })
1203    }
1204
1205    fn fpu_support(&mut self) -> Result<bool, Error> {
1206        Ok(self.state.fp_reg_count != 0)
1207    }
1208
1209    fn floating_point_register_count(&mut self) -> Result<usize, Error> {
1210        Ok(self.state.fp_reg_count)
1211    }
1212
1213    #[tracing::instrument(skip(self))]
1214    fn reset_catch_set(&mut self) -> Result<(), Error> {
1215        self.halted_access(|core| {
1216            core.sequence.reset_catch_set(
1217                &mut *core.memory,
1218                CoreType::Armv7a,
1219                Some(core.base_address),
1220            )?;
1221            Ok(())
1222        })?;
1223        Ok(())
1224    }
1225
1226    #[tracing::instrument(skip(self))]
1227    fn reset_catch_clear(&mut self) -> Result<(), Error> {
1228        // Clear the reset_catch bit which was set earlier.
1229        self.halted_access(|core| {
1230            core.sequence.reset_catch_clear(
1231                &mut *core.memory,
1232                CoreType::Armv7a,
1233                Some(core.base_address),
1234            )?;
1235            Ok(())
1236        })?;
1237        Ok(())
1238    }
1239
1240    #[tracing::instrument(skip(self))]
1241    fn debug_core_stop(&mut self) -> Result<(), Error> {
1242        if matches!(self.state.current_state, CoreStatus::Halted(_)) {
1243            // We may have clobbered registers we wrote during debugging
1244            // Best effort attempt to put them back before we exit debug mode
1245            self.writeback_registers()?;
1246        }
1247
1248        self.sequence
1249            .debug_core_stop(&mut *self.memory, CoreType::Armv7a)?;
1250
1251        Ok(())
1252    }
1253
1254    fn enable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
1255        let address = Dbgvcr::get_mmio_address_from_base(self.base_address)?;
1256        let mut dbgvcr = Dbgvcr(self.memory.read_word_32(address)?);
1257
1258        match condition {
1259            VectorCatchCondition::CoreReset => dbgvcr.set_r(true),
1260            VectorCatchCondition::Svc => dbgvcr.set_ss(true),
1261            VectorCatchCondition::Hlt => dbgvcr.set_su(true),
1262            // HardFault/SecureFault are Cortex-M concepts, not applicable to ARMv7-A/R
1263            _ => {
1264                return Err(Error::NotImplemented(
1265                    "vector catch condition Hardfault/SecureFault",
1266                ));
1267            }
1268        }
1269
1270        self.memory.write_word_32(address, dbgvcr.into())?;
1271        Ok(())
1272    }
1273
1274    fn disable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
1275        let address = Dbgvcr::get_mmio_address_from_base(self.base_address)?;
1276        let mut dbgvcr = Dbgvcr(self.memory.read_word_32(address)?);
1277
1278        match condition {
1279            VectorCatchCondition::CoreReset => dbgvcr.set_r(false),
1280            VectorCatchCondition::Svc => dbgvcr.set_ss(false),
1281            VectorCatchCondition::Hlt => dbgvcr.set_su(false),
1282            // HardFault/SecureFault are Cortex-M concepts, not applicable to ARMv7-A/R
1283            _ => {
1284                return Err(Error::NotImplemented(
1285                    "vector catch condition Hardfault/SecureFault",
1286                ));
1287            }
1288        }
1289
1290        self.memory.write_word_32(address, dbgvcr.into())?;
1291        Ok(())
1292    }
1293}
1294
1295impl MemoryInterface for Armv7ar<'_> {
1296    fn supports_native_64bit_access(&mut self) -> bool {
1297        false
1298    }
1299
1300    fn read_word_64(&mut self, address: u64) -> Result<u64, Error> {
1301        self.halted_access(|core| {
1302            #[repr(align(4))]
1303            struct AlignedBytes([u8; 8]);
1304            let mut bytes = AlignedBytes([0u8; 8]);
1305            core.read(address, &mut bytes.0)?;
1306            let ret = match core.endianness()? {
1307                Endian::Little => u64::from_le_bytes(bytes.0),
1308                Endian::Big => u64::from_be_bytes(bytes.0),
1309            };
1310
1311            Ok(ret)
1312        })
1313    }
1314
1315    fn read_word_32(&mut self, address: u64) -> Result<u32, Error> {
1316        self.halted_access(|core| {
1317            let address = valid_32bit_address(address)?;
1318
1319            // LDC p14, c5, [r0], #4
1320            let instr = build_ldc(14, 5, 0, 4);
1321
1322            // Save r0
1323            core.prepare_r0_for_clobber()?;
1324
1325            // Load r0 with the address to read from
1326            core.set_r0(address)?;
1327
1328            // Read memory from [r0]
1329            core.execute_instruction_with_result(instr)
1330        })
1331    }
1332
1333    fn read_word_16(&mut self, address: u64) -> Result<u16, Error> {
1334        self.halted_access(|core| {
1335            // Find the word this is in and its byte offset
1336            let mut byte_offset = address % 4;
1337            let word_start = address - byte_offset;
1338
1339            // Read the word
1340            let data = core.read_word_32(word_start)?;
1341
1342            // We do 32-bit reads, so we need to take a different field
1343            // if we're running on a big endian device.
1344            if Endian::Big == core.endianness()? {
1345                // TODO: This doesn't work accessing 16-bit words that are not aligned.
1346                if address & 1 != 0 {
1347                    return Err(Error::MemoryNotAligned(MemoryNotAlignedError {
1348                        address,
1349                        alignment: 2,
1350                    }));
1351                }
1352                byte_offset = 2 - byte_offset;
1353            }
1354
1355            // Return the 16-bit word
1356            Ok((data >> (byte_offset * 8)) as u16)
1357        })
1358    }
1359
1360    fn read_word_8(&mut self, address: u64) -> Result<u8, Error> {
1361        self.halted_access(|core| {
1362            // Find the word this is in and its byte offset
1363            let mut byte_offset = address % 4;
1364
1365            let word_start = address - byte_offset;
1366
1367            // Read the word
1368            let data = core.read_word_32(word_start)?;
1369
1370            // We do 32-bit reads, so we need to take a different field
1371            // if we're running on a big endian device.
1372            if Endian::Big == core.endianness()? {
1373                byte_offset = 3 - byte_offset;
1374            }
1375
1376            // Return the byte
1377            Ok(data.to_le_bytes()[byte_offset as usize])
1378        })
1379    }
1380
1381    fn read_64(&mut self, address: u64, data: &mut [u64]) -> Result<(), Error> {
1382        self.halted_access(|core| {
1383            for (i, word) in data.iter_mut().enumerate() {
1384                *word = core.read_word_64(address + ((i as u64) * 8))?;
1385            }
1386
1387            Ok(())
1388        })
1389    }
1390
1391    fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), Error> {
1392        self.halted_access(|core| {
1393            let count = data.len();
1394            if count > 2 {
1395                // Save r0
1396                core.prepare_r0_for_clobber()?;
1397                core.set_r0(valid_32bit_address(address)?)?;
1398
1399                let mut banked = core.banked_access()?;
1400
1401                // Ignore any errors encountered here -- they will set a Data Abort
1402                // which we will pick up in `check_and_clear_data_abort()`
1403                if banked
1404                    .with_dcc_fast_mode(|banked| {
1405                        // LDC p14, c5, [r0], #4
1406                        banked.set_itr(build_ldc(14, 5, 0, 4))?;
1407
1408                        // Throw away the first value, which is from a previous operation
1409                        let _ = banked.dtrtx()?;
1410
1411                        // Continually write the tx register, which will auto-increment.
1412                        // Because reads lag by one instruction, we need to break before
1413                        // we read the final value. If we don't we will end up reading one
1414                        // extra word past the buffer, which may end up outside valid RAM.
1415                        banked.dtrtx_repeated(&mut data[0..count - 1])?;
1416                        Ok(())
1417                    })
1418                    .is_ok()
1419                {
1420                    // Grab the last value that we skipped during the main sequence.
1421                    // Ignore any errors here since they will generate an abort that
1422                    // will be caught below.
1423                    if let Ok(last) = banked.dtrtx()
1424                        && let Some(v) = data.last_mut()
1425                    {
1426                        *v = last;
1427                    }
1428                }
1429
1430                // Check if we had any aborts, if so clear them and fail
1431                let dscr = banked.dscr()?;
1432                check_and_clear_data_abort(&mut *core.memory, core.base_address, dscr)?;
1433            } else {
1434                for (i, word) in data.iter_mut().enumerate() {
1435                    *word = core.read_word_32(address + ((i as u64) * 4))?;
1436                }
1437            }
1438
1439            Ok(())
1440        })
1441    }
1442
1443    fn read_16(&mut self, address: u64, data: &mut [u16]) -> Result<(), Error> {
1444        self.halted_access(|core| {
1445            for (i, word) in data.iter_mut().enumerate() {
1446                *word = core.read_word_16(address + ((i as u64) * 2))?;
1447            }
1448
1449            Ok(())
1450        })
1451    }
1452
1453    fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), Error> {
1454        self.read(address, data)
1455    }
1456
1457    fn read(&mut self, address: u64, data: &mut [u8]) -> Result<(), Error> {
1458        self.halted_access(|core| {
1459            if address.is_multiple_of(4) && data.len().is_multiple_of(4) {
1460                // Avoid heap allocation and copy if we don't need it.
1461                if let Ok((aligned_buffer, _)) =
1462                    <[u32]>::mut_from_prefix_with_elems(data, data.len() / 4)
1463                {
1464                    core.read_32(address, aligned_buffer)?;
1465                } else {
1466                    let mut temporary_buffer = vec![0u32; data.len() / 4];
1467                    core.read_32(address, &mut temporary_buffer)?;
1468                    data.copy_from_slice(temporary_buffer.as_bytes());
1469                }
1470
1471                // We used 32-bit accesses, so swap the 32-bit values if necessary.
1472                if core.endianness()? == Endian::Big {
1473                    for word in data.chunks_exact_mut(4) {
1474                        word.reverse();
1475                    }
1476                }
1477            } else {
1478                let start_address = address & !3;
1479                let end_address = address + (data.len() as u64);
1480                let end_address = end_address + (4 - (end_address & 3));
1481                let start_extra_count = address as usize % 4;
1482                let mut buffer = vec![0u32; (end_address - start_address) as usize / 4];
1483                core.read_32(start_address, &mut buffer)?;
1484                if core.endianness()? == Endian::Big {
1485                    for word in buffer.iter_mut() {
1486                        *word = word.swap_bytes();
1487                    }
1488                }
1489                data.copy_from_slice(
1490                    &buffer.as_bytes()[start_extra_count..start_extra_count + data.len()],
1491                );
1492            }
1493            Ok(())
1494        })
1495    }
1496
1497    fn write_word_64(&mut self, address: u64, data: u64) -> Result<(), Error> {
1498        self.halted_access(|core| {
1499            let (data_low, data_high) = match core.endianness()? {
1500                Endian::Little => (data as u32, (data >> 32) as u32),
1501                Endian::Big => ((data >> 32) as u32, data as u32),
1502            };
1503
1504            core.write_32(address, &[data_low, data_high])
1505        })
1506    }
1507
1508    fn write_word_32(&mut self, address: u64, data: u32) -> Result<(), Error> {
1509        self.halted_access(|core| {
1510            let address = valid_32bit_address(address)?;
1511
1512            // STC p14, c5, [r0], #4
1513            let instr = build_stc(14, 5, 0, 4);
1514
1515            // Save r0
1516            core.prepare_r0_for_clobber()?;
1517
1518            // Load r0 with the address to write to
1519            core.set_r0(address)?;
1520
1521            // Write to [r0]
1522            core.execute_instruction_with_input(instr, data)
1523        })
1524    }
1525
1526    fn write_word_8(&mut self, address: u64, data: u8) -> Result<(), Error> {
1527        self.halted_access(|core| {
1528            // Find the word this is in and its byte offset
1529            let mut byte_offset = address % 4;
1530            let word_start = address - byte_offset;
1531
1532            // We do 32-bit reads and writes, so we need to take a different field
1533            // if we're running on a big endian device.
1534            if Endian::Big == core.endianness()? {
1535                byte_offset = 3 - byte_offset;
1536            }
1537
1538            // Get the current word value
1539            let current_word = core.read_word_32(word_start)?;
1540            let mut word_bytes = current_word.to_le_bytes();
1541            word_bytes[byte_offset as usize] = data;
1542
1543            core.write_word_32(word_start, u32::from_le_bytes(word_bytes))
1544        })
1545    }
1546
1547    fn write_word_16(&mut self, address: u64, data: u16) -> Result<(), Error> {
1548        self.halted_access(|core| {
1549            // Find the word this is in and its byte offset
1550            let mut byte_offset = address % 4;
1551            let word_start = address - byte_offset;
1552
1553            // We do 32-bit reads and writes, so we need to take a different field
1554            // if we're running on a big endian device.
1555            if Endian::Big == core.endianness()? {
1556                // TODO: This doesn't work when accessing 16-bit words that are not aligned.
1557                if address & 1 != 0 {
1558                    return Err(Error::MemoryNotAligned(MemoryNotAlignedError {
1559                        address,
1560                        alignment: 2,
1561                    }));
1562                }
1563                byte_offset = 2 - byte_offset;
1564            }
1565
1566            // Get the current word value
1567            let mut word = core.read_word_32(word_start)?;
1568
1569            // patch the word into it
1570            word &= !(0xFFFFu32 << (byte_offset * 8));
1571            word |= (data as u32) << (byte_offset * 8);
1572
1573            core.write_word_32(word_start, word)
1574        })
1575    }
1576
1577    fn write_64(&mut self, address: u64, data: &[u64]) -> Result<(), Error> {
1578        self.halted_access(|core| {
1579            for (i, word) in data.iter().enumerate() {
1580                core.write_word_64(address + ((i as u64) * 8), *word)?;
1581            }
1582
1583            Ok(())
1584        })
1585    }
1586
1587    fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), Error> {
1588        self.halted_access(|core| {
1589            if data.len() > 2 {
1590                // Save r0
1591                core.prepare_r0_for_clobber()?;
1592                core.set_r0(valid_32bit_address(address)?)?;
1593
1594                let mut banked = core.banked_access()?;
1595
1596                banked
1597                    .with_dcc_fast_mode(|banked| {
1598                        // STC p14, c5, [r0], #4
1599                        banked.set_itr(build_stc(14, 5, 0, 4))?;
1600
1601                        // Continually write the tx register, which will auto-increment
1602                        banked.set_dtrrx_repeated(data)?;
1603                        Ok(())
1604                    })
1605                    .ok();
1606
1607                // Check if we had any aborts, if so clear them and fail
1608                let dscr = banked.dscr()?;
1609                check_and_clear_data_abort(&mut *core.memory, core.base_address, dscr)?;
1610            } else {
1611                // Slow path -- perform multiple writes
1612                for (i, word) in data.iter().enumerate() {
1613                    core.write_word_32(address + ((i as u64) * 4), *word)?;
1614                }
1615            }
1616
1617            Ok(())
1618        })
1619    }
1620
1621    fn write_16(&mut self, address: u64, data: &[u16]) -> Result<(), Error> {
1622        self.halted_access(|core| {
1623            for (i, word) in data.iter().enumerate() {
1624                core.write_word_16(address + ((i as u64) * 2), *word)?;
1625            }
1626
1627            Ok(())
1628        })
1629    }
1630
1631    fn write_8(&mut self, address: u64, data: &[u8]) -> Result<(), Error> {
1632        self.write(address, data)
1633    }
1634
1635    fn write(&mut self, address: u64, data: &[u8]) -> Result<(), Error> {
1636        self.halted_access(|core| {
1637            let len = data.len();
1638            let start_extra_count = ((4 - (address % 4) as usize) % 4).min(len);
1639            let end_extra_count = (len - start_extra_count) % 4;
1640            assert!(start_extra_count < 4);
1641            assert!(end_extra_count < 4);
1642
1643            // Fall back to slower bytewise access if it's not aligned
1644            if start_extra_count != 0 || end_extra_count != 0 {
1645                for (i, byte) in data.iter().enumerate() {
1646                    core.write_word_8(address + (i as u64), *byte)?;
1647                }
1648                return Ok(());
1649            }
1650
1651            // Make sure we don't try to do an empty but potentially unaligned write
1652            // We do a 32 bit write of the remaining bytes that are 4 byte aligned.
1653            let mut buffer = vec![0u32; data.len() / 4];
1654            let endianness = core.endianness()?;
1655            for (bytes, value) in data.chunks_exact(4).zip(buffer.iter_mut()) {
1656                *value = match endianness {
1657                    Endian::Little => u32::from_le_bytes(bytes.try_into().unwrap()),
1658                    Endian::Big => u32::from_be_bytes(bytes.try_into().unwrap()),
1659                }
1660            }
1661            core.write_32(address, &buffer)?;
1662
1663            Ok(())
1664        })
1665    }
1666
1667    fn supports_8bit_transfers(&self) -> Result<bool, Error> {
1668        Ok(false)
1669    }
1670
1671    fn flush(&mut self) -> Result<(), Error> {
1672        // Nothing to do - this runs through the CPU which automatically handles any caching
1673        Ok(())
1674    }
1675}
1676
1677/// Check if the current vector catch halt is a semihosting call.
1678///
1679/// Supports two semihosting mechanisms on A/R-profile cores:
1680/// - SVC-based: `SVC #0x123456` (ARM) or `SVC #0xAB` (Thumb) - vectors to 0x08
1681/// - HLT-based: `HLT #0xF000` (ARM) or `HLT #0x3C` (Thumb) - undefined on ARMv7, vectors to 0x04
1682///
1683/// HLT-based semihosting is preferred as it doesn't interfere with baremetal/OS/RTOS SVC usage.
1684/// Spec: <https://github.com/ARM-software/abi-aa/blob/2025Q1/semihosting/semihosting.rst#the-semihosting-interface>
1685pub(crate) fn check_for_semihosting(
1686    cached_command: Option<SemihostingCommand>,
1687    core: &mut dyn CoreInterface,
1688    lr: u32,
1689) -> Result<Option<SemihostingCommand>, Error> {
1690    // Return cached command if already decoded (avoid re-decoding on repeated status() calls)
1691    if let Some(command) = cached_command {
1692        return Ok(Some(command));
1693    }
1694
1695    // Vector table layout (32-byte aligned):
1696    //   0x00=Reset, 0x04=Undef, 0x08=SVC, ...
1697    //
1698    // We check for semihosting on:
1699    // - SVC vector (0x08): Traditional semihosting via SVC instruction
1700    // - UNDEF vector (0x04): HLT-based semihosting (HLT is undefined on ARMv7)
1701    let pc: u32 = core.read_core_reg(core.program_counter().id)?.try_into()?;
1702
1703    const UNDEF_VECTOR_OFFSET: u32 = 0x04;
1704    const SVC_VECTOR_OFFSET: u32 = 0x08;
1705    const VECTOR_TABLE_MASK: u32 = 32 - 1;
1706
1707    let vector_offset = pc & VECTOR_TABLE_MASK;
1708
1709    // Early return if we're not at a semihosting vector, to not reading potentially invalid memory
1710    // at LR-4
1711    if vector_offset != UNDEF_VECTOR_OFFSET && vector_offset != SVC_VECTOR_OFFSET {
1712        tracing::debug!(
1713            "Vector catch at PC={:#x} (offset {:#x}), not SVC/UNDEF vector, not semihosting",
1714            pc,
1715            vector_offset
1716        );
1717        return Ok(None);
1718    }
1719
1720    // Semihosting instruction encodings:
1721    // SVC-based:
1722    // - ARM state:   `SVC #0x123456` encoded as 0xEF123456
1723    // - Thumb state: `SVC #0xAB`     encoded as 0xDFAB
1724    // HLT-based:
1725    // - ARM state:   `HLT #0xF000`   encoded as 0xE10F0070
1726    // - Thumb state: `HLT #64`       encoded as 0xBABC
1727    const ARM_SEMIHOSTING_SVC: [u8; 4] = 0xEF123456_u32.to_le_bytes();
1728    const THUMB_SEMIHOSTING_SVC: [u8; 2] = 0xDFAB_u16.to_le_bytes();
1729    const ARM_SEMIHOSTING_HLT: [u8; 4] = 0xE10F0070_u32.to_le_bytes();
1730    const THUMB_SEMIHOSTING_HLT: [u8; 2] = 0xBABC_u16.to_le_bytes();
1731
1732    // Read word at LR-4 to check instructions
1733    let instruction_address = lr.wrapping_sub(4);
1734    let mut instruction = [0u8; 4];
1735    core.read_8(instruction_address as u64, &mut instruction)?;
1736
1737    let (is_semihosting, mechanism) = match vector_offset {
1738        SVC_VECTOR_OFFSET => {
1739            let is_arm = instruction == ARM_SEMIHOSTING_SVC;
1740            let is_thumb = instruction[2..] == THUMB_SEMIHOSTING_SVC;
1741            (is_arm || is_thumb, "SVC")
1742        }
1743        UNDEF_VECTOR_OFFSET => {
1744            let is_arm = instruction == ARM_SEMIHOSTING_HLT;
1745            let is_thumb = instruction[2..] == THUMB_SEMIHOSTING_HLT;
1746            (is_arm || is_thumb, "HLT")
1747        }
1748        _ => unreachable!(), // Already handled above in early return
1749    };
1750
1751    if !is_semihosting {
1752        return Ok(None);
1753    }
1754
1755    tracing::debug!(
1756        "{} instruction check: LR={:#x}, bytes at {:#x} = {:#010x}, match={}",
1757        mechanism,
1758        lr,
1759        instruction_address,
1760        u32::from_le_bytes(instruction),
1761        is_semihosting
1762    );
1763
1764    let command = decode_semihosting_syscall(core)?;
1765    tracing::debug!(
1766        "Semihosting {} detected at PC={:#x}: {:?}",
1767        mechanism,
1768        pc,
1769        command
1770    );
1771    Ok(Some(command))
1772}
1773
1774#[cfg(test)]
1775mod test {
1776    use crate::{
1777        architecture::arm::{
1778            FullyQualifiedApAddress, communication_interface::SwdSequence,
1779            sequences::DefaultArmSequence,
1780        },
1781        probe::DebugProbeError,
1782    };
1783
1784    use super::*;
1785
1786    const TEST_BASE_ADDRESS: u64 = 0x8000_1000;
1787
1788    fn address_to_reg_num(address: u64) -> u32 {
1789        ((address - TEST_BASE_ADDRESS) / 4) as u32
1790    }
1791
1792    #[derive(Debug)]
1793    pub struct ExpectedMemoryOp {
1794        read: bool,
1795        address: u64,
1796        value: u32,
1797    }
1798
1799    pub struct MockProbe {
1800        expected_ops: Vec<ExpectedMemoryOp>,
1801    }
1802
1803    impl MockProbe {
1804        pub fn new() -> Self {
1805            MockProbe {
1806                expected_ops: vec![],
1807            }
1808        }
1809
1810        pub fn expected_read(&mut self, addr: u64, value: u32) {
1811            self.expected_ops.push(ExpectedMemoryOp {
1812                read: true,
1813                address: addr,
1814                value,
1815            });
1816        }
1817
1818        pub fn expected_write(&mut self, addr: u64, value: u32) {
1819            self.expected_ops.push(ExpectedMemoryOp {
1820                read: false,
1821                address: addr,
1822                value,
1823            });
1824        }
1825    }
1826
1827    impl MemoryInterface<ArmError> for MockProbe {
1828        fn read_8(&mut self, _address: u64, _data: &mut [u8]) -> Result<(), ArmError> {
1829            todo!()
1830        }
1831
1832        fn read_16(&mut self, _address: u64, _data: &mut [u16]) -> Result<(), ArmError> {
1833            todo!()
1834        }
1835
1836        fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), ArmError> {
1837            if self.expected_ops.is_empty() {
1838                panic!(
1839                    "Received unexpected read_32 op: register {:#}",
1840                    address_to_reg_num(address)
1841                );
1842            }
1843
1844            assert_eq!(data.len(), 1);
1845
1846            let expected_op = self.expected_ops.remove(0);
1847
1848            assert!(
1849                expected_op.read,
1850                "R/W mismatch for register: Expected {:#} Actual: {:#}",
1851                address_to_reg_num(expected_op.address),
1852                address_to_reg_num(address)
1853            );
1854            assert_eq!(
1855                expected_op.address,
1856                address,
1857                "Read from unexpected register: Expected {:#} Actual: {:#}",
1858                address_to_reg_num(expected_op.address),
1859                address_to_reg_num(address)
1860            );
1861
1862            data[0] = expected_op.value;
1863
1864            Ok(())
1865        }
1866
1867        fn read(&mut self, address: u64, data: &mut [u8]) -> Result<(), ArmError> {
1868            self.read_8(address, data)
1869        }
1870
1871        fn write_8(&mut self, _address: u64, _data: &[u8]) -> Result<(), ArmError> {
1872            todo!()
1873        }
1874
1875        fn write_16(&mut self, _address: u64, _data: &[u16]) -> Result<(), ArmError> {
1876            todo!()
1877        }
1878
1879        fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), ArmError> {
1880            if self.expected_ops.is_empty() {
1881                panic!(
1882                    "Received unexpected write_32 op: register {:#}",
1883                    address_to_reg_num(address)
1884                );
1885            }
1886
1887            assert_eq!(data.len(), 1);
1888
1889            let expected_op = self.expected_ops.remove(0);
1890
1891            assert!(
1892                !expected_op.read,
1893                "Read/write mismatch on register: {:#}",
1894                address_to_reg_num(address)
1895            );
1896            assert_eq!(
1897                expected_op.address,
1898                address,
1899                "Write to unexpected register: Expected {:#} Actual: {:#}",
1900                address_to_reg_num(expected_op.address),
1901                address_to_reg_num(address)
1902            );
1903
1904            assert_eq!(
1905                expected_op.value, data[0],
1906                "Write value mismatch Expected {:#X} Actual: {:#X}",
1907                expected_op.value, data[0]
1908            );
1909
1910            Ok(())
1911        }
1912
1913        fn write(&mut self, address: u64, data: &[u8]) -> Result<(), ArmError> {
1914            self.write_8(address, data)
1915        }
1916
1917        fn flush(&mut self) -> Result<(), ArmError> {
1918            todo!()
1919        }
1920
1921        fn read_64(&mut self, _address: u64, _data: &mut [u64]) -> Result<(), ArmError> {
1922            todo!()
1923        }
1924
1925        fn write_64(&mut self, _address: u64, _data: &[u64]) -> Result<(), ArmError> {
1926            todo!()
1927        }
1928
1929        fn supports_8bit_transfers(&self) -> Result<bool, ArmError> {
1930            Ok(false)
1931        }
1932
1933        fn supports_native_64bit_access(&mut self) -> bool {
1934            false
1935        }
1936    }
1937
1938    impl ArmMemoryInterface for MockProbe {
1939        fn fully_qualified_address(&self) -> FullyQualifiedApAddress {
1940            todo!()
1941        }
1942
1943        fn get_arm_debug_interface(
1944            &mut self,
1945        ) -> Result<&mut dyn crate::architecture::arm::ArmDebugInterface, DebugProbeError> {
1946            Err(DebugProbeError::NotImplemented {
1947                function_name: "get_arm_debug_interface",
1948            })
1949        }
1950
1951        fn generic_status(&mut self) -> Result<crate::architecture::arm::ap::CSW, ArmError> {
1952            Err(ArmError::Probe(DebugProbeError::NotImplemented {
1953                function_name: "generic_status",
1954            }))
1955        }
1956
1957        fn base_address(&mut self) -> Result<u64, ArmError> {
1958            todo!()
1959        }
1960    }
1961
1962    impl SwdSequence for MockProbe {
1963        fn swj_sequence(&mut self, _bit_len: u8, _bits: u64) -> Result<(), DebugProbeError> {
1964            todo!()
1965        }
1966
1967        fn swj_pins(
1968            &mut self,
1969            _pin_out: u32,
1970            _pin_select: u32,
1971            _pin_wait: u32,
1972        ) -> Result<u32, DebugProbeError> {
1973            todo!()
1974        }
1975    }
1976
1977    fn add_status_expectations(probe: &mut MockProbe, halted: bool) {
1978        let mut dbgdscr = Dbgdscr(0);
1979        dbgdscr.set_halted(halted);
1980        dbgdscr.set_restarted(true);
1981        probe.expected_read(
1982            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1983            dbgdscr.into(),
1984        );
1985    }
1986
1987    fn add_enable_itr_expectations(probe: &mut MockProbe) {
1988        let mut dbgdscr = Dbgdscr(0);
1989        dbgdscr.set_halted(true);
1990        probe.expected_read(
1991            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1992            dbgdscr.into(),
1993        );
1994        dbgdscr.set_itren(true);
1995        probe.expected_write(
1996            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1997            dbgdscr.into(),
1998        );
1999    }
2000
2001    fn add_read_reg_expectations(probe: &mut MockProbe, reg: u16, value: u32) {
2002        probe.expected_write(
2003            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2004            build_mcr(14, 0, reg, 0, 5, 0),
2005        );
2006        let mut dbgdscr = Dbgdscr(0);
2007        dbgdscr.set_instrcoml_l(true);
2008        dbgdscr.set_txfull_l(true);
2009
2010        probe.expected_read(
2011            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2012            dbgdscr.into(),
2013        );
2014        probe.expected_read(
2015            Dbgdtrtx::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2016            value,
2017        );
2018    }
2019
2020    fn add_read_pc_expectations(probe: &mut MockProbe, value: u32) {
2021        let mut dbgdscr = Dbgdscr(0);
2022        dbgdscr.set_instrcoml_l(true);
2023        dbgdscr.set_txfull_l(true);
2024
2025        probe.expected_write(
2026            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2027            build_mov(0, 15),
2028        );
2029        probe.expected_read(
2030            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2031            dbgdscr.into(),
2032        );
2033        // + 8 to add expected offset on halt
2034        add_read_reg_expectations(probe, 0, value + 8);
2035    }
2036
2037    fn add_read_fp_count_expectations(probe: &mut MockProbe) {
2038        let mut dbgdscr = Dbgdscr(0);
2039        dbgdscr.set_instrcoml_l(true);
2040        dbgdscr.set_txfull_l(true);
2041        let mut cpacr = Cpacr(0);
2042        cpacr.set_cp(10, 0b11);
2043        cpacr.set_cp(11, 0b11);
2044
2045        // CPACR read: MRC
2046        probe.expected_write(
2047            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2048            build_mrc(15, 0, 0, 1, 0, 2),
2049        );
2050        probe.expected_read(
2051            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2052            dbgdscr.into(),
2053        );
2054        // CPACR read: MCR
2055        add_read_reg_expectations(probe, 0, cpacr.0);
2056
2057        // MVFR0 read
2058        probe.expected_write(
2059            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2060            build_vmrs(0, 0b0111),
2061        );
2062        probe.expected_read(
2063            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2064            dbgdscr.into(),
2065        );
2066        add_read_reg_expectations(probe, 0, 0b010);
2067    }
2068
2069    fn add_read_cpsr_expectations(probe: &mut MockProbe, value: u32) {
2070        let mut dbgdscr = Dbgdscr(0);
2071        dbgdscr.set_instrcoml_l(true);
2072        dbgdscr.set_txfull_l(true);
2073
2074        probe.expected_write(
2075            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2076            build_mrs(0),
2077        );
2078        probe.expected_read(
2079            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2080            dbgdscr.into(),
2081        );
2082        add_read_reg_expectations(probe, 0, value);
2083    }
2084
2085    fn add_idr_expectations(probe: &mut MockProbe, bp_count: u32) {
2086        let mut dbgdidr = Dbgdidr(0);
2087        dbgdidr.set_brps(bp_count - 1);
2088        probe.expected_read(
2089            Dbgdidr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2090            dbgdidr.into(),
2091        );
2092    }
2093
2094    fn add_set_r0_expectation(probe: &mut MockProbe, value: u32) {
2095        let mut dbgdscr = Dbgdscr(0);
2096        dbgdscr.set_instrcoml_l(true);
2097        dbgdscr.set_rxfull_l(true);
2098
2099        probe.expected_write(
2100            Dbgdtrrx::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2101            value,
2102        );
2103        probe.expected_read(
2104            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2105            dbgdscr.into(),
2106        );
2107
2108        probe.expected_write(
2109            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2110            build_mrc(14, 0, 0, 0, 5, 0),
2111        );
2112        probe.expected_read(
2113            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2114            dbgdscr.into(),
2115        );
2116    }
2117
2118    fn add_read_memory_expectations(probe: &mut MockProbe, address: u64, value: u32) {
2119        add_set_r0_expectation(probe, address as u32);
2120
2121        let mut dbgdscr = Dbgdscr(0);
2122        dbgdscr.set_instrcoml_l(true);
2123        dbgdscr.set_txfull_l(true);
2124
2125        probe.expected_write(
2126            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2127            build_ldc(14, 5, 0, 4),
2128        );
2129        probe.expected_read(
2130            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2131            dbgdscr.into(),
2132        );
2133        probe.expected_read(
2134            Dbgdtrtx::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2135            value,
2136        );
2137    }
2138
2139    impl Drop for MockProbe {
2140        fn drop(&mut self) {
2141            if !self.expected_ops.is_empty() {
2142                panic!("self.expected_ops is not empty: {:?}", self.expected_ops);
2143            }
2144        }
2145    }
2146
2147    #[test]
2148    fn armv7a_new() {
2149        let mut probe = MockProbe::new();
2150
2151        // Add expectations
2152        add_status_expectations(&mut probe, true);
2153        add_enable_itr_expectations(&mut probe);
2154        add_read_reg_expectations(&mut probe, 0, 0);
2155        add_read_fp_count_expectations(&mut probe);
2156
2157        let mock_mem = Box::new(probe) as _;
2158
2159        let _ = Armv7ar::new(
2160            mock_mem,
2161            &mut CortexARState::new(),
2162            TEST_BASE_ADDRESS,
2163            DefaultArmSequence::create(),
2164            CoreType::Armv7a,
2165        )
2166        .unwrap();
2167    }
2168
2169    #[test]
2170    fn armv7a_core_halted() {
2171        let mut probe = MockProbe::new();
2172        let mut state = CortexARState::new();
2173
2174        // Add expectations
2175        add_status_expectations(&mut probe, true);
2176        add_enable_itr_expectations(&mut probe);
2177        add_read_reg_expectations(&mut probe, 0, 0);
2178        add_read_fp_count_expectations(&mut probe);
2179
2180        let mut dbgdscr = Dbgdscr(0);
2181        dbgdscr.set_halted(false);
2182        probe.expected_read(
2183            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2184            dbgdscr.into(),
2185        );
2186
2187        dbgdscr.set_halted(true);
2188        probe.expected_read(
2189            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2190            dbgdscr.into(),
2191        );
2192
2193        let mock_mem = Box::new(probe) as _;
2194
2195        let mut armv7ar = Armv7ar::new(
2196            mock_mem,
2197            &mut state,
2198            TEST_BASE_ADDRESS,
2199            DefaultArmSequence::create(),
2200            CoreType::Armv7a,
2201        )
2202        .unwrap();
2203
2204        // First read false, second read true
2205        assert!(!armv7ar.core_halted().unwrap());
2206        assert!(armv7ar.core_halted().unwrap());
2207    }
2208
2209    #[test]
2210    fn armv7a_wait_for_core_halted() {
2211        let mut probe = MockProbe::new();
2212        let mut state = CortexARState::new();
2213
2214        // Add expectations
2215        add_status_expectations(&mut probe, true);
2216        add_enable_itr_expectations(&mut probe);
2217        add_read_reg_expectations(&mut probe, 0, 0);
2218        add_read_fp_count_expectations(&mut probe);
2219
2220        let mut dbgdscr = Dbgdscr(0);
2221        dbgdscr.set_halted(false);
2222        probe.expected_read(
2223            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2224            dbgdscr.into(),
2225        );
2226
2227        dbgdscr.set_halted(true);
2228        probe.expected_read(
2229            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2230            dbgdscr.into(),
2231        );
2232
2233        let mock_mem = Box::new(probe) as _;
2234
2235        let mut armv7ar = Armv7ar::new(
2236            mock_mem,
2237            &mut state,
2238            TEST_BASE_ADDRESS,
2239            DefaultArmSequence::create(),
2240            CoreType::Armv7a,
2241        )
2242        .unwrap();
2243
2244        // Should halt on second read
2245        armv7ar
2246            .wait_for_core_halted(Duration::from_millis(100))
2247            .unwrap();
2248    }
2249
2250    #[test]
2251    fn armv7a_status_running() {
2252        let mut probe = MockProbe::new();
2253        let mut state = CortexARState::new();
2254
2255        // Add expectations
2256        add_status_expectations(&mut probe, true);
2257        add_enable_itr_expectations(&mut probe);
2258        add_read_reg_expectations(&mut probe, 0, 0);
2259        add_read_fp_count_expectations(&mut probe);
2260
2261        let mut dbgdscr = Dbgdscr(0);
2262        dbgdscr.set_halted(false);
2263        probe.expected_read(
2264            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2265            dbgdscr.into(),
2266        );
2267
2268        let mock_mem = Box::new(probe) as _;
2269
2270        let mut armv7ar = Armv7ar::new(
2271            mock_mem,
2272            &mut state,
2273            TEST_BASE_ADDRESS,
2274            DefaultArmSequence::create(),
2275            CoreType::Armv7a,
2276        )
2277        .unwrap();
2278
2279        // Should halt on second read
2280        assert_eq!(CoreStatus::Running, armv7ar.status().unwrap());
2281    }
2282
2283    #[test]
2284    fn armv7a_status_halted() {
2285        let mut probe = MockProbe::new();
2286        let mut state = CortexARState::new();
2287
2288        // Add expectations
2289        add_status_expectations(&mut probe, true);
2290        add_enable_itr_expectations(&mut probe);
2291        add_read_reg_expectations(&mut probe, 0, 0);
2292        add_read_fp_count_expectations(&mut probe);
2293
2294        let mut dbgdscr = Dbgdscr(0);
2295        dbgdscr.set_halted(true);
2296        probe.expected_read(
2297            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2298            dbgdscr.into(),
2299        );
2300
2301        let mock_mem = Box::new(probe) as _;
2302
2303        let mut armv7ar = Armv7ar::new(
2304            mock_mem,
2305            &mut state,
2306            TEST_BASE_ADDRESS,
2307            DefaultArmSequence::create(),
2308            CoreType::Armv7a,
2309        )
2310        .unwrap();
2311
2312        // Should halt on second read
2313        assert_eq!(
2314            CoreStatus::Halted(crate::HaltReason::Request),
2315            armv7ar.status().unwrap()
2316        );
2317    }
2318
2319    #[test]
2320    fn armv7a_read_core_reg_common() {
2321        const REG_VALUE: u32 = 0xABCD;
2322
2323        let mut probe = MockProbe::new();
2324        let mut state = CortexARState::new();
2325
2326        // Add expectations
2327        add_status_expectations(&mut probe, true);
2328        add_enable_itr_expectations(&mut probe);
2329        add_read_reg_expectations(&mut probe, 0, 0);
2330        add_read_fp_count_expectations(&mut probe);
2331
2332        // Read register
2333        add_read_reg_expectations(&mut probe, 2, REG_VALUE);
2334
2335        let mock_mem = Box::new(probe) as _;
2336
2337        let mut armv7ar = Armv7ar::new(
2338            mock_mem,
2339            &mut state,
2340            TEST_BASE_ADDRESS,
2341            DefaultArmSequence::create(),
2342            CoreType::Armv7a,
2343        )
2344        .unwrap();
2345
2346        // First read will hit expectations
2347        assert_eq!(
2348            RegisterValue::from(REG_VALUE),
2349            armv7ar.read_core_reg(RegisterId(2)).unwrap()
2350        );
2351
2352        // Second read will cache, no new expectations
2353        assert_eq!(
2354            RegisterValue::from(REG_VALUE),
2355            armv7ar.read_core_reg(RegisterId(2)).unwrap()
2356        );
2357    }
2358
2359    #[test]
2360    fn armv7a_read_core_reg_pc() {
2361        const REG_VALUE: u32 = 0xABCD;
2362
2363        let mut probe = MockProbe::new();
2364        let mut state = CortexARState::new();
2365
2366        // Add expectations
2367        add_status_expectations(&mut probe, true);
2368        add_enable_itr_expectations(&mut probe);
2369        add_read_reg_expectations(&mut probe, 0, 0);
2370        add_read_fp_count_expectations(&mut probe);
2371
2372        // Read PC
2373        add_read_pc_expectations(&mut probe, REG_VALUE);
2374
2375        let mock_mem = Box::new(probe) as _;
2376
2377        let mut armv7ar = Armv7ar::new(
2378            mock_mem,
2379            &mut state,
2380            TEST_BASE_ADDRESS,
2381            DefaultArmSequence::create(),
2382            CoreType::Armv7a,
2383        )
2384        .unwrap();
2385
2386        // First read will hit expectations
2387        assert_eq!(
2388            RegisterValue::from(REG_VALUE),
2389            armv7ar.read_core_reg(RegisterId(15)).unwrap()
2390        );
2391
2392        // Second read will cache, no new expectations
2393        assert_eq!(
2394            RegisterValue::from(REG_VALUE),
2395            armv7ar.read_core_reg(RegisterId(15)).unwrap()
2396        );
2397    }
2398
2399    #[test]
2400    fn armv7a_read_core_reg_cpsr() {
2401        const REG_VALUE: u32 = 0xABCD;
2402
2403        let mut probe = MockProbe::new();
2404        let mut state = CortexARState::new();
2405
2406        // Add expectations
2407        add_status_expectations(&mut probe, true);
2408        add_enable_itr_expectations(&mut probe);
2409        add_read_reg_expectations(&mut probe, 0, 0);
2410        add_read_fp_count_expectations(&mut probe);
2411
2412        // Read CPSR
2413        add_read_cpsr_expectations(&mut probe, REG_VALUE);
2414
2415        let mock_mem = Box::new(probe) as _;
2416
2417        let mut armv7ar = Armv7ar::new(
2418            mock_mem,
2419            &mut state,
2420            TEST_BASE_ADDRESS,
2421            DefaultArmSequence::create(),
2422            CoreType::Armv7a,
2423        )
2424        .unwrap();
2425
2426        // First read will hit expectations
2427        assert_eq!(
2428            RegisterValue::from(REG_VALUE),
2429            armv7ar.read_core_reg(XPSR.id()).unwrap()
2430        );
2431
2432        // Second read will cache, no new expectations
2433        assert_eq!(
2434            RegisterValue::from(REG_VALUE),
2435            armv7ar.read_core_reg(XPSR.id()).unwrap()
2436        );
2437    }
2438
2439    #[test]
2440    fn armv7a_halt() {
2441        const REG_VALUE: u32 = 0xABCD;
2442
2443        let mut probe = MockProbe::new();
2444        let mut state = CortexARState::new();
2445
2446        // Add expectations
2447        add_status_expectations(&mut probe, false);
2448
2449        // Write halt request
2450        let mut dbgdrcr = Dbgdrcr(0);
2451        dbgdrcr.set_hrq(true);
2452        probe.expected_write(
2453            Dbgdrcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2454            dbgdrcr.into(),
2455        );
2456
2457        // Wait for halted
2458        add_status_expectations(&mut probe, true);
2459
2460        // Read status
2461        add_status_expectations(&mut probe, true);
2462        add_enable_itr_expectations(&mut probe);
2463        add_read_reg_expectations(&mut probe, 0, 0);
2464        add_read_fp_count_expectations(&mut probe);
2465
2466        // Read PC
2467        add_read_pc_expectations(&mut probe, REG_VALUE);
2468
2469        let mock_mem = Box::new(probe) as _;
2470
2471        let mut armv7ar = Armv7ar::new(
2472            mock_mem,
2473            &mut state,
2474            TEST_BASE_ADDRESS,
2475            DefaultArmSequence::create(),
2476            CoreType::Armv7a,
2477        )
2478        .unwrap();
2479
2480        // Verify PC
2481        assert_eq!(
2482            REG_VALUE as u64,
2483            armv7ar.halt(Duration::from_millis(100)).unwrap().pc
2484        );
2485    }
2486
2487    #[test]
2488    fn armv7a_run() {
2489        let mut probe = MockProbe::new();
2490        let mut state = CortexARState::new();
2491
2492        // Add expectations
2493        add_status_expectations(&mut probe, true);
2494        add_enable_itr_expectations(&mut probe);
2495        add_read_reg_expectations(&mut probe, 0, 0);
2496        add_read_fp_count_expectations(&mut probe);
2497
2498        // Writeback r0
2499        add_set_r0_expectation(&mut probe, 0);
2500
2501        // Disable ITRen
2502        let mut dbgdscr = Dbgdscr(0);
2503        dbgdscr.set_itren(true);
2504        probe.expected_read(
2505            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2506            dbgdscr.into(),
2507        );
2508        dbgdscr.set_itren(false);
2509        probe.expected_write(
2510            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2511            dbgdscr.into(),
2512        );
2513
2514        // Write resume request
2515        let mut dbgdrcr = Dbgdrcr(0);
2516        dbgdrcr.set_rrq(true);
2517        probe.expected_write(
2518            Dbgdrcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2519            dbgdrcr.into(),
2520        );
2521
2522        // Wait for running
2523        add_status_expectations(&mut probe, false);
2524
2525        // Read status
2526        add_status_expectations(&mut probe, false);
2527
2528        let mock_mem = Box::new(probe) as _;
2529
2530        let mut armv7ar = Armv7ar::new(
2531            mock_mem,
2532            &mut state,
2533            TEST_BASE_ADDRESS,
2534            DefaultArmSequence::create(),
2535            CoreType::Armv7a,
2536        )
2537        .unwrap();
2538
2539        armv7ar.run().unwrap();
2540    }
2541
2542    #[test]
2543    fn armv7a_available_breakpoint_units() {
2544        const BP_COUNT: u32 = 4;
2545        let mut probe = MockProbe::new();
2546        let mut state = CortexARState::new();
2547
2548        // Add expectations
2549        add_status_expectations(&mut probe, true);
2550        add_enable_itr_expectations(&mut probe);
2551        add_read_reg_expectations(&mut probe, 0, 0);
2552        add_read_fp_count_expectations(&mut probe);
2553
2554        // Read breakpoint count
2555        add_idr_expectations(&mut probe, BP_COUNT);
2556
2557        let mock_mem = Box::new(probe) as _;
2558
2559        let mut armv7ar = Armv7ar::new(
2560            mock_mem,
2561            &mut state,
2562            TEST_BASE_ADDRESS,
2563            DefaultArmSequence::create(),
2564            CoreType::Armv7a,
2565        )
2566        .unwrap();
2567
2568        assert_eq!(BP_COUNT, armv7ar.available_breakpoint_units().unwrap());
2569    }
2570
2571    #[test]
2572    fn armv7a_hw_breakpoints() {
2573        const BP_COUNT: u32 = 4;
2574        const BP1: u64 = 0x2345;
2575        const BP2: u64 = 0x8000_0000;
2576        let mut probe = MockProbe::new();
2577        let mut state = CortexARState::new();
2578
2579        // Add expectations
2580        add_status_expectations(&mut probe, true);
2581        add_enable_itr_expectations(&mut probe);
2582        add_read_reg_expectations(&mut probe, 0, 0);
2583        add_read_fp_count_expectations(&mut probe);
2584
2585        // Read breakpoint count
2586        add_idr_expectations(&mut probe, BP_COUNT);
2587
2588        // Read BP values and controls
2589        probe.expected_read(
2590            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2591            BP1 as u32,
2592        );
2593        probe.expected_read(
2594            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2595            1,
2596        );
2597
2598        probe.expected_read(
2599            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + 4,
2600            BP2 as u32,
2601        );
2602        probe.expected_read(
2603            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + 4,
2604            1,
2605        );
2606
2607        probe.expected_read(
2608            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (2 * 4),
2609            0,
2610        );
2611        probe.expected_read(
2612            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (2 * 4),
2613            0,
2614        );
2615
2616        probe.expected_read(
2617            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (3 * 4),
2618            0,
2619        );
2620        probe.expected_read(
2621            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (3 * 4),
2622            0,
2623        );
2624
2625        let mock_mem = Box::new(probe) as _;
2626
2627        let mut armv7ar = Armv7ar::new(
2628            mock_mem,
2629            &mut state,
2630            TEST_BASE_ADDRESS,
2631            DefaultArmSequence::create(),
2632            CoreType::Armv7a,
2633        )
2634        .unwrap();
2635
2636        let results = armv7ar.hw_breakpoints().unwrap();
2637        assert_eq!(Some(BP1), results[0]);
2638        assert_eq!(Some(BP2), results[1]);
2639        assert_eq!(None, results[2]);
2640        assert_eq!(None, results[3]);
2641    }
2642
2643    #[test]
2644    fn armv7a_set_hw_breakpoint() {
2645        const BP_VALUE: u64 = 0x2345;
2646        let mut probe = MockProbe::new();
2647        let mut state = CortexARState::new();
2648
2649        // Add expectations
2650        add_status_expectations(&mut probe, true);
2651        add_enable_itr_expectations(&mut probe);
2652        add_read_reg_expectations(&mut probe, 0, 0);
2653        add_read_fp_count_expectations(&mut probe);
2654
2655        // Update BP value and control
2656        let mut dbgbcr = Dbgbcr(0);
2657        // Match on all modes
2658        dbgbcr.set_hmc(true);
2659        dbgbcr.set_pmc(0b11);
2660        // Match on all bytes
2661        dbgbcr.set_bas(0b1111);
2662        // Enable
2663        dbgbcr.set_e(true);
2664
2665        probe.expected_write(
2666            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2667            BP_VALUE as u32,
2668        );
2669        probe.expected_write(
2670            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2671            dbgbcr.into(),
2672        );
2673
2674        let mock_mem = Box::new(probe) as _;
2675
2676        let mut armv7ar = Armv7ar::new(
2677            mock_mem,
2678            &mut state,
2679            TEST_BASE_ADDRESS,
2680            DefaultArmSequence::create(),
2681            CoreType::Armv7a,
2682        )
2683        .unwrap();
2684
2685        armv7ar.set_hw_breakpoint(0, BP_VALUE).unwrap();
2686    }
2687
2688    #[test]
2689    fn armv7a_clear_hw_breakpoint() {
2690        let mut probe = MockProbe::new();
2691        let mut state = CortexARState::new();
2692
2693        // Add expectations
2694        add_status_expectations(&mut probe, true);
2695        add_enable_itr_expectations(&mut probe);
2696        add_read_reg_expectations(&mut probe, 0, 0);
2697        add_read_fp_count_expectations(&mut probe);
2698
2699        // Update BP value and control
2700        probe.expected_write(
2701            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2702            0,
2703        );
2704        probe.expected_write(
2705            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2706            0,
2707        );
2708
2709        let mock_mem = Box::new(probe) as _;
2710
2711        let mut armv7ar = Armv7ar::new(
2712            mock_mem,
2713            &mut state,
2714            TEST_BASE_ADDRESS,
2715            DefaultArmSequence::create(),
2716            CoreType::Armv7a,
2717        )
2718        .unwrap();
2719
2720        armv7ar.clear_hw_breakpoint(0).unwrap();
2721    }
2722
2723    #[test]
2724    fn armv7a_read_word_32() {
2725        const MEMORY_VALUE: u32 = 0xBA5EBA11;
2726        const MEMORY_ADDRESS: u64 = 0x12345678;
2727
2728        let mut probe = MockProbe::new();
2729        let mut state = CortexARState::new();
2730
2731        // Add expectations
2732        add_status_expectations(&mut probe, true);
2733        add_enable_itr_expectations(&mut probe);
2734        add_read_reg_expectations(&mut probe, 0, 0);
2735        add_read_fp_count_expectations(&mut probe);
2736
2737        // Read memory
2738        add_read_memory_expectations(&mut probe, MEMORY_ADDRESS, MEMORY_VALUE);
2739
2740        let mock_mem = Box::new(probe) as _;
2741
2742        let mut armv7ar = Armv7ar::new(
2743            mock_mem,
2744            &mut state,
2745            TEST_BASE_ADDRESS,
2746            DefaultArmSequence::create(),
2747            CoreType::Armv7a,
2748        )
2749        .unwrap();
2750
2751        assert_eq!(MEMORY_VALUE, armv7ar.read_word_32(MEMORY_ADDRESS).unwrap());
2752    }
2753
2754    fn test_read_word(value: u32, address: u64, memory_word_address: u64, endian: Endian) -> u8 {
2755        let mut probe = MockProbe::new();
2756        let mut state = CortexARState::new();
2757
2758        // Add expectations
2759        add_status_expectations(&mut probe, true);
2760        add_enable_itr_expectations(&mut probe);
2761        add_read_reg_expectations(&mut probe, 0, 0);
2762        add_read_fp_count_expectations(&mut probe);
2763
2764        // Read memory
2765        add_read_memory_expectations(&mut probe, memory_word_address, value);
2766
2767        // Set endianx
2768        let cpsr = if endian == Endian::Big { 1 << 9 } else { 0 };
2769        add_read_cpsr_expectations(&mut probe, cpsr);
2770
2771        let mock_mem = Box::new(probe) as _;
2772
2773        let mut armv7ar = Armv7ar::new(
2774            mock_mem,
2775            &mut state,
2776            TEST_BASE_ADDRESS,
2777            DefaultArmSequence::create(),
2778            CoreType::Armv7a,
2779        )
2780        .unwrap();
2781        armv7ar.read_word_8(address).unwrap()
2782    }
2783
2784    #[test]
2785    fn armv7a_read_word_8() {
2786        const MEMORY_VALUE: u32 = 0xBA5EBB11;
2787        const MEMORY_ADDRESS: u64 = 0x12345679;
2788        const MEMORY_WORD_ADDRESS: u64 = 0x12345678;
2789
2790        assert_eq!(
2791            0xBB,
2792            test_read_word(
2793                MEMORY_VALUE,
2794                MEMORY_ADDRESS,
2795                MEMORY_WORD_ADDRESS,
2796                Endian::Little
2797            )
2798        );
2799    }
2800
2801    #[test]
2802    fn armv7a_read_word_8_be() {
2803        const MEMORY_VALUE: u32 = 0xBA5EBB11;
2804        const MEMORY_ADDRESS: u64 = 0x12345679;
2805        const MEMORY_WORD_ADDRESS: u64 = 0x12345678;
2806
2807        assert_eq!(
2808            0x5E,
2809            test_read_word(
2810                MEMORY_VALUE,
2811                MEMORY_ADDRESS,
2812                MEMORY_WORD_ADDRESS,
2813                Endian::Big
2814            )
2815        );
2816    }
2817}