rogue
Loading...
Searching...
No Matches
JtagDriver.cpp
Go to the documentation of this file.
1
18#include "rogue/Directives.h"
19
21
22#include <arpa/inet.h>
23
24#include <cinttypes>
25#include <climits>
26#include <cmath>
27#include <cstdio>
28#include <cstring>
29#include <memory>
30
32
33#ifndef NO_PYTHON
34 #include <boost/python.hpp>
35namespace bp = boost::python;
36#endif
37
39rpx::JtagDriverPtr rpx::JtagDriver::create(uint16_t port) {
40 // Create shared_ptr
41 rpx::JtagDriverPtr r = std::make_shared<rpx::JtagDriver>(port);
42 return (r);
43}
44
45rpx::JtagDriver::JtagDriver(uint16_t port)
46 : port_(port),
47 drEn_(false),
48 done_{false},
49 drop_(0),
50 log_(nullptr),
51 wordSize_(sizeof(Header)),
52 memDepth_(1),
53 bufSz_(2048),
54 retry_(10),
55 xid_(0),
56 periodNs_(UNKNOWN_PERIOD) {
57 // start out with an initial header size; it might be increased
58 // once we contacted the server...
59 txBuf_.resize(bufSz_);
60 hdBuf_.resize(hdBufMax());
61
62 // Create logger
63 log_ = rogue::Logging::create("xilinx.jtag");
64}
65
66rpx::JtagDriver::Header rpx::JtagDriver::newXid() {
67 if (XID_ANY == ++xid_) ++xid_;
68
69 return (static_cast<Header>(xid_)) << XID_SHIFT;
70}
71
72rpx::JtagDriver::Xid rpx::JtagDriver::getXid(Header x) {
73 return static_cast<Xid>((x >> 20) & 0xff);
74}
75
76uint32_t rpx::JtagDriver::getCmd(Header x) {
77 return x & CMD_MASK;
78}
79
80unsigned rpx::JtagDriver::getErr(Header x) {
81 if (getCmd(x) != CMD_E) return 0;
82
83 return (x & ERR_MASK) >> ERR_SHIFT;
84}
85
86uint64_t rpx::JtagDriver::getLen(Header x) {
87 if (getCmd(x) != CMD_S)
88 throw(
89 rogue::GeneralError::create("JtagDriver::getLen()", "Cannot extract length from non-shift command header"));
90
91 return ((x & LEN_MASK) >> LEN_SHIFT) + 1;
92}
93
94const char* rpx::JtagDriver::getMsg(unsigned e) {
95 switch (e) {
96 case 0:
97 return "NO ERROR";
98 case ERR_BAD_VERSION:
99 return "Unsupported Protocol Version";
100 case ERR_BAD_COMMAND:
101 return "Unsupported Command";
102 case ERR_TRUNCATED:
103 return "Truncated Message";
104 case ERR_NOT_PRESENT:
105 return "XVC Support not Instantiated in Firmware";
106 default:
107 break;
108 }
109 return nullptr;
110}
111
112rpx::JtagDriver::Header rpx::JtagDriver::mkQuery() {
113 return PVERS | CMD_Q | XID_ANY;
114}
115
116rpx::JtagDriver::Header rpx::JtagDriver::mkShift(unsigned len) {
117 if (len == 0)
118 throw(rogue::GeneralError::create("JtagDriver::mkShift()", "shift length must be > 0"));
119 len = len - 1;
120 return PVERS | CMD_S | newXid() | ((len & LEN_MASK) << LEN_SHIFT);
121}
122
123unsigned rpx::JtagDriver::wordSize(Header reply) {
124 return (reply & 0x0000000f) + 1;
125}
126
127unsigned rpx::JtagDriver::memDepth(Header reply) {
128 return (reply >> 4) & 0xffff;
129}
130
131uint32_t rpx::JtagDriver::cvtPerNs(Header reply) {
132 unsigned rawVal = (reply >> XID_SHIFT) & 0xff;
133
134 if (0 == rawVal) {
135 return UNKNOWN_PERIOD;
136 }
137
138 double tmp = static_cast<double>(rawVal) * 4.0 / 256.0;
139
140 return static_cast<uint32_t>(std::round(std::pow(10.0, tmp) * 1.0E9 / REF_FREQ_HZ()));
141}
142
143unsigned rpx::JtagDriver::getWordSize() {
144 return wordSize_;
145}
146
147unsigned rpx::JtagDriver::getMemDepth() {
148 return memDepth_;
149}
150
151rpx::JtagDriver::Header rpx::JtagDriver::getHdr(const uint8_t* buf) {
152 Header hdr{};
153 memcpy(&hdr, buf, sizeof(hdr));
154 if (!isLE()) {
155 hdr = ntohl(hdr);
156 }
157 return hdr;
158}
159
160void rpx::JtagDriver::setHdr(uint8_t* buf, Header hdr) {
161 unsigned ws = getWordSize();
162 if (static_cast<size_t>(ws) < sizeof(hdr))
163 throw(rogue::GeneralError::create("JtagDriver::setHdr()", "wordSize %u < header size %zu", ws, sizeof(hdr)));
164 unsigned empty = ws - static_cast<unsigned>(sizeof(hdr));
165
166 if (!isLE()) {
167 hdr = ntohl(hdr); // just use for byte-swap
168 }
169 memcpy(buf, &hdr, sizeof(hdr));
170 memset(buf + sizeof(hdr), 0, empty);
171}
172
173void rpx::JtagDriver::init() {
174 // obtain server parameters
175 query();
176}
177
178int rpx::JtagDriver::xferRel(uint8_t* txb, unsigned txBytes, Header* phdr, uint8_t* rxb, unsigned sizeBytes) {
179 Xid xid = getXid(getHdr(txb));
180 int got = 0;
181
182 for (unsigned attempt = 0; attempt <= retry_; attempt++) {
183 // Check if thread should exit
184 if (this->done_.load(std::memory_order_acquire)) break;
185
186 // Start data transfer with retry and timeout
187 Header hdr{};
188 try {
189 got = xfer(txb, txBytes, &hdBuf_[0], getWordSize(), rxb, sizeBytes);
190 hdr = getHdr(&hdBuf_[0]);
191
192 unsigned e = getErr(hdr);
193 if (e) {
194 char errb[256];
195 const char* msg = getMsg(e);
196
197 int pos = snprintf(errb, sizeof(errb), "Got error response from server -- ");
198 if (pos < 0) pos = 0;
199 if (static_cast<size_t>(pos) >= sizeof(errb)) pos = static_cast<int>(sizeof(errb) - 1);
200 size_t remaining = sizeof(errb) - static_cast<size_t>(pos);
201
202 if (msg)
203 snprintf(errb + pos, remaining, "%s", msg);
204 else
205 snprintf(errb + pos, remaining, "error %u", e);
206
207 throw(rogue::GeneralError::create("JtagDriver::xferRel()", "%s", errb));
208 }
209 if (xid == XID_ANY || xid == getXid(hdr)) {
210 if (phdr) {
211 *phdr = hdr;
212 }
213 return got;
214 }
215 } catch (rogue::GeneralError&) {}
216 }
217 if (!this->done_.load(std::memory_order_acquire))
218 throw(rogue::GeneralError::create("JtagDriver::xferRel()", "Timeout error"));
219
220 return (0);
221}
222
223uint64_t rpx::JtagDriver::query() {
224 Header hdr{};
225
226 setHdr(&txBuf_[0], mkQuery());
227
228 xferRel(&txBuf_[0], getWordSize(), &hdr, nullptr, 0);
229 wordSize_ = wordSize(hdr);
230
231 if (static_cast<size_t>(wordSize_) < sizeof(hdr)) {
232 log_->debug("Encountered an error. Please ensure the board is powered up.\n");
233 throw(rogue::GeneralError::create("JtagDriver::query()",
234 "Received invalid word size. Please ensure the board is powered up.\n"));
235 }
236
237 memDepth_ = memDepth(hdr);
238 periodNs_ = cvtPerNs(hdr);
239
240 log_->debug("Query result: wordSize %u, memDepth %u, period %" PRIu32 " ns\n",
241 wordSize_,
242 memDepth_,
243 periodNs_);
244
245 if (0 == memDepth_)
246 retry_ = 0;
247 else
248 retry_ = 10;
249
250 uint64_t siz64 = (2ULL * static_cast<uint64_t>(memDepth_) + 1) * static_cast<uint64_t>(wordSize_);
251 if (siz64 > UINT_MAX)
252 throw(rogue::GeneralError::create("JtagDriver::query()", "buffer size overflows unsigned"));
253 unsigned siz = static_cast<unsigned>(siz64);
254 if (siz > bufSz_) {
255 bufSz_ = siz;
256 txBuf_.resize(bufSz_);
257 }
258
259 return static_cast<uint64_t>(memDepth_) * static_cast<uint64_t>(wordSize_);
260}
261
262uint32_t rpx::JtagDriver::getPeriodNs() {
263 return periodNs_;
264}
265
266uint32_t rpx::JtagDriver::setPeriodNs(uint32_t requestedPeriod) {
267 uint32_t currentPeriod = getPeriodNs();
268
269 if (0 == requestedPeriod) return currentPeriod;
270
271 return UNKNOWN_PERIOD == currentPeriod ? requestedPeriod : currentPeriod;
272}
273
274void rpx::JtagDriver::sendVectors(uint64_t bits, uint8_t* tms, uint8_t* tdi, uint8_t* tdo) {
275 if (bits == 0 || bits > LEN_MASK + 1)
276 throw(rogue::GeneralError::create("JtagDriver::sendVectors()",
277 "bit count %" PRIu64 " out of range [1, %u]", bits, static_cast<unsigned>(LEN_MASK + 1)));
278
279 unsigned wsz = getWordSize();
280 uint64_t bytesCeil = (bits + 7) / 8;
281 unsigned wholeWords = static_cast<unsigned>(bytesCeil / wsz);
282 unsigned wholeWordBytes = wholeWords * wsz;
283 unsigned wordCeilBytes = static_cast<unsigned>(((bytesCeil + wsz - 1) / wsz) * wsz);
284 unsigned bytesLeft = static_cast<unsigned>(bytesCeil - wholeWordBytes);
285 unsigned bytesTot = wsz + 2 * wordCeilBytes;
286
287 if (bytesTot > bufSz_)
288 throw(rogue::GeneralError::create("JtagDriver::sendVectors()",
289 "bytesTot %u exceeds buffer size %u", bytesTot, bufSz_));
290
291 log_->debug("sendVec -- bits %" PRIu64 ", bytes %" PRIu64 ", bytesTot %u\n", bits, bytesCeil, bytesTot);
292
293 setHdr(&txBuf_[0], mkShift(static_cast<unsigned>(bits)));
294
295 // reformat
296 uint8_t* wp = &txBuf_[0] + wsz; // past header
297
298 // store sequence of TMS/TDI pairs; word-by-word
299 unsigned idx = 0;
300 for (idx = 0; idx < wholeWordBytes; idx += wsz) {
301 memcpy(wp, &tms[idx], wsz);
302 wp += wsz;
303 memcpy(wp, &tdi[idx], wsz);
304 wp += wsz;
305 }
306 if (bytesLeft) {
307 memcpy(wp, &tms[idx], bytesLeft);
308 memcpy(wp + wsz, &tdi[idx], bytesLeft);
309 }
310 xferRel(&txBuf_[0], bytesTot, nullptr, tdo, static_cast<unsigned>(bytesCeil));
311}
312
313void rpx::JtagDriver::dumpInfo(FILE* f) {
314 fprintf(f, "Word size: %" PRIu64 "\n", static_cast<uint64_t>(getWordSize()));
315 fprintf(f,
316 "Target Memory Depth (bytes) %" PRIu64 "\n",
317 static_cast<uint64_t>(getWordSize()) * static_cast<uint64_t>(getMemDepth()));
318 fprintf(f, "Max. Vector Length (bytes) %" PRIu64 "\n", getMaxVectorSize());
319 fprintf(f, "TCK Period (ns) %" PRIu64 "\n", static_cast<uint64_t>(getPeriodNs()));
320}
321
322void rpx::JtagDriver::setup_python() {
323#ifndef NO_PYTHON
324
325 bp::class_<rpx::JtagDriver, rpx::JtagDriverPtr, boost::noncopyable>("JtagDriver", bp::init<uint16_t>());
326#endif
327}
Generic Rogue exception type.
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
Definition Logging.cpp:95
std::shared_ptr< rogue::Logging > log_
Definition JtagDriver.h:76
unsigned hdBufMax()
Maximum temporary header buffer size in bytes.
Definition JtagDriver.h:302
std::shared_ptr< rogue::protocols::xilinx::JtagDriver > JtagDriverPtr
Definition JtagDriver.h:307