pub(crate) mod communication_interface;
pub use communication_interface::CommunicationInterface;
use crate::config::TargetSelector;
use crate::error;
use crate::{
architecture::{
arm::{memory::ADIMemoryInterface, ArmCommunicationInterface},
riscv::{communication_interface::RiscvCommunicationInterface, Riscv32},
},
Error, MemoryInterface,
};
use crate::{DebugProbeError, Memory, Probe};
use std::{cell::RefCell, rc::Rc};
pub trait CoreRegister: Clone + From<u32> + Into<u32> + Sized + std::fmt::Debug {
const ADDRESS: u32;
const NAME: &'static str;
}
#[derive(Debug, Copy, Clone)]
pub struct CoreRegisterAddress(pub u16);
impl From<CoreRegisterAddress> for u32 {
fn from(value: CoreRegisterAddress) -> Self {
u32::from(value.0)
}
}
impl From<u16> for CoreRegisterAddress {
fn from(value: u16) -> Self {
CoreRegisterAddress(value)
}
}
#[derive(Debug, Clone)]
pub struct CoreInformation {
pub pc: u32,
}
#[derive(Debug, Clone)]
pub struct RegisterDescription {
pub(crate) name: &'static str,
pub(crate) kind: RegisterKind,
pub(crate) address: CoreRegisterAddress,
}
impl RegisterDescription {
pub fn name(&self) -> &'static str {
self.name
}
}
impl From<RegisterDescription> for CoreRegisterAddress {
fn from(description: RegisterDescription) -> CoreRegisterAddress {
description.address
}
}
impl From<&RegisterDescription> for CoreRegisterAddress {
fn from(description: &RegisterDescription) -> CoreRegisterAddress {
description.address
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum RegisterKind {
General,
PC,
}
#[derive(Debug)]
pub struct RegisterFile {
pub(crate) platform_registers: &'static [RegisterDescription],
pub(crate) program_counter: &'static RegisterDescription,
pub(crate) stack_pointer: &'static RegisterDescription,
pub(crate) return_address: &'static RegisterDescription,
pub(crate) argument_registers: &'static [RegisterDescription],
pub(crate) result_registers: &'static [RegisterDescription],
}
impl RegisterFile {
pub fn registers(&self) -> impl Iterator<Item = &RegisterDescription> {
self.platform_registers.iter()
}
pub fn program_counter(&self) -> &RegisterDescription {
&self.program_counter
}
pub fn stack_pointer(&self) -> &RegisterDescription {
&self.stack_pointer
}
pub fn return_address(&self) -> &RegisterDescription {
&self.return_address
}
pub fn argument_register(&self, index: usize) -> &RegisterDescription {
&self.argument_registers[index]
}
pub fn get_argument_register(&self, index: usize) -> Option<&RegisterDescription> {
self.argument_registers.get(index)
}
pub fn result_register(&self, index: usize) -> &RegisterDescription {
&self.result_registers[index]
}
pub fn get_result_register(&self, index: usize) -> Option<&RegisterDescription> {
self.result_registers.get(index)
}
pub fn platform_register(&self, index: usize) -> &RegisterDescription {
&self.platform_registers[index]
}
pub fn get_platform_register(&self, index: usize) -> Option<&RegisterDescription> {
self.platform_registers.get(index)
}
}
pub trait CoreInterface {
fn wait_for_core_halted(&self) -> Result<(), error::Error>;
fn core_halted(&self) -> Result<bool, error::Error>;
fn halt(&self) -> Result<CoreInformation, error::Error>;
fn run(&self) -> Result<(), error::Error>;
fn reset(&self) -> Result<(), error::Error>;
fn reset_and_halt(&self) -> Result<CoreInformation, error::Error>;
fn step(&self) -> Result<CoreInformation, error::Error>;
fn read_core_reg(&self, address: CoreRegisterAddress) -> Result<u32, error::Error>;
fn write_core_reg(&self, address: CoreRegisterAddress, value: u32) -> Result<(), error::Error>;
fn get_available_breakpoint_units(&self) -> Result<u32, error::Error>;
fn enable_breakpoints(&mut self, state: bool) -> Result<(), error::Error>;
fn set_breakpoint(&self, bp_unit_index: usize, addr: u32) -> Result<(), error::Error>;
fn clear_breakpoint(&self, unit_index: usize) -> Result<(), error::Error>;
fn registers(&self) -> &'static RegisterFile;
fn memory(&self) -> Memory;
fn hw_breakpoints_enabled(&self) -> bool;
fn architecture(&self) -> Architecture;
}
impl MemoryInterface for Core {
fn read32(&mut self, address: u32) -> Result<u32, Error> {
self.memory().read32(address)
}
fn read8(&mut self, address: u32) -> Result<u8, Error> {
self.memory().read8(address)
}
fn read_block32(&mut self, address: u32, data: &mut [u32]) -> Result<(), Error> {
self.memory().read_block32(address, data)
}
fn read_block8(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
self.memory().read_block8(address, data)
}
fn write32(&mut self, addr: u32, data: u32) -> Result<(), Error> {
self.memory().write32(addr, data)
}
fn write8(&mut self, addr: u32, data: u8) -> Result<(), Error> {
self.memory().write8(addr, data)
}
fn write_block32(&mut self, addr: u32, data: &[u32]) -> Result<(), Error> {
self.memory().write_block32(addr, data)
}
fn write_block8(&mut self, addr: u32, data: &[u8]) -> Result<(), Error> {
self.memory().write_block8(addr, data)
}
}
#[derive(Copy, Clone)]
pub enum CoreType {
M3,
M4,
M33,
M0,
Riscv,
}
impl CoreType {
pub fn attach_arm(&self, interface: ArmCommunicationInterface) -> Result<Core, Error> {
let memory = if let Some(memory) = interface.dedicated_memory_interface() {
memory
} else {
Memory::new(ADIMemoryInterface::<ArmCommunicationInterface>::new(
interface, 0,
))
};
Ok(match self {
CoreType::M3 => Core::new(crate::architecture::arm::m4::M4::new(memory)),
CoreType::M4 => Core::new(crate::architecture::arm::m4::M4::new(memory)),
CoreType::M33 => Core::new(crate::architecture::arm::m33::M33::new(memory)),
CoreType::M0 => Core::new(crate::architecture::arm::m0::M0::new(memory)),
_ => {
return Err(Error::UnableToOpenProbe(
"Core architecture and Probe mismatch.",
))
}
})
}
pub fn attach_riscv(&self, interface: RiscvCommunicationInterface) -> Result<Core, Error> {
Ok(match self {
CoreType::Riscv => Core::new(Riscv32::new(interface)),
_ => {
return Err(Error::UnableToOpenProbe(
"Core architecture and Probe mismatch.",
))
}
})
}
pub(crate) fn from_string(name: impl AsRef<str>) -> Option<Self> {
match &name.as_ref().to_ascii_lowercase()[..] {
"m0" => Some(CoreType::M0),
"m4" => Some(CoreType::M4),
"m3" => Some(CoreType::M3),
"m33" => Some(CoreType::M33),
"riscv" => Some(CoreType::Riscv),
_ => None,
}
}
}
pub struct Core {
inner: Rc<RefCell<dyn CoreInterface>>,
breakpoints: Vec<Breakpoint>,
}
impl Core {
pub fn new(core: impl CoreInterface + 'static) -> Self {
Self {
inner: Rc::new(RefCell::new(core)),
breakpoints: Vec::new(),
}
}
pub fn auto_attach(target: impl Into<TargetSelector>) -> Result<Core, error::Error> {
let probes = Probe::list_all();
let probe = probes[0].open()?;
let session = probe.attach(target)?;
session.attach_to_core(0)
}
pub fn wait_for_core_halted(&self) -> Result<(), error::Error> {
self.inner.borrow().wait_for_core_halted()
}
pub fn core_halted(&self) -> Result<bool, error::Error> {
self.inner.borrow().core_halted()
}
pub fn halt(&self) -> Result<CoreInformation, error::Error> {
self.inner.borrow().halt()
}
pub fn run(&self) -> Result<(), error::Error> {
self.inner.borrow().run()
}
pub fn reset(&self) -> Result<(), error::Error> {
self.inner.borrow().reset()
}
pub fn reset_and_halt(&self) -> Result<CoreInformation, error::Error> {
self.inner.borrow().reset_and_halt()
}
pub fn step(&self) -> Result<CoreInformation, error::Error> {
self.inner.borrow().step()
}
pub fn read_core_reg(
&self,
address: impl Into<CoreRegisterAddress>,
) -> Result<u32, error::Error> {
self.inner.borrow().read_core_reg(address.into())
}
pub fn write_core_reg(
&self,
address: CoreRegisterAddress,
value: u32,
) -> Result<(), error::Error> {
self.inner.borrow().write_core_reg(address, value)
}
pub fn get_available_breakpoint_units(&self) -> Result<u32, error::Error> {
self.inner.borrow().get_available_breakpoint_units()
}
fn enable_breakpoints(&self, state: bool) -> Result<(), error::Error> {
self.inner.borrow_mut().enable_breakpoints(state)
}
pub fn registers(&self) -> &'static RegisterFile {
self.inner.borrow().registers()
}
pub fn memory(&self) -> Memory {
self.inner.borrow().memory()
}
pub fn read_word_32(&self, address: u32) -> Result<u32, error::Error> {
self.inner.borrow_mut().memory().read32(address)
}
pub fn read_word_8(&self, address: u32) -> Result<u8, error::Error> {
self.inner.borrow_mut().memory().read8(address)
}
pub fn read_32(&self, address: u32, data: &mut [u32]) -> Result<(), error::Error> {
self.inner.borrow_mut().memory().read_block32(address, data)
}
pub fn read_8(&self, address: u32, data: &mut [u8]) -> Result<(), error::Error> {
self.inner.borrow_mut().memory().read_block8(address, data)
}
pub fn write_word_32(&self, addr: u32, data: u32) -> Result<(), error::Error> {
self.inner.borrow_mut().memory().write32(addr, data)
}
pub fn write_word_8(&self, addr: u32, data: u8) -> Result<(), error::Error> {
self.inner.borrow_mut().memory().write8(addr, data)
}
pub fn write_32(&self, addr: u32, data: &[u32]) -> Result<(), error::Error> {
self.inner.borrow_mut().memory().write_block32(addr, data)
}
pub fn write_8(&self, addr: u32, data: &[u8]) -> Result<(), error::Error> {
self.inner.borrow_mut().memory().write_block8(addr, data)
}
pub fn set_hw_breakpoint(&mut self, address: u32) -> Result<(), error::Error> {
log::debug!("Trying to set HW breakpoint at address {:#08x}", address);
let num_hw_breakpoints = self.get_available_breakpoint_units()? as usize;
log::debug!("{} HW breakpoints are supported.", num_hw_breakpoints);
if num_hw_breakpoints <= self.breakpoints.len() {
log::warn!("Maximum number of breakpoints ({}) reached, unable to set additional HW breakpoint.", num_hw_breakpoints);
return Err(error::Error::Probe(DebugProbeError::Unknown));
}
if !self.inner.borrow().hw_breakpoints_enabled() {
self.enable_breakpoints(true)?;
}
let bp_unit = self.find_free_breakpoint_unit();
log::debug!("Using comparator {} of breakpoint unit", bp_unit);
self.inner.borrow_mut().set_breakpoint(bp_unit, address)?;
self.breakpoints.push(Breakpoint {
address,
register_hw: bp_unit,
});
Ok(())
}
pub fn clear_hw_breakpoint(&mut self, address: u32) -> Result<(), error::Error> {
let bp_position = self.breakpoints.iter().position(|bp| bp.address == address);
match bp_position {
Some(bp_position) => {
let bp = &self.breakpoints[bp_position];
self.inner.borrow_mut().clear_breakpoint(bp.register_hw)?;
self.breakpoints.swap_remove(bp_position);
Ok(())
}
None => Err(error::Error::Probe(DebugProbeError::Unknown)),
}
}
fn find_free_breakpoint_unit(&self) -> usize {
let mut used_bp: Vec<_> = self.breakpoints.iter().map(|bp| bp.register_hw).collect();
used_bp.sort();
let mut free_bp = 0;
for bp in used_bp {
if bp == free_bp {
free_bp += 1;
} else {
return free_bp;
}
}
free_bp
}
}
pub struct CoreList(Vec<CoreType>);
impl CoreList {
pub fn new(cores: Vec<CoreType>) -> Self {
Self(cores)
}
}
impl std::ops::Deref for CoreList {
type Target = Vec<CoreType>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct BreakpointId(usize);
impl BreakpointId {
pub fn new(id: usize) -> Self {
BreakpointId(id)
}
}
#[derive(Clone)]
pub struct Breakpoint {
address: u32,
register_hw: usize,
}
pub enum Architecture {
ARM,
RISCV,
}