libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
jtag_dp.hpp
1// jtag_dp.hpp
2#pragma once
3
4#include <cstdint>
5
6#include "jtag.hpp"
7#include "jtag_protocol.hpp"
8#include "libxr_def.hpp"
9
10namespace LibXR::Debug
11{
19class JtagDp final
20{
21 public:
22 explicit JtagDp(Jtag& jtag, JtagProtocol::ChainConfig* chain = nullptr)
23 : jtag_(jtag), chain_(chain)
24 {
25 }
26
27 void SetChainConfig(JtagProtocol::ChainConfig* chain)
28 {
29 chain_ = chain;
30 current_ir_valid_ = false;
31 }
32
33 ErrorCode DpRead(uint8_t addr2b, uint32_t& val, JtagProtocol::Ack& ack)
34 {
36 const ErrorCode EC = Transfer(JtagProtocol::make_dp_req(true, addr2b, 0u), resp);
37 ack = resp.ack;
38 val = resp.rdata;
39 return EC;
40 }
41
42 ErrorCode DpWrite(uint8_t addr2b, uint32_t val, JtagProtocol::Ack& ack)
43 {
45 const ErrorCode EC = Transfer(JtagProtocol::make_dp_req(false, addr2b, val), resp);
46 ack = resp.ack;
47 return EC;
48 }
49
50 ErrorCode DpReadTxn(uint8_t addr2b, uint32_t& val, JtagProtocol::Ack& ack)
51 {
53 ErrorCode EC = Transfer(JtagProtocol::make_dp_req(true, addr2b, 0u), resp);
54 ack = resp.ack;
55 if (EC != ErrorCode::OK)
56 {
57 return EC;
58 }
59 if (resp.ack != JtagProtocol::Ack::OK)
60 {
61 return ErrorCode::OK;
62 }
63 // 读为管线化:第二次读取 RDBUFF 拿到结果
64 EC = Transfer(JtagProtocol::make_dp_req(true, 3u, 0u), resp);
65 ack = resp.ack;
66 if (EC != ErrorCode::OK || resp.ack != JtagProtocol::Ack::OK)
67 {
68 return EC;
69 }
70 val = resp.rdata;
71
72 if ((addr2b & 0x03u) == 0u && val == 0u)
73 {
74 uint32_t idcode = 0u;
75 const ErrorCode id_ec = ReadIdCode(idcode);
76 if (id_ec == ErrorCode::OK && idcode != 0u && idcode != 0xFFFF'FFFFu)
77 {
78 val = idcode;
79 ack = JtagProtocol::Ack::OK;
80 }
81 }
82 return ErrorCode::OK;
83 }
84
85 ErrorCode DpWriteTxn(uint8_t addr2b, uint32_t val, JtagProtocol::Ack& ack)
86 {
87 if ((addr2b & 0x03u) == 0u)
88 {
89 return WriteAbort(val, ack);
90 }
91
92 return DpWrite(addr2b, val, ack);
93 }
94
95 ErrorCode ApReadTxn(uint8_t addr2b, uint32_t& val, JtagProtocol::Ack& ack)
96 {
98 ErrorCode EC = Transfer(JtagProtocol::make_ap_req(true, addr2b, 0u), resp);
99 ack = resp.ack;
100 if (EC != ErrorCode::OK)
101 {
102 return EC;
103 }
104 if (resp.ack != JtagProtocol::Ack::OK)
105 {
106 return ErrorCode::OK;
107 }
108 // AP 读同样是 posted:读 RDBUFF 获取实际数据
109 EC = Transfer(JtagProtocol::make_dp_req(true, 3u, 0u), resp);
110 ack = resp.ack;
111 if (EC != ErrorCode::OK || resp.ack != JtagProtocol::Ack::OK)
112 {
113 return EC;
114 }
115 val = resp.rdata;
116 return ErrorCode::OK;
117 }
118
119 ErrorCode ApWriteTxn(uint8_t addr2b, uint32_t val, JtagProtocol::Ack& ack)
120 {
122 const ErrorCode EC = Transfer(JtagProtocol::make_ap_req(false, addr2b, val), resp);
123 ack = resp.ack;
124 return EC;
125 }
126
127 ErrorCode ReadIdCode(uint32_t& idcode)
128 {
129 return ReadIdCodeWithIr(JtagProtocol::JTAG_IR_IDCODE, idcode);
130 }
131
132 ErrorCode ReadIdCodeWithIr(uint32_t ir, uint32_t& idcode)
133 {
134 const ErrorCode EC = SelectIr(ir);
135 if (EC != ErrorCode::OK)
136 {
137 return EC;
138 }
139
140 uint64_t out_dr = 0u;
141 const ErrorCode EC2 = ShiftValueThroughChain(0u, 32u, out_dr);
142 if (EC2 != ErrorCode::OK)
143 {
144 return EC2;
145 }
146 idcode = static_cast<uint32_t>(out_dr & 0xFFFF'FFFFu);
147 return ErrorCode::OK;
148 }
149
150 ErrorCode WriteAbort(uint32_t data, JtagProtocol::Ack& ack)
151 {
152 const ErrorCode EC = SelectIr(JtagProtocol::JTAG_IR_ABORT);
153 if (EC != ErrorCode::OK)
154 {
155 ack = JtagProtocol::Ack::PROTOCOL;
156 return EC;
157 }
158
159 uint64_t out_dr = 0u;
160 const ErrorCode EC2 = ShiftValueThroughChain(
161 JtagProtocol::PackDpDr(JtagProtocol::make_dp_req(false, 0u, data)),
162 JtagProtocol::JTAG_DP_DR_LEN, out_dr);
163 if (EC2 != ErrorCode::OK)
164 {
165 ack = JtagProtocol::Ack::PROTOCOL;
166 return EC2;
167 }
168
169 (void)out_dr;
170 // JTAG ABORT uses its own scan chain; captured TDO bits are not a
171 // DPACC/APACC ACK field. A completed shift means the ABORT was issued.
172 ack = JtagProtocol::Ack::OK;
173 return ErrorCode::OK;
174 }
175
176 ErrorCode Transfer(const JtagProtocol::Request& req, JtagProtocol::Response& resp)
177 {
178 const ErrorCode EC =
179 SelectIr(req.port == JtagProtocol::Port::AP ? JtagProtocol::JTAG_IR_APACC
180 : JtagProtocol::JTAG_IR_DPACC);
181 if (EC != ErrorCode::OK)
182 {
183 resp.ack = JtagProtocol::Ack::PROTOCOL;
184 return EC;
185 }
186
187 uint64_t out_dr = 0u;
188 const ErrorCode EC2 = ShiftValueThroughChain(JtagProtocol::PackDpDr(req),
189 JtagProtocol::JTAG_DP_DR_LEN, out_dr);
190 if (EC2 != ErrorCode::OK)
191 {
192 resp.ack = JtagProtocol::Ack::PROTOCOL;
193 return EC2;
194 }
195
196 JtagProtocol::UnpackDpDr(out_dr, resp);
197 return ErrorCode::OK;
198 }
199
200 private:
201 static constexpr uint32_t DEFAULT_IR_BITS = 4u;
202 static constexpr uint32_t MAX_BITS = 512u;
203 static constexpr uint32_t MAX_BYTES = (MAX_BITS + 7u) / 8u;
204
205 uint32_t IrBits() const
206 {
207 if (chain_ != nullptr && chain_->ir_length != nullptr && chain_->count > 0 &&
208 chain_->index < chain_->count)
209 {
210 const uint8_t bits = chain_->ir_length[chain_->index];
211 return (bits == 0u) ? DEFAULT_IR_BITS : bits;
212 }
213 return DEFAULT_IR_BITS;
214 }
215
216 uint32_t IrBeforeBits()
217 {
218 if (chain_ == nullptr)
219 {
220 return 0u;
221 }
222 if (chain_->ir_before_bits_len == 0u && chain_->ir_after_bits_len == 0u)
223 {
224 JtagProtocol::UpdateChainCache(*chain_);
225 }
226 return chain_->ir_before_bits_len;
227 }
228
229 uint32_t IrAfterBits()
230 {
231 if (chain_ == nullptr)
232 {
233 return 0u;
234 }
235 if (chain_->ir_before_bits_len == 0u && chain_->ir_after_bits_len == 0u)
236 {
237 JtagProtocol::UpdateChainCache(*chain_);
238 }
239 return chain_->ir_after_bits_len;
240 }
241
242 uint32_t DrBeforeBits()
243 {
244 if (chain_ == nullptr)
245 {
246 return 0u;
247 }
248 return (chain_->count == 0 || chain_->index >= chain_->count)
249 ? 0u
250 : static_cast<uint32_t>(chain_->index);
251 }
252
253 uint32_t DrAfterBits()
254 {
255 if (chain_ == nullptr)
256 {
257 return 0u;
258 }
259 return (chain_->count == 0 || chain_->index >= chain_->count)
260 ? 0u
261 : static_cast<uint32_t>(chain_->count - chain_->index - 1u);
262 }
263
264 ErrorCode SelectIr(uint32_t ir)
265 {
266 if (current_ir_valid_ && current_ir_ == ir)
267 {
268 return ErrorCode::OK;
269 }
270
271 const uint32_t ir_bits = IrBits();
272 const uint32_t pre = IrBeforeBits();
273 const uint32_t post = IrAfterBits();
274 const uint32_t total_bits = pre + ir_bits + post;
275
276 if (total_bits > MAX_BITS)
277 {
278 return ErrorCode::SIZE_ERR;
279 }
280
281 uint8_t buf[MAX_BYTES] = {};
282 PutOnes(buf, 0u, pre);
283 PutBits(buf, pre, ir, ir_bits);
284 PutOnes(buf, pre + ir_bits, post);
285 const ErrorCode EC = jtag_.ShiftIR(total_bits, buf, nullptr);
286 if (EC == ErrorCode::OK)
287 {
288 current_ir_ = ir;
289 current_ir_valid_ = true;
290 }
291 return EC;
292 }
293
294 ErrorCode ShiftValueThroughChain(uint64_t in_value, uint32_t value_bits,
295 uint64_t& out_value)
296 {
297 const uint32_t pre = DrBeforeBits();
298 const uint32_t post = DrAfterBits();
299 const uint32_t total_bits = pre + value_bits + post;
300 if (total_bits > MAX_BITS)
301 {
302 return ErrorCode::SIZE_ERR;
303 }
304
305 uint8_t tx[MAX_BYTES] = {};
306 uint8_t rx[MAX_BYTES] = {};
307 PutOnes(tx, 0u, pre);
308 PutBits64(tx, pre, in_value, value_bits);
309 PutOnes(tx, pre + value_bits, post);
310
311 const ErrorCode EC = jtag_.ShiftDR(total_bits, tx, rx);
312 if (EC != ErrorCode::OK)
313 {
314 return EC;
315 }
316
317 out_value = GetBits64(rx, pre, value_bits);
318 return ErrorCode::OK;
319 }
320
321 static void PutOnes(uint8_t* buf, uint32_t bit_off, uint32_t bits)
322 {
323 for (uint32_t i = 0; i < bits; ++i)
324 {
325 const uint32_t idx = bit_off + i;
326 const uint32_t byte = idx / 8u;
327 const uint32_t shift = idx & 7u;
328 buf[byte] = static_cast<uint8_t>(buf[byte] | (1u << shift));
329 }
330 }
331
332 static void PutBits(uint8_t* buf, uint32_t bit_off, uint32_t value, uint32_t bits)
333 {
334 for (uint32_t i = 0; i < bits; ++i)
335 {
336 const bool bit = ((value >> i) & 0x1u) != 0u;
337 const uint32_t idx = bit_off + i;
338 const uint32_t byte = idx / 8u;
339 const uint32_t shift = idx & 7u;
340 if (bit)
341 {
342 buf[byte] = static_cast<uint8_t>(buf[byte] | (1u << shift));
343 }
344 else
345 {
346 buf[byte] = static_cast<uint8_t>(buf[byte] & ~(1u << shift));
347 }
348 }
349 }
350
351 static void PutBits64(uint8_t* buf, uint32_t bit_off, uint64_t value, uint32_t bits)
352 {
353 for (uint32_t i = 0; i < bits; ++i)
354 {
355 const bool bit = ((value >> i) & 0x1u) != 0u;
356 const uint32_t idx = bit_off + i;
357 const uint32_t byte = idx / 8u;
358 const uint32_t shift = idx & 7u;
359 if (bit)
360 {
361 buf[byte] = static_cast<uint8_t>(buf[byte] | (1u << shift));
362 }
363 else
364 {
365 buf[byte] = static_cast<uint8_t>(buf[byte] & ~(1u << shift));
366 }
367 }
368 }
369
370 static uint64_t GetBits64(const uint8_t* buf, uint32_t bit_off, uint32_t bits)
371 {
372 uint64_t v = 0u;
373 for (uint32_t i = 0; i < bits; ++i)
374 {
375 const uint32_t idx = bit_off + i;
376 const uint32_t byte = idx / 8u;
377 const uint32_t shift = idx & 7u;
378 const uint64_t bit = (buf[byte] >> shift) & 0x1u;
379 v |= (bit << i);
380 }
381 return v;
382 }
383
384 private:
385 Jtag& jtag_;
386 JtagProtocol::ChainConfig* chain_ = nullptr;
387 uint32_t current_ir_ = 0u;
388 bool current_ir_valid_ = false;
389};
390
391} // namespace LibXR::Debug
JTAG-DP 事务层封装(DP/AP 访问与 IDCODE/ABORT)。
Definition jtag_dp.hpp:20
Abstract JTAG base class providing TAP control and IR/DR shifting.
Definition jtag.hpp:37
virtual ErrorCode ShiftDR(uint32_t bits, const uint8_t *in_lsb_first, uint8_t *out_lsb_first)=0
Shift DR, LSB first.
virtual ErrorCode ShiftIR(uint32_t bits, const uint8_t *in_lsb_first, uint8_t *out_lsb_first)=0
Shift IR, LSB first.
ErrorCode
定义错误码枚举
@ SIZE_ERR
尺寸错误 | Size error
@ OK
操作成功 | Operation successful
JTAG 设备链配置 / JTAG device chain configuration.
const uint8_t * ir_length
各设备 IR 长度数组 / IR length array
uint8_t count
设备数(TDO 端为 index=0)/ Device count (TDO side index=0)
uint32_t ir_before_bits_len
前面设备 IR 总位数 / IR bits before
uint32_t ir_after_bits_len
后面设备 IR 总位数 / IR bits after
uint8_t index
当前设备索引 / Current device index
JTAG 传输请求 / JTAG transfer request.
Port port
目标端口(DP/AP)/ Target port (DP/AP)
JTAG 传输响应 / JTAG transfer response.
uint32_t rdata
读数据(仅读响应有效)/ Read data (valid for read responses)