1use core::marker::PhantomData;
2
3use arbitrary_int::{prelude::*, u7};
4
5#[cfg(feature = "vor1x")]
6const BASE_ADDR: usize = 0x4002_0000;
7#[cfg(feature = "vor4x")]
8const BASE_ADDR: usize = 0x4001_8000;
9
10#[bitbybit::bitenum(u3)]
11#[derive(Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum StatusSelect {
14 OneCyclePulse = 0b000,
16 OutputActiveBit = 0b001,
17 ToggleOnEachCycle = 0b010,
19 PwmaOutput = 0b011,
21 PwmbOutput = 0b100,
24 EnabledBit = 0b101,
25 PwmaActiveBit = 0b110,
27}
28
29#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"))]
30pub struct Control {
31 #[bit(9, rw)]
33 request_stop: bool,
34 #[bit(8, rw)]
35 status_invert: bool,
36 #[bits(5..=7, rw)]
37 status_sel: Option<StatusSelect>,
38 #[bit(4, rw)]
39 irq_enable: bool,
40 #[bit(3, rw)]
43 auto_deactivate: bool,
44 #[bit(2, rw)]
47 auto_disable: bool,
48 #[bit(1, r)]
49 active: bool,
50 #[bit(0, rw)]
51 enable: bool,
52}
53
54#[derive(Debug)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56pub struct EnableControl(arbitrary_int::UInt<u32, 1>);
57
58impl EnableControl {
59 pub fn new_disable() -> Self {
60 EnableControl(arbitrary_int::UInt::<u32, 1>::from_u32(0))
61 }
62
63 pub fn new_enable() -> Self {
64 EnableControl(arbitrary_int::UInt::<u32, 1>::from_u32(1))
65 }
66
67 pub fn enabled(&self) -> bool {
68 self.0.value() != 0
69 }
70}
71
72#[bitbybit::bitenum(u1, exhaustive = true)]
73#[derive(Default, Debug, PartialEq, Eq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum CascadeInvert {
76 #[default]
77 ActiveHigh = 0,
78 ActiveLow = 1,
79}
80
81#[bitbybit::bitenum(u1, exhaustive = true)]
83#[derive(Default, Debug, PartialEq, Eq)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub enum DualCascadeOp {
86 #[default]
87 LogicalAnd = 0,
88 LogicalOr = 1,
89}
90
91#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
92pub struct CascadeControl {
93 #[bit(10, rw)]
97 trigger2: bool,
98 #[bit(9, rw)]
99 inv2: CascadeInvert,
100 #[bit(8, rw)]
103 en2: bool,
104 #[bit(7, rw)]
106 trigger1: bool,
107 #[bit(6, rw)]
110 trigger0: bool,
111 #[bit(4, rw)]
114 dual_cascade_op: DualCascadeOp,
115 #[bit(3, rw)]
117 inv1: CascadeInvert,
118 #[bit(2, rw)]
120 en1: bool,
121 #[bit(1, rw)]
123 inv0: CascadeInvert,
124 #[bit(0, rw)]
126 en0: bool,
127}
128
129#[derive(Debug, PartialEq, Eq)]
130#[cfg_attr(feature = "defmt", derive(defmt::Format))]
131pub struct InvalidCascadeSourceId;
132
133#[cfg(feature = "vor1x")]
134#[derive(Debug, PartialEq, Eq)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136#[repr(u8)]
137pub enum CascadeSource {
138 PortA(u8),
139 PortB(u8),
140 Tim(u8),
141 RamSbe = 96,
142 RamMbe = 97,
143 RomSbe = 98,
144 RomMbe = 99,
145 Txev = 100,
146 ClockDivider(u8),
147}
148
149#[cfg(feature = "vor4x")]
150#[derive(Debug, PartialEq, Eq)]
151#[cfg_attr(feature = "defmt", derive(defmt::Format))]
152#[repr(u8)]
153pub enum CascadeSource {
154 PortA(u8),
155 PortB(u8),
156 PortC(u8),
157 PortD(u8),
158 PortE(u8),
159 Tim(u8),
160 TxEv,
161 AdcIrq,
162 RomSbe,
163 RomMbe,
164 Ram0Sbe,
165 Ram0Mbe,
166 Ram1Sbe,
167 Ram1Mbe,
168 WdogIrq,
169}
170
171impl CascadeSource {
172 #[cfg(feature = "vor1x")]
173 pub fn id(&self) -> Result<u7, InvalidCascadeSourceId> {
174 let port_check = |base: u8, id: u8, len: u8| -> Result<u7, InvalidCascadeSourceId> {
175 if id > len - 1 {
176 return Err(InvalidCascadeSourceId);
177 }
178 Ok(u7::new(base + id))
179 };
180 match self {
181 CascadeSource::PortA(id) => port_check(0, *id, 32),
182 CascadeSource::PortB(id) => port_check(32, *id, 32),
183 CascadeSource::Tim(id) => port_check(64, *id, 24),
184 CascadeSource::RamSbe => Ok(u7::new(96)),
185 CascadeSource::RamMbe => Ok(u7::new(97)),
186 CascadeSource::RomSbe => Ok(u7::new(98)),
187 CascadeSource::RomMbe => Ok(u7::new(99)),
188 CascadeSource::Txev => Ok(u7::new(100)),
189 CascadeSource::ClockDivider(id) => port_check(120, *id, 8),
190 }
191 }
192
193 #[cfg(feature = "vor4x")]
194 fn id(&self) -> Result<u7, InvalidCascadeSourceId> {
195 let port_check = |base: u8, id: u8| -> Result<u7, InvalidCascadeSourceId> {
196 if id > 15 {
197 return Err(InvalidCascadeSourceId);
198 }
199 Ok(u7::new(base + id))
200 };
201 match self {
202 CascadeSource::PortA(id) => port_check(0, *id),
203 CascadeSource::PortB(id) => port_check(16, *id),
204 CascadeSource::PortC(id) => port_check(32, *id),
205 CascadeSource::PortD(id) => port_check(48, *id),
206 CascadeSource::PortE(id) => port_check(64, *id),
207 CascadeSource::Tim(id) => {
208 if *id > 23 {
209 return Err(InvalidCascadeSourceId);
210 }
211 Ok(u7::new(80 + id))
212 }
213 CascadeSource::TxEv => Ok(u7::new(104)),
214 CascadeSource::AdcIrq => Ok(u7::new(105)),
215 CascadeSource::RomSbe => Ok(u7::new(106)),
216 CascadeSource::RomMbe => Ok(u7::new(106)),
217 CascadeSource::Ram0Sbe => Ok(u7::new(108)),
218 CascadeSource::Ram0Mbe => Ok(u7::new(109)),
219 CascadeSource::Ram1Sbe => Ok(u7::new(110)),
220 CascadeSource::Ram1Mbe => Ok(u7::new(111)),
221 CascadeSource::WdogIrq => Ok(u7::new(112)),
222 }
223 }
224
225 #[cfg(feature = "vor1x")]
226 pub fn from_raw(raw: u32) -> Result<Self, InvalidCascadeSourceId> {
227 let id = u7::new((raw & 0x7F) as u8);
228 if id.value() > 127 {
229 return Err(InvalidCascadeSourceId);
230 }
231 let id = id.as_u8();
232 if id < 32 {
233 return Ok(CascadeSource::PortA(id));
234 } else if (32..56).contains(&id) {
235 return Ok(CascadeSource::PortB(id - 32));
236 } else if (64..88).contains(&id) {
237 return Ok(CascadeSource::Tim(id - 64));
238 } else if id > 120 {
239 return Ok(CascadeSource::ClockDivider(id - 120));
240 }
241 match id {
242 96 => Ok(CascadeSource::RamSbe),
243 97 => Ok(CascadeSource::RamMbe),
244 98 => Ok(CascadeSource::RomSbe),
245 99 => Ok(CascadeSource::RomMbe),
246 100 => Ok(CascadeSource::Txev),
247 _ => Err(InvalidCascadeSourceId),
248 }
249 }
250 #[cfg(feature = "vor4x")]
251 pub fn from_raw(raw: u32) -> Result<Self, InvalidCascadeSourceId> {
252 use crate::NUM_PORT_DEFAULT;
253
254 let id = u7::new((raw & 0x7F) as u8);
255 if id.value() > 127 {
256 return Err(InvalidCascadeSourceId);
257 }
258 let id = id.as_u8();
259 if id < 16 {
260 return Ok(CascadeSource::PortA(id));
261 } else if (16..16 + NUM_PORT_DEFAULT as u8).contains(&id) {
262 return Ok(CascadeSource::PortB(id - 16));
263 } else if (32..32 + NUM_PORT_DEFAULT as u8).contains(&id) {
264 return Ok(CascadeSource::PortC(id - 32));
265 } else if (48..48 + NUM_PORT_DEFAULT as u8).contains(&id) {
266 return Ok(CascadeSource::PortD(id - 48));
267 } else if (64..64 + NUM_PORT_DEFAULT as u8).contains(&id) {
268 return Ok(CascadeSource::PortE(id - 64));
269 } else if (80..104).contains(&id) {
270 return Ok(CascadeSource::Tim(id - 80));
271 }
272 match id {
273 104 => Ok(CascadeSource::TxEv),
274 105 => Ok(CascadeSource::AdcIrq),
275 106 => Ok(CascadeSource::RomSbe),
276 107 => Ok(CascadeSource::RomMbe),
277 108 => Ok(CascadeSource::Ram0Sbe),
278 109 => Ok(CascadeSource::Ram0Mbe),
279 110 => Ok(CascadeSource::Ram1Sbe),
280 111 => Ok(CascadeSource::Ram1Mbe),
281 112 => Ok(CascadeSource::WdogIrq),
282 _ => Err(InvalidCascadeSourceId),
283 }
284 }
285}
286
287#[bitbybit::bitfield(u32)]
288pub struct CascadeSourceReg {
289 #[bits(0..=6, rw)]
290 raw: u7,
291}
292
293impl CascadeSourceReg {
294 pub fn new(source: CascadeSource) -> Result<Self, InvalidCascadeSourceId> {
295 let id = source.id()?;
296 Ok(Self::new_with_raw_value(id.as_u32()))
297 }
298
299 pub fn as_cascade_source(&self) -> Result<CascadeSource, InvalidCascadeSourceId> {
300 CascadeSource::from_raw(self.raw().as_u32())
301 }
302}
303
304#[derive(derive_mmio::Mmio)]
305#[mmio(no_ctors)]
306#[repr(C)]
307pub struct Timer {
308 control: Control,
309 reset_value: u32,
310 count_value: u32,
311 enable_control: EnableControl,
312 cascade_control: CascadeControl,
313 cascade: [CascadeSourceReg; 3],
316 pwma_value: u32,
318 pwmb_value: u32,
320 #[cfg(feature = "vor1x")]
321 _reserved: [u32; 0x3f5],
322 #[cfg(feature = "vor4x")]
323 _reserved: [u32; 0xf5],
324 perid: u32,
326}
327
328cfg_if::cfg_if! {
329 if #[cfg(feature = "vor1x")] {
330 static_assertions::const_assert_eq!(core::mem::size_of::<Timer>(), 0x1000);
331 } else if #[cfg(feature = "vor4x")] {
332 static_assertions::const_assert_eq!(core::mem::size_of::<Timer>(), 0x400);
333 }
334}
335
336#[derive(Debug, PartialEq, Eq)]
337#[cfg_attr(feature = "defmt", derive(defmt::Format))]
338pub struct InvalidTimerIndex(pub usize);
339
340#[derive(Debug, Copy, Clone, PartialEq, Eq)]
341#[cfg_attr(feature = "defmt", derive(defmt::Format))]
342pub struct TimId(u8);
343
344impl TimId {
345 pub const fn new(index: usize) -> Result<Self, InvalidTimerIndex> {
346 if index > 23 {
347 return Err(InvalidTimerIndex(index));
348 }
349 Ok(TimId(index as u8))
350 }
351
352 pub const fn new_unchecked(index: usize) -> Self {
353 if index > 23 {
354 panic!("invalid timer index");
355 }
356 TimId(index as u8)
357 }
358
359 pub const unsafe fn steal_regs(&self) -> MmioTimer<'static> {
365 Timer::new_mmio(*self)
366 }
367
368 pub const fn value(&self) -> u8 {
369 self.0
370 }
371
372 #[cfg(feature = "vor4x")]
373 pub const fn interrupt_id(&self) -> va416xx::Interrupt {
374 match self.value() {
375 0 => va416xx::Interrupt::TIM0,
376 1 => va416xx::Interrupt::TIM1,
377 2 => va416xx::Interrupt::TIM2,
378 3 => va416xx::Interrupt::TIM3,
379 4 => va416xx::Interrupt::TIM4,
380 5 => va416xx::Interrupt::TIM5,
381 6 => va416xx::Interrupt::TIM6,
382 7 => va416xx::Interrupt::TIM7,
383 8 => va416xx::Interrupt::TIM8,
384 9 => va416xx::Interrupt::TIM9,
385 10 => va416xx::Interrupt::TIM10,
386 11 => va416xx::Interrupt::TIM11,
387 12 => va416xx::Interrupt::TIM12,
388 13 => va416xx::Interrupt::TIM13,
389 14 => va416xx::Interrupt::TIM14,
390 15 => va416xx::Interrupt::TIM15,
391 16 => va416xx::Interrupt::TIM16,
392 17 => va416xx::Interrupt::TIM17,
393 18 => va416xx::Interrupt::TIM18,
394 19 => va416xx::Interrupt::TIM19,
395 20 => va416xx::Interrupt::TIM20,
396 21 => va416xx::Interrupt::TIM21,
397 22 => va416xx::Interrupt::TIM22,
398 23 => va416xx::Interrupt::TIM23,
399 _ => unreachable!(),
400 }
401 }
402}
403
404impl Timer {
405 const fn new_mmio_at(base: usize) -> MmioTimer<'static> {
406 MmioTimer {
407 ptr: base as *mut _,
408 phantom: PhantomData,
409 }
410 }
411
412 pub const fn new_mmio(id: TimId) -> MmioTimer<'static> {
413 if cfg!(feature = "vor1x") {
414 Timer::new_mmio_at(BASE_ADDR + 0x1000 * id.value() as usize)
415 } else {
416 Timer::new_mmio_at(BASE_ADDR + 0x400 * id.value() as usize)
417 }
418 }
419 pub fn new_mmio_with_raw_index(
420 timer_index: usize,
421 ) -> Result<MmioTimer<'static>, InvalidTimerIndex> {
422 if timer_index > 23 {
423 return Err(InvalidTimerIndex(timer_index));
424 }
425 if cfg!(feature = "vor1x") {
426 Ok(Timer::new_mmio_at(BASE_ADDR + 0x1000 * timer_index))
427 } else {
428 Ok(Timer::new_mmio_at(BASE_ADDR + 0x400 * timer_index))
429 }
430 }
431}