use crate::arm::register::{DpRegister, ReadableRegister, RegisterDescriptor, WritableRegister};
use crate::{register_data_r, register_data_rw, register_data_w};
use alloc::{format, string::String};
use core::fmt;
pub struct IdCodeRegister;
impl RegisterDescriptor for IdCodeRegister {
const ADDRESS: u8 = 0x00;
type Value = IdCode;
}
impl ReadableRegister for IdCodeRegister {}
impl DpRegister for IdCodeRegister {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct IdCode(u32);
impl IdCode {
pub const fn new(value: u32) -> Self {
IdCode(value)
}
pub fn data(&self) -> u32 {
self.0
}
pub fn revision(&self) -> u8 {
((self.0 >> 28) & 0xF) as u8
}
pub fn part_number(&self) -> u8 {
((self.0 >> 20) & 0xFF) as u8
}
pub fn version(&self) -> u8 {
((self.0 >> 12) & 0xF) as u8
}
pub fn min(&self) -> bool {
(self.0 & (1 << 16)) != 0
}
pub fn designer_id(&self) -> u16 {
((self.0 >> 1) & 0x7FF) as u16
}
pub fn is_valid(&self) -> bool {
(self.0 & 1) == 1
}
pub fn rao(&self) -> bool {
(self.0 & 1) != 0
}
pub fn designer_name(&self) -> &'static str {
match self.designer_id() {
0x23B => "ARM Ltd",
_ => "Unknown",
}
}
pub fn part_description(&self) -> &'static str {
if self.designer_id() == 0x23B {
if self.part_number() == 0xBA {
match self.version() {
0 => "ARM Debug Port v0",
1 => "ARM Debug Port v1",
2 => "ARM Debug Port v2",
_ => "Unknown ARM Debug Port Version",
}
} else {
"unknown"
}
} else {
"unknown"
}
}
pub fn is_arm_debug_port(&self) -> bool {
self.designer_id() == 0x23B && self.part_number() == 0xBA
}
pub const fn from_u32(value: u32) -> Self {
IdCode(value)
}
}
impl From<u32> for IdCode {
fn from(value: u32) -> Self {
Self::from_u32(value)
}
}
impl fmt::Display for IdCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
if !self.is_valid() {
return write!(f, "Invalid IDCODE: 0x{:08X} (LSB not set)", self.0);
}
write!(f, "0x{:08X} {}", self.0, self.part_description())
} else {
write!(f, "0x{:08X}", self.0)
}
}
}
impl fmt::LowerHex for IdCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{:08x}", self.0)
}
}
impl fmt::UpperHex for IdCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{:08X}", self.0)
}
}
pub struct AbortRegister;
impl RegisterDescriptor for AbortRegister {
const ADDRESS: u8 = 0x00;
type Value = Abort;
}
impl WritableRegister for AbortRegister {}
impl DpRegister for AbortRegister {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Abort(u32);
register_data_w!(Abort);
impl Abort {
const STKCMPCLR: u32 = 1 << 1;
const STKERRCLR: u32 = 1 << 2;
const WDERRCLR: u32 = 1 << 3;
const ORUNERRCLR: u32 = 1 << 4;
pub fn set_stkcmpclr(&mut self, enable: bool) {
if enable {
self.0 |= Self::STKCMPCLR;
} else {
self.0 &= !Self::STKCMPCLR;
}
}
pub fn set_stkerrclr(&mut self, enable: bool) {
if enable {
self.0 |= Self::STKERRCLR;
} else {
self.0 &= !Self::STKERRCLR;
}
}
pub fn set_wderrclr(&mut self, enable: bool) {
if enable {
self.0 |= Self::WDERRCLR;
} else {
self.0 &= !Self::WDERRCLR;
}
}
pub fn set_orunerrclr(&mut self, enable: bool) {
if enable {
self.0 |= Self::ORUNERRCLR;
} else {
self.0 &= !Self::ORUNERRCLR;
}
}
}
pub struct CtrlStatRegister;
impl RegisterDescriptor for CtrlStatRegister {
const ADDRESS: u8 = 0x04;
type Value = CtrlStat;
}
impl ReadableRegister for CtrlStatRegister {}
impl WritableRegister for CtrlStatRegister {}
impl DpRegister for CtrlStatRegister {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct CtrlStat(u32);
register_data_rw!(CtrlStat);
impl CtrlStat {
const ORUNDETECT: u32 = 1 << 0;
const STICKYORUN: u32 = 1 << 1;
const TRNMODE_MASK: u32 = 0b11;
const TRNMODE_SHIFT: u32 = 2;
const STICKYCMP: u32 = 1 << 4;
const STICKYERR: u32 = 1 << 5;
const READOK: u32 = 1 << 6;
const WDATAERR: u32 = 1 << 7;
const MASKLANE_MASK: u32 = 0b1111;
const MASKLANE_SHIFT: u32 = 8;
const TRNCNT_MASK: u32 = 0b111111111111;
const TRNCNT_SHIFT: u32 = 12;
const CDBGRSTREQ: u32 = 1 << 26;
const CDBGRSTACK: u32 = 1 << 27;
const CDBGPWRUPREQ: u32 = 1 << 28;
const CDBGPWRUPACK: u32 = 1 << 29;
const CSYSPWRUPREQ: u32 = 1 << 30;
const CSYSPWRUPACK: u32 = 1 << 31;
pub const TRNMODE_NORMAL: u32 = 0b00;
pub const TRNMODE_VERIFY: u32 = 0b01;
pub const TRNMODE_COMPARE: u32 = 0b10;
pub fn value(&self) -> u32 {
self.0
}
pub fn orundetect(&self) -> bool {
self.0 & Self::ORUNDETECT != 0
}
pub fn stickyorun(&self) -> bool {
self.0 & Self::STICKYORUN != 0
}
pub fn trnmode(&self) -> u32 {
(self.0 >> Self::TRNMODE_SHIFT) & Self::TRNMODE_MASK
}
pub fn stickycmp(&self) -> bool {
self.0 & Self::STICKYCMP != 0
}
pub fn stickyerr(&self) -> bool {
self.0 & Self::STICKYERR != 0
}
pub fn readok(&self) -> bool {
self.0 & Self::READOK != 0
}
pub fn wdataerr(&self) -> bool {
self.0 & Self::WDATAERR != 0
}
pub fn masklane(&self) -> u32 {
(self.0 >> Self::MASKLANE_SHIFT) & Self::MASKLANE_MASK
}
pub fn trncnt(&self) -> u32 {
(self.0 >> Self::TRNCNT_SHIFT) & Self::TRNCNT_MASK
}
pub fn cdbgrstreq(&self) -> bool {
self.0 & Self::CDBGRSTREQ != 0
}
pub fn cdbgrstack(&self) -> bool {
self.0 & Self::CDBGRSTACK != 0
}
pub fn cdbgpwrupreq(&self) -> bool {
self.0 & Self::CDBGPWRUPREQ != 0
}
pub fn cdbgpwrupack(&self) -> bool {
self.0 & Self::CDBGPWRUPACK != 0
}
pub fn csyspwrupreq(&self) -> bool {
self.0 & Self::CSYSPWRUPREQ != 0
}
pub fn csyspwrupack(&self) -> bool {
self.0 & Self::CSYSPWRUPACK != 0
}
pub fn has_errors(&self) -> bool {
self.stickyorun()
|| self.stickycmp()
|| self.stickyerr()
|| self.wdataerr()
|| self.stickyorun()
}
pub fn set_orundetect(&mut self, enable: bool) {
if enable {
self.0 |= Self::ORUNDETECT;
} else {
self.0 &= !Self::ORUNDETECT;
}
}
pub fn set_stickyorun(&mut self, enable: bool) {
if enable {
self.0 |= Self::STICKYORUN;
} else {
self.0 &= !Self::STICKYORUN;
}
}
pub fn set_trnmode(&mut self, mode: u32) {
self.0 = (self.0 & !(Self::TRNMODE_MASK << Self::TRNMODE_SHIFT))
| ((mode & Self::TRNMODE_MASK) << Self::TRNMODE_SHIFT);
}
pub fn set_stickycmp(&mut self, enable: bool) {
if enable {
self.0 |= Self::STICKYCMP;
} else {
self.0 &= !Self::STICKYCMP;
}
}
pub fn set_stickyerr(&mut self, enable: bool) {
if enable {
self.0 |= Self::STICKYERR;
} else {
self.0 &= !Self::STICKYERR;
}
}
pub fn set_masklane(&mut self, mask: u32) {
self.0 = (self.0 & !(Self::MASKLANE_MASK << Self::MASKLANE_SHIFT))
| ((mask & Self::MASKLANE_MASK) << Self::MASKLANE_SHIFT);
}
pub fn set_trncnt(&mut self, count: u32) {
self.0 = (self.0 & !(Self::TRNCNT_MASK << Self::TRNCNT_SHIFT))
| ((count & Self::TRNCNT_MASK) << Self::TRNCNT_SHIFT);
}
pub fn set_cdbgrstreq(&mut self, enable: bool) {
if enable {
self.0 |= Self::CDBGRSTREQ;
} else {
self.0 &= !Self::CDBGRSTREQ;
}
}
pub fn set_cdbgpwrupreq(&mut self, enable: bool) {
if enable {
self.0 |= Self::CDBGPWRUPREQ;
} else {
self.0 &= !Self::CDBGPWRUPREQ;
}
}
pub fn set_csyspwrupreq(&mut self, enable: bool) {
if enable {
self.0 |= Self::CSYSPWRUPREQ;
} else {
self.0 &= !Self::CSYSPWRUPREQ;
}
}
pub fn error_states(&self) -> String {
let mut errors = [""; 5];
let mut count = 0;
if self.stickyorun() {
errors[count] = "STICKYORUN";
count += 1;
}
if self.stickycmp() {
errors[count] = "STICKYCMP";
count += 1;
}
if self.stickyerr() {
errors[count] = "STICKYERR";
count += 1;
}
if self.wdataerr() {
errors[count] = "WDATAERR";
count += 1;
}
if self.orundetect() {
errors[count] = "ORUNDETECT";
count += 1;
}
if count == 0 {
format!("No errors{}", if self.readok() { " (READOK)" } else { "" })
} else {
format!("Errors: {}", errors[..count].join(", "))
}
}
pub fn power_states(&self) -> String {
format!(
"Debug: {}/{}, System: {}/{}",
if self.cdbgpwrupreq() { "REQ" } else { "off" },
if self.cdbgpwrupack() { "ACK" } else { "nak" },
if self.csyspwrupreq() { "REQ" } else { "off" },
if self.csyspwrupack() { "ACK" } else { "nak" }
)
}
pub fn transaction_state(&self) -> String {
let mode = match self.trnmode() {
Self::TRNMODE_NORMAL => "Normal",
Self::TRNMODE_VERIFY => "Verify",
Self::TRNMODE_COMPARE => "Compare",
_ => "Reserved",
};
format!(
"Mode: {}, Count: {}, Mask: 0x{:x}",
mode,
self.trncnt(),
self.masklane()
)
}
}
pub struct SelectRegister;
impl RegisterDescriptor for SelectRegister {
const ADDRESS: u8 = 0x08;
type Value = Select;
}
impl ReadableRegister for SelectRegister {}
impl WritableRegister for SelectRegister {}
impl DpRegister for SelectRegister {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Select(u32);
register_data_rw!(Select);
impl Select {
const APSEL_MASK: u32 = 0xFF;
const APSEL_SHIFT: u32 = 24;
pub const DPBANKSEL_MASK: u32 = 0xF;
pub const DPBANKSEL_SHIFT: u32 = 0;
pub const APBANKSEL_MASK: u32 = 0xF;
pub const APBANKSEL_SHIFT: u32 = 4;
pub fn value(&self) -> u32 {
self.0
}
pub fn apsel(&self) -> u32 {
(self.0 >> Self::APSEL_SHIFT) & Self::APSEL_MASK
}
pub fn dpbanksel(&self) -> u32 {
(self.0 >> Self::DPBANKSEL_SHIFT) & Self::DPBANKSEL_MASK
}
pub fn apbanksel(&self) -> u32 {
(self.0 >> Self::APBANKSEL_SHIFT) & Self::APBANKSEL_MASK
}
pub fn set_apsel(&mut self, apsel: u32) {
self.0 = (self.0 & !(Self::APSEL_MASK << Self::APSEL_SHIFT))
| ((apsel & Self::APSEL_MASK) << Self::APSEL_SHIFT);
}
pub fn set_dpbanksel(&mut self, banksel: u8) {
let banksel = banksel as u32;
self.0 = (self.0 & !(Self::DPBANKSEL_MASK << Self::DPBANKSEL_SHIFT))
| ((banksel & Self::DPBANKSEL_MASK) << Self::DPBANKSEL_SHIFT);
}
pub fn set_apbanksel(&mut self, banksel: u8) {
let banksel = banksel as u32;
self.0 = (self.0 & !(Self::APBANKSEL_MASK << Self::APBANKSEL_SHIFT))
| ((banksel & Self::APBANKSEL_MASK) << Self::APBANKSEL_SHIFT);
}
pub fn set_dpbanksel_from_addr(&mut self, addr: u8) {
let banksel = (addr >> 4) & 0xF;
self.set_dpbanksel(banksel);
}
pub fn set_apbanksel_from_addr(&mut self, addr: u8) {
let banksel = (addr >> 4) & 0xF;
self.set_apbanksel(banksel);
}
pub fn selection_info(&self) -> String {
format!(
"AP: {}, DP Bank: {}, AP Bank: {}",
self.apsel(),
self.dpbanksel(),
self.apbanksel()
)
}
}
pub struct RdBuffRegister;
impl RegisterDescriptor for RdBuffRegister {
const ADDRESS: u8 = 0x0C;
type Value = RdBuff;
}
impl ReadableRegister for RdBuffRegister {}
impl DpRegister for RdBuffRegister {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct RdBuff(u32);
register_data_r!(RdBuff);
impl RdBuff {
pub fn data(&self) -> u32 {
self.0
}
}
pub struct TargetSelRegister;
impl RegisterDescriptor for TargetSelRegister {
const ADDRESS: u8 = 0x0C;
type Value = TargetSel;
}
impl WritableRegister for TargetSelRegister {}
impl DpRegister for TargetSelRegister {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct TargetSel(u32);
register_data_w!(TargetSel);
impl TargetSel {
pub const fn new(value: u32) -> Self {
TargetSel(value)
}
pub fn data(&self) -> u32 {
self.0
}
}
impl From<IdCode> for TargetSel {
fn from(id: IdCode) -> Self {
TargetSel(id.data())
}
}
pub const TARGET_SEL_RP2040_BASE: u32 = 0x01002927;
pub const TARGET_SEL_RP2040_CORE0: TargetSel = TargetSel(TARGET_SEL_RP2040_BASE);
pub const TARGET_SEL_RP2040_CORE1: TargetSel = TargetSel(0x1 << 28 | TARGET_SEL_RP2040_BASE);
pub const TARGET_SEL_RP2040_RESCUE_DP: TargetSel = TargetSel(0xF << 28 | TARGET_SEL_RP2040_BASE);
pub const TARGET_SEL_RP2040_ALL: [TargetSel; 3] = [
TARGET_SEL_RP2040_CORE0,
TARGET_SEL_RP2040_CORE1,
TARGET_SEL_RP2040_RESCUE_DP,
];