use crate::MemoryMappedRegister;
use crate::architecture::arm::armv6m::Demcr;
use crate::architecture::arm::dp::{Ctrl, DpAddress, DpRegister};
use crate::architecture::arm::memory::ArmMemoryInterface;
use crate::architecture::arm::sequences::{ArmDebugSequence, cortex_m_reset_system};
use crate::architecture::arm::{ApV2Address, ArmError, FullyQualifiedApAddress};
use std::sync::Arc;
use std::time::Duration;
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_SPEED_KHZ: u32 = 1_000;
const WATCHDOG_BASE: u64 = 0x400d_8000;
const WATCHDOG_SCRATCH4: u64 = WATCHDOG_BASE + 0x1c;
const WATCHDOG_SCRATCH5: u64 = WATCHDOG_BASE + 0x20;
const WATCHDOG_SCRATCH6: u64 = WATCHDOG_BASE + 0x24;
const WATCHDOG_SCRATCH7: u64 = WATCHDOG_BASE + 0x28;
const WATCHDOG_MAGIC: u32 = 0xb007_c0d3;
const WATCHDOG_MAGIC_NEGATED: u32 = 0u32.wrapping_sub(WATCHDOG_MAGIC);
const WATCHDOG_MAGIC_BOOTSEL: u32 = 2;
const WATCHDOG_MAGIC_ENTRY: u32 = 0xb007_c0d3;
const BOOTROM_STARTUP_TIME: Duration = Duration::from_millis(30);
#[derive(Debug)]
pub struct Rp235x {}
impl Rp235x {
pub fn create() -> Arc<Self> {
Arc::new(Rp235x {})
}
}
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::warn!("Skipping reset of core {core_id}");
return Ok(());
}
let should_catch_reset =
Demcr(core.read_word_32(Demcr::get_mmio_address())?).vc_corereset();
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}");
let probe_speed = arm_interface.try_dap_probe_mut().map(|probe| {
let speed = probe.speed_khz();
tracing::debug!("Lowering SWD speed to {RESET_SPEED_KHZ} kHz for reset sequence");
let _ = probe.set_speed(RESET_SPEED_KHZ);
speed
});
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)?;
core.write_word_32(WATCHDOG_SCRATCH4, WATCHDOG_MAGIC)?;
core.write_word_32(
WATCHDOG_SCRATCH5,
WATCHDOG_MAGIC_ENTRY ^ WATCHDOG_MAGIC_NEGATED,
)?;
core.write_word_32(WATCHDOG_SCRATCH6, WATCHDOG_MAGIC_BOOTSEL)?;
core.write_word_32(WATCHDOG_SCRATCH7, WATCHDOG_MAGIC_ENTRY)?;
cortex_m_reset_system(core)?;
std::thread::sleep(BOOTROM_STARTUP_TIME);
if should_catch_reset {
tracing::trace!("Re-setting reset catch");
self.reset_catch_set(core, core_type, debug_base)?
}
cortex_m_reset_system(core)?;
let arm_interface = core.get_arm_debug_interface()?;
if let (Some(probe), Some(speed)) = (arm_interface.try_dap_probe_mut(), probe_speed) {
tracing::debug!("Restoring SWD speed to {speed} kHz");
let _ = probe.set_speed(speed);
}
core.read_word_32(RAM_ADDRESS).map(|_| ())
}
}