1use std::{cell::OnceCell, path::Path, sync::Arc};
2
3use bitvec::vec::BitVec;
4
5use crate::{
6 Error,
7 jtag::{
8 Backend, JtagInterface, JtagState,
9 Register::{Data, Instruction},
10 },
11 scanner::PinScanner,
12 types::TapInfo,
13};
14
15pub struct PinScannerBuilder {
18 interface: Box<dyn JtagInterface>,
19 idcodes: OnceCell<Vec<u32>>,
20 tap_infos: Vec<TapInfo>,
21 extest_keep_present: bool,
22}
23
24impl PinScannerBuilder {
25 pub fn new<T: Backend>(cable: T) -> Result<Self, Error> {
28 let interface = cable.into_interface()?;
29 Ok(Self {
30 interface,
31 idcodes: OnceCell::new(),
32 tap_infos: Vec::new(),
33 extest_keep_present: false,
34 })
35 }
36
37 pub fn scan_tap_info(&mut self, path: &Path) -> Result<(), Error> {
43 if !path.exists() || !path.is_dir() {
44 return Err("Invalid path".into());
45 }
46 let mut bsdls = Vec::new();
47 let mut bypassed = Vec::new();
48 for entry in path.read_dir().map_err(|e| e.to_string())? {
49 if let Ok(entry) = entry
50 && let Ok(file_type) = entry.file_type()
51 && file_type.is_file()
52 && let Some(ext) = entry.path().extension()
53 {
54 match ext.to_string_lossy().to_lowercase().as_str() {
55 "bsd" | "bsdl" => match bsdl::Entity::parse(&entry.path(), None) {
56 Ok(bsdl) => bsdls.push((bsdl, entry.path())),
57 Err(e) => println!("Error parsing {}: {e}", entry.file_name().display()),
58 },
59 "bypass" => {
60 let path = entry.path();
61 let stem = path.file_stem().unwrap_or_default().to_string_lossy();
62 let mut stem_iter = stem.split('_');
63 let (Some(idcode), Some(ir_len)) = (stem_iter.next(), stem_iter.next())
64 else {
65 println!("Error parsing file name {}", entry.file_name().display());
66 continue;
67 };
68 let (Ok(idcode), Ok(ir_len)) =
69 (u32::from_str_radix(idcode, 16), ir_len.parse())
70 else {
71 println!("Error parsing file name {}", entry.file_name().display());
72 continue;
73 };
74 bypassed.push((idcode, ir_len));
75 }
76 _ => (),
77 }
78 }
79 }
80
81 let mut tap_infos = Vec::new();
82 for idcode in self.get_id_codes()? {
83 if let Some((_, path)) = bsdls
84 .iter()
85 .find(|(i, _)| i.idcode_register()[0] == jtag_idcode::IDCode::new(idcode))
86 {
87 tap_infos.push(TapInfo::WithBsdl(Arc::new(
91 bsdl::Entity::parse(path, None).unwrap(),
92 )));
93 } else if let Some(&(idcode, ir_len)) = bypassed.iter().find(|(i, _)| *i == idcode) {
94 tap_infos.push(TapInfo::AlwaysBypass { idcode, ir_len });
95 } else {
96 return Err(format!("BSDL or BYPASS file of {idcode:08x} not found").into());
97 };
98 }
99
100 self.tap_infos = tap_infos;
101 Ok(())
102 }
103
104 pub fn add_tap_info(&mut self, info: TapInfo) -> Result<(), Error> {
107 let idcodes = self.get_id_codes()?;
108 if self.tap_infos.len() >= idcodes.len() {
109 return Err("already having enough `TapInfo`".into());
110 }
111 if !info.matches_idcode(idcodes[self.tap_infos.len()]) {
112 return Err("IDCODE mismatch".into());
113 }
114 self.tap_infos.push(info);
115 Ok(())
116 }
117
118 pub fn extest_keep_present(&mut self, new_val: bool) {
126 self.extest_keep_present = new_val;
127 }
128
129 pub fn build(mut self) -> Result<PinScanner, Error> {
131 if self.tap_infos.len() != self.get_id_codes()?.len() {
132 return Err("not having enough `TapInfo`".into());
133 }
134
135 let ir_len = self.interface.measure_ir_len()?;
137 let info_ir_len: usize = self.tap_infos.iter().map(|info| info.ir_len()).sum();
138 if info_ir_len != ir_len {
139 return Err(format!(
140 "IR length mismatch, current: {}, from given info: {}",
141 ir_len, info_ir_len,
142 )
143 .into());
144 }
145
146 PinScanner::build(
147 self.interface,
148 self.tap_infos,
149 ir_len,
150 self.extest_keep_present,
151 )
152 }
153
154 pub fn get_id_codes(&mut self) -> Result<Vec<u32>, Error> {
156 if let Some(idcodes) = self.idcodes.get() {
157 return Ok(idcodes.clone());
158 }
159
160 let dev_cnt = self.count_devices()?;
161
162 self.interface.mode_reset()?; let dr_len = self.interface.measure_dr_len()?;
164 if dr_len != dev_cnt * 32 {
165 return Err(format!("Found device without IDCODE register, dr_len: {dr_len}").into());
166 }
167
168 self.interface.mode_reset()?; self.interface.switch_mode(JtagState::CaptureDR, false)?;
171 let mut raw_idcodes = BitVec::repeat(false, 32 * dev_cnt);
173 self.interface.read_bits(Data, &mut raw_idcodes)?;
174 self.interface.mode_reset()?; let mut idcodes = Vec::new();
177 for raw_idcode in raw_idcodes.as_raw_slice().chunks(4) {
178 let idcode = (raw_idcode[0] as u32)
179 | ((raw_idcode[1] as u32) << 8)
180 | ((raw_idcode[2] as u32) << 16)
181 | ((raw_idcode[3] as u32) << 24);
182 idcodes.push(idcode);
183 }
184 idcodes.reverse();
185
186 let _ = self.idcodes.set(idcodes.clone());
187 Ok(idcodes)
188 }
189
190 fn count_devices(&mut self) -> Result<usize, Error> {
191 self.interface.mode_reset()?; self.interface.write_repeated(Instruction, 1, 1024)?;
195 self.interface.switch_mode(JtagState::Idle, true)?;
196
197 self.interface.measure_dr_len()
198 }
199}