1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
// Copyright 2021 Adam Greig
// Licensed under the MIT license.

#![allow(clippy::upper_case_acronyms)]

//! # svf
//!
//! Parse and generate SVF files.
//!
//! Use [`parse_complete`] to parse a full SVF file into a vector of [`Command`],
//! [`parse_iter`] to create an iterator over [`Command`] which parses incrementally,
//! or [`parse_iter_bufread`] to create an iterator using a `BufRead` input, allowing
//! both the input and output to be processed piece-by-piece.
//!
//! Once parsed, or if you construct [`Command`] manually, the `Display` trait
//! implementation on [`Command`] can be used to generate SVF files.

mod display;
mod parser;
pub use parser::{parse_complete, parse_iter, parse_iter_bufread, SVFParseError as ParseError};

/// IEEE 1149.1 TAP states with SVF TAP state names.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    /// Test-Logic-Reset
    RESET,

    /// Run-Test/Idle
    IDLE,

    /// Select-DR-Scan
    DRSELECT,

    /// Capture-DR
    DRCAPTURE,

    /// Shift-DR
    DRSHIFT,

    /// Exit1-DR
    DREXIT1,

    /// Pause-DR
    DRPAUSE,

    /// Exit2-DR
    DREXIT2,

    /// Update-DR
    DRUPDATE,

    /// Select-IR-Scan
    IRSELECT,

    /// Capture-IR
    IRCAPTURE,

    /// Shift-IR
    IRSHIFT,

    /// Exit1-IR
    IREXIT1,

    /// Pause-IR
    IRPAUSE,

    /// Exit2-IR
    IREXIT2,

    /// Update-IR
    IRUPDATE,
}

impl State {
    /// Check if this state is one of the stable states IRPAUSE, DRPAUSE, RESET, or IDLE.
    pub fn is_stable(&self) -> bool {
        matches!(self, State::DRPAUSE | State::IRPAUSE | State::RESET | State::IDLE)
    }

    /// Return the default path to move from the current state `self` to an end state `end`,
    /// when both `self` and `end` are stable states.
    ///
    /// The returned path only includes the intermediate states and not the start or end state.
    /// If either `self` or `end` are not stable, None is returned.
    pub fn default_path(&self, end: &State) -> Option<Vec<State>> {
        use State::*;
        match (self, end) {
            (RESET, RESET)      => Some(vec![]),
            (RESET, IDLE)       => Some(vec![]),
            (RESET, DRPAUSE)    => Some(vec![IDLE, DRSELECT, DRCAPTURE, DREXIT1]),
            (RESET, IRPAUSE)    => Some(vec![IDLE, DRSELECT, IRSELECT, IRCAPTURE, IREXIT1]),
            (IDLE, RESET)       => Some(vec![DRSELECT, IRSELECT]),
            (IDLE, IDLE)        => Some(vec![]),
            (IDLE, DRPAUSE)     => Some(vec![DRSELECT, DRCAPTURE, DREXIT1]),
            (IDLE, IRPAUSE)     => Some(vec![DRSELECT, IRSELECT, IRCAPTURE, IREXIT1]),
            (DRPAUSE, RESET)    => Some(vec![DREXIT2, DRUPDATE, DRSELECT, IRSELECT]),
            (DRPAUSE, IDLE)     => Some(vec![DREXIT2, DRUPDATE]),
            (DRPAUSE, DRPAUSE)  => Some(vec![DREXIT2, DRUPDATE, DRSELECT, DRCAPTURE, DREXIT1]),
            (DRPAUSE, IRPAUSE)  => Some(vec![DREXIT2, DRUPDATE, DRSELECT, IRSELECT, IRCAPTURE,
                                             IREXIT1]),
            (IRPAUSE, RESET)    => Some(vec![IREXIT2, IRUPDATE, DRSELECT, IRSELECT]),
            (IRPAUSE, IDLE)     => Some(vec![IREXIT2, IRUPDATE]),
            (IRPAUSE, DRPAUSE)  => Some(vec![IREXIT2, IRUPDATE, DRSELECT, DRCAPTURE, DREXIT1]),
            (IRPAUSE, IRPAUSE)  => Some(vec![IREXIT2, IRUPDATE, DRSELECT, IRSELECT, IRCAPTURE,
                                             IREXIT1]),
            _                   => None,
        }
    }
}

/// Vector characters for a parallel test vector.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum VectorChar {
    /// Drive logical 1
    H,

    /// Drive logical 0
    L,

    /// Drive high impedance
    Z,

    /// Detect logical 1
    U,

    /// Detect logical 0
    D,

    /// Detect unknown
    X,
}

/// Data pattern used for HDR, HIR, SDR, SIR, TDR, and TIR commands.
#[derive(Clone, Debug, PartialEq)]
pub struct Pattern {
    /// Number of bits to be scanned.
    pub length: u32,

    /// Value to be scanned into the target.
    /// If not specified, the previously specified TDI for this command is used.
    /// Bits are packed into bytes least-significant-bit and least-significant-byte first,
    /// and the vector is automatically zero-padded to contain enough bits for the length.
    pub tdi: Option<Vec<u8>>,

