use std::sync::Arc;
use probe_rs_target::CoreType;
use crate::architecture::arm::{
ArmDebugInterface, ArmError, FullyQualifiedApAddress,
component::{TraceFunnel, TraceSink},
memory::{ArmMemoryInterface, CoresightComponent, PeripheralType, romtable::RomTableError},
sequences::ArmDebugSequence,
};
#[derive(Debug)]
pub enum Stm32h7Line {
H7,
H7S,
}
const SWTF_BASE_ADDRESS: u64 = 0xE00E_4000;
const CSTF_BASE_ADDRESS: u64 = 0xE00F_3000;
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
enum TraceFunnelId {
SerialWire = SWTF_BASE_ADDRESS,
CoreSight = CSTF_BASE_ADDRESS,
}
#[derive(Debug)]
pub struct Stm32h7 {
ap: u8,
}
impl Stm32h7 {
pub fn create(family: Stm32h7Line) -> Arc<Self> {
let ap = match family {
Stm32h7Line::H7 => 2,
Stm32h7Line::H7S => 1,
};
Arc::new(Self { ap })
}
pub fn enable_debug_components(
&self,
memory: &mut dyn ArmMemoryInterface,
enable: bool,
) -> Result<(), ArmError> {
if enable {
tracing::info!("Enabling STM32H7 debug components");
} else {
tracing::info!("Disabling STM32H7 debug components");
}
let mut control = dbgmcu::Control::read(memory)?;
control.enable_d1_clock(enable);
control.enable_d3_clock(enable);
control.enable_traceck(enable);
control.enable_d1_standby_debug(enable);
control.enable_d1_sleep_debug(enable);
control.enable_d1_stop_debug(enable);
control.enable_d2_standby_debug(enable);
control.enable_d2_sleep_debug(enable);
control.enable_d2_stop_debug(enable);
control.write(memory)?;
Ok(())
}
}
mod dbgmcu {
use crate::architecture::arm::ArmError;
use crate::architecture::arm::memory::ArmMemoryInterface;
use bitfield::bitfield;
const DBGMCU: u64 = 0xE00E_1000;
bitfield! {
pub struct Control(u32);
impl Debug;
pub u8, dbgsleep_d1, enable_d1_sleep_debug: 0;
pub u8, dbgstop_d1, enable_d1_stop_debug: 1;
pub u8, dbgstby_d1, enable_d1_standby_debug: 2;
pub u8, dbgsleep_d2, enable_d2_sleep_debug: 3;
pub u8, dbgstop_d2, enable_d2_stop_debug: 4;
pub u8, dbgstby_d2, enable_d2_standby_debug: 5;
pub u8, d3dbgcken, enable_d3_clock: 22;
pub u8, d1dbgcken, enable_d1_clock: 21;
pub u8, traceclken, enable_traceck: 20;
}
impl Control {
const ADDRESS: u64 = 0x04;
pub fn read(memory: &mut (impl ArmMemoryInterface + ?Sized)) -> Result<Self, ArmError> {
let contents = memory.read_word_32(DBGMCU + Self::ADDRESS)?;
Ok(Self(contents))
}
pub fn write(
&mut self,
memory: &mut (impl ArmMemoryInterface + ?Sized),
) -> Result<(), ArmError> {
memory.write_word_32(DBGMCU + Self::ADDRESS, self.0)
}
}
}
fn find_trace_funnel(
components: &[CoresightComponent],
trace_funnel: TraceFunnelId,
) -> Result<&CoresightComponent, ArmError> {
components
.iter()
.find_map(|comp| {
comp.iter().find(|component| {
let id = component.component.id();
id.peripheral_id().is_of_type(PeripheralType::TraceFunnel)
&& id.component_address() == trace_funnel as u64
})
})
.ok_or_else(|| {
ArmError::from(RomTableError::ComponentNotFound(
PeripheralType::TraceFunnel,
))
})
}
impl ArmDebugSequence for Stm32h7 {
fn debug_device_unlock(
&self,
interface: &mut dyn ArmDebugInterface,
_default_ap: &FullyQualifiedApAddress,
_permissions: &crate::Permissions,
) -> Result<(), ArmError> {
let ap = &FullyQualifiedApAddress::v1_with_default_dp(self.ap);
let mut memory = interface.memory_interface(ap)?;
self.enable_debug_components(&mut *memory, true)?;
Ok(())
}
fn debug_core_stop(
&self,
memory: &mut dyn ArmMemoryInterface,
_core_type: CoreType,
) -> Result<(), ArmError> {
self.enable_debug_components(&mut *memory, false)?;
Ok(())
}
fn trace_start(
&self,
interface: &mut dyn ArmDebugInterface,
components: &[CoresightComponent],
sink: &TraceSink,
) -> Result<(), ArmError> {
tracing::warn!("Enabling tracing for STM32H7");
let mut cstf = TraceFunnel::new(
interface,
find_trace_funnel(components, TraceFunnelId::CoreSight)?,
);
cstf.unlock()?;
match sink {
TraceSink::Swo(_) => cstf.enable_port(0b00)?,
TraceSink::Tpiu(_) | TraceSink::TraceMemory => cstf.enable_port(0b10)?,
}
let mut swtf = TraceFunnel::new(
interface,
find_trace_funnel(components, TraceFunnelId::SerialWire)?,
);
swtf.unlock()?;
if matches!(sink, TraceSink::Swo(_)) {
swtf.enable_port(0b01)?;
} else {
swtf.enable_port(0b00)?;
}
Ok(())
}
}