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 do {
274 bytes = rem / 8;
275
276 // Aligned
277 if ((srcBit == 0) && (dstBit == 0) && (bytes > 0)) {
278 std::memcpy(&(dstData[dstByte]), &(srcData[srcByte]), bytes);
279 dstByte += bytes;
280 srcByte += bytes;
281 rem -= (bytes * 8);
282
283 // Not aligned
284 } else {
285 dstData[dstByte] &= ((0x1 << dstBit) ^ 0xFF);
286 dstData[dstByte] |= ((srcData[srcByte] >> srcBit) & 0x1) << dstBit;
287 srcByte += (++srcBit / 8);
288 dstByte += (++dstBit / 8);
289 srcBit %= 8;
290 dstBit %= 8;
291 rem -= 1;
292 }
293 } while (rem != 0);
294}
295
296#ifndef NO_PYTHON
297
299void rim::Master::copyBitsPy(boost::python::object dst,
300 uint32_t dstLsb,
301 boost::python::object src,
302 uint32_t srcLsb,
303 uint32_t size) {
304 Py_buffer srcBuf;
305 Py_buffer dstBuf;
306
307 if (PyObject_GetBuffer(dst.ptr(), &dstBuf, PyBUF_CONTIG) < 0)
308 throw(rogue::GeneralError("Master::copyBits", "Python Buffer Error"));
309
310 if ((dstLsb + size) > (dstBuf.len * 8)) {
311 PyBuffer_Release(&dstBuf);
312 throw(rogue::GeneralError::create("Master::copyBits",
313 "Attempt to copy %" PRIu32 " bits starting from bit %" PRIu32
314 " from dest array with bitSize %" PRIu32,
315 size,
316 dstLsb,
317 dstBuf.len * 8));
318 }
319
320 if (PyObject_GetBuffer(src.ptr(), &srcBuf, PyBUF_SIMPLE) < 0) {
321 PyBuffer_Release(&dstBuf);
322 throw(rogue::GeneralError("Master::copyBits", "Python Buffer Error"));
323 }
324
325 if ((srcLsb + size) > (srcBuf.len * 8)) {
326 PyBuffer_Release(&srcBuf);
327 PyBuffer_Release(&dstBuf);
328 throw(rogue::GeneralError::create("Master::copyBits",
329 "Attempt to copy %" PRIu32 " bits starting from bit %" PRIu32
330 " from source array with bitSize %" PRIu32,
331 size,
332 srcLsb,
333 srcBuf.len * 8));
334 }
335
336 copyBits(reinterpret_cast<uint8_t*>(dstBuf.buf), dstLsb, reinterpret_cast<uint8_t*>(srcBuf.buf), srcLsb, size);
337
338 PyBuffer_Release(&srcBuf);
339 PyBuffer_Release(&dstBuf);
340}
341
342#endif
343
345void rim::Master::setBits(uint8_t* dstData, uint32_t lsb, uint32_t size) {
346 uint32_t dstBit;
347 uint32_t dstByte;
348 uint32_t rem;
349 uint32_t bytes;
350
351 dstByte = lsb / 8;
352 dstBit = lsb % 8;
353 rem = size;
354
355 do {
356 bytes = rem / 8;
357
358 // Aligned
359 if ((dstBit == 0) && (bytes > 0)) {
360 memset(&(dstData[dstByte]), 0xFF, bytes);
361 dstByte += bytes;
362 rem -= (bytes * 8);
363
364 // Not aligned
365 } else {
366 dstData[dstByte] |= (0x1 << dstBit);
367 dstByte += (++dstBit / 8);
368 dstBit %= 8;
369 rem -= 1;
370 }
371 } while (rem != 0);
372}
373
374#ifndef NO_PYTHON
375
377void rim::Master::setBitsPy(boost::python::object dst, uint32_t lsb, uint32_t size) {
378 Py_buffer dstBuf;
379
380 if (PyObject_GetBuffer(dst.ptr(), &dstBuf, PyBUF_CONTIG) < 0)
381 throw(rogue::GeneralError("Master::setBits", "Python Buffer Error"));
382
383 if ((lsb + size) > (dstBuf.len * 8)) {
384 PyBuffer_Release(&dstBuf);
385 throw(rogue::GeneralError::create("Master::setBits",
386 "Attempt to set %" PRIu32 " bits starting from bit %" PRIu32
387 " in array with bitSize %" PRIu32,
388 size,
389 lsb,
390 dstBuf.len * 8));
391 }
392
393 setBits(reinterpret_cast<uint8_t*>(dstBuf.buf), lsb, size);
394
395 PyBuffer_Release(&dstBuf);
396}
397
398#endif
399
401bool rim::Master::anyBits(uint8_t* dstData, uint32_t lsb, uint32_t size) {
402 uint32_t dstBit;
403 uint32_t dstByte;
404 uint32_t rem;
405 uint32_t bytes;
406 bool ret;
407
408 dstByte = lsb / 8;
409 dstBit = lsb % 8;
410 rem = size;
411 ret = false;
412
413 do {
414 bytes = rem / 8;
415
416 // Aligned
417 if ((dstBit == 0) && (bytes > 0)) {
418 if (dstData[dstByte] != 0) ret = true;
419 dstByte += 1;
420 rem -= 8;
421
422 // Not aligned
423 } else {
424 if ((dstData[dstByte] & (0x1 << dstBit)) != 0) ret = true;
425 dstByte += (++dstBit / 8);
426 dstBit %= 8;
427 rem -= 1;
428 }
429 } while (ret == false && rem != 0);
430
431 return ret;
432}
433
434#ifndef NO_PYTHON
435
437bool rim::Master::anyBitsPy(boost::python::object dst, uint32_t lsb, uint32_t size) {
438 Py_buffer dstBuf;
439 bool ret;
440
441 if (PyObject_GetBuffer(dst.ptr(), &dstBuf, PyBUF_SIMPLE) < 0)
442 throw(rogue::GeneralError("Master::anyBits", "Python Buffer Error"));
443
444 if ((lsb + size) > (dstBuf.len * 8)) {
445 PyBuffer_Release(&dstBuf);
446 throw(rogue::GeneralError::create("Master::anyBits",
447 "Attempt to access %" PRIu32 " bits starting from bit %" PRIu32
448 " from array with bitSize %" PRIu32,
449 size,
450 lsb,
451 dstBuf.len * 8));
452 }
453
454 ret = anyBits(reinterpret_cast<uint8_t*>(dstBuf.buf), lsb, size);
455
456 PyBuffer_Release(&dstBuf);
457 return ret;
458}
459
460void rim::Master::rshiftPy(bp::object p) {
461 rim::SlavePtr slv;
462
463 // First Attempt to access object as a memory slave
464 boost::python::extract<rim::SlavePtr> get_slave(p);
465
466 // Test extraction
467 if (get_slave.check()) {
468 slv = get_slave();
469
470 // Otherwise look for indirect call
471 } else if (PyObject_HasAttrString(p.ptr(), "_getMemorySlave")) {
472 // Attempt to convert returned object to slave pointer
473 boost::python::extract<rim::SlavePtr> get_slave(p.attr("_getMemorySlave")());
474
475 // Test extraction
476 if (get_slave.check()) slv = get_slave();
477 }
478
479 // Success
480 if (slv != NULL)
481 setSlave(slv);
482 else
483 throw(rogue::GeneralError::create("memory::Master::rshiftPy",
484 "Attempt to use >> operator with incompatible memory slave"));
485}
486
487#endif
488
490rim::SlavePtr& rim::Master::operator>>(rim::SlavePtr& other) {
491 setSlave(other);
492 return other;
493}
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:60
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