    /// Value to compare against actual values scanned out of the target.
    /// If not specified, no comparison is performed.
    /// Bits are packed into bytes least-significant-bit and least-significant-byte first,
    /// and the vector is automatically zero-padded to contain enough bits for the length.
    pub tdo: Option<Vec<u8>>,

    /// Mask used when comparing TDO values against actual values.
    /// 1 indicates care, 0 indicates don't-care.
    /// If not specified, the previously specified MASK for this command is used.
    /// Bits are packed into bytes least-significant-bit and least-significant-byte first,
    /// and the vector is automatically zero-padded to contain enough bits for the length.
    pub mask: Option<Vec<u8>>,

    /// Mask TDI data.
    /// 1 indicates care, 0 indicates don't-care.
    /// If not specified, the previously specified SMASK for this command is used.
    /// Bits are packed into bytes least-significant-bit and least-significant-byte first,
    /// and the vector is automatically zero-padded to contain enough bits for the length.
    pub smask: Option<Vec<u8>>,
}

impl Pattern {
    /// Extend all non-None scan data to contain as many trailing 0s
    /// as required to make up the bit length.
    fn extend(mut self) -> Self {
        for data in [&mut self.tdi, &mut self.tdo, &mut self.mask, &mut self.smask].iter_mut() {
            if let Some(data) = data {
                while data.len() * 8 < self.length as usize {
                    data.push(0);
                }
            }
        }
        self
    }
}

/// Possible directions for a column in a PIOMAP command.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PIOMapDirection {
    /// Input to the unit under test, uses H, L, or Z characters.
    In,

    /// Output from the unit under test, uses U, D, or X characters.
    Out,

    /// Bidirectional, may use any characters.
    InOut,
}

/// Possible clocks for the `run_clk` argument to RUNTEST.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RunClock {
    /// Test clock
    TCK,

    /// System clock
    SCK,
}

/// Possible modes for the TRST signal.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TRSTMode {
    /// Active (logic 0)
    On,

    /// Active (logic 1)
    Off,

    /// High impedance
    Z,

    /// Not present
    Absent,
}

/// Minimum and optional maximum time to run a RunTest command for.
#[derive(Clone, Debug, PartialEq)]
pub struct RunTestTime {
    pub min: f64,
    pub max: Option<f64>,
}

/// Possible forms of the RunTest arguments.
#[derive(Clone, Debug, PartialEq)]
pub enum RunTestForm {
    Clocked {
        run_count: u32,
        run_clk: RunClock,
        time: Option<RunTestTime>,
    },
    Timed(RunTestTime),
}

/// SVF command and corresponding parsed data.
#[derive(Clone, Debug, PartialEq)]
pub enum Command {
    /// State for the bus after a DR scan.
    ///
    /// The state is checked to be a stable state when parsing.
    EndDR(State),

    /// State for the bus after an IR scan.
    ///
    /// The state is checked to be a stable state when parsing.
    EndIR(State),

    /// Maximum TCK frequency for subsequent scans, state changes, and test operations.
    Frequency(Option<f64>),

    /// Default header pattern to be shifted in before every data register scan operation.
    HDR(Pattern),

    /// Default header pattern to be shifted in before every instruction register scan operation.
    HIR(Pattern),

    /// Parallel input/output test vector.
    PIO(Vec<VectorChar>),

    /// Define I/O direction and name for each column in a PIO command.
    /// Each entry corresponds to a column with associated direction and logical name.
    PIOMap(Vec<(PIOMapDirection, String)>),

    /// Force the target to the specified state for a specified number of clocks
    /// or a specified length of time or both, then move to the specified end state.
    RunTest {
        /// State to hold during this command.
        /// Checked to be a stable state when parsing.
        /// If not specified, use the run_state specified in the previous RUNTEST command.
        run_state: Option<State>,

        /// The run_count, run_clk, min_time, and max_time parameters are stored
        /// in this RunTestForm enum which encodes the various ways in which they
        /// may be specified or omitted.
        form: RunTestForm,

        /// State to enter after completion of command.
        /// Checked to be a stable state when parsing.
        /// If not specified, use the default end state, which is the most
        /// recently specified end_state or run_state, or IDLE otherwise.
        end_state: Option<State>,
    },

    /// Scan data register with specified pattern.
    SDR(Pattern),

    /// Scan instruction register with specified pattern.
    SIR(Pattern),

    /// Force target to a stable state, optionally specifying the path to traverse.
    /// If no path is specified, use the default path between the current and final state.
    State {
        /// Path to take to reach the end state. States must be in an order that obeys the
        /// TAP state machine. If not specified, the default path from the current state to
        /// the end state is used.
        path: Option<Vec<State>>,

        /// Final state to reach. Checked to be a stable state when parsing.
        end: State,
    },

    /// Default trailer pattern to be shifted in before every data register scan operation.
    TDR(Pattern),

    /// Default trailer pattern to be shifted in before every instruction register scan operation.
    TIR(Pattern),

    /// Operation of TRST signal.
    TRST(TRSTMode),
}