use std::{
borrow::Cow,
collections::VecDeque,
ops::{Deref, DerefMut},
};
use bitvec::{order::Lsb0, vec::BitVec};
use jtag_taps::{cable::Cable, statemachine::JtagSM};
use crate::{
Error,
jtag::{Backend, JtagInterface, JtagState, Register},
};
impl<T: jtag_taps::cable::Cable + 'static> Backend for T {
fn into_interface(self) -> Result<Box<dyn JtagInterface>, Error> {
let wrapper = CableWrapper(self);
let mut sm: Box<dyn JtagInterface> =
Box::new(jtag_taps::statemachine::JtagSM::new(wrapper));
sm.mode_reset()?;
Ok(sm)
}
}
struct CableWrapper<T: jtag_taps::cable::Cable>(T);
impl<T: jtag_taps::cable::Cable> Deref for CableWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: jtag_taps::cable::Cable> DerefMut for CableWrapper<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T, U> JtagInterface for JtagSM<T>
where
T: std::ops::DerefMut<Target = U>,
U: Cable + ?Sized,
{
fn switch_mode(&mut self, new_state: JtagState, flush: bool) -> Result<(), Error> {
self.change_mode(new_state);
if flush {
self.cable.flush();
}
Ok(())
}
fn write_bits(
&mut self,
reg: Register,
bits: &BitVec<u8, Lsb0>,
flush: bool,
) -> Result<(), Error> {
if bits.is_empty() {
return Ok(());
}
let bits = get_aligned(bits);
self.write_reg(reg, bits.as_raw_slice(), last_byte_bits(&bits), true);
if flush {
self.cable.flush();
}
Ok(())
}
fn read_bits(&mut self, reg: Register, bits: &mut BitVec<u8, Lsb0>) -> Result<(), Error> {
if bits.is_empty() {
return Ok(());
}
let bits_read = self.read_reg(reg, bits.len());
bits.force_align();
bits.as_raw_mut_slice().copy_from_slice(&bits_read);
Ok(())
}
fn read_write_bits(
&mut self,
reg: Register,
read_bits: &mut BitVec<u8, Lsb0>,
write_bits: &BitVec<u8, Lsb0>,
) -> Result<(), Error> {
if write_bits.is_empty() {
return Ok(());
}
let write_bits = get_aligned(write_bits);
let bits_read = self.read_write_reg(
reg,
write_bits.as_raw_slice(),
last_byte_bits(&write_bits),
true,
);
read_bits.resize(write_bits.len(), false);
read_bits.force_align();
read_bits.as_raw_mut_slice().copy_from_slice(&bits_read);
Ok(())
}
fn batch(
&mut self,
count: usize,
writer: &mut dyn FnMut(usize, &mut BitVec<u8, Lsb0>) -> Result<(), Error>,
reader: &mut dyn FnMut(usize, &BitVec<u8, Lsb0>) -> Result<(), Error>,
) -> Result<(), Error> {
self.cable.flush();
let drain = |sm: &mut Self, queue: &mut VecDeque<(usize, usize)>| {
while let Some((_, len)) = queue.pop_front() {
let _ = sm.cable.finish_read(len); }
};
let mut writer_buf = BitVec::new();
let mut reader_buf = BitVec::new();
let mut queue = VecDeque::new();
let mut i_write = 0; let mut pending = false; while i_write < count || !queue.is_empty() {
if i_write < count {
if !pending {
writer_buf.clear();
writer_buf.force_align();
if let Err(e) = writer(i_write, &mut writer_buf) {
drain(self, &mut queue);
return Err(e);
}
if writer_buf.is_empty() {
drain(self, &mut queue);
return Err("empty transfer".into());
}
writer_buf.force_align();
pending = true;
}
if self.queue_read_write(
Register::Data,
writer_buf.as_raw_slice(),
last_byte_bits(&writer_buf),
true,
) {
self.change_mode(JtagState::Idle); queue.push_back((i_write, writer_buf.len()));
i_write += 1;
pending = false;
continue;
} else if queue.is_empty() {
return Err("transfer does not fit into the cable's queue".into());
}
}
while let Some((i, len)) = queue.pop_front() {
let res = self.cable.finish_read(len);
reader_buf.resize(len, false);
reader_buf.force_align();
reader_buf.as_raw_mut_slice().copy_from_slice(&res);
if let Err(e) = reader(i, &reader_buf) {
drain(self, &mut queue);
return Err(e);
}
}
}
Ok(())
}
}
fn get_aligned<'a>(bv: &'a BitVec<u8, Lsb0>) -> Cow<'a, BitVec<u8, Lsb0>> {
use bitvec::domain::Domain::*;
if matches!(bv.domain(), Enclave(_) | Region { head: Some(_), .. }) {
let mut bv = bv.to_bitvec();
bv.force_align();
Cow::Owned(bv)
} else {
Cow::Borrowed(bv)
}
}
fn last_byte_bits(bv: &BitVec<u8, Lsb0>) -> u8 {
if bv.is_empty() {
0
} else if bv.len().is_multiple_of(8) {
8
} else {
(bv.len() % 8) as u8
}
}