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