use std::{borrow::Cow, collections::VecDeque};
use bitvec::{order::Lsb0, vec::BitVec};
use jtag_taps::{
cable::Cable,
statemachine::{
JtagSM,
Register::{Data, Instruction},
},
};
pub use jtag_taps::statemachine::{JtagState, Register};
pub trait JtagInterface {
fn switch_mode(&mut self, new_state: JtagState) -> Result<(), String>;
fn mode_reset(&mut self) -> Result<(), String> {
self.switch_mode(JtagState::Reset)
}
fn write_bits(&mut self, reg: Register, bits: &BitVec<u8, Lsb0>) -> Result<(), String>;
fn read_bits(&mut self, reg: Register, bits: &mut BitVec<u8, Lsb0>) -> Result<(), String>;
fn read_write_bits(
&mut self,
reg: Register,
read_bits: &mut BitVec<u8, Lsb0>,
write_bits: &BitVec<u8, Lsb0>,
) -> Result<(), String>;
fn batch<E: Into<String>>(
&mut self,
count: usize,
writer: impl FnMut(usize, &mut BitVec<u8, Lsb0>) -> Result<(), E>,
reader: impl FnMut(usize, &BitVec<u8, Lsb0>) -> Result<(), E>,
) -> Result<(), String>;
fn write_repeated(
&mut self,
reg: Register,
one_or_zero: u8,
bits: usize,
) -> Result<(), String> {
let (cnt_blocks, cnt_rem) = (bits / 512, bits % 512);
for _ in 0..cnt_blocks {
let data = BitVec::repeat(one_or_zero > 0, 512);
self.write_bits(reg, &data)?;
}
let data = BitVec::repeat(one_or_zero > 0, cnt_rem);
self.write_bits(reg, &data)
}
fn measure_ir_len(&mut self) -> Result<usize, String> {
self.write_repeated(Instruction, 0, 1024)?;
let buf_one = BitVec::repeat(true, 1); let mut buf_read = BitVec::repeat(false, 1);
let mut ir_len = 0;
loop {
self.read_write_bits(Instruction, &mut buf_read, &buf_one)?;
if buf_read[0] {
break;
}
ir_len += 1;
if ir_len > 1024 {
return Err("broken chain: TDO holds 0".into());
}
}
if ir_len < 2 {
return Err("broken chain: TDO holds 1".into());
}
Ok(ir_len)
}
fn measure_dr_len(&mut self) -> Result<usize, String> {
self.write_repeated(Data, 1, 65536)?;
let buf_zero = BitVec::repeat(false, 1); let mut buf_read = BitVec::repeat(true, 1);
let mut dr_len = 0;
loop {
self.read_write_bits(Data, &mut buf_read, &buf_zero)?;
if !buf_read[0] {
break;
}
dr_len += 1;
if dr_len > 1024 {
return Err("broken chain: TDO holds 1".into());
}
}
if dr_len < 1 {
return Err("broken chain: TDO holds 0".into());
}
Ok(dr_len)
}
}
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) -> Result<(), String> {
self.change_mode(new_state);
self.cable.flush();
Ok(())
}
fn write_bits(&mut self, reg: Register, bits: &BitVec<u8, Lsb0>) -> Result<(), String> {
if bits.is_empty() {
return Ok(());
}
let bits = get_aligned(bits);
self.write_reg(reg, bits.as_raw_slice(), last_byte_bits(&bits), true);
self.cable.flush();
Ok(())
}
fn read_bits(&mut self, reg: Register, bits: &mut BitVec<u8, Lsb0>) -> Result<(), String> {
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<(), String> {
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<E: Into<String>>(
&mut self,
count: usize,
mut writer: impl FnMut(usize, &mut BitVec<u8, Lsb0>) -> Result<(), E>,
mut reader: impl FnMut(usize, &BitVec<u8, Lsb0>) -> Result<(), E>,
) -> Result<(), String>
where
Self: Sized,
{
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.into());
}
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(
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.into());
}
}
}
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
}
}