1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use num::AsUsize;

use crate::gicv2::InterruptId;
use crate::memory_mapped_register as reg;
use crate::reg::memory_mapped::{PaddingBytes, Register};
use crate::reg::prelude::*;

#[repr(C)]
pub struct DistributorRegisterBlock {
    /// 0x000: GICD_CTLR (Distributor Control Register)
    pub ctlr: Register<GICD_CTLR>,
    /// 0x004: GICD_TYPER (Interrupt Controller Type Register)
    pub typer: Register<u32>,
    /// 0x008: GICD_IIDR (Distributor Implementer Identification Register)
    pub iidr: Register<u32>,
    /// 0x00C-0x01C: Reserved
    _0: PaddingBytes<0x14>,
    /// 0x020-0x03C: IMPLEMENTATION DEFINED registers
    _1: PaddingBytes<0x20>,
    /// 0x040-0x07C: Reserved
    _2: PaddingBytes<0x40>,
    /// 0x080: GICD_IGROUPRnb (Interrupt Group Registers)
    pub igroupr: [Register<u32>; 32],
    /// 0x100-0x17C: GICD_ISENABLERn (Interrupt Set-Enable Registers)
    pub isenabler: [Register<GICD_ISENABLER>; 32],
    /// 0x180-0x1FC: GICD_ICENABLERn (Interrupt Clear-Enable Registers)
    pub icenabler: [Register<u32>; 32],
    /// 0x200-0x27C: GICD_ISPENDRn (Interrupt Set-Pending Registers)
    pub ispender: [Register<u32>; 32],
    /// 0x280-0x2FC: GICD_ICPENDRn (Interrupt Clear-Pending Registers)
    pub icpendr: [Register<u32>; 32],
    /// 0x300-0x37C: GICD_ISACTIVERn (GICv2 Interrupt Set-Active Registers)
    pub isactiver: [Register<u32>; 32],
    /// 0x380-0x3FC: GICD_ICACTIVERn (Interrupt Clear-Active Registers)
    pub icactiver: [Register<u32>; 32],
    /// 0x400-0x7F8: GICD_IPRIORITYRn (Interrupt Priority Registers)
    pub ipriorityr: [Register<u32>; 255],
    /// 0x7FC: Reserved
    _3: PaddingBytes<0x4>,
    /// 0x800-0x81C: GICD_ITARGETSRn (Interrupt Processor Targets Registers)
    pub itargetsr: [Register<u32>; 255],
    /// 0xBFC: Reserved
    _4: PaddingBytes<0x4>,
    /// 0xC00-0xCFC: GICD_ICFGRn (Interrupt Configuration Registers)
    pub icfgr: [Register<u32>; 64],
    /// 0xD00-0xDFC: IMPLEMENTATION DEFINED registers
    _5: PaddingBytes<0x100>,
    /// 0xE00-0xEFC: GICD_NSACRn (Non-secure Access Control Registers, optional)
    pub nsacr: [Register<u32>; 64],
    /// 0xF00: GICD_SGIR (Software Generated Interrupt Register)
    pub sgir: Register<u32>,
    /// 0xF04-0xF0C: Reserved
    _6: PaddingBytes<0xa>,
    /// 0xF10-0xF1C: GICD_CPENDSGIRn (SGI Clear-Pending Registers)
    pub cpendsgir: [Register<u32>; 4],
    /// 0xF20-0xF2C: GICD_SPENDSGIRn (SGI Set-Pending Registers)
    pub spendsgi: [Register<u32>; 4],
    /// 0xF30-0xFCC: Reserved
    _7: PaddingBytes<0xa0>,
    /// 0xFD0-0xFFC:  - ( Identification registers on page 4-119)
    _8: PaddingBytes<0x20>,
}

reg! { GICD_CTLR(u32), rwi=0x0000_0000 }

#[allow(dead_code)]
impl RegisterReader<GICD_CTLR> {
    pub fn enable(&self) -> bool {
        self.bit(0)
    }
}

#[allow(dead_code)]
impl RegisterWriter<GICD_CTLR> {
    pub fn enable(&mut self, enable: bool) {
        unsafe { self.bit(0, enable) }
    }
}

reg! { GICD_ISENABLER(u32), wi=0x0000_0000 }

