use std::{
sync::Arc,
thread,
time::{Duration, Instant},
};
use probe_rs_target::CoreType;
use crate::{
Error,
architecture::arm::{
ArmDebugInterface, ArmError, FullyQualifiedApAddress,
armv8m::Aircr,
core::armv8m::Dhcsr,
memory::ArmMemoryInterface,
sequences::{ArmDebugSequence, cortex_m_core_start},
},
core::MemoryMappedRegister,
};
#[derive(Debug)]
pub struct OL23D0(());
impl OL23D0 {
pub fn create() -> Arc<dyn ArmDebugSequence> {
Arc::new(Self(()))
}
}
impl ArmDebugSequence for OL23D0 {
fn debug_core_start(
&self,
interface: &mut dyn ArmDebugInterface,
core_ap: &FullyQualifiedApAddress,
_core_type: CoreType,
_debug_base: Option<u64>,
_cti_base: Option<u64>,
) -> Result<(), ArmError> {
let mut memory = interface.memory_interface(core_ap)?;
cortex_m_core_start(&mut *memory)?;
let memory = memory.as_mut();
let mut core = OL23D0Core { memory };
if core.halt(Duration::from_millis(100)).is_err() {
core.set_breakpoints()?;
core.reset(Duration::from_millis(100))?;
} else {
core.run()?;
}
Ok(())
}
fn reset_catch_set(
&self,
core: &mut dyn ArmMemoryInterface,
_core_type: CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
let mut core = OL23D0Core { memory: core };
core.set_breakpoints()?;
Ok(())
}
fn reset_catch_clear(
&self,
core: &mut dyn ArmMemoryInterface,
_core_type: CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
let mut core = OL23D0Core { memory: core };
core.clear_breakpoints()?;
Ok(())
}
fn reset_system(
&self,
interface: &mut dyn ArmMemoryInterface,
_core_type: CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
let mut core = OL23D0Core { memory: interface };
if core.halt(Duration::from_millis(100)).is_err() {
}
core.reset(Duration::from_millis(100))?;
Ok(())
}
}
struct OL23D0Core<'a> {
memory: &'a mut dyn ArmMemoryInterface,
}
impl OL23D0Core<'_> {
fn set_breakpoints(&mut self) -> Result<(), ArmError> {
self.memory.write_word_32(0xE0002008, 0x00200001)?;
self.memory.write_word_32(0xE000200C, 0x20002001)?;
self.memory.write_word_32(0xE0002010, 0x20004001)?;
self.memory.write_word_32(0xE0002014, 0x20005001)?;
self.memory.write_word_32(0xE0002000, 0x10000083)?;
Ok(())
}
fn clear_breakpoints(&mut self) -> Result<(), ArmError> {
self.memory.write_word_32(0xE0002000, 0x10000082)?;
self.memory.write_word_32(0xE0002008, 0x0)?;
self.memory.write_word_32(0xE000200C, 0x0)?;
self.memory.write_word_32(0xE0002010, 0x0)?;
self.memory.write_word_32(0xE0002014, 0x0)?;
Ok(())
}
fn reset(&mut self, timeout: Duration) -> Result<(), ArmError> {
let mut aircr = Aircr(0);
aircr.set_sysresetreq(true);
aircr.vectkey();
self.memory
.write_word_32(Aircr::get_mmio_address(), aircr.into())?;
thread::sleep(Duration::from_millis(10));
self.wait_for_core_halted(timeout).ok();
self.memory.write_word_32(0x4000A834, 0)?;
Ok(())
}
fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), ArmError> {
let start = Instant::now();
while !self.core_halted()? {
if start.elapsed() >= timeout {
return Err(ArmError::Timeout);
}
std::thread::sleep(Duration::from_millis(1));
}
Ok(())
}
fn core_halted(&mut self) -> Result<bool, ArmError> {
let dhcsr = Dhcsr(self.memory.read_word_32(Dhcsr::get_mmio_address())?);
Ok(dhcsr.s_halt())
}
fn halt(&mut self, timeout: Duration) -> Result<(), Error> {
let mut value = Dhcsr(0);
value.set_c_halt(true);
value.set_c_debugen(true);
value.enable_write();
self.memory
.write_word_32(Dhcsr::get_mmio_address(), value.into())?;
self.wait_for_core_halted(timeout)?;
Ok(())
}
fn run(&mut self) -> Result<(), ArmError> {
let mut value = Dhcsr(0);
value.set_c_halt(false);
value.set_c_debugen(true);
value.enable_write();
self.memory
.write_word_32(Dhcsr::get_mmio_address(), value.into())?;
self.memory.flush()?;
Ok(())
}
}