use crate::architecture::arm::{
RegisterParseError,
ap::{AddressIncrement, ApClass, ApType, BaseAddrFormat, DataSize},
};
macro_rules! define_ap_register {
(
$(#[$outer:meta])*
name: $name:ident,
address: $address_v1:expr,
fields: [$($(#[$inner:meta])*$field:ident: $type:ty$(,)?)*],
from: $from_param:ident => $from:expr,
to: $to_param:ident => $to:expr
)
=> {
$(#[$outer])*
#[allow(non_snake_case)]
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct $name {
$($(#[$inner])*pub $field: $type,)*
}
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($from_param: u32) -> Result<$name, Self::Error> {
$from
}
}
impl From<$name> for u32 {
fn from($to_param: $name) -> u32 {
$to
}
}
}
}
pub(crate) use define_ap_register;
define_ap_register!(
name: CSW,
address: 0x00,
fields: [
DbgSwEnable: bool, Prot: u8, SDeviceEn: bool, RMEEN: u8, _RES0: u8,
ERRSTOP: bool,
ERRNPASS: bool,
MTE: bool, Type: u8, Mode: u8, TrInProg: bool, DeviceEn: bool, AddrInc: AddressIncrement, _RES1: u8, SIZE: DataSize, ],
from: value => Ok(CSW {
DbgSwEnable: ((value >> 31) & 0x01) != 0,
Prot: ((value >> 24) & 0x7F) as u8,
SDeviceEn: ((value >> 23) & 0x01) != 0,
RMEEN: ((value >> 21) & 0x3) as u8,
_RES0: ((value >> 18) & 0x07) as u8,
ERRSTOP: ((value >> 17) & 0b1) != 0,
ERRNPASS: ((value >> 16) & 0b1) != 0,
MTE: ((value >> 15) & 0x01) != 0,
Type: ((value >> 12) & 0x07) as u8,
Mode: ((value >> 8) & 0x0F) as u8,
TrInProg: ((value >> 7) & 0x01) != 0,
DeviceEn: ((value >> 6) & 0x01) != 0,
AddrInc: AddressIncrement::from_u8(((value >> 4) & 0x03) as u8).ok_or_else(|| RegisterParseError::new("CSW", value))?,
_RES1: ((value >> 3) & 1) as u8,
SIZE: DataSize::try_from((value & 0x07) as u8).map_err(|_| RegisterParseError::new("CSW", value))?,
}),
to: value => (u32::from(value.DbgSwEnable) << 31)
| (u32::from(value.Prot ) << 24)
| (u32::from(value.SDeviceEn ) << 23)
| (u32::from(value.RMEEN ) << 21)
| (u32::from(value._RES0 ) << 18)
| (u32::from(value.ERRSTOP as u8) << 17)
| (u32::from(value.ERRNPASS as u8) << 16)
| (u32::from(value.MTE ) << 15)
| (u32::from(value.Type ) << 12)
| (u32::from(value.Mode ) << 8)
| (u32::from(value.TrInProg ) << 7)
| (u32::from(value.DeviceEn ) << 6)
| (u32::from(value.AddrInc as u8) << 4)
| (u32::from(value._RES1 ) << 1)
| (value.SIZE as u32)
);
define_ap_register!(
name: TAR,
address: 0x04,
fields: [
address: u32,
],
from: value => Ok(TAR { address: value }),
to: value => value.address
);
define_ap_register!(
name: TAR2,
address: 0x08,
fields: [
address: u32,
],
from: value => Ok(TAR2 { address: value }),
to: value => value.address
);
define_ap_register!(
name: DRW,
address: 0x0C,
fields: [
data: u32,
],
from: value => Ok(DRW { data: value }),
to: value => value.data
);
define_ap_register!(
name: BD0,
address: 0x10,
fields: [
data: u32,
],
from: value => Ok(BD0 { data: value }),
to: value => value.data
);
define_ap_register!(
name: BD1,
address: 0x14,
fields: [
data: u32,
],
from: value => Ok(BD1 { data: value }),
to: value => value.data
);
define_ap_register!(
name: BD2,
address: 0x18,
fields: [
data: u32,
],
from: value => Ok(BD2 { data: value }),
to: value => value.data
);
define_ap_register!(
name: BD3,
address: 0x1C,
fields: [
data: u32,
],
from: value => Ok(BD3 { data: value }),
to: value => value.data
);
define_ap_register!(
name: MBT,
address: 0x20,
fields: [
data: u32,
],
from: value => Ok(MBT { data: value }),
to: value => value.data
);
define_ap_register!(
name: BASE2,
address: 0xF0,
fields: [
BASEADDR: u32
],
from: value => Ok(BASE2 { BASEADDR: value }),
to: value => value.BASEADDR
);
define_ap_register!(
name: CFG,
address: 0xF4,
fields: [
LD: bool,
LA: bool,
BE: bool,
],
from: value => Ok(CFG {
LD: ((value >> 2) & 0x01) != 0,
LA: ((value >> 1) & 0x01) != 0,
BE: (value & 0x01) != 0,
}),
to: value => ((value.LD as u32) << 2) | ((value.LA as u32) << 1) | (value.BE as u32)
);
define_ap_register!(
name: BASE,
address: 0xF8,
fields: [
BASEADDR: u32,
_RES0: u8,
Format: BaseAddrFormat,
present: bool,
],
from: value => Ok(BASE {
BASEADDR: (value & 0xFFFF_F000) >> 12,
_RES0: 0,
Format: match ((value >> 1) & 0x01) as u8 {
0 => BaseAddrFormat::Legacy,
1 => BaseAddrFormat::ADIv5,
_ => panic!("This is a bug. Please report it."),
},
present: match (value & 0x01) as u8 {
0 => false,
1 => true,
_ => panic!("This is a bug. Please report it."),
},
}),
to: value =>
(value.BASEADDR << 12)
| (u32::from(value.Format as u8) << 1)
| u32::from(value.present)
);
define_ap_register!(
name: IDR,
address: 0x0FC,
fields: [
REVISION: u8,
DESIGNER: jep106::JEP106Code,
CLASS: ApClass,
#[doc(hidden)]
_RES0: u8,
VARIANT: u8,
TYPE: ApType,
],
from: value => Ok(IDR {
REVISION: ((value >> 28) & 0x0F) as u8,
DESIGNER: {
let designer = ((value >> 17) & 0x7FF) as u16;
let cc = (designer >> 7) as u8;
let id = (designer & 0x7f) as u8;
jep106::JEP106Code::new(cc, id)
},
CLASS: ApClass::from_u8(((value >> 13) & 0x0F) as u8).ok_or_else(|| RegisterParseError::new("IDR", value))?,
_RES0: 0,
VARIANT: ((value >> 4) & 0x0F) as u8,
TYPE: ApType::from_u8((value & 0x0F) as u8).ok_or_else(|| RegisterParseError::new("IDR", value))?
}),
to: value => (u32::from(value.REVISION) << 28)
| (((u32::from(value.DESIGNER.cc) << 7) | u32::from(value.DESIGNER.id)) << 17)
| ((value.CLASS as u32) << 13)
| (u32::from(value.VARIANT) << 4)
| (value.TYPE as u32)
);