1use bitvec::{order::Lsb0, vec::BitVec};
2
3use crate::{
4 AccessMask, Error,
5 ErrorKind::{BrokenChain, WrongPinType},
6 PinIdIter,
7 jtag::{
8 JtagInterface, JtagState,
9 Register::{Data, Instruction},
10 },
11 types::{PinId, PinState, TapCmd, TapInfo, TapState},
12};
13
14pub struct PinScanner {
16 sm: Box<dyn JtagInterface>,
17 tap_infos: Vec<TapInfo>,
18 tap_cmds: Vec<TapCmd>,
19 dr_in: BitVec<u8, Lsb0>,
20 dr_out: BitVec<u8, Lsb0>,
21 extest_keep_present: bool,
22}
23
24impl PinScanner {
25 pub(crate) fn build(
26 mut sm: Box<dyn JtagInterface>,
27 tap_infos: Vec<TapInfo>,
28 ir_len: usize,
29 extest_keep_present: bool,
30 ) -> Result<Self, Error> {
31 sm.write_repeated(Instruction, 1, ir_len + 1)?;
33 sm.switch_mode(JtagState::Idle, true)?;
34 let cnt_taps = tap_infos.len();
35 Ok(Self {
36 sm,
37 tap_infos,
38 tap_cmds: vec![TapCmd::Bypass; cnt_taps],
39 dr_in: BitVec::repeat(false, cnt_taps),
40 dr_out: BitVec::repeat(false, cnt_taps),
41 extest_keep_present,
42 })
43 }
44
45 pub fn tap_count(&self) -> usize {
47 self.tap_infos.len()
48 }
49
50 pub fn tap_infos(&self) -> &[TapInfo] {
52 &self.tap_infos
53 }
54
55 pub fn get_tap_info(&self, i: usize) -> Result<TapInfo, Error> {
57 ChainView::get_tap_info(self, i)
58 }
59
60 pub fn get_tap_state(&self, i: usize) -> Result<TapState, Error> {
62 ChainView::get_tap_state(self, i)
63 }
64
65 pub fn set_tap_state(&mut self, i: usize, new_state: TapState) -> Result<(), Error> {
68 let state = self.get_tap_state(i)?;
72 if state == new_state {
73 return Ok(());
74 }
75 if state == TapState::Bypass && new_state == TapState::Extest {
76 self.set_tap_state(i, TapState::Sample)?;
78 }
79
80 match (self.get_tap_state(i)?, new_state) {
81 (TapState::Bypass, TapState::Sample) => {
82 self.command(i, TapCmd::Idcode)?;
84 let raw_idcodes = self.split_dr_data(&self.dr_in);
85 let raw_idcode = raw_idcodes[i].as_raw_slice();
86 let idcode = (raw_idcode[0] as u32)
87 | ((raw_idcode[1] as u32) << 8)
88 | ((raw_idcode[2] as u32) << 16)
89 | ((raw_idcode[3] as u32) << 24);
90 if !self.tap_infos[i].matches_idcode(idcode) {
91 self.command(i, TapCmd::Bypass)?;
92 return Err("IDCODE check failed".into());
93 }
94 if !self.tap_cmds.contains(&TapCmd::Extest) {
95 self.command(i, TapCmd::Sample)?;
97 if self.sm.measure_dr_len()? != self.dr_in.len() {
98 self.command(i, TapCmd::Bypass)?;
99 return Err("IDCODE check failed".into());
100 }
101 }
102 }
103 (TapState::Sample, TapState::Extest) => {
104 self.command(i, TapCmd::Preload)?;
106 let mut splited_dr_out = self.split_dr_data(&self.dr_out);
107 let preload_values = if self.extest_keep_present {
108 &self.split_dr_data(&self.dr_in)[i]
110 } else {
111 &self.tap_infos[i].safe_bsr_value()
112 };
113 splited_dr_out[i].copy_from_bitslice(preload_values);
114 self.dr_out = self.merge_dr_data(&mut splited_dr_out);
115 self.update()?;
116 }
117 _ => (),
118 }
119 self.command(i, new_state.into())?;
120 Ok(())
121 }
122
123 pub(crate) fn is_extesting(&self) -> bool {
124 self.tap_cmds.contains(&TapCmd::Extest)
125 }
126
127 pub fn pin_ids_for_tap(&self, i_tap: usize) -> Result<PinIdIter, Error> {
130 let TapInfo::WithBsdl(bsdl) = self.get_tap_info(i_tap)? else {
131 return Err("not loaded BSDL of this TAP".into());
132 };
133 Ok(PinIdIter::new(i_tap, bsdl))
134 }
135
136 pub fn get_pin_id(&self, i_tap: usize, pin_name: &str) -> Result<PinId, Error> {
141 let TapInfo::WithBsdl(bsdl) = self.get_tap_info(i_tap)? else {
142 return Err("not loaded BSDL of this TAP".into());
143 };
144 PinId::from_name(i_tap, bsdl, pin_name)
145 }
146
147 pub fn get_pin_state(&self, pin_id: &PinId) -> Result<PinState, Error> {
150 BsrView::new(self, None).get(pin_id)
151 }
152
153 pub fn set_pin_state(&mut self, pin_id: &PinId, new_state: Option<bool>) -> Result<(), Error> {
162 BsrEdit::new(self, None).set(pin_id, new_state)
163 }
164
165 pub fn update(&mut self) -> Result<(), Error> {
169 self.sm.switch_mode(JtagState::CaptureDR, false)?;
170 self.sm
171 .read_write_bits(Data, &mut self.dr_in, &self.dr_out)?;
172 self.check_dr_in()?;
173 if self.is_extesting() {
174 self.sm.switch_mode(JtagState::Idle, true)?;
177 }
178 Ok(())
179 }
180
181 pub fn write_update(&mut self) -> Result<(), Error> {
185 if !self.is_extesting() {
186 return self.update();
187 }
188
189 self.sm.write_bits(Data, &self.dr_out, false)?;
195 self.sm.switch_mode(JtagState::Idle, false)?;
196
197 self.sm
199 .read_write_bits(Data, &mut self.dr_in, &self.dr_out)?;
200 self.check_dr_in()?;
201 Ok(())
202 }
203
204 pub fn release(&mut self) -> Result<(), Error> {
206 self.sm.mode_reset()?;
207 let ir_len: usize = self.tap_infos().iter().map(|t| t.ir_len()).sum();
208 self.sm.write_repeated(Instruction, 1, ir_len + 1)?;
209 self.sm.switch_mode(JtagState::UpdateIR, true)?;
210 self.sm.switch_mode(JtagState::Idle, true)?;
211 self.tap_cmds = vec![TapCmd::Bypass; self.tap_count()];
212 self.dr_in.truncate(self.tap_count());
213 self.dr_out.truncate(self.tap_count());
214 Ok(())
215 }
216
217 fn command(&mut self, i: usize, tap_cmd: TapCmd) -> Result<(), Error> {
222 let old_dr_len = self.tap_infos[i].dr_len(self.tap_cmds[i]);
223 let new_dr_len = self.tap_infos[i].dr_len(tap_cmd);
224 if old_dr_len != new_dr_len {
225 let mut splited_dr_in = self.split_dr_data(&self.dr_in);
226 splited_dr_in[i].resize(new_dr_len, false);
227 self.dr_in = self.merge_dr_data(&mut splited_dr_in);
228 let mut splited_dr_out = self.split_dr_data(&self.dr_out);
229 splited_dr_out[i].resize(new_dr_len, false);
230 self.dr_out = self.merge_dr_data(&mut splited_dr_out);
231 }
232 self.tap_cmds[i] = tap_cmd;
233 let ir_data = {
234 let mut ir_data = BitVec::new();
235 for (i, &cmd) in self.tap_cmds.iter().enumerate().rev() {
238 self.tap_infos[i].push_opcode(cmd, &mut ir_data);
239 }
240 ir_data
241 };
242 let mut ir_readback = BitVec::new();
243 self.sm
244 .read_write_bits(Instruction, &mut ir_readback, &ir_data)?;
245 self.sm.switch_mode(JtagState::Idle, true)?;
246 if ir_readback.all() {
247 return Error::result(BrokenChain, "TDO holds 1");
248 } else if ir_readback.not_any() {
249 return Error::result(BrokenChain, "TDO holds 0");
250 }
251 self.update()?;
252 Ok(())
253 }
254
255 fn check_dr_in(&mut self) -> Result<(), Error> {
257 if self.dr_in.all() || self.dr_in.not_any() {
258 let test_pattern = {
259 let mut pattern = BitVec::with_capacity(self.dr_in.len());
260 for _ in 0..self.dr_in.len() / 2 {
261 pattern.push(true);
262 pattern.push(false);
263 }
264 if pattern.len() < self.dr_in.len() {
265 pattern.push(false);
266 }
267 pattern
268 };
269 self.sm.write_bits(Data, &test_pattern, false)?;
270 let mut readback = BitVec::new();
272 self.sm.read_write_bits(Data, &mut readback, &self.dr_out)?;
273 if readback == test_pattern {
274 return Ok(());
275 } else {
276 let msg = if readback.all() {
277 "TDO holds 1"
278 } else if readback.not_any() {
279 "TDO holds 0"
280 } else {
281 &format!("disturbing, {readback}, expected: {test_pattern}")
282 };
283 return Error::result(BrokenChain, msg);
284 }
285 }
286 Ok(())
287 }
288
289 fn split_dr_data(&self, dr: &BitVec<u8, Lsb0>) -> Vec<BitVec<u8, Lsb0>> {
290 let mut result = Vec::new();
291 let mut slice_rem = &dr[..];
292 for (i, &cmd) in self.tap_cmds.iter().enumerate().rev() {
294 let dr_len = self.tap_infos()[i].dr_len(cmd);
295 let splited = &slice_rem[..dr_len];
296 slice_rem = &slice_rem[dr_len..];
297 let mut splited = BitVec::from_bitslice(splited);
298 splited.force_align();
299 result.push(splited);
300 }
301 result.reverse();
303 result
304 }
305
306 fn merge_dr_data(&self, splited_dr: &mut [BitVec<u8, Lsb0>]) -> BitVec<u8, Lsb0> {
307 let mut result = BitVec::new();
308 for dr in splited_dr.iter_mut().rev() {
310 dr.force_align();
311 result.extend_from_bitslice(dr);
312 }
313 result
314 }
315}
316
317impl PinScanner {
318 pub fn batch(
380 &mut self,
381 count: usize,
382 writer: impl FnMut(usize, &mut BsrEdit) -> Result<(), Error>,
383 reader: impl FnMut(usize, &BsrView) -> Result<(), Error>,
384 ) -> Result<(), Error> {
385 self.batch_with_mask(count, writer, reader, None)
386 }
387
388 pub(crate) fn batch_with_mask(
389 &mut self,
390 count: usize,
391 mut writer: impl FnMut(usize, &mut BsrEdit) -> Result<(), Error>,
392 mut reader: impl FnMut(usize, &BsrView) -> Result<(), Error>,
393 access_mask: Option<&AccessMask>,
394 ) -> Result<(), Error> {
395 self.write_update()?;
396 let mut dr_out = self.dr_out.clone();
397 let mut bsr_edit = BsrEdit {
398 tap_infos: &self.tap_infos,
399 tap_cmds: &self.tap_cmds,
400 dr_out: &mut dr_out,
401 access_mask,
402 };
403 let res = self.sm.batch(
404 count,
405 &mut |i, write_buf| {
406 writer(i, &mut bsr_edit)?;
407 write_buf.resize(bsr_edit.dr_out.len(), false);
408 write_buf.copy_from_bitslice(bsr_edit.dr_out);
409 Ok(())
410 },
411 &mut |i, read_buf| {
412 let bsr_view = BsrView {
413 tap_infos: &self.tap_infos,
414 tap_cmds: &self.tap_cmds,
415 dr_in: read_buf,
416 access_mask,
417 };
418 reader(i, &bsr_view)
419 },
420 );
421 self.dr_out.copy_from_bitslice(&dr_out);
422 self.update()?;
423 res
424 }
425}
426
427impl Drop for PinScanner {
428 fn drop(&mut self) {
429 let _ = self
430 .release()
431 .inspect_err(|e| eprintln!("failed to set taps to bypass mode: {e}"));
432 }
433}
434
435pub struct BsrView<'a, 'm> {
437 tap_infos: &'a [TapInfo],
438 tap_cmds: &'a [TapCmd],
439 dr_in: &'a BitVec<u8, Lsb0>,
440 access_mask: Option<&'m AccessMask>,
441}
442
443pub struct BsrEdit<'a, 'm> {
445 tap_infos: &'a [TapInfo],
446 tap_cmds: &'a [TapCmd],
447 dr_out: &'a mut BitVec<u8, Lsb0>,
448 access_mask: Option<&'m AccessMask>,
449}
450
451impl<'a, 'm> BsrView<'a, 'm> {
452 pub(crate) fn new(scanner: &'a PinScanner, access_mask: Option<&'m AccessMask>) -> Self {
453 Self {
454 tap_infos: scanner.tap_infos(),
455 tap_cmds: scanner.tap_cmds(),
456 dr_in: &scanner.dr_in,
457 access_mask,
458 }
459 }
460
461 pub fn get(&self, pin_id: &PinId) -> Result<PinState, Error> {
463 self.verify_pin_id(pin_id, false)?;
464 let tap_state = self.get_tap_state(pin_id.tap_index())?;
465 if tap_state == TapState::Bypass {
466 return Err("the chip that owns the pin is bypassed".into());
467 }
468 let get_val = |cell: Option<usize>| {
469 cell.map(|i| self.index_in_dr(pin_id.tap_index(), i))
470 .map(|i| self.dr_in[i])
471 };
472 Ok(PinState {
473 input: get_val(pin_id.cell_i()),
474 output: get_val(pin_id.cell_o()),
475 output_enable: get_val(pin_id.cell_oe()).map(|v| v != pin_id.cell_oe_disabler()),
476 })
477 }
478}
479
480impl<'a, 'm> BsrEdit<'a, 'm> {
481 pub(crate) fn new(scanner: &'a mut PinScanner, access_mask: Option<&'m AccessMask>) -> Self {
482 Self {
483 tap_infos: &scanner.tap_infos,
484 tap_cmds: &scanner.tap_cmds,
485 dr_out: &mut scanner.dr_out,
486 access_mask,
487 }
488 }
489
490 pub fn set(&mut self, pin_id: &PinId, new_state: Option<bool>) -> Result<(), Error> {
499 self.verify_pin_id(pin_id, true)?;
500 if self.get_tap_state(pin_id.tap_index())? != TapState::Extest {
501 return Err("the chip that owns the pin is not in EXTEST mode".into());
502 }
503 if let Some(new_state) = new_state {
504 let Some(i) = pin_id
505 .cell_o()
506 .map(|i| self.index_in_dr(pin_id.tap_index(), i))
507 else {
508 return Error::result(WrongPinType, "not output pin");
509 };
510 *self.dr_out.get_mut(i).unwrap() = new_state;
512 }
513 if let Some(i) = pin_id
514 .cell_oe()
515 .map(|i| self.index_in_dr(pin_id.tap_index(), i))
516 {
517 let new_state_oe = if pin_id.cell_oe_disabler() {
519 new_state.is_none()
520 } else {
521 new_state.is_some()
522 };
523 *self.dr_out.get_mut(i).unwrap() = new_state_oe
525 } else if new_state.is_none() {
526 return Error::result(WrongPinType, "not tristated pin");
527 }
528 Ok(())
529 }
530}
531
532pub(crate) trait ChainView {
533 fn tap_infos(&self) -> &[TapInfo];
535
536 fn tap_cmds(&self) -> &[TapCmd];
538
539 fn access_mask(&self) -> Option<&AccessMask>;
541
542 fn tap_count(&self) -> usize {
544 self.tap_infos().len()
545 }
546
547 fn get_tap_info(&self, i: usize) -> Result<TapInfo, Error> {
549 if i >= self.tap_count() {
550 return Err("given TAP index exceeds TAP count".into());
551 }
552 Ok(self.tap_infos()[i].clone())
553 }
554
555 fn get_tap_state(&self, i: usize) -> Result<TapState, Error> {
557 if i >= self.tap_count() {
558 return Err("given TAP index exceeds TAP count".into());
559 }
560 Ok(match self.tap_cmds()[i] {
561 TapCmd::Bypass => TapState::Bypass,
562 TapCmd::Sample => TapState::Sample,
563 TapCmd::Extest => TapState::Extest,
564 _ => unreachable!(),
565 })
566 }
567
568 fn verify_pin_id(&self, pin_id: &PinId, for_write: bool) -> Result<(), Error> {
571 if for_write && !pin_id.is_output() {
572 return Error::result(WrongPinType, "not output pin");
573 }
574 let tap_info = self.get_tap_info(pin_id.tap_index())?;
575 if tap_info.sessioned_tap_id() != pin_id.sessioned_tap_id() {
576 return Err("bad pin ID".into());
577 }
578 if let Some(mask) = self.access_mask() {
579 mask.check_access(pin_id, for_write)?;
580 }
581 Ok(())
582 }
583
584 fn index_in_dr(&self, i_tap: usize, i_cell: usize) -> usize {
587 self.tap_infos()
589 .iter()
590 .enumerate()
591 .rev()
592 .take(self.tap_count() - i_tap - 1)
593 .map(|(i, tap)| tap.dr_len(self.tap_cmds()[i]))
594 .sum::<usize>()
595 + i_cell
596 }
597}
598
599impl<'a, 'm> ChainView for BsrView<'a, 'm> {
600 fn tap_infos(&self) -> &[TapInfo] {
601 self.tap_infos
602 }
603 fn tap_cmds(&self) -> &[TapCmd] {
604 self.tap_cmds
605 }
606 fn access_mask(&self) -> Option<&AccessMask> {
607 self.access_mask
608 }
609}
610
611impl<'a, 'm> ChainView for BsrEdit<'a, 'm> {
612 fn tap_infos(&self) -> &[TapInfo] {
613 self.tap_infos
614 }
615 fn tap_cmds(&self) -> &[TapCmd] {
616 self.tap_cmds
617 }
618 fn access_mask(&self) -> Option<&AccessMask> {
619 self.access_mask
620 }
621}
622
623impl ChainView for PinScanner {
624 fn tap_infos(&self) -> &[TapInfo] {
625 &self.tap_infos
626 }
627 fn tap_cmds(&self) -> &[TapCmd] {
628 &self.tap_cmds
629 }
630 fn access_mask(&self) -> Option<&AccessMask> {
631 None
632 }
633}