29 static constexpr uint32_t MIN_HZ = 10'000u;
30 static constexpr uint32_t MAX_HZ = 100'000'000u;
32 static constexpr uint32_t NS_PER_SEC = 1'000'000'000u;
33 static constexpr uint32_t LOOPS_SCALE = 1000u;
34 static constexpr uint32_t CEIL_BIAS = LOOPS_SCALE - 1u;
36 static constexpr uint32_t DEFAULT_CLOCK_HZ = 500'000u;
37 static constexpr uint32_t RESET_CYCLES = 5u;
39 static constexpr uint32_t HALF_PERIOD_NS_MAX =
40 (NS_PER_SEC + (2u * MIN_HZ) - 1u) / (2u * MIN_HZ);
41 static constexpr uint32_t MAX_LOOPS_PER_US =
42 (UINT32_MAX - CEIL_BIAS) / HALF_PERIOD_NS_MAX;
55 TdoGpioType& tdo, uint32_t loops_per_us,
56 uint32_t default_hz = DEFAULT_CLOCK_HZ)
57 : tck_(tck), tms_(tms), tdi_(tdi), tdo_(tdo), loops_per_us_(loops_per_us)
59 if (loops_per_us_ > MAX_LOOPS_PER_US)
61 loops_per_us_ = MAX_LOOPS_PER_US;
64 tck_.SetConfig({TckGpioType::Direction::OUTPUT_PUSH_PULL, TckGpioType::Pull::NONE});
65 tms_.SetConfig({TmsGpioType::Direction::OUTPUT_PUSH_PULL, TmsGpioType::Pull::UP});
66 tdi_.SetConfig({TdiGpioType::Direction::OUTPUT_PUSH_PULL, TdiGpioType::Pull::NONE});
67 tdo_.SetConfig({TdoGpioType::Direction::INPUT, TdoGpioType::Pull::NONE});
88 half_period_loops_ = 0u;
103 half_period_ns_ = (NS_PER_SEC + (2u * hz) - 1u) / (2u * hz);
105 if (loops_per_us_ == 0u)
107 half_period_loops_ = 0u;
111 const uint64_t LOOPS_SCALED =
112 static_cast<uint64_t
>(loops_per_us_) *
static_cast<uint64_t
>(half_period_ns_);
113 if (LOOPS_SCALED < LOOPS_SCALE)
115 half_period_loops_ = 0u;
119 const uint64_t LOOPS_CEIL = (LOOPS_SCALED + CEIL_BIAS) / LOOPS_SCALE;
121 (LOOPS_CEIL > UINT32_MAX) ? UINT32_MAX :
static_cast<uint32_t
>(LOOPS_CEIL);
137 for (uint32_t i = 0; i < RESET_CYCLES; ++i)
139 ClockCycle(
true,
false,
nullptr);
141 current_state_ = TapState::TEST_LOGIC_RESET;
147 if (target == current_state_)
154 case TapState::TEST_LOGIC_RESET:
156 case TapState::RUN_TEST_IDLE:
159 case TapState::SHIFT_IR:
161 ApplyTmsSequence(SEQ_TO_SHIFT_IR, SEQ_TO_SHIFT_IR_LEN);
162 current_state_ = TapState::SHIFT_IR;
164 case TapState::SHIFT_DR:
166 ApplyTmsSequence(SEQ_TO_SHIFT_DR, SEQ_TO_SHIFT_DR_LEN);
167 current_state_ = TapState::SHIFT_DR;
175 uint8_t* out_lsb_first)
override
188 ShiftBits(bits, in_lsb_first, out_lsb_first);
194 uint8_t* out_lsb_first)
override
207 ShiftBits(bits, in_lsb_first, out_lsb_first);
213 uint8_t* tdo_lsb_first)
override
220 if (tdo_lsb_first !=
nullptr)
222 const uint32_t BYTES = (cycles + 7u) / 8u;
226 for (uint32_t i = 0; i < cycles; ++i)
228 const bool TDI_VAL = (tdi_lsb_first ==
nullptr)
230 : (((tdi_lsb_first[i / 8u] >> (i & 7u)) & 0x1u) != 0u);
231 bool tdo_bit =
false;
232 ClockCycle(tms, TDI_VAL, tdo_lsb_first ? &tdo_bit :
nullptr);
234 if (tdo_lsb_first !=
nullptr && tdo_bit)
236 tdo_lsb_first[i / 8u] =
237 static_cast<uint8_t
>(tdo_lsb_first[i / 8u] | (1u << (i & 7u)));
251 (void)
GotoState(TapState::RUN_TEST_IDLE);
252 for (uint32_t i = 0; i < cycles; ++i)
254 ClockCycle(
false,
false,
nullptr);
259 static constexpr uint8_t SEQ_TO_SHIFT_DR[] = {1u, 0u, 0u};
260 static constexpr uint32_t SEQ_TO_SHIFT_DR_LEN = 3u;
261 static constexpr uint8_t SEQ_TO_SHIFT_IR[] = {1u, 1u, 0u, 0u};
262 static constexpr uint32_t SEQ_TO_SHIFT_IR_LEN = 4u;
264 void ApplyTmsSequence(
const uint8_t* seq, uint32_t len)
266 for (uint32_t i = 0; i < len; ++i)
268 const bool TMS_VAL = (seq[i] != 0u);
269 ClockCycle(TMS_VAL,
false,
nullptr);
275 if (current_state_ == TapState::RUN_TEST_IDLE)
280 ClockCycle(
false,
false,
nullptr);
281 current_state_ = TapState::RUN_TEST_IDLE;
286 ClockCycle(
true,
false,
nullptr);
287 ClockCycle(
false,
false,
nullptr);
288 current_state_ = TapState::RUN_TEST_IDLE;
291 void ShiftBits(uint32_t bits,
const uint8_t* in_lsb_first, uint8_t* out_lsb_first)
293 if (out_lsb_first !=
nullptr && bits != 0u)
295 const uint32_t BYTES = (bits + 7u) / 8u;
306 (void)
Sequence(bits - 1u,
false, in_lsb_first, out_lsb_first);
309 const uint32_t LAST = bits - 1u;
310 const bool LAST_TDI = (in_lsb_first ==
nullptr)
312 : (((in_lsb_first[LAST / 8u] >> (LAST & 7u)) & 0x1u) != 0u);
313 bool last_tdo =
false;
314 ClockCycle(
true, LAST_TDI, out_lsb_first ? &last_tdo :
nullptr);
316 if (out_lsb_first !=
nullptr && last_tdo)
318 out_lsb_first[LAST / 8u] =
319 static_cast<uint8_t
>(out_lsb_first[LAST / 8u] | (1u << (LAST & 7u)));
323 void ClockCycle(
bool tms,
bool tdi,
bool* tdo)
328 if (half_period_loops_ == 0u)
352 inline void DelayHalf() { BusyLoop(half_period_loops_); }
354 static void BusyLoop(uint32_t loops)
356 volatile uint32_t sink = loops;
368 uint32_t clock_hz_ = 0u;
369 uint32_t loops_per_us_ = 0u;
370 uint32_t half_period_ns_ = 0u;
371 uint32_t half_period_loops_ = 0u;
373 TapState current_state_ = TapState::TEST_LOGIC_RESET;
ErrorCode Sequence(uint32_t cycles, bool tms, const uint8_t *tdi_lsb_first, uint8_t *tdo_lsb_first) override
Shift a fixed-TMS sequence, LSB first.