mod dwt;
mod itm;
mod scs;
mod swo;
mod tmc;
mod tpiu;
mod trace_funnel;
use super::ap::{GenericAp, MemoryAp};
use super::memory::romtable::{CoresightComponent, PeripheralType, RomTableError};
use super::memory::Component;
use super::ArmError;
use super::{ApAddress, ApInformation, DpAddress, MemoryApInformation};
use crate::architecture::arm::core::armv6m::Demcr;
use crate::architecture::arm::{ArmProbeInterface, SwoConfig, SwoMode};
use crate::{Core, Error, MemoryInterface, MemoryMappedRegister};
pub use self::itm::Itm;
pub use dwt::Dwt;
pub use scs::Scs;
pub use swo::Swo;
pub use tmc::TraceMemoryController;
pub use tpiu::Tpiu;
pub use trace_funnel::TraceFunnel;
#[derive(Debug, Copy, Clone)]
pub enum TraceSink {
Swo(SwoConfig),
Tpiu(SwoConfig),
TraceMemory,
}
#[derive(thiserror::Error, Debug)]
pub enum ComponentError {
#[error("Nordic does not support TPIU CLK value of {0}")]
NordicUnsupportedTPUICLKValue(u32),
}
pub trait DebugRegister: Clone + From<u32> + Into<u32> + Sized + std::fmt::Debug {
const ADDRESS: u32;
const NAME: &'static str;
fn load(
component: &CoresightComponent,
interface: &mut dyn ArmProbeInterface,
) -> Result<Self, ArmError> {
Ok(Self::from(component.read_reg(interface, Self::ADDRESS)?))
}
fn load_unit(
component: &CoresightComponent,
interface: &mut dyn ArmProbeInterface,
unit: usize,
) -> Result<Self, ArmError> {
Ok(Self::from(
component.read_reg(interface, Self::ADDRESS + 16 * unit as u32)?,
))
}
fn store(
&self,
component: &CoresightComponent,
interface: &mut dyn ArmProbeInterface,
) -> Result<(), ArmError> {
component.write_reg(interface, Self::ADDRESS, self.clone().into())
}
fn store_unit(
&self,
component: &CoresightComponent,
interface: &mut dyn ArmProbeInterface,
unit: usize,
) -> Result<(), ArmError> {
component.write_reg(
interface,
Self::ADDRESS + 16 * unit as u32,
self.clone().into(),
)
}
}
pub fn get_arm_components(
interface: &mut dyn ArmProbeInterface,
dp: DpAddress,
) -> Result<Vec<CoresightComponent>, ArmError> {
let mut components = Vec::new();
for ap_index in 0..(interface.num_access_ports(dp)? as u8) {
let ap_information = interface
.ap_information(GenericAp::new(ApAddress { dp, ap: ap_index }))?
.clone();
let component = match ap_information {
ApInformation::MemoryAp(MemoryApInformation {
debug_base_address: 0,
..
}) => Err(Error::Other(anyhow::anyhow!("AP has a base address of 0"))),
ApInformation::MemoryAp(MemoryApInformation {
address,
debug_base_address,
..
}) => {
let ap = MemoryAp::new(address);
let mut memory = interface.memory_interface(ap)?;
let component = Component::try_parse(&mut *memory, debug_base_address)?;
Ok(CoresightComponent::new(component, ap))
}
ApInformation::Other { address, .. } => {
Err(Error::Other(anyhow::anyhow!(
"AP {:#x?} is not a MemoryAP, unable to get ARM component.",
address
)))
}
};
match component {
Ok(component) => {
components.push(component);
}
Err(e) => {
tracing::info!("Not counting AP {} because of: {}", ap_index, e);
}
}
}
Ok(components)
}
pub fn find_component(
components: &[CoresightComponent],
peripheral_type: PeripheralType,
) -> Result<&CoresightComponent, ArmError> {
let component = components
.iter()
.find_map(|component| component.find_component(peripheral_type))
.ok_or_else(|| RomTableError::ComponentNotFound(peripheral_type))?;
Ok(component)
}
fn configure_tpiu(
interface: &mut dyn ArmProbeInterface,
component: &CoresightComponent,
config: &SwoConfig,
) -> Result<(), Error> {
let mut tpiu = Tpiu::new(interface, component);
tpiu.set_port_size(1)?;
let prescaler = (config.tpiu_clk() / config.baud()) - 1;
tpiu.set_prescaler(prescaler)?;
match config.mode() {
SwoMode::Manchester => tpiu.set_pin_protocol(1)?,
SwoMode::Uart => tpiu.set_pin_protocol(2)?,
}
if config.tpiu_continuous_formatting() {
tpiu.set_formatter(0x102)?;
} else {
tpiu.set_formatter(0x100)?;
}
Ok(())
}
pub(crate) fn setup_tracing(
interface: &mut dyn ArmProbeInterface,
components: &[CoresightComponent],
sink: &TraceSink,
) -> Result<(), Error> {
let mut dwt = Dwt::new(interface, find_component(components, PeripheralType::Dwt)?);
dwt.enable()?;
dwt.enable_exception_trace()?;
let mut itm = Itm::new(interface, find_component(components, PeripheralType::Itm)?);
itm.unlock()?;
itm.tx_enable()?;
match sink {
TraceSink::Tpiu(config) => {
configure_tpiu(
interface,
find_component(components, PeripheralType::Tpiu)?,
config,
)?;
}
TraceSink::Swo(config) => {
if let Ok(peripheral) = find_component(components, PeripheralType::Swo) {
let mut swo = Swo::new(interface, peripheral);
swo.unlock()?;
let prescaler = (config.tpiu_clk() / config.baud()) - 1;
swo.set_prescaler(prescaler)?;
match config.mode() {
SwoMode::Manchester => swo.set_pin_protocol(1)?,
SwoMode::Uart => swo.set_pin_protocol(2)?,
}
} else {
configure_tpiu(
interface,
find_component(components, PeripheralType::Tpiu)?,
config,
)?;
}
}
TraceSink::TraceMemory => {
let mut tmc = TraceMemoryController::new(
interface,
find_component(components, PeripheralType::Tmc)?,
);
tmc.disable_capture()?;
while !tmc.ready()? {}
tmc.set_mode(tmc::Mode::Software)?;
tmc.enable_capture()?;
}
}
Ok(())
}
pub(crate) fn read_trace_memory(
interface: &mut dyn ArmProbeInterface,
components: &[CoresightComponent],
) -> Result<Vec<u8>, ArmError> {
let mut tmc =
TraceMemoryController::new(interface, find_component(components, PeripheralType::Tmc)?);
let fifo_size = tmc.fifo_size()?;
let mut etf_trace: Vec<u8> = Vec::new();
loop {
match tmc.read()? {
Some(data) => etf_trace.extend_from_slice(&data.to_le_bytes()),
None => {
if (etf_trace.len() % 16) == 0 {
break;
}
}
}
let frame_boundary = (etf_trace.len() % 16) == 0;
if frame_boundary && etf_trace.len() >= fifo_size as usize {
break;
}
}
let mut id = 0.into();
let mut itm_trace = Vec::new();
for frame_buffer in etf_trace.chunks_exact(16) {
let mut frame = tmc::Frame::new(frame_buffer, id);
for (id, data) in &mut frame {
match id.into() {
13 => itm_trace.push(data),
0 => (),
id => tracing::warn!("Unexpected trace source ATID {id}: {data}, ignoring"),
}
}
id = frame.id();
}
Ok(itm_trace)
}
pub(crate) fn add_swv_data_trace(
interface: &mut dyn ArmProbeInterface,
components: &[CoresightComponent],
unit: usize,
address: u32,
) -> Result<(), ArmError> {
let mut dwt = Dwt::new(interface, find_component(components, PeripheralType::Dwt)?);
dwt.enable_data_trace(unit, address)
}
pub fn remove_swv_data_trace(
interface: &mut dyn ArmProbeInterface,
components: &[CoresightComponent],
unit: usize,
) -> Result<(), ArmError> {
let mut dwt = Dwt::new(interface, find_component(components, PeripheralType::Dwt)?);
dwt.disable_data_trace(unit)
}
pub fn enable_tracing(core: &mut Core) -> Result<(), Error> {
let mut demcr = Demcr(core.read_word_32(Demcr::ADDRESS)?);
demcr.set_dwtena(true);
core.write_word_32(Demcr::ADDRESS, demcr.into())?;
Ok(())
}
pub fn disable_swv(core: &mut Core) -> Result<(), Error> {
let mut demcr = Demcr(core.read_word_32(Demcr::ADDRESS)?);
demcr.set_dwtena(false);
core.write_word_32(Demcr::ADDRESS, demcr.into())?;
Ok(())
}