#![allow(non_snake_case, non_upper_case_globals)]
use crate::{ral, vcell::VCell};
#[repr(C)]
pub struct Td {
NEXT: VCell<u32>,
TOKEN: VCell<u32>,
BUFFER_POINTERS: [VCell<u32>; 5],
last_transfer_size: usize,
}
impl Td {
pub const fn new() -> Self {
Td {
NEXT: VCell::new(0),
TOKEN: VCell::new(0),
BUFFER_POINTERS: [
VCell::new(0),
VCell::new(0),
VCell::new(0),
VCell::new(0),
VCell::new(0),
],
last_transfer_size: 0,
}
}
pub fn set_buffer(&mut self, ptr: *mut u8, size: usize) {
ral::modify_reg!(crate::td, self, TOKEN, TOTAL_BYTES: size as u32);
self.last_transfer_size = size;
if size != 0 {
const PTR_ALIGNMENT: u32 = 4096;
const PTR_MASK: u32 = !(PTR_ALIGNMENT - 1);
self.BUFFER_POINTERS[0].write(ptr as u32);
for idx in 1..self.BUFFER_POINTERS.len() {
let mut ptr = self.BUFFER_POINTERS[idx - 1].read();
ptr &= PTR_MASK;
ptr += PTR_ALIGNMENT;
self.BUFFER_POINTERS[idx].write(ptr);
}
} else {
for buffer_pointer in self.BUFFER_POINTERS.iter_mut() {
buffer_pointer.write(0);
}
}
}
pub fn bytes_transferred(&self) -> usize {
let total_bytes = ral::read_reg!(crate::td, self, TOKEN, TOTAL_BYTES) as usize;
self.last_transfer_size - total_bytes
}
pub fn status(&self) -> Status {
let status = ral::read_reg!(crate::td, self, TOKEN, STATUS);
Status::from_bits_truncate(status)
}
pub fn clear_status(&mut self) {
ral::modify_reg!(crate::td, self, TOKEN, STATUS: 0);
}
pub fn set_terminate(&mut self) {
ral::write_reg!(crate::td, self, NEXT, 1);
}
pub fn set_next(&mut self, next: *const Td) {
ral::write_reg!(crate::td, self, NEXT, next as u32);
}
pub fn set_active(&mut self) {
ral::modify_reg!(crate::td, self, TOKEN, STATUS: ACTIVE);
}
pub fn set_interrupt_on_complete(&mut self, ioc: bool) {
ral::modify_reg!(crate::td, self, TOKEN, IOC: ioc as u32);
}
pub fn clean_invalidate_dcache(&self) {
crate::cache::clean_invalidate_dcache_by_address(
&self as *const _ as usize,
core::mem::size_of_val(self),
);
}
}
bitflags::bitflags! {
pub struct Status : u32 {
const ACTIVE = TOKEN::STATUS::RW::ACTIVE;
const HALTED = TOKEN::STATUS::RW::HALTED;
const DATA_BUFFER_ERROR = TOKEN::STATUS::RW::DATA_BUFFER_ERROR;
const TRANSACTION_ERROR = TOKEN::STATUS::RW::TRANSACTION_ERROR;
}
}
mod TOKEN {
pub mod STATUS {
pub const offset: u32 = 0;
pub const mask: u32 = 0xFF << offset;
pub mod RW {
pub const ACTIVE: u32 = 1 << 7;
pub const HALTED: u32 = 1 << 6;
pub const DATA_BUFFER_ERROR: u32 = 1 << 5;
pub const TRANSACTION_ERROR: u32 = 1 << 3;
}
pub mod R {}
pub mod W {}
}
pub mod IOC {
pub const offset: u32 = 15;
pub const mask: u32 = 1 << offset;
pub mod RW {}
pub mod R {}
pub mod W {}
}
pub mod TOTAL_BYTES {
pub const offset: u32 = 16;
pub const mask: u32 = 0x7FFF << offset;
pub mod RW {}
pub mod R {}
pub mod W {}
}
}
#[cfg(test)]
mod test {
use super::Td;
use crate::ral;
#[test]
fn terminate() {
let mut td = Td::new();
td.set_terminate();
assert_eq!(td.NEXT.read(), 1);
}
#[test]
fn next() {
let mut td = Td::new();
td.set_terminate();
let other = u32::max_value() & !(31);
td.set_next(other as *const _);
assert_eq!(td.NEXT.read(), other);
}
#[test]
fn status() {
let mut td = Td::new();
ral::write_reg!(super, &mut td, TOKEN, STATUS: u32::max_value());
assert_eq!(td.TOKEN.read(), 0b11111111);
}
#[test]
fn ioc() {
let mut td = Td::new();
ral::write_reg!(super, &mut td, TOKEN, IOC: u32::max_value());
assert_eq!(td.TOKEN.read(), 1 << 15);
}
#[test]
fn total_bytes() {
let mut td = Td::new();
ral::write_reg!(super, &mut td, TOKEN, TOTAL_BYTES: u32::max_value());
assert_eq!(td.TOKEN.read(), 0x7FFF << 16);
}
#[test]
fn set_buffer() {
let mut td = Td::new();
let mut buffer = [0; 32];
td.set_buffer(buffer.as_mut_ptr(), buffer.len());
assert_eq!(td.NEXT.read(), 0);
assert_eq!(td.TOKEN.read(), (32 << 16));
assert!(td.status().is_empty());
for buffer_pointer in td.BUFFER_POINTERS.iter() {
assert!(buffer_pointer.read() != 0);
}
}
}
#[cfg(target_arch = "arm")]
const _: [(); 1] = [(); (core::mem::size_of::<Td>() == 32) as usize];