rogue
Loading...
Searching...
No Matches
Master.cpp
Go to the documentation of this file.
1
17#include "rogue/Directives.h"
18
20
21#include <inttypes.h>
22
23#include <cstdlib>
24#include <cstring>
25#include <memory>
26#include <string>
27
28#include "rogue/GeneralError.h"
29#include "rogue/GilRelease.h"
30#include "rogue/Helpers.h"
31#include "rogue/ScopedGil.h"
35
37
38#ifndef NO_PYTHON
39 #include <boost/python.hpp>
40namespace bp = boost::python;
41#endif
42
44rim::MasterPtr rim::Master::create() {
45 rim::MasterPtr m = std::make_shared<rim::Master>();
46 return (m);
47}
48
49void rim::Master::setup_python() {
50#ifndef NO_PYTHON
51 bp::class_<rim::Master, rim::MasterPtr, boost::noncopyable>("Master", bp::init<>())
52 .def("_setSlave", &rim::Master::setSlave)
53 .def("_getSlave", &rim::Master::getSlave)
54 .def("_reqSlaveId", &rim::Master::reqSlaveId)
55 .def("_reqSlaveName", &rim::Master::reqSlaveName)
56 .def("_reqMinAccess", &rim::Master::reqMinAccess)
57 .def("_reqMaxAccess", &rim::Master::reqMaxAccess)
58 .def("_reqAddress", &rim::Master::reqAddress)
59 .def("_getError", &rim::Master::getError)
60 .def("_clearError", &rim::Master::clearError)
61 .def("_setTimeout", &rim::Master::setTimeout)
62 .def("_reqTransaction", &rim::Master::reqTransactionPy)
63 .def("_waitTransaction", &rim::Master::waitTransaction)
64 .def("_copyBits", &rim::Master::copyBits)
65 .staticmethod("_copyBits")
66 .def("_setBits", &rim::Master::setBits)
67 .staticmethod("_setBits")
68 .def("_anyBits", &rim::Master::anyBits)
69 .staticmethod("_anyBits")
70 .def("__rshift__", &rim::Master::rshiftPy)
71 .def("_stop", &rim::Master::stop);
72#endif
73}
74
76rim::Master::Master() {
77 error_ = "";
78 slave_ = rim::Slave::create(4, 0); // Empty placeholder
79
80 rogue::defaultTimeout(sumTime_);
81
82 log_ = rogue::Logging::create("memory.Master");
83}
84
86rim::Master::~Master() {}
87
89void rim::Master::stop() {}
90
92void rim::Master::setSlave(rim::SlavePtr slave) {
94 std::lock_guard<std::mutex> lock(mastMtx_);
95 slave_ = slave;
96}
97
99rim::SlavePtr rim::Master::getSlave() {
100 return (slave_);
101}
102
104uint32_t rim::Master::reqSlaveId() {
105 return (slave_->doSlaveId());
106}
107
109std::string rim::Master::reqSlaveName() {
110 return (slave_->doSlaveName());
111}
112
114uint32_t rim::Master::reqMinAccess() {
115 return (slave_->doMinAccess());
116}
117
119uint32_t rim::Master::reqMaxAccess() {
120 return (slave_->doMaxAccess());
121}
122
124uint64_t rim::Master::reqAddress() {
125 return (slave_->doAddress());
126}
127
129std::string rim::Master::getError() {
130 return error_;
131}
132
134void rim::Master::clearError() {
135 rogue::GilRelease noGil;
136 std::lock_guard<std::mutex> lock(mastMtx_);
137 error_ = "";
138}
139
141void rim::Master::setTimeout(uint64_t timeout) {
142 rogue::GilRelease noGil;
143 std::lock_guard<std::mutex> lock(mastMtx_);
144
145 if (timeout != 0) {
146 div_t divResult = div(timeout, 1000000);
147 sumTime_.tv_sec = divResult.quot;
148 sumTime_.tv_usec = divResult.rem;
149 }
150}
151
153uint32_t rim::Master::reqTransaction(uint64_t address, uint32_t size, void* data, uint32_t type) {
154 rim::TransactionPtr tran = rim::Transaction::create(sumTime_);
155
156 tran->iter_ = reinterpret_cast<uint8_t*>(data);
157 tran->size_ = size;
158 tran->address_ = address;
159 tran->type_ = type;
160
161 return (intTransaction(tran));
162}
163
164#ifndef NO_PYTHON
165
167uint32_t rim::Master::reqTransactionPy(uint64_t address,
168 boost::python::object p,
169 uint32_t size,
170 uint32_t offset,
171 uint32_t type) {
172 rim::TransactionPtr tran = rim::Transaction::create(sumTime_);
173
174 if ((type == rim::Read) || (type == rim::Verify)) {
175 if (PyObject_GetBuffer(p.ptr(), &(tran->pyBuf_), PyBUF_CONTIG) < 0)
176 throw(rogue::GeneralError("Master::reqTransactionPy", "Python Buffer contig Error"));
177 } else {
178 if (PyObject_GetBuffer(p.ptr(), &(tran->pyBuf_), PyBUF_SIMPLE) < 0)
179 throw(rogue::GeneralError("Master::reqTransactionPy", "Python Buffer simple Error"));
180 }
181
182 if (size == 0)
183 tran->size_ = tran->pyBuf_.len;
184 else
185 tran->size_ = size;
186
187 if ((tran->size_ + offset) > tran->pyBuf_.len) {
188 PyBuffer_Release(&(tran->pyBuf_));
189 throw(rogue::GeneralError::create("Master::reqTransactionPy",
190 "Attempt to access %" PRIu32 " bytes in python buffer with size %" PRIu32
191 " at offset %" PRIu32,
192 tran->size_,
193 tran->pyBuf_.len,
194 offset));
195 }
196
197 tran->pyValid_ = true;
198 tran->iter_ = reinterpret_cast<uint8_t*>(tran->pyBuf_.buf) + offset;
199 tran->type_ = type;
200 tran->address_ = address;
201
202 return (intTransaction(tran));
203}
204
205#endif
206
207uint32_t rim::Master::intTransaction(rim::TransactionPtr tran) {
208 TransactionMap::iterator it;
209 struct timeval currTime;
210 rim::SlavePtr slave;
211
212 {
213 rogue::GilRelease noGil;
214 std::lock_guard<std::mutex> lock(mastMtx_);
215 slave = slave_;
216 tranMap_[tran->id_] = tran;
217 }
218
219 log_->debug("Request transaction type=%" PRIu32 " id=%" PRIu32, tran->type_, tran->id_);
220 tran->log_->debug("Created transaction type=%" PRIu32 " id=%" PRIu32 ", address=0x%016" PRIx64 ", size=%" PRIu32,
221 tran->type_,
222 tran->id_,
223 tran->address_,
224 tran->size_);
225 slave->doTransaction(tran);
226 tran->refreshTimer(tran);
227 return (tran->id_);
228}
229
230// Wait for transaction. Timeout in seconds
231void rim::Master::waitTransaction(uint32_t id) {
232 TransactionMap::iterator it;
234 std::string error;
235
236 rogue::GilRelease noGil;
237 while (1) {
238 { // Lock the vector
239 std::unique_lock<std::mutex> lock(mastMtx_);
240 if (id != 0)
241 it = tranMap_.find(id);
242 else
243 it = tranMap_.begin();
244
245 if (it != tranMap_.end()) {
246 tran = it->second;
247 tranMap_.erase(it);
248 } else {
249 break;
250 }
251 }
252
253 // Outside of lock
254 if ((error = tran->wait()) != "") error_ = error;
255 }
256}
257
259void rim::Master::copyBits(uint8_t* dstData, uint32_t dstLsb, uint8_t* srcData, uint32_t srcLsb, uint32_t size) {
260 uint32_t srcBit;
261 uint32_t srcByte;
262 uint32_t dstBit;
263 uint32_t dstByte;
264 uint32_t rem;
265 uint32_t bytes;
266
267 srcByte = srcLsb / 8;
268 srcBit = srcLsb % 8;
269 dstByte = dstLsb / 8;
270 dstBit = dstLsb % 8;
271 rem = size;
272
273 if (rem == 0) return;
274
275 do {
276 bytes = rem / 8;
277
278 // Aligned
279 if ((srcBit == 0) && (dstBit == 0) && (bytes > 0)) {
280 std::memcpy(&(dstData[dstByte]), &(srcData[srcByte]), bytes);
281 dstByte += bytes;
282 srcByte += bytes;
283 rem -= (bytes * 8);
284
285 // Not aligned
286 } else {
287 dstData[dstByte] &= ((0x1 << dstBit) ^ 0xFF);
288 dstData[dstByte] |= ((srcData[srcByte] >> srcBit) & 0x1) << dstBit;
289 srcByte += (++srcBit / 8);
290 dstByte += (++dstBit / 8);
291 srcBit %= 8;
292 dstBit %= 8;
293 rem -= 1;
294 }
295 } while (rem != 0);
296}
297
298#ifndef NO_PYTHON
299
301void rim::Master::copyBitsPy(boost::python::object dst,
302 uint32_t dstLsb,
303 boost::python::object src,
304 uint32_t srcLsb,
305 uint32_t size) {
306 Py_buffer srcBuf;
307 Py_buffer dstBuf;
308
309 if (PyObject_GetBuffer(dst.ptr(), &dstBuf, PyBUF_CONTIG) < 0)
310 throw(rogue::GeneralError("Master::copyBits", "Python Buffer Error"));
311
312 if ((dstLsb + size) > (dstBuf.len * 8)) {
313 PyBuffer_Release(&dstBuf);
314 throw(rogue::GeneralError::create("Master::copyBits",
315 "Attempt to copy %" PRIu32 " bits starting from bit %" PRIu32
316 " from dest array with bitSize %" PRIu32,
317 size,
318 dstLsb,
319 dstBuf.len * 8));
320 }
321
322 if (PyObject_GetBuffer(src.ptr(), &srcBuf, PyBUF_SIMPLE) < 0) {
323 PyBuffer_Release(&dstBuf);
324 throw(rogue::GeneralError("Master::copyBits", "Python Buffer Error"));
325 }
326
327 if ((srcLsb + size) > (srcBuf.len * 8)) {
328 PyBuffer_Release(&srcBuf);
329 PyBuffer_Release(&dstBuf);
330 throw(rogue::GeneralError::create("Master::copyBits",
331 "Attempt to copy %" PRIu32 " bits starting from bit %" PRIu32
332 " from source array with bitSize %" PRIu32,
333 size,
334 srcLsb,
335 srcBuf.len * 8));
336 }
337
338 copyBits(reinterpret_cast<uint8_t*>(dstBuf.buf), dstLsb, reinterpret_cast<uint8_t*>(srcBuf.buf), srcLsb, size);
339
340 PyBuffer_Release(&srcBuf);
341 PyBuffer_Release(&dstBuf);
342}
343
344#endif
345
347void rim::Master::setBits(uint8_t* dstData, uint32_t lsb, uint32_t size) {
348 uint32_t dstBit;
349 uint32_t dstByte;
350 uint32_t rem;
351 uint32_t bytes;
352
353 dstByte = lsb / 8;
354 dstBit = lsb % 8;
355 rem = size;
356
357 if (rem == 0) return;
358
359 do {
360 bytes = rem / 8;
361
362 // Aligned
363 if ((dstBit == 0) && (bytes > 0)) {
364 memset(&(dstData[dstByte]), 0xFF, bytes);
365 dstByte += bytes;
366 rem -= (bytes * 8);
367
368 // Not aligned
369 } else {
370 dstData[dstByte] |= (0x1 << dstBit);
371 dstByte += (++dstBit / 8);
372 dstBit %= 8;
373 rem -= 1;
374 }
375 } while (rem != 0);
376}
377
378#ifndef NO_PYTHON
379
381void rim::Master::setBitsPy(boost::python::object dst, uint32_t lsb, uint32_t size) {
382 Py_buffer dstBuf;
383
384 if (PyObject_GetBuffer(dst.ptr(), &dstBuf, PyBUF_CONTIG) < 0)
385 throw(rogue::GeneralError("Master::setBits", "Python Buffer Error"));
386
387 if ((lsb + size) > (dstBuf.len * 8)) {
388 PyBuffer_Release(&dstBuf);
389 throw(rogue::GeneralError::create("Master::setBits",
390 "Attempt to set %" PRIu32 " bits starting from bit %" PRIu32
391 " in array with bitSize %" PRIu32,
392 size,
393 lsb,
394 dstBuf.len * 8));
395 }
396
397 setBits(reinterpret_cast<uint8_t*>(dstBuf.buf), lsb, size);
398
399 PyBuffer_Release(&dstBuf);
400}
401
402#endif
403
405bool rim::Master::anyBits(uint8_t* dstData, uint32_t lsb, uint32_t size) {
406 uint32_t dstBit;
407 uint32_t dstByte;
408 uint32_t rem;
409 uint32_t bytes;
410 bool ret;
411
412 dstByte = lsb / 8;
413 dstBit = lsb % 8;
414 rem = size;
415 ret = false;
416
417 if (rem == 0) return false;
418
419 do {
420 bytes = rem / 8;
421
422 // Aligned
423 if ((dstBit == 0) && (bytes > 0)) {
424 if (dstData[dstByte] != 0) ret = true;
425 dstByte += 1;
426 rem -= 8;
427
428 // Not aligned
429 } else {
430 if ((dstData[dstByte] & (0x1 << dstBit)) != 0) ret = true;
431 dstByte += (++dstBit / 8);
432 dstBit %= 8;
433 rem -= 1;
434 }
435 } while (ret == false && rem != 0);
436
437 return ret;
438}
439
440#ifndef NO_PYTHON
441
443bool rim::Master::anyBitsPy(boost::python::object dst, uint32_t lsb, uint32_t size) {
444 Py_buffer dstBuf;
445 bool ret;
446
447 if (PyObject_GetBuffer(dst.ptr(), &dstBuf, PyBUF_SIMPLE) < 0)
448 throw(rogue::GeneralError("Master::anyBits", "Python Buffer Error"));
449
450 if ((lsb + size) > (dstBuf.len * 8)) {
451 PyBuffer_Release(&dstBuf);
452 throw(rogue::GeneralError::create("Master::anyBits",
453 "Attempt to access %" PRIu32 " bits starting from bit %" PRIu32
454 " from array with bitSize %" PRIu32,
455 size,
456 lsb,
457 dstBuf.len * 8));
458 }
459
460 ret = anyBits(reinterpret_cast<uint8_t*>(dstBuf.buf), lsb, size);
461
462 PyBuffer_Release(&dstBuf);
463 return ret;
464}
465
466void rim::Master::rshiftPy(bp::object p) {
467 rim::SlavePtr slv;
468
469 // First Attempt to access object as a memory slave
470 boost::python::extract<rim::SlavePtr> get_slave(p);
471
472 // Test extraction
473 if (get_slave.check()) {
474 slv = get_slave();
475
476 // Otherwise look for indirect call
477 } else if (PyObject_HasAttrString(p.ptr(), "_getMemorySlave")) {
478 // Attempt to convert returned object to slave pointer
479 boost::python::extract<rim::SlavePtr> get_slave(p.attr("_getMemorySlave")());
480
481 // Test extraction
482 if (get_slave.check()) slv = get_slave();
483 }
484
485 // Success
486 if (slv != NULL)
487 setSlave(slv);
488 else
489 throw(rogue::GeneralError::create("memory::Master::rshiftPy",
490 "Attempt to use >> operator with incompatible memory slave"));
491}
492
493#endif
494
496rim::SlavePtr& rim::Master::operator>>(rim::SlavePtr& other) {
497 setSlave(other);
498 return other;
499}
Generic Rogue exception type.
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
RAII helper that releases the Python GIL for a scope.
Definition GilRelease.h:36
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::interfaces::memory::Slave > SlavePtr
Shared pointer alias for Slave.
Definition Slave.h:310
std::shared_ptr< rogue::interfaces::memory::Master > MasterPtr
Shared pointer alias for Master.
Definition Master.h:410
static const uint32_t Read
Memory read transaction type.
Definition Constants.h:36
std::shared_ptr< rogue::interfaces::memory::Transaction > TransactionPtr
Shared pointer alias for Transaction.
static const uint32_t Verify
Memory verify readback transaction type.
Definition Constants.h:57
void defaultTimeout(struct timeval &tout)
Returns Rogue default timeout as a timeval.
Definition Helpers.h:49