Skip to main content

jtag_adi/
lib.rs

1//! This crate allows for interacting with ARM Debug Interface components over JTAG, such as the
2//! Mem AP for accessing memory-mapped resources.  It uses the jtag-taps library for the link layer
3//! and so supports all cables supported by that crate.
4
5use std::cell::RefCell;
6use std::ops::DerefMut;
7use std::rc::Rc;
8
9use jtag_taps::cable::Cable;
10use jtag_taps::taps::Taps;
11
12pub mod armv8;
13
14/// Selects between Debug Port (DP) and Access Port (AP)
15#[derive(Clone,Copy)]
16pub enum Port {
17    Abort = 8, // Only for ADIv5
18    DP = 10,
19    AP = 11,
20}
21
22/// Debug Port registers
23pub enum DPReg {
24    Abort = 0, // Also DpIdr in ADIv6
25    CtrlStat = 1,
26    Select = 2,
27    Rdbuff = 3,
28}
29
30pub struct ArmDebugInterface<T> {
31    taps: Taps<T>,
32    lastbank: u32,
33    lastir: Vec<u8>,
34    good_ack: u64,
35    pub version: u64,
36}
37
38impl<T, U> ArmDebugInterface<T>
39where
40    T: DerefMut<Target = U>,
41    U: Cable + ?Sized,
42{
43    pub fn new(taps: Taps<T>) -> Self {
44        let mut adi = Self {
45            taps,
46            lastbank: 0xff,
47            lastir: vec![],
48            good_ack: 2,
49            version: 5,
50        };
51
52        // Select bank 0.  Don't use bank_select() because we don't want error checking because we
53        // don't know what version we've got yet
54        let _ = adi.write_adi_nobank(Port::DP, DPReg::Select as u32, 0, false);
55
56        // Abort any in-progress transactions
57        if let Err(4) = adi.write_adi_nobank(Port::DP, DPReg::Abort as u32, 1, true) {
58            // Possibly ADIv6
59            adi.good_ack = 4;
60            let val = adi.read_adi_nobank(Port::DP, DPReg::Abort as u32).expect("abort");
61            let version = (val >> 12) & 0xf;
62            assert_eq!(version, 3);
63
64            // ADIv6 confirmed, so use the correct abort register
65            adi.version = 6;
66            adi.write_adi_nobank(Port::Abort, 0, 1, true).expect("abort");
67        }
68
69        // Make sure everything is powered up and STICKY errors are cleared
70        adi.write_adi_nobank(
71            Port::DP,
72            DPReg::CtrlStat as u32,
73            1 << 30 | 1 << 28 | 1 << 24 | 1 << 5 | 1 << 1,
74            true,
75        )
76        .expect("clear errors");
77
78        adi
79    }
80
81    fn write_ir(&mut self, ir: &[u8]) {
82        if self.lastir != ir {
83            self.taps.write_ir(ir);
84            self.lastir = ir.to_vec();
85        }
86    }
87
88    fn parse_ack(mut dr: Vec<u8>, good_ack: u64) -> Result<u32, u8> {
89        dr.push(0);
90        dr.push(0);
91        dr.push(0);
92        let val = u64::from_le_bytes(dr.try_into().unwrap());
93        let val = val & ((1 << 35) - 1);
94
95        let ack = val & 7;
96        if ack != good_ack {
97            return Err(ack as u8);
98        }
99
100        Ok((val >> 3) as u32)
101    }
102
103    pub fn queue_read_adi_nobank(&mut self, port: Port, reg: u32) -> bool {
104        let ir = [port as u8];
105        self.write_ir(&ir);
106        let mut buf = (reg << 1 | 1).to_le_bytes().to_vec();
107        buf.push(0);
108
109        self.taps.write_dr(&buf, 3);
110        self.taps.queue_dr_read(35)
111    }
112
113    pub fn finish_read(&mut self) -> Result<u32, u8> {
114        let mut dr = self.taps.finish_dr_read(35);
115
116        dr.push(0);
117        dr.push(0);
118        dr.push(0);
119        let val = u64::from_le_bytes(dr.try_into().unwrap());
120        let val = val & ((1 << 35) - 1);
121
122        let ack = val & 7;
123        if ack != self.good_ack {
124            return Err(ack as u8);
125        }
126
127        let val = (val >> 3) as u32;
128        Ok(val)
129    }
130
131    /// Read register `reg` from `port`.  This function assumes that the correct bank is already
132    /// selected.  You probably want `read_adi` unless you know what you're doing.
133    pub fn read_adi_nobank(&mut self, port: Port, reg: u32) -> Result<u32, u8> {
134        let result = self.queue_read_adi_nobank(port, reg);
135        assert!(result);
136        self.finish_read()
137    }
138
139    pub fn read_adi_retry(&mut self, apsel: u32, port: Port, mut reg: u32) -> Result<u32, u8> {
140        let bank = reg >> 2;
141        reg &= 3;
142        self.bank_select(apsel, bank as u32, 0);
143        loop {
144            match self.read_adi_nobank(port, reg) {
145                Ok(x) => { return Ok(x); }
146                Err(1) => continue,
147                Err(e) => { return Err(e); }
148            }
149        };
150    }
151
152
153
154    /// Write `val` to register `reg` on `port`.  This function assumes that the correct bank is already
155    /// selected.  If `check` is true then the return code of the write will be verified, however
156    /// this comes at a performance penalty. You probably want `write_adi` unless you know what
157    /// you're doing.
158    pub fn write_adi_nobank(
159        &mut self,
160        port: Port,
161        reg: u32,
162        val: u32,
163        check: bool,
164    ) -> Result<(), u8> {
165        let ir = [port as u8];
166
167        let mut val = val as u64;
168        val <<= 3;
169        val |= (reg << 1) as u64;
170
171        let bytes = val.to_le_bytes();
172        loop {
173            self.write_ir(&ir);
174            self.taps.write_dr(&bytes[0..5], 3);
175            if !check {
176                return Ok(());
177            } else {
178                let mut dr = self.taps.read_dr(35);
179
180                dr.push(0);
181                dr.push(0);
182                dr.push(0);
183                let val = u64::from_le_bytes(dr.try_into().unwrap());
184                let val = val & ((1 << 35) - 1);
185
186                let ack = val & 7;
187                if ack == self.good_ack {
188                    return Ok(());
189                }
190                if ack == 1 {
191                    continue;
192                }
193                return Err(ack as u8);
194            }
195        }
196    }
197
198    /// Select the given access port and banks on the access port and debug port.
199    pub fn bank_select(&mut self, apsel: u32, apbank: u32, dpbank: u32) {
200        let val = (apsel << 24) | (apbank << 4) | dpbank;
201        if val != self.lastbank {
202            self.write_adi_nobank(Port::DP, DPReg::Select as u32, val, true)
203                .expect("bank sel");
204            self.lastbank = val;
205        }
206    }
207
208    /// Read register `reg` from AP `apsel` and `port`.
209    pub fn read_adi(&mut self, apsel: u32, port: Port, mut reg: u32) -> Result<u32, u8> {
210        let bank = reg >> 2;
211        reg &= 3;
212        self.bank_select(apsel, bank as u32, 0);
213        self.read_adi_nobank(port, reg)
214    }
215
216    /// Read register `reg` from AP `apsel` and `port`.
217    pub fn queue_read_adi(&mut self, apsel: u32, port: Port, mut reg: u32) -> bool {
218        let bank = reg >> 2;
219        reg &= 3;
220        self.bank_select(apsel, bank as u32, 0);
221        self.queue_read_adi_nobank(port, reg)
222    }
223
224    /// Write `val` to register `reg` of AP `apsel` and `port`.
225    pub fn write_adi(&mut self, apsel: u32, port: Port, mut reg: u32, val: u32) -> Result<(), u8> {
226        let bank = reg >> 2;
227        reg &= 3;
228        self.bank_select(apsel, bank as u32, 0);
229        self.write_adi_nobank(port, reg, val, true)
230    }
231
232    /// Write `val` to register `reg` of AP `apsel` and `port` without checking for success.  This
233    /// is slightly faster than `write_adi`, especially when doing a sequence of writes.
234    pub fn write_adi_nocheck(
235        &mut self,
236        apsel: u32,
237        port: Port,
238        mut reg: u32,
239        val: u32,
240    ) -> Result<(), u8> {
241        let bank = reg >> 2;
242        reg &= 3;
243        self.bank_select(apsel, bank as u32, bank as u32);
244        self.write_adi_nobank(port, reg, val, false)
245    }
246
247    /// Read multiple registers.  `reg` is an array of register values to access.  The result is
248    /// returned in the corresponding index of the returned Vec.  This function makes more
249    /// efficient use of the JTAG bus when there are multiple reads to perform.
250    pub fn read_adi_pipelined(
251        &mut self,
252        apsel: u32,
253        port: Port,
254        reg: &[u32],
255    ) -> Vec<Result<u32, u8>> {
256        let bank = reg[0] >> 2;
257        self.bank_select(apsel, bank as u32, 0);
258
259        let ir = [port as u8];
260        self.write_ir(&ir);
261        let mut buf = ((reg[0] & 3) << 1 | 1).to_le_bytes().to_vec();
262        buf.push(0);
263
264        self.taps.write_dr(&buf, 3);
265
266        let mut count = 0;
267        let mut queue_full = false;
268        for r in &reg[1..] {
269            // Make sure all registers are in the same bank
270            assert_eq!(r >> 2, reg[0] >> 2);
271            let  mut buf = ((r & 3) << 1 | 1).to_le_bytes().to_vec();
272            buf.push(0);
273
274            if !self.taps.queue_dr_read_write(&buf, 3) {
275                queue_full = true;
276                break;
277            }
278            count += 1;
279        }
280
281        if !queue_full {
282            if self.taps.queue_dr_read(35) {
283                count += 1;
284            }
285        }
286
287        let mut data = vec![];
288        for _ in 0..count {
289            data.push(Self::parse_ack(self.taps.finish_dr_read(35), self.good_ack));
290        }
291
292        data
293    }
294
295    /// Write multiple registers.  Each item of `reg` is a tuple consisting of the register address
296    /// and the value to write.  This function makes more efficient use of the JTAG bus when there
297    /// are multiple reads to perform.
298    pub fn write_adi_pipelined(
299        &mut self,
300        apsel: u32,
301        port: Port,
302        reg: &[(u32, u32)],
303    ) -> Result<(), u8> {
304        let bank = reg[0].0 >> 2;
305        self.bank_select(apsel, bank as u32, 0);
306
307        let ir = [port as u8];
308        self.write_ir(&ir);
309
310        for (r, val) in reg {
311            // Make sure all registers are in the same bank
312            assert_eq!(r >> 2, reg[0].0 >> 2);
313
314            let mut val = *val as u64;
315            val <<= 3;
316            val |= ((r & 3) << 1) as u64;
317
318            let bytes = val.to_le_bytes();
319            self.taps.write_dr(&bytes[0..5], 3);
320        }
321        Ok(())
322    }
323}
324
325#[allow(clippy::upper_case_acronyms)]
326enum MemAPReg {
327    CSW = 0,
328    TAR = 1,
329    DRW = 3,
330    //Base0 = 0xf0 >> 2,
331    //CFG = 0xf4 >> 2,
332    //Base1 = 0xf8 >> 2,
333    //IDR = 0xfc >> 2,
334}
335
336/// Functions for interacting with a Memory Access Port
337pub struct MemAP<T> {
338    adi: Rc<RefCell<ArmDebugInterface<T>>>,
339    base: u32,
340    csw: u32,
341    tar: u32,
342}
343
344impl<T, U> MemAP<T>
345where
346    T: DerefMut<Target = U>,
347    U: Cable + ?Sized,
348{
349    pub fn new(adi: Rc<RefCell<ArmDebugInterface<T>>>, mut base: u32) -> Self {
350        if adi.borrow().version == 6 {
351            base += 0xd00;
352        }
353        base = base >> 2;
354        let csw = adi
355            .borrow_mut()
356            .read_adi_retry(0, Port::AP, MemAPReg::CSW as u32 + base)
357            .expect("read csw");
358        let tar = adi
359            .borrow_mut()
360            .read_adi_retry(0, Port::AP, MemAPReg::TAR as u32 + base)
361            .expect("read tar");
362        Self { adi, base, csw, tar }
363    }
364
365    /// Set the control and status word of the MemAP.  `MemAP` caches the value of this register,
366    /// so it should not be modified other than by this function.
367    pub fn write_csw(&mut self, csw: u32) -> Result<(), u8> {
368        if csw != self.csw {
369            self.adi
370                .borrow_mut()
371                .write_adi(0, Port::AP, MemAPReg::CSW as u32 + self.base, csw)?;
372            self.csw = csw;
373        }
374        Ok(())
375    }
376
377    /// Read a single 32-bit quantity from `addr`
378    pub fn read(&mut self, addr: u32) -> Result<u32, u8> {
379        // Make sure we're not in auto-increment mode
380        self.write_csw(self.csw & !(1 << 4))?;
381        if self.tar != addr {
382            self.adi
383                .borrow_mut()
384                .write_adi(0, Port::AP, MemAPReg::TAR as u32 + self.base, addr)?;
385            self.tar = addr;
386        }
387        let val = self
388            .adi
389            .borrow_mut()
390            .read_adi_retry(0, Port::AP, MemAPReg::DRW as u32 + self.base)?;
391        let stat = self
392            .adi
393            .borrow_mut()
394            .read_adi_retry(0, Port::DP, DPReg::CtrlStat as u32)?;
395        if stat & 5 != 0 {
396            return Err(5);
397        }
398        Ok(val)
399    }
400
401    pub fn queue_read(&mut self, addr: u32) -> Result<bool, u8> {
402        // Make sure we're not in auto-increment mode
403        self.write_csw(self.csw & !(1 << 4))?;
404        if self.tar != addr {
405            self.adi
406                .borrow_mut()
407                .write_adi_nocheck(0, Port::AP, MemAPReg::TAR as u32 + self.base, addr)?;
408            self.tar = addr;
409        }
410
411        let val = self
412            .adi
413            .borrow_mut()
414            .queue_read_adi(0, Port::AP, MemAPReg::DRW as u32 + self.base);
415        if !val {
416            return Ok(false);
417        }
418        Ok(true)
419    }
420
421    pub fn finish_read(&mut self) -> Result<u32, u8> {
422        let val = self.adi.borrow_mut().finish_read()?;
423        Ok(val)
424    }
425
426    /// Write `value` to `addr`
427    pub fn write(&mut self, addr: u32, value: u32) -> Result<(), u8> {
428        // Make sure we're not in auto-increment mode
429        self.write_csw(self.csw & !(1 << 4))?;
430        if self.tar != addr {
431            self.adi
432                .borrow_mut()
433                .write_adi(0, Port::AP, MemAPReg::TAR as u32 + self.base, addr)?;
434            self.tar = addr;
435        }
436        self.adi
437            .borrow_mut()
438            .write_adi(0, Port::AP, MemAPReg::DRW as u32 + self.base, value)?;
439        if let Ok(_) = std::env::var("YOLO_MODE") {
440            return Ok(())
441        }
442        let stat = self
443            .adi
444            .borrow_mut()
445            .read_adi_retry(0, Port::DP, DPReg::CtrlStat as u32)?;
446        if stat & 5 != 0 {
447            return Err(5);
448        }
449        Ok(())
450    }
451
452    /// Write `value` to `addr`
453    pub fn write_nocheck(&mut self, addr: u32, value: u32) -> Result<(), u8> {
454        // Make sure we're not in auto-increment mode
455        self.write_csw(self.csw & !(1 << 4))?;
456        if self.tar != addr {
457            self.adi
458                .borrow_mut()
459                .write_adi_nocheck(0, Port::AP, MemAPReg::TAR as u32 + self.base, addr)?;
460            self.tar = addr;
461        }
462        self.adi
463            .borrow_mut()
464            .write_adi_nocheck(0, Port::AP, MemAPReg::DRW as u32 + self.base, value)?;
465        Ok(())
466    }
467
468    /// Read multiple values from memory.  If `check_status` is true, then the CTRL/STAT
469    /// register is checked for errors at the end of the transaction, which comes with a slight
470    /// performance penalty.  If `auto_increment` is true, then each value will come from the next
471    /// sequential address, otherwise every read is from `addr`
472    pub fn read_multi(
473        &mut self,
474        addr: u32,
475        count: usize,
476        auto_increment: bool,
477        check_status: bool,
478    ) -> Result<Vec<u32>, u8> {
479        // Enable auto-increment mode
480        if auto_increment {
481            self.write_csw(self.csw | (1 << 4))?;
482        } else {
483            self.write_csw(self.csw & !(1 << 4))?;
484        }
485
486        if self.tar != addr {
487            self.adi
488                .borrow_mut()
489                .write_adi(0, Port::AP, MemAPReg::TAR as u32 + self.base, addr)?;
490            self.tar = addr;
491            if auto_increment {
492                self.tar += 4 * count as u32;
493            }
494        }
495
496        let reg = vec![MemAPReg::DRW as u32 + self.base; count];
497        let val = self
498            .adi
499            .borrow_mut()
500            .read_adi_pipelined(0, Port::AP, &reg);
501
502        // Since we are always reading from the same register, any WAIT acks can be dropped
503        let mut result = vec![];
504        for item in val {
505            match item {
506                Ok(x) => result.push(x),
507                Err(1) => continue,
508                Err(e) => return Err(e),
509            }
510        }
511
512        if check_status {
513            let stat =
514                self.adi
515                    .borrow_mut()
516                    .read_adi_retry(0, Port::DP, DPReg::CtrlStat as u32)?;
517            if stat & 5 != 0 {
518                return Err(5);
519            }
520        }
521        Ok(result)
522    }
523
524    /// Read multiple consective values from memory.  If `check_status` is true, then the CTRL/STAT
525    /// register is checked for errors at the end of the transaction, which comes with a slight
526    /// performance penalty.
527    pub fn read_block(
528        &mut self,
529        addr: u32,
530        count: usize,
531        check_status: bool,
532    ) -> Result<Vec<u32>, u8> {
533        self.read_multi(addr, count, true, check_status)
534    }
535
536
537    /// Write `data` starting at `addr`.  If `check_status` is true, then the CTRL/STAT
538    /// register is checked for errors at the end of the transaction, which comes with a slight
539    /// performance penalty.
540    pub fn write_block(&mut self, addr: u32, data: &[u32], check_status: bool) -> Result<(), u8> {
541        // Enable auto-increment mode
542        self.write_csw(self.csw | (1 << 4))?;
543
544        if self.tar != addr {
545            self.adi
546                .borrow_mut()
547                .write_adi(0, Port::AP, MemAPReg::TAR as u32 + self.base, addr)?;
548            self.tar = addr + 4 * data.len() as u32;
549        }
550
551        let reg: Vec<(u32, u32)> = data.iter().map(|x| (MemAPReg::DRW as u32 + self.base, *x)).collect();
552        self.adi
553            .borrow_mut()
554            .write_adi_pipelined(0, Port::AP, &reg)?;
555
556        if check_status {
557            let stat =
558                self.adi
559                    .borrow_mut()
560                    .read_adi_retry(0, Port::DP, DPReg::CtrlStat as u32)?;
561            if stat & 5 != 0 {
562                return Err(5);
563            }
564        }
565        Ok(())
566    }
567}