1use core::num::NonZeroU32;
15
16use bitbybit::bitfield;
17use num_traits::ToPrimitive;
18use xous::MemoryRange;
19
20use crate::IoxPort;
21
22pub const BIO_SERVER_NAME: &'static str = "_BIO server_";
23
24pub trait BioApi<'a> {
26 fn init_core(
33 &mut self,
34 core: BioCore,
35 code: &[u8],
36 offset: usize,
37 config: CoreConfig,
38 ) -> Result<Option<u32>, BioError>;
39
40 fn de_init_core(&mut self, core: BioCore) -> Result<(), BioError>;
42
43 fn update_bio_freq(&mut self, freq: u32) -> u32;
52
53 fn get_bio_freq(&self) -> u32;
55
56 fn get_core_freq(&self, core: BioCore) -> Option<u32>;
62
63 fn set_core_state(&mut self, which: [CoreRunSetting; 4]) -> Result<(), BioError>;
65
66 unsafe fn get_core_handle(&self, fifo: Fifo) -> Result<Option<CoreHandle>, BioError>;
86
87 fn setup_irq_config(&mut self, config: IrqConfig) -> Result<(), BioError>;
90
91 fn setup_dma_windows(&mut self, windows: DmaFilterWindows) -> Result<(), BioError>;
94
95 fn setup_io_config(&mut self, config: IoConfig) -> Result<(), BioError>;
97
98 fn setup_fifo_event_triggers(&mut self, config: FifoEventConfig) -> Result<(), BioError>;
100
101 fn get_version(&self) -> u32;
103}
104
105#[macro_export]
106macro_rules! bio_code {
118 ($fn_name:ident, $name_start:ident, $name_end:ident, $($item:expr),*) => {
119 pub fn $fn_name() -> &'static [u8] {
120 extern "C" {
121 static $name_start: *const u8;
122 static $name_end: *const u8;
123 }
124 unsafe { core::slice::from_raw_parts($name_start.add(4), ($name_end as usize) - ($name_start as usize) - 4)}
126 }
127
128 core::arch::global_asm!(
129 ".align 4",
130 concat!(".globl ", stringify!($name_start)),
131 concat!(stringify!($name_start), ":"),
132 ".word .",
133 $($item),*
134 , ".align 4",
135 concat!(".globl ", stringify!($name_end)),
136 concat!(stringify!($name_end), ":"),
137 ".word .",
138 );
139 };
140}
141
142#[derive(Debug, Copy, Clone, num_derive::FromPrimitive, num_derive::ToPrimitive)]
143pub enum BioOp {
144 InitCore,
145 DeInitCore,
146 UpdateBioFreq,
147 GetCoreFreq,
148 GetBioFreq,
149 CoreState,
150 GetCoreHandle,
151 ReleaseCoreHandle,
152 IrqConfig,
153 DmaWindows,
154 IoConfig,
155 FifoEventTriggers,
156 GetVersion,
157
158 ClaimResources,
160 ReleaseResources,
161 ResourceAvailability,
162 CheckResources,
163 CheckResourcesBatch,
164 ClaimDynamicPin,
165 ReleaseDynamicPin,
166
167 InvalidCall,
168}
169
170#[derive(Debug, Copy, Clone)]
171#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
172#[repr(align(4096))]
174pub struct CoreInitRkyv {
175 pub core: BioCore,
176 pub offset: usize,
177 pub actual_freq: Option<u32>,
178 pub config: CoreConfig,
179 pub code: [u8; 4096],
180 pub result: BioError,
181}
182
183#[repr(usize)]
184#[derive(Copy, Clone, Debug, PartialEq, Eq)]
185#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
186pub enum BioCore {
187 Core0 = 0,
188 Core1 = 1,
189 Core2 = 2,
190 Core3 = 3,
191}
192
193impl From<usize> for BioCore {
194 fn from(value: usize) -> Self {
195 match value {
196 0 => BioCore::Core0,
197 1 => BioCore::Core1,
198 2 => BioCore::Core2,
199 3 => BioCore::Core3,
200 _ => panic!("Invalid BioCore value: {}", value),
201 }
202 }
203}
204
205#[repr(usize)]
206#[derive(Copy, Clone, Debug, PartialEq, Eq)]
207#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
208pub enum CoreRunSetting {
209 Unchanged = 0,
210 Start = 1,
211 Stop = 2,
212}
213
214impl From<usize> for CoreRunSetting {
215 fn from(value: usize) -> Self {
216 match value {
217 0 => CoreRunSetting::Unchanged,
218 1 => CoreRunSetting::Start,
219 2 => CoreRunSetting::Stop,
220 _ => panic!("Invalid CoreRunSetting: {}", value),
221 }
222 }
223}
224
225#[derive(Debug, Copy, Clone)]
226#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
227pub enum BioError {
228 Uninit,
230 None,
232 InvalidCore,
234 Oom,
236 NoFreeMachines,
238 ResourceInUse,
240 CodeCheck(usize),
242 InternalError,
244}
245
246impl From<xous::Error> for BioError {
247 fn from(error: xous::Error) -> Self {
248 match error {
249 xous::Error::OutOfMemory => BioError::Oom,
250 xous::Error::ServerNotFound => BioError::InvalidCore,
251 xous::Error::ServerExists => BioError::NoFreeMachines,
252 _ => panic!("Cannot convert Error::{:?} to BioError", error),
254 }
255 }
256}
257
258#[derive(Debug, Clone, Copy)]
259#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
260pub struct BioPin {
261 pin_number: u8,
262}
263impl BioPin {
264 pub fn pin_number(&self) -> u8 { self.pin_number }
265
266 pub fn new(pin: u8) -> Self {
267 if pin < 32 { Self { pin_number: pin } } else { panic!("Pin value out of range") }
268 }
269}
270
271#[derive(Debug, Copy, Clone)]
272#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
273pub enum ClockMode {
274 FixedDivider(u16, u8),
276 TargetFreqFrac(u32),
280 TargetFreqInt(u32),
284 ExternalPin(BioPin),
286}
287
288#[derive(Debug, Copy, Clone)]
289#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
290pub struct CoreConfig {
291 pub clock_mode: ClockMode,
292}
293
294#[derive(Debug, Copy, Clone, Eq, PartialEq)]
295#[repr(usize)]
296#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
297pub enum IoConfigMode {
298 Overwrite = 0,
300 SetOnly = 1,
302 ClearOnly = 2,
304}
305
306impl From<usize> for IoConfigMode {
307 fn from(value: usize) -> Self {
308 match value {
309 0 => IoConfigMode::Overwrite,
310 1 => IoConfigMode::SetOnly,
311 2 => IoConfigMode::ClearOnly,
312 _ => unimplemented!(),
313 }
314 }
315}
316
317#[derive(Debug, Copy, Clone)]
318#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
319pub struct IoConfig {
320 pub mode: IoConfigMode,
322 pub mapped: u32,
324 pub sync_bypass: u32,
327 pub oe_inv: u32,
329 pub o_inv: u32,
332 pub i_inv: u32,
335 pub snap_inputs: Option<BioCore>,
337 pub snap_outputs: Option<BioCore>,
339}
340impl Default for IoConfig {
341 fn default() -> Self {
342 Self {
343 mode: IoConfigMode::Overwrite,
344 mapped: 0,
345 sync_bypass: 0,
346 oe_inv: 0,
347 o_inv: 0,
348 i_inv: 0,
349 snap_inputs: None,
350 snap_outputs: None,
351 }
352 }
353}
354
355#[bitfield(u8)]
356#[derive(Debug)]
357#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
358pub struct TriggerSlot {
359 #[bits(1..=7)]
360 _reserved: arbitrary_int::u7,
361 #[bit(0, rw)]
362 trigger_slot: arbitrary_int::u1,
363}
364
365#[bitfield(u8)]
366#[derive(Debug)]
367#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
368pub struct FifoLevel {
369 #[bits(3..=7)]
370 _reserved: arbitrary_int::u5,
371 #[bits(0..=2, rw)]
372 level: arbitrary_int::u3,
373}
374
375#[derive(Debug)]
377#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
378pub struct FifoEventConfig {
379 pub which: Fifo,
381 pub trigger_slot: TriggerSlot,
383 pub level: FifoLevel,
385 pub trigger_less_than: bool,
387 pub trigger_greater_than: bool,
388 pub trigger_equal_to: bool,
389}
390
391#[derive(Debug, Copy, Clone, Eq, PartialEq)]
392#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
393#[repr(usize)]
394pub enum Fifo {
395 Fifo0 = 0,
396 Fifo1 = 1,
397 Fifo2 = 2,
398 Fifo3 = 3,
399}
400
401impl Fifo {
402 pub fn to_usize_checked(self) -> usize {
403 let discriminant = self as usize;
404 assert!(discriminant <= 3, "Invalid discriminant");
405 discriminant
406 }
407}
408
409#[derive(Debug, Copy, Clone)]
410#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
411#[repr(usize)]
412pub enum Irq {
413 Irq0 = 0,
414 Irq1 = 1,
415 Irq2 = 2,
416 Irq3 = 3,
417}
418
419impl Irq {
420 pub fn to_usize_checked(self) -> usize {
421 let discriminant = self as usize;
422 assert!(discriminant <= 3, "Invalid discriminant");
423 discriminant
424 }
425}
426
427#[bitfield(u32)]
428#[derive(Debug)]
429#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
430pub struct IrqMask {
431 #[bit(31, rw)]
432 fifo3_trigger1: bool,
433 #[bit(30, rw)]
434 fifo3_trigger0: bool,
435 #[bit(29, rw)]
436 fifo2_trigger1: bool,
437 #[bit(28, rw)]
438 fifo2_trigger0: bool,
439 #[bit(27, rw)]
440 fifo1_trigger1: bool,
441 #[bit(26, rw)]
442 fifo1_trigger0: bool,
443 #[bit(25, rw)]
444 fifo0_trigger1: bool,
445 #[bit(24, rw)]
446 fifo0_trigger0: bool,
447 #[bits(0..=23, rw)]
448 software: arbitrary_int::u24,
449}
450
451#[derive(Debug, Copy, Clone)]
452#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
453pub struct IrqConfig {
454 pub which: Irq,
456 pub edge_triggered: bool,
457 pub mask: IrqMask,
460}
461
462#[derive(Debug, Copy, Clone)]
465#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
466pub struct DmaWindow {
467 pub base: u32,
468 pub bounds: NonZeroU32,
469}
470
471#[derive(Debug, Copy, Clone)]
473#[cfg_attr(feature = "std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
474pub struct DmaFilterWindows {
475 pub windows: [Option<DmaWindow>; 4],
476}
477
478pub struct CoreHandle {
479 conn: xous::CID,
480 handle: usize,
481 fifo: arbitrary_int::u2,
482}
483
484impl CoreHandle {
485 pub fn new(conn: xous::CID, handle: usize, fifo: arbitrary_int::u2) -> Self {
486 Self { conn, handle, fifo }
487 }
488
489 pub unsafe fn handle(&self) -> usize { self.handle }
492}
493
494impl Drop for CoreHandle {
495 fn drop(&mut self) {
496 xous::unmap_memory(unsafe { MemoryRange::new(self.handle, 4096).unwrap() }).unwrap();
499 xous::send_message(
500 self.conn,
501 xous::Message::new_blocking_scalar(
502 BioOp::ReleaseCoreHandle.to_usize().unwrap(),
503 self.fifo.value() as usize,
504 0,
505 0,
506 0,
507 ),
508 )
509 .unwrap();
510 }
511}
512
513pub fn bio_bit_to_port_and_pin(bit: arbitrary_int::u5) -> (IoxPort, u8) {
514 match bit.value() {
515 0 => (IoxPort::PB, 0),
517 1 => (IoxPort::PB, 1),
518 2 => (IoxPort::PB, 2),
519 3 => (IoxPort::PB, 3),
520 4 => (IoxPort::PB, 4),
521 5 => (IoxPort::PB, 5),
522 6 => (IoxPort::PB, 6),
523 7 => (IoxPort::PB, 7),
524 8 => (IoxPort::PB, 8),
525 9 => (IoxPort::PB, 9),
526 10 => (IoxPort::PB, 10),
527 11 => (IoxPort::PB, 11),
528 12 => (IoxPort::PB, 12),
529 13 => (IoxPort::PB, 13),
530 14 => (IoxPort::PB, 14),
531 15 => (IoxPort::PB, 15),
532 16 => (IoxPort::PC, 0),
534 17 => (IoxPort::PC, 1),
535 18 => (IoxPort::PC, 2),
536 19 => (IoxPort::PC, 3),
537 20 => (IoxPort::PC, 4),
538 21 => (IoxPort::PC, 5),
539 22 => (IoxPort::PC, 6),
540 23 => (IoxPort::PC, 7),
541 24 => (IoxPort::PC, 8),
542 25 => (IoxPort::PC, 9),
543 26 => (IoxPort::PC, 10),
544 27 => (IoxPort::PC, 11),
545 28 => (IoxPort::PC, 12),
546 29 => (IoxPort::PC, 13),
547 30 => (IoxPort::PC, 14),
548 31 => (IoxPort::PC, 15),
549 _ => unreachable!(),
550 }
551}
552
553pub fn port_and_pin_to_bio_bit(port: IoxPort, pin: u8) -> Option<arbitrary_int::u5> {
554 match port {
555 IoxPort::PA => None,
556 IoxPort::PB => {
557 if pin >= 16 {
558 None
559 } else {
560 let bio_bit = 15 - pin;
561 Some(arbitrary_int::u5::new(bio_bit))
562 }
563 }
564 IoxPort::PC => {
565 if pin < 16 {
566 let bio_bit = pin + 16;
567 Some(arbitrary_int::u5::new(bio_bit))
568 } else {
569 None
570 }
571 }
572 _ => None,
573 }
574}