#[allow(dead_code)]
impl RegisterWriter<GICD_ISENABLER> {
    pub fn set_enable(&mut self, m: usize) {
        unsafe { self.bit(m, true) }
    }
}

#[repr(C)]
pub struct CpuInterfaceRegisterBlock {
    /// 0x0000: GICC_CTLR (CPU Interface Control Register)
    pub ctlr: Register<GICC_CTLR>,
    /// 0x0004: GICC_PMR (Interrupt Priority Mask Register)
    pub pmr: Register<GICC_PMR>,
    /// 0x0008: GICC_BPR (Binary Point Register)
    pub bpr: Register<u32>,
    /// 0x000C: GICC_IAR (Interrupt Acknowledge Register)
    pub iar: Register<GICC_IAR>,
    /// 0x0010: GICC_EOIR (End of Interrupt Register)
    pub eoir: Register<GICC_EOIR>,
    /// 0x0014: GICC_RPR (Running Priority Register)
    pub rpr: Register<u32>,
    /// 0x0018: GICC_HPPIR (Highest Priority Pending Interrupt Register)
    pub hppir: Register<u32>,
    /// 0x001C: GICC_ABPR (Aliased Binary Point Register)
    pub abpr: Register<u32>,
    /// 0x0020: GICC_AIAR (Aliased Interrupt Acknowledge Register)
    pub aiar: Register<u32>,
    /// 0x0024: GICC_AEOIR (Aliased End of Interrupt Register)
    pub aeoir: Register<u32>,
    /// 0x0028: GICC_AHPPIR (Aliased Highest Priority Pending Interrupt Register)
    pub ahppir: Register<u32>,
    /// 0x002C-0x003C: Reserved
    _0: PaddingBytes<0x14>,
    /// 0x0040-0x00CF: IMPLEMENTATION DEFINED registers
    _1: PaddingBytes<0x90>,
    /// 0x00D0-0x00DC: GICC_APRn (Active Priorities Registers)
    pub apr: [Register<u32>; 4],
    /// 0x00E0-0x00EC: GICC_NSAPRn (Non-secure Active Priorities Registers)
    pub nsapr: [Register<u32>; 4],
    /// 0x00ED-0x00F8: Reserved
    _2: PaddingBytes<0xf>,
    /// 0x00FC: GICC_IIDR (CPU Interface Identification Register)
    pub iidr: Register<u32>,
    // for some reason, this gap is left unmentioned
    _3: PaddingBytes<0xf00>,
    /// 0x1000: GICC_DIR (Deactivate Interrupt Register)
    pub dir: Register<u32>,
}

reg! { GICC_CTLR(u32), rwi=0x0000_0000 }

#[allow(dead_code)]
impl RegisterReader<GICC_CTLR> {
    pub fn enable(&self) -> bool {
        self.bit(0)
    }
}

#[allow(dead_code)]
impl RegisterWriter<GICC_CTLR> {
    pub fn enable(&mut self, enable: bool) {
        unsafe { self.bit(0, enable) }
    }
}

reg! { GICC_PMR(u32), rwi=0x0000_0000 }

#[allow(dead_code)]
impl RegisterReader<GICC_PMR> {
    pub fn priority(&self) -> u8 {
        self.field(0..=7) as _
    }
}

#[allow(dead_code)]
impl RegisterWriter<GICC_PMR> {
    pub fn priority(&mut self, priority: u8) {
        unsafe { self.field(0..=7, priority as _) }
    }
}

reg! { GICC_IAR(u32), r }

#[allow(dead_code)]
impl RegisterReader<GICC_IAR> {
    pub fn entire(&self) -> u32 {
        self.bits()
    }
    pub fn cpuid(&self) -> u8 {
        self.field(10..=12) as _
    }
    pub fn interrupt_id(&self) -> InterruptId {
        self.field(0..=9).as_usize().try_into().unwrap()
    }
}

// IHI 0048B.b § 4.4.5 “If software writes the ID of a spurious interrupt to the
// GICC_EOIR, the GIC ignores that write.”
reg! { GICC_EOIR(u32), wi=0x000003FF }

#[allow(dead_code)]
impl RegisterWriter<GICC_EOIR> {
    pub fn entire_iar(&mut self, iar: u32) {
        unsafe { self.bits(iar) }
    }
}