#![allow(non_snake_case)]
use crate::architecture::arm::ap::{AddressIncrement, ApClass, ApType, BaseAddrFormat, DataSize};
macro_rules! define_ap_register {
(
$(#[$outer:meta])*
name: $name:ident,
address: $address_v1:expr,
fields: [ $($fields:tt)* ]
$(,)?
) => {
bitfield::bitfield! {
$(#[$outer])*
#[derive(Copy, Clone, PartialEq, Eq)]
#[allow(clippy::upper_case_acronyms)]
pub struct $name(u32);
impl Debug;
$($fields)*
}
impl $name {
pub const fn from_raw(value: u32) -> Self {
$name(value)
}
}
impl $crate::architecture::arm::ap::ApRegister for $name {
const NAME: &'static str = stringify!($name);
const ADDRESS: u64 = 0xD00 | $address_v1;
}
impl TryFrom<u32> for $name {
type Error = $crate::architecture::arm::RegisterParseError;
fn try_from(value: u32) -> Result<$name, Self::Error> {
Ok($name(value))
}
}
impl From<$name> for u32 {
fn from(register: $name) -> u32 {
register.0
}
}
}
}
pub(crate) use define_ap_register;
define_ap_register!(
/// Control and Status Word register
///
/// The control and status word register (CSW) is used
name: CSW,
address: 0x00,
fields: [
pub DbgSwEnable, set_DbgSwEnable: 31;
pub u8, Prot, set_Prot: 30, 24;
pub SDeviceEn, set_SDeviceEn: 23;
pub u8, RMEEN, set_RMEEN: 22, 21;
pub ERRSTOP, set_ERRSTOP: 17;
pub ERRNPASS, set_ERRNPASS: 16;
pub MTE, set_MTE: 15;
pub u8, Type, set_Type: 14, 12;
pub u8, Mode, set_Mode: 11, 8;
pub TrInProg, set_TrInProg: 7;
pub DeviceEn, set_DeviceEn: 6;
pub u8, from into AddressIncrement, AddrInc, set_AddrInc: 5, 4;
pub u8, from into DataSize, SIZE, set_SIZE: 2, 0;
]
);
define_ap_register!(
/// Transfer Address Register
///
/// The transfer address register (TAR) holds the memory
name: TAR,
address: 0x04,
fields: [
pub u32, address, set_address: 31, 0;
]
);
define_ap_register!(
/// Transfer Address Register - upper word
///
/// The transfer address register (TAR) holds the memory
name: TAR2,
address: 0x08,
fields: [
pub u32, address, set_address: 31, 0;
]
);
define_ap_register!(
/// Data Read/Write register
///
/// The data read/write register (DRW) can be used to read
name: DRW,
address: 0x0C,
fields: [
pub u32, data, set_data: 31, 0;
]
);
define_ap_register!(
/// Banked Data 0 register
name: BD0,
address: 0x10,
fields: [
/// The data held in this bank.
pub u32, data, set_data: 31, 0;
]
);
define_ap_register!(
/// Banked Data 1 register
name: BD1,
address: 0x14,
fields: [
/// The data held in this bank.
pub u32, data, set_data: 31, 0;
]
);
define_ap_register!(
/// Banked Data 2 register
name: BD2,
address: 0x18,
fields: [
/// The data held in this bank.
pub u32, data, set_data: 31, 0;
]
);
define_ap_register!(
/// Banked Data 3 register
name: BD3,
address: 0x1C,
fields: [
/// The data held in this bank.
pub u32, data, set_data: 31, 0;
]
);
define_ap_register!(
/// Memory Barrier Transfer register
///
/// The memory barrier transfer register (MBT) can
name: MBT,
address: 0x20,
fields: [
pub u32, data, set_data: 31, 0;
]
);
define_ap_register!(
/// Base register
name: BASE2,
address: 0xF0,
fields: [
/// The second part of the base address of this access point if required.
pub u32, BASEADDR, set_BASEADDR: 31, 0;
]
);
define_ap_register!(
/// Configuration register
///
/// The configuration register (CFG) is used to determine
name: CFG,
address: 0xF4,
fields: [
pub LD, set_LD: 2;
pub LA, set_LA: 1;
pub BE, set_BE: 0;
]
);
define_ap_register!(
/// Base register
name: BASE,
address: 0xF8,
fields: [
/// The base address of this access point.
pub u32, BASEADDR, set_BASEADDR: 31, 12;
/// The base address format of this access point.
pub u8, from into BaseAddrFormat, Format, set_Format: 1, 1;
/// Does this access point exists?
/// This field can be used to detect access points by iterating over all possible ones until one is found which has `present == false`.
pub present, set_present: 0;
]
);
define_ap_register!(
/// Identification Register
///
/// The identification register is used to identify
/// an AP.
///
/// It has to be present on every AP.
name: IDR,
address: 0x0FC,
fields: [
/// The revision of this access point.
pub u8, REVISION, set_REVISION: 31, 28;
/// The raw JEP106 designer bits. Use [`IDR::DESIGNER`] for the decoded value.
u16, designer_bits, set_designer_bits: 27, 17;
/// The class of this access point.
pub u8, from into ApClass, CLASS, set_CLASS: 16, 13;
/// The variant of this access port.
pub u8, VARIANT, set_VARIANT: 7, 4;
/// The type of this access port.
pub u8, from into ApType, TYPE, set_TYPE: 3, 0;
]
);
impl IDR {
pub fn DESIGNER(&self) -> jep106::JEP106Code {
let designer = self.designer_bits();
let cc = (designer >> 7) as u8;
let id = (designer & 0x7f) as u8;
jep106::JEP106Code::new(cc, id)
}
pub fn set_DESIGNER(&mut self, designer: jep106::JEP106Code) {
self.set_designer_bits((u16::from(designer.cc) << 7) | u16::from(designer.id));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::architecture::arm::ap::{AddressIncrement, ApClass, DataSize};
#[test]
fn csw_field_positions_and_roundtrip() {
let mut csw = CSW::try_from(0).unwrap();
csw.set_DbgSwEnable(true); csw.set_AddrInc(AddressIncrement::Packed); csw.set_SIZE(DataSize::U256);
let raw: u32 = csw.into();
assert_eq!(raw & (1 << 31), 1 << 31, "DbgSwEnable must be bit 31");
assert_eq!(raw & (0b11 << 4), 0b10 << 4, "AddrInc must be bits 5:4");
assert_eq!(raw & 0b111, 0b101, "SIZE must be bits 2:0");
let csw = CSW::try_from(raw).unwrap();
assert!(csw.DbgSwEnable());
assert_eq!(csw.AddrInc(), AddressIncrement::Packed);
assert_eq!(csw.SIZE(), DataSize::U256);
}
#[test]
fn base_baseaddr_is_shifted() {
let mut base = BASE::try_from(0).unwrap();
base.set_BASEADDR(0xA_BCDE); base.set_present(true);
let raw: u32 = base.into();
assert_eq!(raw & 0xFFFF_F000, 0xA_BCDE << 12);
assert_eq!(raw & 1, 1);
assert_eq!(BASE::try_from(raw).unwrap().BASEADDR(), 0xA_BCDE);
}
#[test]
fn idr_designer_splits_cc_and_id() {
let mut idr = IDR::try_from(0).unwrap();
idr.set_DESIGNER(jep106::JEP106Code::new(4, 0x3b));
idr.set_CLASS(ApClass::MemAp);
let idr = IDR::try_from(u32::from(idr)).unwrap();
assert_eq!(idr.DESIGNER(), jep106::JEP106Code::new(4, 0x3b));
assert_eq!(idr.CLASS(), ApClass::MemAp);
}
#[test]
fn unknown_enum_encoding_is_preserved() {
use crate::architecture::arm::ap::ApType;
let csw = CSW::from_raw(0b111);
assert_eq!(csw.SIZE(), DataSize::Unknown(0b111));
assert_eq!(u32::from(csw) & 0b111, 0b111);
assert_eq!(IDR::from_raw(0x3).TYPE(), ApType::Unknown(0x3));
assert_eq!(CSW::from_raw(0b010).SIZE(), DataSize::U32);
}
}