use crate::MemoryMappedRegister;
use crate::architecture::arm::armv6m::{Aircr, Demcr};
use crate::architecture::arm::dp::{Ctrl, DpAddress, DpRegister};
use crate::architecture::arm::memory::ArmMemoryInterface;
use crate::architecture::arm::sequences::{ArmDebugSequence, cortex_m_wait_for_reset};
use crate::architecture::arm::{ApV2Address, ArmError, FullyQualifiedApAddress};
use std::sync::Arc;
use std::time::{Duration, Instant};
const SIO_CPUID_OFFSET: u64 = 0xd000_0000;
const RP_AP: FullyQualifiedApAddress =
FullyQualifiedApAddress::v2_with_dp(DpAddress::Default, ApV2Address(Some(0x80000)));
const RAM_ADDRESS: u64 = 0x2000_0000;
const RESET_TIMEOUT: Duration = Duration::from_secs(1);
#[derive(Debug)]
pub struct Rp235x {}
impl Rp235x {
pub fn create() -> Arc<Self> {
Arc::new(Rp235x {})
}
fn perform_reset(
&self,
core: &mut dyn ArmMemoryInterface,
core_type: crate::CoreType,
debug_base: Option<u64>,
should_catch_reset: bool,
) -> Result<(), ArmError> {
let ap = core.fully_qualified_address();
let arm_interface = core.get_arm_debug_interface()?;
let existing_core_0 = arm_interface.read_raw_dp_register(ap.dp(), Ctrl::ADDRESS)?;
tracing::trace!("Core 0 DP_CTRL: {existing_core_0:08x}");
const CTRL: u64 = 0;
const RESCUE_RESTART: u32 = 0x8000_0000;
let ctrl = arm_interface.read_raw_ap_register(&RP_AP, CTRL)?;
arm_interface.write_raw_ap_register(&RP_AP, CTRL, ctrl | RESCUE_RESTART)?;
let ctrl = arm_interface.read_raw_ap_register(&RP_AP, CTRL)?;
arm_interface.write_raw_ap_register(&RP_AP, CTRL, ctrl & !RESCUE_RESTART)?;
let new_core_0 = arm_interface.read_raw_dp_register(ap.dp(), Ctrl::ADDRESS)?;
tracing::trace!("new core 0 CTRL: {new_core_0:08x}");
self.debug_core_start(arm_interface, &ap, core_type, debug_base, None)?;
tracing::trace!("Restoring ctrl values");
arm_interface.write_raw_dp_register(ap.dp(), Ctrl::ADDRESS, existing_core_0)?;
if should_catch_reset {
tracing::trace!("Re-setting reset catch");
self.reset_catch_set(core, core_type, debug_base)?
}
let mut aircr = Aircr(0);
aircr.vectkey();
aircr.set_sysresetreq(true);
core.write_word_32(Aircr::get_mmio_address(), aircr.into())?;
cortex_m_wait_for_reset(core)?;
core.read_word_32(RAM_ADDRESS).map(|_| ())
}
}
impl ArmDebugSequence for Rp235x {
fn reset_system(
&self,
core: &mut dyn ArmMemoryInterface,
core_type: crate::CoreType,
debug_base: Option<u64>,
) -> Result<(), ArmError> {
tracing::trace!("reset_system(interface, {core_type:?}, {debug_base:x?})");
let core_id = core.read_word_32(SIO_CPUID_OFFSET)?;
if core_id != 0 {
tracing::error!("Skipping reset of core {core_id}");
return Ok(());
}
let should_catch_reset =
Demcr(core.read_word_32(Demcr::get_mmio_address())?).vc_corereset();
let start = Instant::now();
let mut attempt = 0;
loop {
attempt += 1;
tracing::debug!("Performing reset (attempt {attempt})...");
let Err(e) = self.perform_reset(core, core_type, debug_base, should_catch_reset) else {
tracing::info!(
"Finished RP235x reset sequence after {attempt} attempts and {} ms",
start.elapsed().as_millis()
);
return Ok(());
};
if start.elapsed() > RESET_TIMEOUT {
tracing::error!(
"Reset failed after {attempt} attempts and {} ms: {e}",
start.elapsed().as_millis()
);
return Err(e);
}
}
}
}