mod protocol;
use std::{
convert::TryInto,
iter,
time::{Duration, Instant},
};
use crate::{
architecture::{
arm::{
communication_interface::{DapProbe, UninitializedArmProbe},
SwoAccess,
},
riscv::communication_interface::{RiscvCommunicationInterface, RiscvError},
},
probe::jlink::bits_to_byte,
DebugProbe, DebugProbeError, DebugProbeSelector, WireProtocol,
};
use self::protocol::ProtocolHandler;
use super::JTAGAccess;
pub use protocol::list_espjtag_devices;
#[derive(Debug)]
pub(crate) struct EspUsbJtag {
protocol: ProtocolHandler,
jtag_idle_cycles: u8,
current_ir_reg: u32,
speed_khz: u32,
}
impl EspUsbJtag {
fn idle_cycles(&self) -> u8 {
self.jtag_idle_cycles
}
fn read_dr(&mut self, register_bits: usize) -> Result<Vec<u8>, DebugProbeError> {
tracing::debug!("Read {} bits from DR", register_bits);
let tms_enter_shift = [true, false, false];
let tms_shift_out_value = iter::repeat(false).take(register_bits - 1);
let tms_enter_idle = [true, true, false];
let mut tms = Vec::with_capacity(register_bits + 7);
tms.extend_from_slice(&tms_enter_shift);
tms.extend(tms_shift_out_value);
tms.extend_from_slice(&tms_enter_idle);
let tdi = iter::repeat(false).take(tms.len() + self.idle_cycles() as usize);
tms.extend(iter::repeat(false).take(self.idle_cycles() as usize));
let mut response = self.protocol.jtag_io(tms, tdi, true)?;
tracing::trace!("Response: {:?}", response);
let _remainder = response.split_off(tms_enter_shift.len());
let mut remaining_bits = register_bits;
let mut result = Vec::new();
while remaining_bits >= 8 {
let byte = bits_to_byte(response.split_off(8)) as u8;
result.push(byte);
remaining_bits -= 8;
}
if remaining_bits > 0 {
result.push(bits_to_byte(response.split_off(remaining_bits)) as u8);
}
tracing::debug!("Read from DR: {:?}", result);
Ok(result)
}
fn write_ir(&mut self, data: &[u8], len: usize) -> Result<(), DebugProbeError> {
tracing::debug!("Write IR: {:?}, len={}", data, len);
if data.len() * 8 < len {
todo!("Proper error for incorrect length");
}
if len < 1 {
todo!("Proper error for incorrect length");
}
let tms_enter_ir_shift = [true, true, false, false];
let tms_data = iter::repeat(false).take(len - 1);
let tms_enter_idle = [true, true, false];
let mut tms = Vec::with_capacity(tms_enter_ir_shift.len() + len + tms_enter_idle.len());
tms.extend_from_slice(&tms_enter_ir_shift);
tms.extend(tms_data);
tms.extend_from_slice(&tms_enter_idle);
let tdi_enter_ir_shift = [false, false, false, false];
let tdi_enter_idle = [false, false];
let mut tdi = Vec::with_capacity(tdi_enter_ir_shift.len() + len + tdi_enter_idle.len());
tdi.extend_from_slice(&tdi_enter_ir_shift);
let num_bytes = len / 8;
let num_bits = len - (num_bytes * 8);
for bytes in &data[..num_bytes] {
let mut byte = *bytes;
for _ in 0..8 {
tdi.push(byte & 1 == 1);
byte >>= 1;
}
}
if num_bits > 0 {
let mut remaining_byte = data[num_bytes];
for _ in 0..num_bits {
tdi.push(remaining_byte & 1 == 1);
remaining_byte >>= 1;
}
}
tdi.extend_from_slice(&tdi_enter_idle);
tracing::trace!("tms: {:?}", tms);
tracing::trace!("tdi: {:?}", tdi);
let response = self.protocol.jtag_io(tms, tdi, true)?;
tracing::trace!("Response: {:?}", response);
if len >= 8 {
return Err(DebugProbeError::NotImplemented(
"Not yet implemented for IR registers larger than 8 bit",
));
}
self.current_ir_reg = data[0] as u32;
Ok(())
}
fn write_dr(&mut self, data: &[u8], register_bits: usize) -> Result<Vec<u8>, DebugProbeError> {
tracing::debug!("Write DR: {:?}, len={}", data, register_bits);
let tms_enter_shift = [true, false, false];
let tms_shift_out_value = iter::repeat(false).take(register_bits - 1);
let tms_enter_idle = [true, true, false];
let mut tms = Vec::with_capacity(register_bits + 7);
tms.extend_from_slice(&tms_enter_shift);
tms.extend(tms_shift_out_value);
tms.extend_from_slice(&tms_enter_idle);
let tdi_enter_shift = [false, false, false];
let tdi_enter_idle = [false, false];
let mut tdi =
Vec::with_capacity(tdi_enter_shift.len() + tdi_enter_idle.len() + register_bits);
tdi.extend_from_slice(&tdi_enter_shift);
let num_bytes = register_bits / 8;
let num_bits = register_bits - (num_bytes * 8);
for bytes in &data[..num_bytes] {
let mut byte = *bytes;
for _ in 0..8 {
tdi.push(byte & 1 == 1);
byte >>= 1;
}
}
if num_bits > 0 {
let mut remaining_byte = data[num_bytes];
for _ in 0..num_bits {
tdi.push(remaining_byte & 1 == 1);
remaining_byte >>= 1;
}
}
tdi.extend_from_slice(&tdi_enter_idle);
tms.extend(iter::repeat(false).take(self.idle_cycles() as usize));
tdi.extend(iter::repeat(false).take(self.idle_cycles() as usize));
let mut response = self.protocol.jtag_io(tms, tdi, true)?;
tracing::trace!("Response: {:?}", response);
let _remainder = response.split_off(tms_enter_shift.len());
let mut remaining_bits = register_bits;
let mut result = Vec::new();
while remaining_bits >= 8 {
let byte = bits_to_byte(response.split_off(8)) as u8;
result.push(byte);
remaining_bits -= 8;
}
if remaining_bits > 0 {
result.push(bits_to_byte(response.split_off(remaining_bits)) as u8);
}
tracing::trace!("result: {:?}", result);
Ok(result)
}
}
impl JTAGAccess for EspUsbJtag {
fn set_ir_len(&mut self, len: u32) {
if len != 5 {
panic!("Only IR Length of 5 is currently supported");
}
}
fn read_register(&mut self, address: u32, len: u32) -> Result<Vec<u8>, DebugProbeError> {
let address_bits = address.to_le_bytes();
if address > 0x1f {
return Err(DebugProbeError::NotImplemented(
"JTAG Register addresses are fixed to 5 bits",
));
}
if self.current_ir_reg != address {
self.write_ir(&address_bits[..1], 5)?;
}
self.read_dr(len as usize)
}
fn write_register(
&mut self,
address: u32,
data: &[u8],
len: u32,
) -> Result<Vec<u8>, DebugProbeError> {
let address_bits = address.to_le_bytes();
if address > 0x1f {
return Err(DebugProbeError::NotImplemented(
"JTAG Register addresses are fixed to 5 bits",
));
}
if self.current_ir_reg != address {
self.write_ir(&address_bits[..1], 5)?;
}
self.write_dr(data, len as usize)
}
fn set_idle_cycles(&mut self, idle_cycles: u8) {
self.jtag_idle_cycles = idle_cycles;
}
fn get_idle_cycles(&self) -> u8 {
self.jtag_idle_cycles
}
}
impl DebugProbe for EspUsbJtag {
fn new_from_selector(
selector: impl Into<DebugProbeSelector>,
) -> Result<Box<Self>, DebugProbeError> {
let protocol = ProtocolHandler::new_from_selector(selector)?;
Ok(Box::new(EspUsbJtag {
protocol,
jtag_idle_cycles: 0,
current_ir_reg: 1,
speed_khz: 0,
}))
}
fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
if matches!(protocol, WireProtocol::Jtag) {
Ok(())
} else {
Err(DebugProbeError::UnsupportedProtocol(protocol))
}
}
fn active_protocol(&self) -> Option<WireProtocol> {
Some(WireProtocol::Jtag)
}
fn get_name(&self) -> &'static str {
"Esp USB JTAG"
}
fn speed_khz(&self) -> u32 {
self.speed_khz
}
fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
Ok(speed_khz)
}
fn attach(&mut self) -> Result<(), super::DebugProbeError> {
tracing::debug!("Attaching to ESP USB JTAG");
tracing::debug!("Resetting JTAG chain using trst");
self.protocol.set_reset(true, true)?;
self.protocol.set_reset(false, false)?;
tracing::debug!("Resetting JTAG chain by setting tms high for 5 bits");
let tms = vec![true, true, true, true, true, false];
let tdi = iter::repeat(false).take(6);
let response: Vec<_> = self.protocol.jtag_io(tms, tdi, false)?.collect();
tracing::debug!("Response to reset: {:?}", response);
let start = Instant::now();
let idcode = loop {
let idcode_bytes = self.read_dr(32)?;
if idcode_bytes.iter().any(|&x| x != 0)
|| Instant::now().duration_since(start) > Duration::from_secs(1)
{
break u32::from_le_bytes((&idcode_bytes[..]).try_into().unwrap());
}
};
tracing::info!("JTAG IDCODE: {:#010x}", idcode);
Ok(())
}
fn detach(&mut self) -> Result<(), crate::Error> {
Ok(())
}
fn target_reset(&mut self) -> Result<(), super::DebugProbeError> {
Err(super::DebugProbeError::NotImplemented("target_reset"))
}
fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
tracing::info!("reset_assert!");
self.protocol.set_reset(false, false)?;
Ok(())
}
fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
tracing::info!("reset_deassert!");
self.protocol.set_reset(true, true)?;
Ok(())
}
fn try_get_riscv_interface(
self: Box<Self>,
) -> Result<RiscvCommunicationInterface, (Box<dyn DebugProbe>, RiscvError)> {
match RiscvCommunicationInterface::new(self) {
Ok(interface) => Ok(interface),
Err((probe, err)) => Err((probe.into_probe(), err)),
}
}
fn get_swo_interface(&self) -> Option<&dyn SwoAccess> {
None
}
fn get_swo_interface_mut(&mut self) -> Option<&mut dyn SwoAccess> {
None
}
fn has_arm_interface(&self) -> bool {
false
}
fn has_riscv_interface(&self) -> bool {
true
}
fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
self
}
fn try_as_dap_probe(&mut self) -> Option<&mut dyn DapProbe> {
None
}
fn try_get_arm_interface<'probe>(
self: Box<Self>,
) -> Result<Box<dyn UninitializedArmProbe + 'probe>, (Box<dyn DebugProbe>, DebugProbeError)>
{
Err((self, DebugProbeError::InterfaceNotAvailable("SWD/ARM")))
}
fn get_target_voltage(&mut self) -> Result<Option<f32>, DebugProbeError> {
Ok(None)
}
}