use probe_rs_target::CoreType;
use std::{
sync::Arc,
time::{Duration, Instant},
};
use crate::{
MemoryMappedRegister,
architecture::arm::{
ArmDebugInterface, ArmError, FullyQualifiedApAddress,
ap::{ApRegister, DRW, TAR},
armv8m::Aircr,
core::{cortex_m::write_core_reg, registers::cortex_m::CORTEX_M_WITH_FP_CORE_REGISTERS},
memory::ArmMemoryInterface,
sequences::{ArmDebugSequence, cortex_m_wait_for_reset},
},
};
const DBGMCU_AP: FullyQualifiedApAddress = FullyQualifiedApAddress::v1_with_default_dp(0);
const DBGMCU_SR: u32 = 0x8000_10fc;
#[derive(Debug)]
pub struct Stm32n6 {}
impl Stm32n6 {
pub fn create() -> Arc<Self> {
Arc::new(Self {})
}
fn read_dbgmcu(
&self,
arm_interface: &mut dyn ArmDebugInterface,
address: u32,
) -> Result<u32, ArmError> {
arm_interface.write_raw_ap_register(&DBGMCU_AP, TAR::ADDRESS, address)?;
arm_interface.read_raw_ap_register(&DBGMCU_AP, DRW::ADDRESS)
}
}
impl ArmDebugSequence for Stm32n6 {
fn reset_system(
&self,
interface: &mut dyn ArmMemoryInterface,
core_type: CoreType,
debug_base: Option<u64>,
) -> Result<(), ArmError> {
let ap = interface.fully_qualified_address();
let mut aircr = Aircr(0);
aircr.vectkey();
aircr.set_sysresetreq(true);
interface.write_word_32(Aircr::get_mmio_address(), aircr.into())?;
interface.flush()?;
let start = Instant::now();
let arm_interface = interface.get_arm_debug_interface()?;
loop {
if start.elapsed() > Duration::from_millis(500) {
tracing::warn!("reset timed out after {:?} ms", start.elapsed());
return Err(ArmError::Timeout);
}
let dbgmcu_sr = self.read_dbgmcu(arm_interface, DBGMCU_SR)?;
tracing::trace!("DBGMCU_SR: {dbgmcu_sr:08x}");
if dbgmcu_sr & 1 << 17 != 0 {
tracing::info!(
"AP1 is out of reset after {} msec",
start.elapsed().as_millis()
);
break;
}
}
tracing::trace!("Waiting for core to reset...");
cortex_m_wait_for_reset(interface).ok();
tracing::trace!("Restarting debug core");
let arm_interface = interface.get_arm_debug_interface()?;
let start = Instant::now();
loop {
if self
.debug_core_start(arm_interface, &ap, core_type, debug_base, None)
.is_ok()
{
break;
}
arm_interface.reinitialize().ok();
if start.elapsed() > Duration::from_millis(500) {
tracing::error!("Debug core didn't start");
return Err(ArmError::Timeout);
}
}
tracing::trace!("Core restarted after {} ms", start.elapsed().as_millis());
Ok(())
}
fn reset_catch_clear(
&self,
core: &mut dyn ArmMemoryInterface,
_core_type: CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
for reg in CORTEX_M_WITH_FP_CORE_REGISTERS.all_registers() {
write_core_reg(core, reg.into(), 0u32)?;
}
write_core_reg(
core,
CORTEX_M_WITH_FP_CORE_REGISTERS.psr().unwrap().into(),
0x0100_0000_u32,
)?;
write_core_reg(
core,
CORTEX_M_WITH_FP_CORE_REGISTERS
.other_by_name("EXTRA")
.unwrap()
.into(),
0x0000_0001_u32,
)?;
core.write_word_32(0xE000_EF34, 0xc000_0000)?;
core.write_word_32(0xE000_ED14, 0x201)?;
core.write_word_32(0xE000_EF50, 0)?;
const RCC_MEMENR: u64 = 0x4602_824C;
const RCC_MEMENR_AXISRAM3456_EN: u32 = 0xF;
core.read_word_32(RCC_MEMENR)
.and_then(|val| core.write_word_32(RCC_MEMENR, val | RCC_MEMENR_AXISRAM3456_EN))
.inspect_err(|_| tracing::error!("failed to enable axisram"))?;
for sram in 3..=6 {
const RAMCFG_BASE: u64 = 0x42023000;
const RAMCFG_AXISRAMXCR_BASE: u64 = RAMCFG_BASE;
let ramcfg_axisramncr = RAMCFG_AXISRAMXCR_BASE + 0x80 * (sram - 1);
core.write_word_32(ramcfg_axisramncr, 0)
.inspect_err(|_| tracing::error!("failed to power up AXISRAM"))?;
}
Ok(())
}
}