n64_pac/si.rs
1//! RCP - Serial Interface
2
3use core::ops::Deref;
4use proc_bitfield::bitfield;
5use crate::RW;
6
7/// A wrapper around a mutable reference to the Serial Interface's memory mapped registers.
8///
9/// See [`SerialInterface::new()`] for usage details.
10pub struct SerialInterface {
11 r: &'static mut RegisterBlock,
12}
13
14#[repr(C)]
15pub struct RegisterBlock {
16 pub dram_addr: RW<u32>,
17 pub pif_ad_rd64b: RW<u32>,
18 pub pif_ad_wr4b: RW<u32>,
19 /// Seemingly unused; more research required
20 _spacer: u32,
21 pub pif_ad_wr64b: RW<u32>,
22 pub pif_ad_rd4b: RW<u32>,
23 pub status: RW<StatusReg>,
24}
25impl SerialInterface {
26 /// Creates a new wrapped mutable reference to the Serial Interface's memory mapped registers, starting at `0xA4800000`.
27 ///
28 /// Developers are recommended to use [`Hardware::take()`][crate::Hardware::take()] instead.
29 /// But for unrestricted, unsafe, access, this struct provides a method-based version to the
30 /// static functions available at the [module][crate::si] level.
31 ///
32 /// # Safety
33 /// This provides unrestricted access to memory mapped registers. Data races _could_ occur if writing
34 /// to a register in both regular code and inside interrupt handlers.
35 ///
36 /// This is especially problematic if performing a read-modify-write operation; an interrupt
37 /// could trigger between reading a register, and writing a modified value back to the same
38 /// register. Thus anything written to that register inside the interrupt, would only apply for
39 /// a short moment before being overwritten.
40 #[inline(always)]
41 pub unsafe fn new() -> Self { Self {
42 r: &mut *(0xA4800000 as *mut RegisterBlock)
43 }}
44}
45impl Deref for SerialInterface {
46 type Target = RegisterBlock;
47
48 #[inline(always)]
49 fn deref(&self) -> &Self::Target {
50 self.r
51 }
52}
53
54regfn_rw!(SerialInterface, dram_addr, DRAM_ADDR, u32);
55regfn_rw!(SerialInterface, pif_ad_rd64b, PIF_AD_RD64B, u32);
56regfn_rw!(SerialInterface, pif_ad_wr4b, PIF_AD_WR4B, u32);
57regfn_rw!(SerialInterface, pif_ad_wr64b, PIF_AD_WR64B, u32);
58regfn_rw!(SerialInterface, pif_ad_rd4b, PIF_AD_RD4B, u32);
59regfn_rw!(SerialInterface, status, STATUS, StatusReg);
60
61
62bitfield! {
63 #[derive(Copy, Clone, PartialEq, Eq)]
64 pub struct StatusReg(pub u32): Debug {
65 pub whole_register: u32 [wo] @ ..,
66
67 pub dma_busy: bool [ro] @ 0,
68 pub io_busy: bool [ro] @ 1,
69 pub read_pending: bool [ro] @ 2,
70 pub dma_error: bool [ro] @ 3,
71 pub pch_state: u8 [ro] @ 4..=7,
72 pub dma_state: u8 [ro] @ 8..=11,
73
74 /// Mirror of the SI interrupt flag from the `MI_INTERRUPT` register.
75 ///
76 /// Writing any value to the `SI_STATUS` register clears the flag across all three locations
77 /// (this bit, `MI_INTERRUPT`, and the RCP Interrupt Cause register).
78 ///
79 /// SI Interrupts occur when a DMA write finishes.
80 pub interrupt: bool @ 12,
81 }
82}