rogue
Loading...
Searching...
No Matches
Block.cpp
Go to the documentation of this file.
1
18#include "rogue/Directives.h"
19
20#ifndef NO_PYTHON
21
22#define NO_IMPORT_ARRAY
23#include "rogue/numpy.h"
24#include <boost/python.hpp>
25
26namespace bp = boost::python;
27
28#endif
29
31
32#include <inttypes.h>
33#include <sys/time.h>
34
35#include <cmath>
36#include <cstdio>
37#include <cstring>
38#include <exception>
39#include <iomanip>
40#include <memory>
41#include <sstream>
42#include <string>
43#include <vector>
44
45#include "rogue/GeneralError.h"
46#include "rogue/GilRelease.h"
47#include "rogue/ScopedGil.h"
52
54
55
56// Class factory which returns a pointer to a Block (BlockPtr)
57rim::BlockPtr rim::Block::create(uint64_t offset, uint32_t size) {
58 rim::BlockPtr b = std::make_shared<rim::Block>(offset, size);
59 return (b);
60}
61
62#ifndef NO_PYTHON
63// Setup class for use in python
64void rim::Block::setup_python() {
65 bp::class_<rim::Block, rim::BlockPtr, bp::bases<rim::Master>, boost::noncopyable>("Block",
66 bp::init<uint64_t, uint32_t>())
67 .add_property("path", &rim::Block::path)
68 .add_property("mode", &rim::Block::mode)
69 .add_property("bulkOpEn", &rim::Block::bulkOpEn)
70 .add_property("offset", &rim::Block::offset)
71 .add_property("address", &rim::Block::address)
72 .add_property("size", &rim::Block::size)
73 .def("setEnable", &rim::Block::setEnable)
74 .def("_startTransaction", &rim::Block::startTransactionPy)
75 .def("_checkTransaction", &rim::Block::checkTransactionPy)
76 .def("addVariables", &rim::Block::addVariablesPy)
77 .def("_rateTest", &rim::Block::rateTest)
78 .add_property("variables", &rim::Block::variablesPy);
79
80 bp::implicitly_convertible<rim::BlockPtr, rim::MasterPtr>();
81}
82#endif
83
84// Create a Hub device with a given offset
85rim::Block::Block(uint64_t offset, uint32_t size) {
86 path_ = "Undefined";
87 mode_ = "RW";
88 bulkOpEn_ = false;
89 updateEn_ = false;
90 offset_ = offset;
91 size_ = size;
92 verifyEn_ = false;
93 verifyReq_ = false;
94 verifyInp_ = false;
95 doUpdate_ = false;
96 blockPyTrans_ = false;
97 enable_ = false;
98 stale_ = false;
99 retryCount_ = 0;
100
101 verifyBase_ = 0; // Verify Range
102 verifySize_ = 0; // Verify Range
103
104 blockData_ = reinterpret_cast<uint8_t*>(malloc(size_));
105 memset(blockData_, 0, size_);
106
107 verifyData_ = reinterpret_cast<uint8_t*>(malloc(size_));
108 memset(verifyData_, 0, size_);
109
110 verifyMask_ = reinterpret_cast<uint8_t*>(malloc(size_));
111 memset(verifyMask_, 0, size_);
112
113 verifyBlock_ = reinterpret_cast<uint8_t*>(malloc(size_));
114 memset(verifyBlock_, 0, size_);
115
116 expectedData_ = reinterpret_cast<uint8_t*>(malloc(size_));
117 memset(expectedData_, 0, size_);
118}
119
120// Destroy the Hub
121rim::Block::~Block() {
122 // Custom clean
123 customClean();
124
125 free(blockData_);
126 free(verifyData_);
127 free(verifyMask_);
128 free(verifyBlock_);
129 free(expectedData_);
130}
131
132// Return the path of the block
133std::string rim::Block::path() {
134 return path_;
135}
136
137// Return the mode of the block
138std::string rim::Block::mode() {
139 return mode_;
140}
141
142// Return bulk enable flag
143bool rim::Block::bulkOpEn() {
144 return bulkOpEn_;
145}
146
147// Set enable state
148void rim::Block::setEnable(bool newState) {
149 rogue::GilRelease noGil;
150 std::lock_guard<std::mutex> lock(mtx_);
151 enable_ = newState;
152}
153
154// Get offset of this Block
155uint64_t rim::Block::offset() {
156 return offset_;
157}
158
159// Get full address of this Block
160uint64_t rim::Block::address() {
161 return (reqAddress() + offset_);
162}
163
164// Get size of this block in bytes.
165uint32_t rim::Block::size() {
166 return size_;
167}
168
169// Block transactions
170bool rim::Block::blockPyTrans() {
171 return blockPyTrans_;
172}
173
174// Start a transaction for this block
175void rim::Block::intStartTransaction(uint32_t type, bool forceWr, bool check, rim::Variable* var, int32_t index) {
176 uint32_t x;
177 uint32_t tOff;
178 uint32_t tSize;
179 uint8_t* tData;
180 uint32_t highByte;
181 uint32_t lowByte;
182 uint32_t minAccess = getSlave()->doMinAccess();
183
184 std::vector<rim::VariablePtr>::iterator vit;
185
186 // Check for valid combinations
187 if ((type == rim::Write && ((mode_ == "RO") || (!stale_ && !forceWr))) || (type == rim::Post && (mode_ == "RO")) ||
188 (type == rim::Read && ((mode_ == "WO") || stale_)) ||
189 (type == rim::Verify && ((mode_ == "WO") || (mode_ == "RO") || stale_ || !verifyReq_)))
190 return;
191 {
192 rogue::GilRelease noGil;
193 std::lock_guard<std::mutex> lock(mtx_);
194 waitTransaction(0);
195 clearError();
196
197 // Determine transaction range
198 if (var == NULL) {
199 lowByte = 0;
200 highByte = size_ - 1;
201 if (type == rim::Write || type == rim::Post) {
202 stale_ = false;
203 for (vit = variables_.begin(); vit != variables_.end(); ++vit) {
204 (*vit)->stale_ = false;
205 }
206 }
207 } else {
208 if (type == rim::Read || type == rim::Verify) {
209 if (index < 0 || index >= var->numValues_) {
210 lowByte = var->lowTranByte_[0];
211
212 if (var->numValues_ == 0) {
213 highByte = var->highTranByte_[0];
214 } else {
215 highByte = var->highTranByte_[var->numValues_ - 1];
216 }
217 } else {
218 lowByte = var->lowTranByte_[index];
219 highByte = var->highTranByte_[index];
220 }
221 } else {
222 lowByte = var->staleLowByte_;
223 highByte = var->staleHighByte_;
224
225 // Catch case where fewer stale bytes than min access or non-aligned
226 if (lowByte % minAccess != 0) lowByte -= lowByte % minAccess;
227 if ((highByte + 1) % minAccess != 0) highByte += minAccess - ((highByte + 1) % minAccess);
228 stale_ = false;
229 for (vit = variables_.begin(); vit != variables_.end(); ++vit) {
230 if ((*vit)->stale_) {
231 if ((*vit)->staleLowByte_ < lowByte) lowByte = (*vit)->staleLowByte_;
232 if ((*vit)->staleHighByte_ > highByte) highByte = (*vit)->staleHighByte_;
233 (*vit)->stale_ = false;
234 }
235 }
236 }
237 }
238
239 // Device is disabled, check after clearing stale states
240 if (!enable_) return;
241
242 // Setup verify data, clear verify write flag if verify transaction
243 if (type == rim::Verify) {
244 tOff = verifyBase_;
245 tSize = verifySize_;
246 tData = verifyData_ + verifyBase_;
247 verifyInp_ = true;
248
249 // Not a verify transaction
250 } else {
251 // Derive offset and size based upon min transaction size
252 tOff = lowByte;
253 tSize = (highByte - lowByte) + 1;
254
255 // Set transaction pointer
256 tData = blockData_ + tOff;
257
258 // Track verify after writes.
259 // Only verify blocks that have been written since last verify
260 if (type == rim::Write) {
261 verifyBase_ = tOff;
262 verifySize_ = tSize;
263 verifyReq_ = verifyEn_;
264
265 // Snapshot expected data at write time so that concurrent
266 // modifications to blockData_ do not cause false verify failures
267 memcpy(expectedData_ + tOff, blockData_ + tOff, tSize);
268 }
269 }
270 doUpdate_ = updateEn_;
271
272 bLog_->debug("Start transaction type = %" PRIu32 ", Offset=0x%" PRIx64 ", lByte=%" PRIu32 ", hByte=%" PRIu32
273 ", tOff=0x%" PRIx32 ", tSize=%" PRIu32,
274 type,
275 offset_,
276 lowByte,
277 highByte,
278 tOff,
279 tSize);
280
281 // Start transaction
282 reqTransaction(offset_ + tOff, tSize, tData, type);
283 }
284}
285
286// Start a transaction for this block, cpp version
287void rim::Block::startTransaction(uint32_t type, bool forceWr, bool check, rim::Variable* var, int32_t index) {
288 uint32_t count;
289 bool fWr;
290
291 count = 0;
292 fWr = forceWr;
293
294 do {
295 intStartTransaction(type, fWr, check, var, index);
296
297 try {
298 if (check || retryCount_ > 0) checkTransaction();
299 count = retryCount_; // Success
300 } catch (rogue::GeneralError err) {
301 fWr = true; // Stale state is now lost
302
303 // Rethrow the error if this is the final retry, else log warning
304 if ((count + 1) > retryCount_) {
305 bLog_->error("Error on try %" PRIu32 " out of %" PRIu32 ": %s",
306 (count + 1),
307 (retryCount_ + 1),
308 err.what());
309 throw err;
310 } else {
311 bLog_->warning("Error on try %" PRIu32 " out of %" PRIu32 ": %s",
312 (count + 1),
313 (retryCount_ + 1),
314 err.what());
315 }
316 }
317 } while (count++ < retryCount_);
318}
319
320#ifndef NO_PYTHON
321
322// Start a transaction for this block, python version
323void rim::Block::startTransactionPy(uint32_t type, bool forceWr, bool check, rim::VariablePtr var, int32_t index) {
324 uint32_t count;
325 bool upd;
326 bool fWr;
327
328 if (blockPyTrans_) return;
329
330 count = 0;
331 upd = false;
332 fWr = forceWr;
333
334 do {
335 intStartTransaction(type, fWr, check, var.get(), index);
336
337 try {
338 if (check || retryCount_ > 0) upd = checkTransaction();
339 count = retryCount_; // Success
340 } catch (rogue::GeneralError err) {
341 fWr = true; // Stale state is now lost
342
343 // Rethrow the error if this is the final retry, else log warning
344 if ((count + 1) > retryCount_) {
345 bLog_->error("Error on try %" PRIu32 " out of %" PRIu32 ": %s",
346 (count + 1),
347 (retryCount_ + 1),
348 err.what());
349 throw err;
350 } else {
351 bLog_->warning("Error on try %" PRIu32 " out of %" PRIu32 ": %s",
352 (count + 1),
353 (retryCount_ + 1),
354 err.what());
355 }
356 }
357 } while (count++ < retryCount_);
358
359 if (upd) varUpdate();
360}
361
362#endif
363
364// Check transaction result
365bool rim::Block::checkTransaction() {
366 std::string err;
367 bool locUpdate;
368 uint32_t x;
369
370 {
371 rogue::GilRelease noGil;
372 std::lock_guard<std::mutex> lock(mtx_);
373 waitTransaction(0);
374
375 err = getError();
376 clearError();
377
378 if (err != "") {
379 throw(rogue::GeneralError::create("Block::checkTransaction",
380 "Transaction error for block %s with address 0x%.8x. Error %s",
381 path_.c_str(),
382 address(),
383 err.c_str()));
384 }
385
386 // Device is disabled
387 if (!enable_) return false;
388
389 // Check verify data if verifyInp is set
390 if (verifyInp_) {
391 bLog_->debug("Verfying data. Base=0x%" PRIx32 ", size=%" PRIu32, verifyBase_, verifySize_);
392 verifyReq_ = false;
393 verifyInp_ = false;
394
395 for (x = verifyBase_; x < verifyBase_ + verifySize_; x++) {
396 if ((verifyData_[x] & verifyMask_[x]) != (expectedData_[x] & verifyMask_[x])) {
397 throw(rogue::GeneralError::create("Block::checkTransaction",
398 "Verify error for block %s with address 0x%.8" PRIx64
399 ". Byte: %" PRIu32 ". Got: 0x%.2" PRIx8 ", Exp: 0x%.2" PRIx8
400 ", Mask: 0x%.2" PRIx8,
401 path_.c_str(),
402 address(),
403 x,
404 verifyData_[x],
405 expectedData_[x],
406 verifyMask_[x]));
407 }
408 }
409 }
410 bLog_->debug("Transaction complete");
411
412 locUpdate = doUpdate_;
413 doUpdate_ = false;
414 }
415 return locUpdate;
416}
417
418#ifndef NO_PYTHON
419
420// Check transaction result
421void rim::Block::checkTransactionPy() {
422 if (blockPyTrans_) return;
423
424 if (checkTransaction()) varUpdate();
425}
426
427#endif
428
429// Write sequence
430void rim::Block::write(rim::Variable* var, int32_t index) {
431 startTransaction(rim::Write, true, false, var, index);
432 startTransaction(rim::Verify, false, false, var, index);
433 checkTransaction();
434}
435
436// Read sequence
437void rim::Block::read(rim::Variable* var, int32_t index) {
438 startTransaction(rim::Read, false, false, var, index);
439 checkTransaction();
440}
441
442#ifndef NO_PYTHON
443
444// Call variable update for all variables
445void rim::Block::varUpdate() {
446 std::vector<rim::VariablePtr>::iterator vit;
447
449
450 for (vit = variables_.begin(); vit != variables_.end(); ++vit) {
451 if ((*vit)->updateNotify_) (*vit)->queueUpdate();
452 }
453}
454
455#endif
456
457// Add variables to block
458void rim::Block::addVariables(std::vector<rim::VariablePtr> variables) {
459 std::vector<rim::VariablePtr>::iterator vit;
460
461 uint32_t x;
462
463 uint8_t excMask[size_];
464 uint8_t oleMask[size_];
465
466 memset(excMask, 0, size_);
467 memset(oleMask, 0, size_);
468
469 variables_ = variables;
470
471 for (vit = variables_.begin(); vit != variables_.end(); ++vit) {
472 (*vit)->block_ = this;
473
474 if (vit == variables_.begin()) {
475 path_ = (*vit)->path_;
476 std::string logName = "memory.block." + path_;
477 bLog_ = rogue::Logging::create(logName.c_str());
478 mode_ = (*vit)->mode_;
479 }
480
481 if ((*vit)->bulkOpEn_) bulkOpEn_ = true;
482 if ((*vit)->updateNotify_) updateEn_ = true;
483
484 // Retry count
485 if ((*vit)->retryCount_ > retryCount_) retryCount_ = (*vit)->retryCount_;
486
487 // If variable modes mismatch, set block to read/write
488 if (mode_ != (*vit)->mode_) mode_ = "RW";
489
490 // Update variable masks for standard variable
491 if ((*vit)->numValues_ == 0) {
492 for (x = 0; x < (*vit)->bitOffset_.size(); x++) {
493 // Variable allows overlaps, add to overlap enable mask
494 if ((*vit)->overlapEn_) {
495 setBits(oleMask, (*vit)->bitOffset_[x], (*vit)->bitSize_[x]);
496
497 // Otherwise add to exclusive mask and check for existing mapping
498 } else {
499 if (anyBits(excMask, (*vit)->bitOffset_[x], (*vit)->bitSize_[x]))
501 "Block::addVariables",
502 "Variable bit overlap detected for block %s with address 0x%.8x and variable %s",
503 path_.c_str(),
504 address(),
505 (*vit)->name_.c_str()));
506
507 setBits(excMask, (*vit)->bitOffset_[x], (*vit)->bitSize_[x]);
508 }
509
510 // update verify mask
511 if ((*vit)->mode_ == "RW" && (*vit)->verifyEn_) {
512 verifyEn_ = true;
513 setBits(verifyMask_, (*vit)->bitOffset_[x], (*vit)->bitSize_[x]);
514 }
515
516 // update verify block
517 if ((*vit)->mode_ == "RO" || (*vit)->mode_ == "WO" || !(*vit)->verifyEn_) {
518 setBits(verifyBlock_, (*vit)->bitOffset_[x], (*vit)->bitSize_[x]);
519 }
520
521 bLog_->debug(
522 "Adding variable %s to block %s at offset 0x%.8x, bitIdx=%i, bitOffset %i, bitSize %i, mode %s, "
523 "verifyEn "
524 "%d " PRIx64,
525 (*vit)->name_.c_str(),
526 path_.c_str(),
527 offset_,
528 x,
529 (*vit)->bitOffset_[x],
530 (*vit)->bitSize_[x],
531 (*vit)->mode_.c_str(),
532 (*vit)->verifyEn_);
533 }
534
535 // List variables
536 } else {
537 for (x = 0; x < (*vit)->numValues_; x++) {
538 // Variable allows overlaps, add to overlap enable mask
539 if ((*vit)->overlapEn_) {
540 setBits(oleMask, x * (*vit)->valueStride_ + (*vit)->bitOffset_[0], (*vit)->valueBits_);
541
542 // Otherwise add to exclusive mask and check for existing mapping
543 } else {
544 if (anyBits(excMask, x * (*vit)->valueStride_ + (*vit)->bitOffset_[0], (*vit)->valueBits_))
546 "Block::addVariables",
547 "Variable bit overlap detected for block %s with address 0x%.8x and variable %s",
548 path_.c_str(),
549 address(),
550 (*vit)->name_.c_str()));
551
552 setBits(excMask, x * (*vit)->valueStride_ + (*vit)->bitOffset_[0], (*vit)->valueBits_);
553 }
554
555 // update verify mask
556 if ((*vit)->mode_ == "RW" && (*vit)->verifyEn_) {
557 verifyEn_ = true;
558 setBits(verifyMask_, x * (*vit)->valueStride_ + (*vit)->bitOffset_[0], (*vit)->valueBits_);
559 }
560
561 // update verify block
562 if ((*vit)->mode_ == "RO" || (*vit)->mode_ == "WO" || !(*vit)->verifyEn_) {
563 setBits(verifyBlock_, x * (*vit)->valueStride_ + (*vit)->bitOffset_[0], (*vit)->valueBits_);
564 }
565
566 bLog_->debug(
567 "Adding variable %s to block %s at offset 0x%.8x, index=%i, valueOffset=%i, valueBits %i, mode %s, "
568 "verifyEn %d",
569 (*vit)->name_.c_str(),
570 path_.c_str(),
571 offset_,
572 x,
573 x * (*vit)->valueStride_ + (*vit)->bitOffset_[0],
574 (*vit)->valueBits_,
575 (*vit)->mode_.c_str(),
576 (*vit)->verifyEn_);
577 }
578 }
579 }
580
581 // Check for overlaps by anding exclusive and overlap bit vectors
582 for (x = 0; x < size_; x++) {
583 if (oleMask[x] & excMask[x])
584 throw(rogue::GeneralError::create("Block::addVariables",
585 "Variable bit mask overlap detected for block %s with address 0x%.8x",
586 path_.c_str(),
587 address()));
588
589 // Update very mask using verify block
590 verifyMask_[x] &= (verifyBlock_[x] ^ 0xFF);
591 }
592
593 // Execute custom init
594 customInit();
595
596 // Debug the results of the build
597 std::stringstream ss;
598 uint32_t rem = size_;
599 uint32_t idx;
600 idx = 0;
601 x = 0;
602
603 while (rem > 0) {
604 ss << "0x" << std::setfill('0') << std::hex << std::setw(2) << static_cast<uint32_t>(verifyMask_[x]) << " ";
605 x++;
606 rem--;
607 if (rem == 0 || x % 10 == 0) {
608 bLog_->debug("Done adding variables. Verify Mask %.3i - %.3i: %s", idx, x - 1, ss.str().c_str());
609 ss.str("");
610 idx = x;
611 }
612 }
613}
614
615#ifndef NO_PYTHON
616
617// Add variables to block
618void rim::Block::addVariablesPy(bp::object variables) {
619 std::vector<rim::VariablePtr> vars = py_list_to_std_vector<rim::VariablePtr>(variables);
620 addVariables(vars);
621}
622
623#endif
624
626std::vector<rim::VariablePtr> rim::Block::variables() {
627 return variables_;
628}
629
630#ifndef NO_PYTHON
631
633bp::object rim::Block::variablesPy() {
634 return std_vector_to_py_list<rim::VariablePtr>(variables_);
635}
636
637#endif
638
639// byte reverse
640void rim::Block::reverseBytes(uint8_t* data, uint32_t byteSize) {
641 uint32_t x;
642 uint8_t tmp;
643
644 for (x = 0; x < byteSize / 2; x++) {
645 tmp = data[x];
646 data[x] = data[byteSize - x - 1];
647 data[byteSize - x - 1] = tmp;
648 }
649}
650
651// Set data from pointer to internal staged memory
652void rim::Block::setBytes(const uint8_t* data, rim::Variable* var, uint32_t index) {
653 uint32_t srcBit;
654 uint32_t x;
655 uint8_t tmp;
656 uint8_t* buff;
657
658 rogue::GilRelease noGil;
659 std::lock_guard<std::mutex> lock(mtx_);
660
661 // Set stale flag
662 if (var->mode_ != "RO") stale_ = true;
663
664 // Change byte order, need to make a copy
665 if (var->byteReverse_) {
666 buff = reinterpret_cast<uint8_t*>(malloc(var->valueBytes_));
667 memcpy(buff, data, var->valueBytes_);
668 reverseBytes(buff, var->valueBytes_);
669 } else {
670 buff = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(data));
671 }
672
673 // List variable
674 if (var->numValues_ != 0) {
675 // Verify range
676 if (index < 0 || index >= var->numValues_)
677 throw(rogue::GeneralError::create("Block::setBytes",
678 "Index %" PRIu32 " is out of range for %s",
679 index,
680 var->name_.c_str()));
681
682 // Fast copy
683 if (var->fastByte_ != NULL)
684 memcpy(blockData_ + var->fastByte_[index], buff, var->valueBytes_);
685
686 else
687 copyBits(blockData_, var->bitOffset_[0] + (index * var->valueStride_), buff, 0, var->valueBits_);
688
689 if (var->mode_ != "RO") {
690 if (var->stale_) {
691 if (var->lowTranByte_[index] < var->staleLowByte_) var->staleLowByte_ = var->lowTranByte_[index];
692
693 if (var->highTranByte_[index] > var->staleHighByte_) var->staleHighByte_ = var->highTranByte_[index];
694 } else {
695 var->staleLowByte_ = var->lowTranByte_[index];
696 var->staleHighByte_ = var->highTranByte_[index];
697 }
698 }
699
700 // Standard variable
701 } else {
702 if (var->mode_ != "RO") {
703 var->staleLowByte_ = var->lowTranByte_[0];
704 var->staleHighByte_ = var->highTranByte_[0];
705 }
706
707 // Fast copy
708 if (var->fastByte_ != NULL) {
709 memcpy(blockData_ + var->fastByte_[0], buff, var->valueBytes_);
710
711 } else if (var->bitOffset_.size() == 1) {
712 copyBits(blockData_, var->bitOffset_[0], buff, 0, var->bitSize_[0]);
713
714 } else {
715 srcBit = 0;
716 for (x = 0; x < var->bitOffset_.size(); x++) {
717 copyBits(blockData_, var->bitOffset_[x], buff, srcBit, var->bitSize_[x]);
718 srcBit += var->bitSize_[x];
719 }
720 }
721 }
722 if ( var->mode_ != "RO" ) var->stale_ = true;
723 if (var->byteReverse_) free(buff);
724}
725
726// Get data to pointer from internal block or staged memory
727void rim::Block::getBytes(uint8_t* data, rim::Variable* var, uint32_t index) {
728 uint32_t dstBit;
729 uint32_t x;
730
731 rogue::GilRelease noGil;
732 std::lock_guard<std::mutex> lock(mtx_);
733
734 // List variable
735 if (var->numValues_ != 0) {
736 // Verify range
737 if (index < 0 || index >= var->numValues_)
738 throw(rogue::GeneralError::create("Block::getBytes",
739 "Index %" PRIu32 " is out of range for %s",
740 index,
741 var->name_.c_str()));
742
743 // Fast copy
744 if (var->fastByte_ != NULL)
745 memcpy(data, blockData_ + var->fastByte_[index], var->valueBytes_);
746
747 else
748 copyBits(data, 0, blockData_, var->bitOffset_[0] + (index * var->valueStride_), var->valueBits_);
749
750 } else {
751 // Fast copy
752 if (var->fastByte_ != NULL) {
753 memcpy(data, blockData_ + var->fastByte_[0], var->valueBytes_);
754
755 } else if (var->bitOffset_.size() == 1) {
756 copyBits(data, 0, blockData_, var->bitOffset_[0], var->bitSize_[0]);
757
758 } else {
759 dstBit = 0;
760 for (x = 0; x < var->bitOffset_.size(); x++) {
761 copyBits(data, dstBit, blockData_, var->bitOffset_[x], var->bitSize_[x]);
762 dstBit += var->bitSize_[x];
763 }
764 }
765 }
766
767 // Change byte order
768 if (var->byteReverse_) {
769 reverseBytes(data, var->valueBytes_);
770 }
771}
772
774// Python functions
776
777#ifndef NO_PYTHON
778
779// Set data using python function
780void rim::Block::setPyFunc(bp::object& value, rim::Variable* var, int32_t index) {
781 uint32_t x;
782 Py_buffer valueBuf;
783 bp::object tmp;
784
785 if (index == -1) index = 0;
786
787 // Passed value is a numpy value
788 if (PyArray_Check(value.ptr())) {
789 throw(rogue::GeneralError::create("Block::setPyFunc",
790 "Passing ndarray not supported for %s",
791 var->name_.c_str()));
792
793 // Is passed value a list
794 } else if (PyList_Check(value.ptr())) {
795 bp::list vl = bp::extract<bp::list>(value);
796 uint32_t vlen = len(vl);
797
798 if ((index + vlen) > var->numValues_)
799 throw(rogue::GeneralError::create("Block::setPyFunc",
800 "Overflow error for passed array with length %" PRIu32
801 " at index %" PRIu32 ". Variable length = %" PRIu32 " for %s",
802 vlen,
803 index,
804 var->numValues_,
805 var->name_.c_str()));
806
807 for (x = 0; x < vlen; x++) {
808 tmp = vl[x];
809 bp::object ret = ((rim::VariableWrap*)var)->toBytes(tmp);
810
811 if (PyObject_GetBuffer(ret.ptr(), &(valueBuf), PyBUF_SIMPLE) < 0)
812 throw(rogue::GeneralError::create("Block::setPyFunc",
813 "Failed to extract byte array for %s",
814 var->name_.c_str()));
815
816 setBytes(reinterpret_cast<uint8_t*>(valueBuf.buf), var, index + x);
817 PyBuffer_Release(&valueBuf);
818 }
819
820 // Single value
821 } else {
822 // Call python function
823 bp::object ret = ((rim::VariableWrap*)var)->toBytes(value);
824
825 if (PyObject_GetBuffer(ret.ptr(), &(valueBuf), PyBUF_SIMPLE) < 0)
826 throw(rogue::GeneralError::create("Block::setPyFunc",
827 "Failed to extract byte array from pyFunc return value for %s",
828 var->name_.c_str()));
829
830 setBytes(reinterpret_cast<uint8_t*>(valueBuf.buf), var, index);
831 PyBuffer_Release(&valueBuf);
832 }
833}
834
835// Get data using python function
836bp::object rim::Block::getPyFunc(rim::Variable* var, int32_t index) {
837 uint8_t getBuffer[var->valueBytes_];
838
839 // Unindexed with a list variable not supported
840 if (index < 0 && var->numValues_ > 0) {
841 throw(rogue::GeneralError::create("Block::getPyFunc",
842 "Accessing unindexed value not support for %s",
843 var->name_.c_str()));
844
845 // Single value
846 } else {
847 memset(getBuffer, 0, var->valueBytes_);
848
849 getBytes(getBuffer, var, index);
850 PyObject* val = Py_BuildValue("y#", getBuffer, var->valueBytes_);
851
852 if (val == NULL) throw(rogue::GeneralError::create("Block::getPyFunc", "Failed to generate bytearray"));
853
854 bp::handle<> handle(val);
855 bp::object pass = bp::object(handle);
856
857 return ((rim::VariableWrap*)var)->fromBytes(pass);
858 }
859}
860
861#endif
862
864// Byte Array
866
867#ifndef NO_PYTHON
868
869// Set data using byte array
870void rim::Block::setByteArrayPy(bp::object& value, rim::Variable* var, int32_t index) {
871 Py_buffer valueBuf;
872
873 // Unindexed with a list variable
874 if (index < 0 && var->numValues_ > 0)
875 throw(rogue::GeneralError::create("Block::setByteArrayPy",
876 "Accessing unindexed value not supported for %s",
877 var->name_.c_str()));
878
879 if (PyObject_GetBuffer(value.ptr(), &(valueBuf), PyBUF_SIMPLE) < 0)
880 throw(rogue::GeneralError::create("Block::setByteArray",
881 "Failed to extract byte array for %s",
882 var->name_.c_str()));
883
884 setBytes(reinterpret_cast<uint8_t*>(valueBuf.buf), var, index);
885 PyBuffer_Release(&valueBuf);
886}
887
888// Get data using byte array
889bp::object rim::Block::getByteArrayPy(rim::Variable* var, int32_t index) {
890 uint8_t getBuffer[var->valueBytes_];
891
892 // Unindexed with a list variable
893 if (index < 0 && var->numValues_ > 0)
894 throw(rogue::GeneralError::create("Block::setByteArrayPy",
895 "Accessing unindexed value not supported for %s",
896 var->name_.c_str()));
897
898 memset(getBuffer, 0, var->valueBytes_);
899
900 getBytes(getBuffer, var, index);
901 PyObject* val = Py_BuildValue("y#", getBuffer, var->valueBytes_);
902
903 if (val == NULL) throw(rogue::GeneralError::create("Block::setByteArrayPy", "Failed to generate bytearray"));
904
905 bp::handle<> handle(val);
906 return bp::object(handle);
907}
908
909#endif
910
911// Set data using byte array
912void rim::Block::setByteArray(const uint8_t* value, rim::Variable* var, int32_t index) {
913 setBytes(value, var, index);
914}
915
916// Get data using byte array
917void rim::Block::getByteArray(uint8_t* value, rim::Variable* var, int32_t index) {
918 getBytes(value, var, index);
919}
920
922// Unsigned Int
924
925#ifndef NO_PYTHON
926
927// Set data using unsigned int
928void rim::Block::setUIntPy(bp::object& value, rim::Variable* var, int32_t index) {
929 if (index == -1) index = 0;
930
931 // Lambda to process an array of unsigned values.
932 auto process_uint_array = [&](auto* src, npy_intp stride, npy_intp length) {
933 for (npy_intp i = 0; i < length; ++i) {
934 setUInt(src[i * stride], var, index + i);
935 }
936 };
937
938 // Passed value is a numpy value
939 if (PyArray_Check(value.ptr())) {
940 // Cast to an array object and check that the numpy array
941 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(value.ptr());
942 npy_intp ndims = PyArray_NDIM(arr);
943 npy_intp* dims = PyArray_SHAPE(arr);
944 npy_intp* strides = PyArray_STRIDES(arr);
945 if (ndims != 1)
946 throw(rogue::GeneralError::create("Block::setUIntPy",
947 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
948 ndims,
949 var->name_.c_str()));
950
951 if ((index + dims[0]) > var->numValues_)
952 throw(rogue::GeneralError::create("Block::setUIntPy",
953 "Overflow error for passed array with length %" PRIu32
954 " at index %" PRIu32 ". Variable length = %" PRIu32 " for %s",
955 dims[0],
956 index,
957 var->numValues_,
958 var->name_.c_str()));
959
960 int type = PyArray_TYPE(arr);
961 switch (type) {
962 case NPY_UINT64: {
963 uint64_t* src = reinterpret_cast<uint64_t*>(PyArray_DATA(arr));
964 npy_intp stride = strides[0] / sizeof(uint64_t);
965 process_uint_array(src, stride, dims[0]);
966 break;
967 }
968 case NPY_UINT32: {
969 uint32_t* src = reinterpret_cast<uint32_t*>(PyArray_DATA(arr));
970 npy_intp stride = strides[0] / sizeof(uint32_t);
971 process_uint_array(src, stride, dims[0]);
972 break;
973 }
974 case NPY_UINT16: {
975 uint16_t* src = reinterpret_cast<uint16_t*>(PyArray_DATA(arr));
976 npy_intp stride = strides[0] / sizeof(uint16_t);
977 process_uint_array(src, stride, dims[0]);
978 break;
979 }
980 case NPY_UINT8: {
981 uint8_t* src = reinterpret_cast<uint8_t*>(PyArray_DATA(arr));
982 npy_intp stride = strides[0] / sizeof(uint8_t);
983 process_uint_array(src, stride, dims[0]);
984 break;
985 }
986 default:
987 throw(rogue::GeneralError::create("Block::setUIntPy",
988 "Passed nparray is not of an accepted unsigned int type (uint64, uint32, uint16, uint8) for %s",
989 var->name_.c_str()));
990 }
991
992 // Is passed value a list
993 } else if (PyList_Check(value.ptr())) {
994 bp::list vl = bp::extract<bp::list>(value);
995 uint32_t vlen = len(vl);
996 if ((index + vlen) > var->numValues_)
997 throw(rogue::GeneralError::create("Block::setUIntPy",
998 "Overflow error for passed list with length %" PRIu32
999 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1000 vlen,
1001 index,
1002 var->numValues_,
1003 var->name_.c_str()));
1004 for (uint32_t i = 0; i < vlen; i++) {
1005 bp::extract<uint64_t> tmp(vl[i]);
1006 if (!tmp.check())
1007 throw(rogue::GeneralError::create("Block::setUIntPy",
1008 "Failed to extract value for %s.",
1009 var->name_.c_str()));
1010 setUInt(tmp, var, index + i);
1011 }
1012
1013 // Passed scalar numpy value
1014 } else if (PyArray_CheckScalar(value.ptr())) {
1015 int type_num = PyArray_DescrFromScalar(value.ptr())->type_num;
1016 switch (type_num) {
1017 case NPY_UINT64: {
1018 uint64_t val;
1019 PyArray_ScalarAsCtype(value.ptr(), &val);
1020 setUInt(val, var, index);
1021 break;
1022 }
1023 case NPY_UINT32: {
1024 uint32_t val;
1025 PyArray_ScalarAsCtype(value.ptr(), &val);
1026 setUInt(val, var, index);
1027 break;
1028 }
1029 case NPY_UINT16: {
1030 uint16_t val;
1031 PyArray_ScalarAsCtype(value.ptr(), &val);
1032 setUInt(val, var, index);
1033 break;
1034 }
1035 case NPY_UINT8: {
1036 uint8_t val;
1037 PyArray_ScalarAsCtype(value.ptr(), &val);
1038 setUInt(val, var, index);
1039 break;
1040 }
1041 default:
1042 throw(rogue::GeneralError::create("Block::setUIntPy",
1043 "Failed to extract scalar unsigned int value for %s.",
1044 var->name_.c_str()));
1045 }
1046 } else {
1047 bp::extract<uint64_t> tmp(value);
1048 if (!tmp.check())
1049 throw(rogue::GeneralError::create("Block::setUIntPy", "Failed to extract value for %s.", var->name_.c_str()));
1050 setUInt(tmp, var, index);
1051 }
1052}
1053
1054// Get data using unsigned int
1055bp::object rim::Block::getUIntPy(rim::Variable* var, int32_t index) {
1056 bp::object ret;
1057
1058 // Unindexed with a list variable
1059 if (index < 0 && var->numValues_ > 0) {
1060 // Create a numpy array to receive it and locate the destination data buffer
1061 npy_intp dims[1] = {var->numValues_};
1062 int npType;
1063 // Choose numpy type based on the variable's valueBits.
1064 if (var->valueBits_ <= 8) {
1065 npType = NPY_UINT8;
1066 } else if (var->valueBits_ <= 16) {
1067 npType = NPY_UINT16;
1068 } else if (var->valueBits_ <= 32) {
1069 npType = NPY_UINT32;
1070 } else {
1071 npType = NPY_UINT64;
1072 }
1073
1074 PyObject* obj = PyArray_SimpleNew(1, dims, npType);
1075 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
1076 uint32_t x;
1077 switch (npType) {
1078 case NPY_UINT8: {
1079 uint8_t* dst = reinterpret_cast<uint8_t*>(PyArray_DATA(arr));
1080 for (x = 0; x < var->numValues_; x++) {
1081 dst[x] = static_cast<uint8_t>(getUInt(var, x));
1082 }
1083 break;
1084 }
1085 case NPY_UINT16: {
1086 uint16_t* dst = reinterpret_cast<uint16_t*>(PyArray_DATA(arr));
1087 for (x = 0; x < var->numValues_; x++) {
1088 dst[x] = static_cast<uint16_t>(getUInt(var, x));
1089 }
1090 break;
1091 }
1092 case NPY_UINT32: {
1093 uint32_t* dst = reinterpret_cast<uint32_t*>(PyArray_DATA(arr));
1094 for (x = 0; x < var->numValues_; x++) {
1095 dst[x] = static_cast<uint32_t>(getUInt(var, x));
1096 }
1097 break;
1098 }
1099 case NPY_UINT64: {
1100 uint64_t* dst = reinterpret_cast<uint64_t*>(PyArray_DATA(arr));
1101 for (x = 0; x < var->numValues_; x++) {
1102 dst[x] = getUInt(var, x);
1103 }
1104 break;
1105 }
1106 }
1107 boost::python::handle<> handle(obj);
1108 ret = bp::object(handle);
1109 } else {
1110 PyObject* val = Py_BuildValue("K", getUInt(var, index));
1111 if (val == NULL)
1112 throw(rogue::GeneralError::create("Block::getUIntPy", "Failed to generate UInt"));
1113 bp::handle<> handle(val);
1114 ret = bp::object(handle);
1115 }
1116 return ret;
1117}
1118
1119#endif
1120
1121// Set data using unsigned int
1122void rim::Block::setUInt(const uint64_t& val, rim::Variable* var, int32_t index) {
1123 // Check range
1124 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
1125 throw(rogue::GeneralError::create("Block::setUInt",
1126 "Value range error for %s. Value=%" PRIu64 ", Min=%f, Max=%f",
1127 var->name_.c_str(),
1128 val,
1129 var->minValue_,
1130 var->maxValue_));
1131
1132 setBytes(reinterpret_cast<uint8_t*>(const_cast<uint64_t*>(&val)), var, index);
1133}
1134
1135// Get data using unsigned int
1136uint64_t rim::Block::getUInt(rim::Variable* var, int32_t index) {
1137 uint64_t tmp = 0;
1138
1139 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
1140
1141 return tmp;
1142}
1143
1145// Signed Int
1147
1148#ifndef NO_PYTHON
1149
1150// Set data using int
1151void rim::Block::setIntPy(bp::object& value, rim::Variable* var, int32_t index) {
1152 if (index == -1) index = 0;
1153
1154 // Lambda to process an array of signed values.
1155 auto process_int_array = [&](auto* src, npy_intp stride, npy_intp length) {
1156 for (npy_intp i = 0; i < length; ++i) {
1157 setInt(src[i * stride], var, index + i);
1158 }
1159 };
1160
1161 // Passed value is a numpy value
1162 if (PyArray_Check(value.ptr())) {
1163 // Cast to an array object and check that the numpy array
1164 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(value.ptr());
1165 npy_intp ndims = PyArray_NDIM(arr);
1166 npy_intp* dims = PyArray_SHAPE(arr);
1167 npy_intp* strides = PyArray_STRIDES(arr);
1168 if (ndims != 1)
1169 throw(rogue::GeneralError::create("Block::setIntPy",
1170 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
1171 ndims,
1172 var->name_.c_str()));
1173
1174 if ((index + dims[0]) > var->numValues_)
1175 throw(rogue::GeneralError::create("Block::setIntPy",
1176 "Overflow error for passed array with length %" PRIu32
1177 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1178 dims[0],
1179 index,
1180 var->numValues_,
1181 var->name_.c_str()));
1182
1183 int type = PyArray_TYPE(arr);
1184 switch (type) {
1185 case NPY_INT64: {
1186 int64_t* src = reinterpret_cast<int64_t*>(PyArray_DATA(arr));
1187 npy_intp stride = strides[0] / sizeof(int64_t);
1188 process_int_array(src, stride, dims[0]);
1189 break;
1190 }
1191 case NPY_INT32: {
1192 int32_t* src = reinterpret_cast<int32_t*>(PyArray_DATA(arr));
1193 npy_intp stride = strides[0] / sizeof(int32_t);
1194 process_int_array(src, stride, dims[0]);
1195 break;
1196 }
1197 case NPY_INT16: {
1198 int16_t* src = reinterpret_cast<int16_t*>(PyArray_DATA(arr));
1199 npy_intp stride = strides[0] / sizeof(int16_t);
1200 process_int_array(src, stride, dims[0]);
1201 break;
1202 }
1203 case NPY_INT8: {
1204 int8_t* src = reinterpret_cast<int8_t*>(PyArray_DATA(arr));
1205 npy_intp stride = strides[0] / sizeof(int8_t);
1206 process_int_array(src, stride, dims[0]);
1207 break;
1208 }
1209 default:
1210 throw(rogue::GeneralError::create("Block::setIntPy",
1211 "Passed nparray is not of an accepted signed int type (int64, int32, int16, int8) for %s",
1212 var->name_.c_str()));
1213 }
1214
1215 // Is passed value a list
1216 } else if (PyList_Check(value.ptr())) {
1217 bp::list vl = bp::extract<bp::list>(value);
1218 uint32_t vlen = len(vl);
1219
1220 if ((index + vlen) > var->numValues_)
1221 throw(rogue::GeneralError::create("Block::setIntPy",
1222 "Overflow error for passed list with length %" PRIu32
1223 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1224 vlen,
1225 index,
1226 var->numValues_,
1227 var->name_.c_str()));
1228 for (uint32_t i = 0; i < vlen; i++) {
1229 bp::extract<int64_t> tmp(vl[i]);
1230 if (!tmp.check())
1231 throw(rogue::GeneralError::create("Block::setIntPy",
1232 "Failed to extract value for %s.",
1233 var->name_.c_str()));
1234 setInt(tmp, var, index + i);
1235 }
1236
1237 // Passed scalar numpy value
1238 } else if (PyArray_CheckScalar(value.ptr())) {
1239 int type_num = PyArray_DescrFromScalar(value.ptr())->type_num;
1240 switch (type_num) {
1241 case NPY_INT64: {
1242 int64_t val;
1243 PyArray_ScalarAsCtype(value.ptr(), &val);
1244 setInt(val, var, index);
1245 break;
1246 }
1247 case NPY_INT32: {
1248 int32_t val;
1249 PyArray_ScalarAsCtype(value.ptr(), &val);
1250 setInt(val, var, index);
1251 break;
1252 }
1253 case NPY_INT16: {
1254 int16_t val;
1255 PyArray_ScalarAsCtype(value.ptr(), &val);
1256 setInt(val, var, index);
1257 break;
1258 }
1259 case NPY_INT8: {
1260 int8_t val;
1261 PyArray_ScalarAsCtype(value.ptr(), &val);
1262 setInt(val, var, index);
1263 break;
1264 }
1265 default:
1266 throw(rogue::GeneralError::create("Block::setIntPy",
1267 "Failed to extract scalar signed int value for %s.",
1268 var->name_.c_str()));
1269 }
1270 } else {
1271 bp::extract<int64_t> tmp(value);
1272
1273 if (!tmp.check())
1274 throw(rogue::GeneralError::create("Block::setIntPy", "Failed to extract value for %s.", var->name_.c_str()));
1275 setInt(tmp, var, index);
1276 }
1277}
1278
1279// Get data using int
1280bp::object rim::Block::getIntPy(rim::Variable* var, int32_t index) {
1281 bp::object ret;
1282
1283 // Unindexed with a list variable
1284 if (index < 0 && var->numValues_ > 0) {
1285 // Create a numpy array to receive it and locate the destination data buffer
1286 npy_intp dims[1] = {var->numValues_};
1287 int npType;
1288 if (var->valueBits_ <= 8) {
1289 npType = NPY_INT8;
1290 } else if (var->valueBits_ <= 16) {
1291 npType = NPY_INT16;
1292 } else if (var->valueBits_ <= 32) {
1293 npType = NPY_INT32;
1294 } else {
1295 npType = NPY_INT64;
1296 }
1297 PyObject* obj = PyArray_SimpleNew(1, dims, npType);
1298 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
1299 uint32_t x;
1300 switch (npType) {
1301 case NPY_INT8: {
1302 int8_t* dst = reinterpret_cast<int8_t*>(PyArray_DATA(arr));
1303 for (x = 0; x < var->numValues_; x++) {
1304 dst[x] = static_cast<int8_t>(getInt(var, x));
1305 }
1306 break;
1307 }
1308 case NPY_INT16: {
1309 int16_t* dst = reinterpret_cast<int16_t*>(PyArray_DATA(arr));
1310 for (x = 0; x < var->numValues_; x++) {
1311 dst[x] = static_cast<int16_t>(getInt(var, x));
1312 }
1313 break;
1314 }
1315 case NPY_INT32: {
1316 int32_t* dst = reinterpret_cast<int32_t*>(PyArray_DATA(arr));
1317 for (x = 0; x < var->numValues_; x++) {
1318 dst[x] = static_cast<int32_t>(getInt(var, x));
1319 }
1320 break;
1321 }
1322 case NPY_INT64: {
1323 int64_t* dst = reinterpret_cast<int64_t*>(PyArray_DATA(arr));
1324 for (x = 0; x < var->numValues_; x++) {
1325 dst[x] = getInt(var, x);
1326 }
1327 break;
1328 }
1329 }
1330 boost::python::handle<> handle(obj);
1331 ret = bp::object(handle);
1332 } else {
1333 PyObject* val = Py_BuildValue("L", getInt(var, index));
1334 if (val == NULL)
1335 throw(rogue::GeneralError::create("Block::getIntPy", "Failed to generate Int"));
1336 bp::handle<> handle(val);
1337 ret = bp::object(handle);
1338 }
1339 return ret;
1340}
1341
1342#endif
1343
1344// Set data using int
1345void rim::Block::setInt(const int64_t& val, rim::Variable* var, int32_t index) {
1346 // Check range
1347 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
1348 throw(rogue::GeneralError::create("Block::setInt",
1349 "Value range error for %s. Value=%" PRId64 ", Min=%f, Max=%f",
1350 var->name_.c_str(),
1351 val,
1352 var->minValue_,
1353 var->maxValue_));
1354
1355 // This works because all bits between the msb and bit 64 are set to '1' for a negative value
1356 setBytes(reinterpret_cast<uint8_t*>(const_cast<int64_t*>(&val)), var, index);
1357}
1358
1359// Get data using int
1360int64_t rim::Block::getInt(rim::Variable* var, int32_t index) {
1361 int64_t tmp = 0;
1362
1363 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
1364
1365 if (var->valueBits_ != 64) {
1366 if (tmp >= static_cast<uint64_t>(pow(2, var->valueBits_ - 1))) {
1367 tmp -= static_cast<uint64_t>(pow(2, var->valueBits_));
1368 }
1369 }
1370 return tmp;
1371}
1372
1374// Bool
1376
1377#ifndef NO_PYTHON
1378
1379// Set data using bool
1380void rim::Block::setBoolPy(bp::object& value, rim::Variable* var, int32_t index) {
1381 uint32_t x;
1382
1383 if (index == -1) index = 0;
1384
1385 // Passed value is a numpy value
1386 if (PyArray_Check(value.ptr())) {
1387 // Cast to an array object and check that the numpy array
1388 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
1389 npy_intp ndims = PyArray_NDIM(arr);
1390 npy_intp* dims = PyArray_SHAPE(arr);
1391 npy_intp* strides = PyArray_STRIDES(arr);
1392
1393 if (ndims != 1)
1394 throw(rogue::GeneralError::create("Block::setBoolPy",
1395 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
1396 ndims,
1397 var->name_.c_str()));
1398
1399 if ((index + dims[0]) > var->numValues_)
1400 throw(rogue::GeneralError::create("Block::setBoolPy",
1401 "Overflow error for passed array with length %" PRIu32
1402 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1403 dims[0],
1404 index,
1405 var->numValues_,
1406 var->name_.c_str()));
1407
1408 if (PyArray_TYPE(arr) == NPY_BOOL) {
1409 bool* src = reinterpret_cast<bool*>(PyArray_DATA(arr));
1410 npy_intp stride = strides[0] / sizeof(bool);
1411 for (x = 0; x < dims[0]; x++) {
1412 setBool(src[x * stride], var, index + x);
1413 }
1414 } else {
1415 throw(rogue::GeneralError::create("Block::setBoolPy",
1416 "Passed nparray is not of type (bool) for %s",
1417 var->name_.c_str()));
1418 }
1419
1420 // Is passed value a list
1421 } else if (PyList_Check(value.ptr())) {
1422 bp::list vl = bp::extract<bp::list>(value);
1423 uint32_t vlen = len(vl);
1424
1425 if ((index + vlen) > var->numValues_)
1426 throw(rogue::GeneralError::create("Block::setBoolPy",
1427 "Overflow error for passed array with length %" PRIu32
1428 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1429 vlen,
1430 index,
1431 var->numValues_,
1432 var->name_.c_str()));
1433
1434 for (x = 0; x < vlen; x++) {
1435 bp::extract<bool> tmp(vl[x]);
1436
1437 if (!tmp.check())
1438 throw(rogue::GeneralError::create("Block::setBoolPy",
1439 "Failed to extract value for %s.",
1440 var->name_.c_str()));
1441
1442 setBool(tmp, var, index + x);
1443 }
1444
1445 // Passed scalar numpy value
1446 } else if (PyArray_CheckScalar(value.ptr())) {
1447 if (PyArray_DescrFromScalar(value.ptr())->type_num == NPY_BOOL) {
1448 bool val;
1449 PyArray_ScalarAsCtype(value.ptr(), &val);
1450 setBool(val, var, index);
1451 } else {
1452 throw(
1453 rogue::GeneralError::create("Block::setBoolPy", "Failed to extract value for %s.", var->name_.c_str()));
1454 }
1455 } else {
1456 bp::extract<bool> tmp(value);
1457
1458 if (!tmp.check())
1459 throw(
1460 rogue::GeneralError::create("Block::setBoolPy", "Failed to extract value for %s.", var->name_.c_str()));
1461
1462 setBool(tmp, var, index);
1463 }
1464}
1465
1466// Get data using bool
1467bp::object rim::Block::getBoolPy(rim::Variable* var, int32_t index) {
1468 bp::object ret;
1469 uint32_t x;
1470
1471 // Unindexed with a list variable
1472 if (index < 0 && var->numValues_ > 0) {
1473 // Create a numpy array to receive it and locate the destination data buffer
1474 npy_intp dims[1] = {var->numValues_};
1475 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_BOOL);
1476 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
1477 bool* dst = reinterpret_cast<bool*>(PyArray_DATA(arr));
1478
1479 for (x = 0; x < var->numValues_; x++) dst[x] = getBool(var, x);
1480
1481 boost::python::handle<> handle(obj);
1482 ret = bp::object(handle);
1483
1484 } else {
1485 bp::handle<> handle(bp::borrowed(getBool(var, index) ? Py_True : Py_False));
1486 ret = bp::object(handle);
1487 }
1488 return ret;
1489}
1490
1491#endif
1492
1493// Set data using bool
1494void rim::Block::setBool(const bool& value, rim::Variable* var, int32_t index) {
1495 uint8_t val = (uint8_t)value;
1496 setBytes(reinterpret_cast<uint8_t*>(&val), var, index);
1497}
1498
1499// Get data using bool
1500bool rim::Block::getBool(rim::Variable* var, int32_t index) {
1501 uint8_t tmp = 0;
1502
1503 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
1504
1505 return tmp ? true : false;
1506}
1507
1509// String
1511
1512#ifndef NO_PYTHON
1513
1514// Set data using string
1515void rim::Block::setStringPy(bp::object& value, rim::Variable* var, int32_t index) {
1516 uint32_t x;
1517 std::string strVal;
1518
1519 // Unindexed with a list variable
1520 if (index < 0 && var->numValues_ > 0)
1521 throw(rogue::GeneralError::create("Block::setStringPy",
1522 "Using nparray not supported for %s",
1523 var->name_.c_str()));
1524
1525 bp::extract<char*> tmp(value);
1526
1527 if (!tmp.check())
1528 throw(rogue::GeneralError::create("Block::setStringPy", "Failed to extract value for %s.", var->name_.c_str()));
1529
1530 strVal = tmp;
1531 setString(strVal, var, index);
1532}
1533
1534// Get data using string
1535bp::object rim::Block::getStringPy(rim::Variable* var, int32_t index) {
1536 bp::object ret;
1537 std::string strVal;
1538 uint32_t x;
1539
1540 // Unindexed with a list variable
1541 if (index < 0 && var->numValues_ > 0)
1542 throw(
1543 rogue::GeneralError::create("Block::getStringPy", "Using ndarry not supported for %s", var->name_.c_str()));
1544
1545 getString(var, strVal, index);
1546 PyObject* val = Py_BuildValue("s", strVal.c_str());
1547
1548 if (val == NULL) throw(rogue::GeneralError::create("Block::getStringPy", "Failed to generate String"));
1549
1550 bp::handle<> handle(val);
1551 return bp::object(handle);
1552}
1553
1554#endif
1555
1556// Set data using string
1557void rim::Block::setString(const std::string& value, rim::Variable* var, int32_t index) {
1558 uint8_t getBuffer[var->valueBytes_];
1559
1560 memset(getBuffer, 0, var->valueBytes_);
1561
1562 strncpy(reinterpret_cast<char*>(getBuffer), value.c_str(), var->valueBytes_ - 1);
1563
1564 setBytes(getBuffer, var, index);
1565}
1566
1567// Get data using string
1568std::string rim::Block::getString(rim::Variable* var, int32_t index) {
1569 std::string ret;
1570 getString(var, ret, index);
1571 return ret;
1572}
1573
1574// Get data into string
1575void rim::Block::getString(rim::Variable* var, std::string& retString, int32_t index) {
1576 char getBuffer[var->valueBytes_ + 1];
1577
1578 memset(getBuffer, 0, var->valueBytes_ + 1);
1579
1580 getBytes(reinterpret_cast<uint8_t*>(getBuffer), var, index);
1581
1582 retString = getBuffer;
1583}
1584
1586// Float
1588
1589#ifndef NO_PYTHON
1590
1591// Set data using float
1592void rim::Block::setFloatPy(bp::object& value, rim::Variable* var, int32_t index) {
1593 uint32_t x;
1594
1595 if (index == -1) index = 0;
1596
1597 // Passed value is a numpy value
1598 if (PyArray_Check(value.ptr())) {
1599 // Cast to an array object and check that the numpy array
1600 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
1601 npy_intp ndims = PyArray_NDIM(arr);
1602 npy_intp* dims = PyArray_SHAPE(arr);
1603 npy_intp* strides = PyArray_STRIDES(arr);
1604
1605 if (ndims != 1)
1606 throw(rogue::GeneralError::create("Block::setFloatPy",
1607 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
1608 ndims,
1609 var->name_.c_str()));
1610
1611 if ((index + dims[0]) > var->numValues_)
1612 throw(rogue::GeneralError::create("Block::setFloatPy",
1613 "Overflow error for passed array with length %" PRIu32
1614 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1615 dims[0],
1616 index,
1617 var->numValues_,
1618 var->name_.c_str()));
1619
1620 if (PyArray_TYPE(arr) == NPY_FLOAT32) {
1621 float* src = reinterpret_cast<float*>(PyArray_DATA(arr));
1622 npy_intp stride = strides[0] / sizeof(float);
1623 for (x = 0; x < dims[0]; x++) {
1624 setFloat(src[x * stride], var, index + x);
1625 }
1626 } else {
1627 throw(rogue::GeneralError::create("Block::setFLoatPy",
1628 "Passed nparray is not of type (float32) for %s",
1629 var->name_.c_str()));
1630 }
1631
1632 // Is passed value a list
1633 } else if (PyList_Check(value.ptr())) {
1634 bp::list vl = bp::extract<bp::list>(value);
1635 uint32_t vlen = len(vl);
1636
1637 if ((index + vlen) > var->numValues_)
1638 throw(rogue::GeneralError::create("Block::setFloatPy",
1639 "Overflow error for passed array with length %" PRIu32
1640 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
1641 vlen,
1642 index,
1643 var->numValues_,
1644 var->name_.c_str()));
1645
1646 for (x = 0; x < vlen; x++) {
1647 bp::extract<float> tmp(vl[x]);
1648
1649 if (!tmp.check())
1650 throw(rogue::GeneralError::create("Block::setFloatPy",
1651 "Failed to extract value for %s.",
1652 var->name_.c_str()));
1653
1654 setFloat(tmp, var, index + x);
1655 }
1656
1657 // Passed scalar numpy value
1658 } else if (PyArray_CheckScalar(value.ptr())) {
1659 if (PyArray_DescrFromScalar(value.ptr())->type_num == NPY_FLOAT32) {
1660 float val;
1661 PyArray_ScalarAsCtype(value.ptr(), &val);
1662 setFloat(val, var, index);
1663 } else {
1664 throw(rogue::GeneralError::create("Block::setFloatPy",
1665 "Failed to extract value for %s.",
1666 var->name_.c_str()));
1667 }
1668 } else {
1669 bp::extract<float> tmp(value);
1670
1671 if (!tmp.check())
1672 throw(rogue::GeneralError::create("Block::setFloatPy",
1673 "Failed to extract value for %s.",
1674 var->name_.c_str()));
1675
1676 setFloat(tmp, var, index);
1677 }
1678}
1679
1680// Get data using float
1681bp::object rim::Block::getFloatPy(rim::Variable* var, int32_t index) {
1682 bp::object ret;
1683 uint32_t x;
1684
1685 // Unindexed with a list variable
1686 if (index < 0 && var->numValues_ > 0) {
1687 // Create a numpy array to receive it and locate the destination data buffer
1688 npy_intp dims[1] = {var->numValues_};
1689 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT32);
1690 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
1691 float* dst = reinterpret_cast<float*>(PyArray_DATA(arr));
1692
1693 for (x = 0; x < var->numValues_; x++) dst[x] = getFloat(var, x);
1694
1695 boost::python::handle<> handle(obj);
1696 ret = bp::object(handle);
1697
1698 } else {
1699 PyObject* val = Py_BuildValue("f", getFloat(var, index));
1700
1701 if (val == NULL) throw(rogue::GeneralError::create("Block::getFloatPy", "Failed to generate Float"));
1702
1703 bp::handle<> handle(val);
1704 ret = bp::object(handle);
1705 }
1706 return ret;
1707}
1708
1709#endif
1710
1711// Set data using float
1712void rim::Block::setFloat(const float& val, rim::Variable* var, int32_t index) {
1713 // Check range
1714 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
1715 throw(rogue::GeneralError::create("Block::setFloat",
1716 "Value range error for %s. Value=%f, Min=%f, Max=%f",
1717 var->name_.c_str(),
1718 val,
1719 var->minValue_,
1720 var->maxValue_));
1721
1722 setBytes(reinterpret_cast<uint8_t*>(const_cast<float*>(&val)), var, index);
1723}
1724
1725// Get data using float
1726float rim::Block::getFloat(rim::Variable* var, int32_t index) {
1727 float tmp = 0;
1728
1729 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
1730
1731 return tmp;
1732}
1733
1734// IEEE 754 half-precision conversion helpers
1735namespace {
1736
1737uint16_t floatToHalf(float value) {
1738 uint32_t f;
1739 std::memcpy(&f, &value, sizeof(f));
1740
1741 uint16_t sign = (f >> 16) & 0x8000;
1742 int32_t exponent = ((f >> 23) & 0xFF) - 127 + 15;
1743 uint32_t mantissa = f & 0x7FFFFF;
1744
1745 if (exponent <= 0) {
1746 if (exponent < -10) return sign;
1747 mantissa |= 0x800000;
1748 uint32_t shift = 14 - exponent;
1749 uint32_t halfMant = mantissa >> shift;
1750 return sign | static_cast<uint16_t>(halfMant);
1751 } else if (exponent == 0xFF - 127 + 15) {
1752 if (mantissa) {
1753 uint16_t halfMantissa = static_cast<uint16_t>(mantissa >> 13);
1754 if (halfMantissa == 0) halfMantissa = 0x0001;
1755 return sign | 0x7C00 | halfMantissa;
1756 }
1757 return sign | 0x7C00;
1758 } else if (exponent > 30) {
1759 return sign | 0x7C00;
1760 }
1761 return sign | (exponent << 10) | (mantissa >> 13);
1762}
1763
1764float halfToFloat(uint16_t h) {
1765 uint32_t sign = (h & 0x8000) << 16;
1766 uint32_t exponent = (h >> 10) & 0x1F;
1767 uint32_t mantissa = h & 0x3FF;
1768
1769 uint32_t f;
1770 if (exponent == 0) {
1771 if (mantissa == 0) {
1772 f = sign;
1773 } else {
1774 int32_t exponentWork = 1;
1775 while (!(mantissa & 0x400)) {
1776 mantissa <<= 1;
1777 exponentWork--;
1778 }
1779 mantissa &= 0x3FF;
1780 f = sign | (static_cast<uint32_t>(exponentWork + 127 - 15) << 23) | (mantissa << 13);
1781 }
1782 } else if (exponent == 31) {
1783 f = sign | 0x7F800000 | (mantissa << 13);
1784 } else {
1785 f = sign | ((exponent + 127 - 15) << 23) | (mantissa << 13);
1786 }
1787
1788 float result;
1789 std::memcpy(&result, &f, sizeof(result));
1790 return result;
1791}
1792
1793uint8_t floatToFloat8(float value) {
1794 uint32_t f;
1795 std::memcpy(&f, &value, sizeof(f));
1796
1797 uint8_t sign = (f >> 24) & 0x80;
1798 int32_t exponent = ((f >> 23) & 0xFF) - 127 + 7; // rebias float32 to E4M3 bias=7
1799 uint32_t mantissa = f & 0x7FFFFF;
1800
1801 // NaN input -> NaN output (0x7F)
1802 if (((f >> 23) & 0xFF) == 0xFF && mantissa != 0) return 0x7F;
1803
1804 // Infinity or overflow -> max finite (0x7E positive, 0xFE negative)
1805 if (((f >> 23) & 0xFF) == 0xFF || exponent > 15) return sign | 0x7E;
1806
1807 if (exponent <= 0) {
1808 // Subnormal path
1809 if (exponent < -3) return sign; // too small, flush to zero
1810 mantissa |= 0x800000;
1811 uint32_t shift = 1 - exponent;
1812 mantissa >>= shift;
1813 return sign | ((mantissa >> 20) & 0x07);
1814 }
1815 return sign | (exponent << 3) | ((mantissa >> 20) & 0x07);
1816}
1817
1818float float8ToFloat(uint8_t f8) {
1819 // Both 0x7F and 0xFF are NaN (sign bit can be 0 or 1, exp=1111, mant=111)
1820 if ((f8 & 0x7F) == 0x7F) {
1821 uint32_t nan = 0x7FC00000;
1822 float result;
1823 std::memcpy(&result, &nan, sizeof(result));
1824 return result;
1825 }
1826
1827 uint32_t sign = (static_cast<uint32_t>(f8) & 0x80) << 24;
1828 uint32_t exponent = (f8 >> 3) & 0x0F;
1829 uint32_t mantissa = f8 & 0x07;
1830
1831 uint32_t f;
1832 if (exponent == 0) {
1833 if (mantissa == 0) {
1834 f = sign; // zero
1835 } else {
1836 // Subnormal: shift left until the implicit leading 1 reaches bit 3,
1837 // then strip it. Use int32_t so exponentWork can go negative safely.
1838 int32_t exponentWork = 1;
1839 while (!(mantissa & 0x08)) {
1840 mantissa <<= 1;
1841 exponentWork--;
1842 }
1843 mantissa &= 0x07;
1844 f = sign | (static_cast<uint32_t>(exponentWork + 127 - 7) << 23) | (mantissa << 20);
1845 }
1846 } else {
1847 f = sign | (static_cast<uint32_t>(exponent + 127 - 7) << 23) | (mantissa << 20);
1848 }
1849
1850 float result;
1851 std::memcpy(&result, &f, sizeof(result));
1852 return result;
1853}
1854
1855uint16_t floatToBFloat16(float value) {
1856 uint32_t f;
1857 std::memcpy(&f, &value, sizeof(f));
1858 // BFloat16 is simply the upper 16 bits of the float32 bit pattern.
1859 // All special values (NaN, infinity, zero, subnormals) are preserved.
1860 uint16_t bf16 = static_cast<uint16_t>(f >> 16);
1861 // Preserve NaN: truncation can clear payload bits, turning NaN into Inf.
1862 uint32_t exponent = (f >> 23) & 0xFF;
1863 uint32_t mantissa = f & 0x7FFFFF;
1864 if (exponent == 0xFF && mantissa != 0 && (bf16 & 0x007F) == 0) {
1865 bf16 |= 0x0001;
1866 }
1867 return bf16;
1868}
1869
1870float bfloat16ToFloat(uint16_t bf16) {
1871 uint32_t f = static_cast<uint32_t>(bf16) << 16;
1872 float result;
1873 std::memcpy(&result, &f, sizeof(result));
1874 return result;
1875}
1876
1877// TensorFloat32: 1s / 8e / 10m, bias=127, same exponent as float32
1878// Stored in 4 bytes; lower 13 mantissa bits are zeroed.
1879
1880uint32_t floatToTensorFloat32(float value) {
1881 uint32_t f;
1882 std::memcpy(&f, &value, sizeof(f));
1883 uint32_t tf32 = f & 0xFFFFE000U;
1884 // Preserve NaN: masking can clear payload bits, turning NaN into Inf.
1885 if ((f & 0x7F800000U) == 0x7F800000U && (f & 0x007FFFFFU) != 0 &&
1886 (tf32 & 0x007FFFFFU) == 0) {
1887 tf32 |= 0x00002000U;
1888 }
1889 return tf32;
1890}
1891
1892float tensorFloat32ToFloat(uint32_t tf32) {
1893 float result;
1894 std::memcpy(&result, &tf32, sizeof(result));
1895 return result;
1896}
1897
1898// Float6 E3M2: 1s / 3e / 2m, bias=3, no Inf/NaN
1899// Stored in lower 6 bits of uint8_t
1900
1901uint8_t floatToFloat6(float value) {
1902 uint32_t f;
1903 std::memcpy(&f, &value, sizeof(f));
1904
1905 uint8_t sign = (f >> 26) & 0x20; // sign bit -> bit 5 of result
1906 int32_t exponent = ((f >> 23) & 0xFF) - 127 + 3; // rebias to E3M2 bias=3
1907 uint32_t mantissa = f & 0x7FFFFF;
1908
1909 // NaN or Infinity input -> clamp to max finite (no NaN/Inf in E3M2)
1910 if (((f >> 23) & 0xFF) == 0xFF) {
1911 // NaN has no meaningful sign: always clamp to positive max.
1912 // Infinity preserves sign.
1913 uint8_t nan_sign = (f & 0x7FFFFF) ? 0x00 : static_cast<uint8_t>(sign);
1914 return nan_sign | 0x1F;
1915 }
1916
1917 // Overflow -> clamp to max finite
1918 if (exponent > 7) return sign | 0x1F;
1919
1920 if (exponent <= 0) {
1921 // Subnormal path
1922 if (exponent < -2) return sign; // too small, flush to zero
1923 mantissa |= 0x800000;
1924 uint32_t shift = 1 - exponent;
1925 mantissa >>= shift;
1926 return sign | ((mantissa >> 21) & 0x03);
1927 }
1928 return sign | (exponent << 2) | ((mantissa >> 21) & 0x03);
1929}
1930
1931float float6ToFloat(uint8_t f6) {
1932 // Mask to 6 bits (upper 2 bits of byte are unused)
1933 f6 &= 0x3F;
1934
1935 float sign = (f6 & 0x20) ? -1.0f : 1.0f;
1936 uint32_t exponent = (f6 >> 2) & 0x07;
1937 uint32_t mantissa = f6 & 0x03;
1938
1939 if (exponent == 0) {
1940 if (mantissa == 0) {
1941 return sign * 0.0f; // +/- zero
1942 }
1943 // Subnormal: value = sign * mantissa/4 * 2^(1-3) = sign * mantissa * 2^(-4)
1944 return sign * static_cast<float>(mantissa) * 0.0625f; // 0.0625 = 2^(-4)
1945 }
1946 // Normal: value = sign * (1 + mantissa/4) * 2^(exponent-3)
1947 float frac = 1.0f + static_cast<float>(mantissa) / 4.0f;
1948 return sign * std::ldexp(frac, static_cast<int>(exponent) - 3);
1949}
1950
1951// Float4 E2M1: 1s / 2e / 1m, bias=1, no Inf/NaN
1952// Stored in lower 4 bits of uint8_t
1953uint8_t floatToFloat4(float value) {
1954 uint32_t f;
1955 std::memcpy(&f, &value, sizeof(f));
1956
1957 uint8_t sign = (f >> 28) & 0x08; // sign bit -> bit 3 of result
1958 int32_t exponent = ((f >> 23) & 0xFF) - 127 + 1; // rebias to E2M1 bias=1
1959 uint32_t mantissa = f & 0x7FFFFF;
1960
1961 // NaN or Infinity input -> clamp to max finite (no NaN/Inf in E2M1)
1962 if (((f >> 23) & 0xFF) == 0xFF) {
1963 // NaN has no meaningful sign: always clamp to positive max.
1964 // Infinity preserves sign.
1965 uint8_t nan_sign = (f & 0x7FFFFF) ? 0x00 : static_cast<uint8_t>(sign);
1966 return nan_sign | 0x07;
1967 }
1968
1969 // Overflow -> clamp to max finite
1970 if (exponent > 3) return sign | 0x07;
1971
1972 if (exponent <= 0) {
1973 // Subnormal path
1974 if (exponent < -1) return sign; // too small, flush to zero
1975 mantissa |= 0x800000;
1976 uint32_t shift = 1 - exponent;
1977 mantissa >>= shift;
1978 return sign | ((mantissa >> 22) & 0x01);
1979 }
1980 return sign | (exponent << 1) | ((mantissa >> 22) & 0x01);
1981}
1982
1983float float4ToFloat(uint8_t f4) {
1984 // Mask to 4 bits (upper 4 bits of byte are unused)
1985 f4 &= 0x0F;
1986
1987 float sign = (f4 & 0x08) ? -1.0f : 1.0f;
1988 uint32_t exponent = (f4 >> 1) & 0x03;
1989 uint32_t mantissa = f4 & 0x01;
1990
1991 if (exponent == 0) {
1992 if (mantissa == 0) {
1993 return sign * 0.0f; // +/- zero
1994 }
1995 // Subnormal: value = sign * mantissa * 0.5 (only one subnormal: +/-0.5)
1996 return sign * static_cast<float>(mantissa) * 0.5f;
1997 }
1998 // Normal: value = sign * (1 + mantissa/2) * 2^(exponent-1)
1999 float frac = 1.0f + static_cast<float>(mantissa) / 2.0f;
2000 return sign * std::ldexp(frac, static_cast<int>(exponent) - 1);
2001}
2002
2003} // anonymous namespace
2004
2006// Float16 (half-precision)
2008
2009#ifndef NO_PYTHON
2010
2011// Set data using float16
2012void rim::Block::setFloat16Py(bp::object& value, rim::Variable* var, int32_t index) {
2013 uint32_t x;
2014
2015 if (index == -1) index = 0;
2016
2017 // Passed value is a numpy value
2018 if (PyArray_Check(value.ptr())) {
2019 // Cast to an array object and check that the numpy array
2020 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2021 npy_intp ndims = PyArray_NDIM(arr);
2022 npy_intp* dims = PyArray_SHAPE(arr);
2023 npy_intp* strides = PyArray_STRIDES(arr);
2024
2025 if (ndims != 1)
2026 throw(rogue::GeneralError::create("Block::setFloat16Py",
2027 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2028 ndims,
2029 var->name_.c_str()));
2030
2031 if ((index + dims[0]) > var->numValues_)
2032 throw(rogue::GeneralError::create("Block::setFloat16Py",
2033 "Overflow error for passed array with length %" PRIu32
2034 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2035 dims[0],
2036 index,
2037 var->numValues_,
2038 var->name_.c_str()));
2039
2040 if (PyArray_TYPE(arr) == NPY_HALF) {
2041 npy_half* src = reinterpret_cast<npy_half*>(PyArray_DATA(arr));
2042 npy_intp stride = strides[0] / sizeof(npy_half);
2043 for (x = 0; x < dims[0]; x++) {
2044 float val = halfToFloat(src[x * stride]);
2045 setFloat16(val, var, index + x);
2046 }
2047 } else {
2048 throw(rogue::GeneralError::create("Block::setFloat16Py",
2049 "Passed nparray is not of type (float16) for %s",
2050 var->name_.c_str()));
2051 }
2052
2053 // Is passed value a list
2054 } else if (PyList_Check(value.ptr())) {
2055 bp::list vl = bp::extract<bp::list>(value);
2056 uint32_t vlen = len(vl);
2057
2058 if ((index + vlen) > var->numValues_)
2059 throw(rogue::GeneralError::create("Block::setFloat16Py",
2060 "Overflow error for passed array with length %" PRIu32
2061 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2062 vlen,
2063 index,
2064 var->numValues_,
2065 var->name_.c_str()));
2066
2067 for (x = 0; x < vlen; x++) {
2068 bp::extract<float> tmp(vl[x]);
2069
2070 if (!tmp.check())
2071 throw(rogue::GeneralError::create("Block::setFloat16Py",
2072 "Failed to extract value for %s.",
2073 var->name_.c_str()));
2074
2075 setFloat16(tmp, var, index + x);
2076 }
2077
2078 // Passed scalar numpy value
2079 } else if (PyArray_CheckScalar(value.ptr())) {
2080 if (PyArray_DescrFromScalar(value.ptr())->type_num == NPY_HALF) {
2081 npy_half val;
2082 PyArray_ScalarAsCtype(value.ptr(), &val);
2083 float fval = halfToFloat(val);
2084 setFloat16(fval, var, index);
2085 } else {
2086 throw(rogue::GeneralError::create("Block::setFloat16Py",
2087 "Failed to extract value for %s.",
2088 var->name_.c_str()));
2089 }
2090 } else {
2091 bp::extract<float> tmp(value);
2092
2093 if (!tmp.check())
2094 throw(rogue::GeneralError::create("Block::setFloat16Py",
2095 "Failed to extract value for %s.",
2096 var->name_.c_str()));
2097
2098 setFloat16(tmp, var, index);
2099 }
2100}
2101
2102// Get data using float16
2103bp::object rim::Block::getFloat16Py(rim::Variable* var, int32_t index) {
2104 bp::object ret;
2105 uint32_t x;
2106
2107 // Unindexed with a list variable
2108 if (index < 0 && var->numValues_ > 0) {
2109 // Create a numpy array to receive it and locate the destination data buffer
2110 npy_intp dims[1] = {var->numValues_};
2111 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_HALF);
2112 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2113 npy_half* dst = reinterpret_cast<npy_half*>(PyArray_DATA(arr));
2114
2115 for (x = 0; x < var->numValues_; x++) dst[x] = floatToHalf(getFloat16(var, x));
2116
2117 boost::python::handle<> handle(obj);
2118 ret = bp::object(handle);
2119
2120 } else {
2121 PyObject* val = Py_BuildValue("f", getFloat16(var, index));
2122
2123 if (val == NULL) throw(rogue::GeneralError::create("Block::getFloat16Py", "Failed to generate Float16"));
2124
2125 bp::handle<> handle(val);
2126 ret = bp::object(handle);
2127 }
2128 return ret;
2129}
2130
2131#endif
2132
2133// Set data using float16
2134void rim::Block::setFloat16(const float& val, rim::Variable* var, int32_t index) {
2135 // Check range
2136 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2137 throw(rogue::GeneralError::create("Block::setFloat16",
2138 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2139 var->name_.c_str(),
2140 val,
2141 var->minValue_,
2142 var->maxValue_));
2143
2144 // Convert float to half-precision and store as 2 bytes
2145 uint16_t half = floatToHalf(val);
2146 setBytes(reinterpret_cast<uint8_t*>(&half), var, index);
2147}
2148
2149// Get data using float16
2150float rim::Block::getFloat16(rim::Variable* var, int32_t index) {
2151 uint16_t tmp = 0;
2152
2153 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
2154
2155 return halfToFloat(tmp);
2156}
2157
2159// Float8 (E4M3)
2161
2162#ifndef NO_PYTHON
2163
2164// Set data using float8
2165void rim::Block::setFloat8Py(bp::object& value, rim::Variable* var, int32_t index) {
2166 uint32_t x;
2167
2168 if (index == -1) index = 0;
2169
2170 // Passed value is a numpy value
2171 if (PyArray_Check(value.ptr())) {
2172 // Cast to an array object and check that the numpy array
2173 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2174 npy_intp ndims = PyArray_NDIM(arr);
2175 npy_intp* dims = PyArray_SHAPE(arr);
2176 npy_intp* strides = PyArray_STRIDES(arr);
2177
2178 if (ndims != 1)
2179 throw(rogue::GeneralError::create("Block::setFloat8Py",
2180 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2181 ndims,
2182 var->name_.c_str()));
2183
2184 if ((index + dims[0]) > var->numValues_)
2185 throw(rogue::GeneralError::create("Block::setFloat8Py",
2186 "Overflow error for passed array with length %" PRIu32
2187 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2188 dims[0],
2189 index,
2190 var->numValues_,
2191 var->name_.c_str()));
2192
2193 if (PyArray_TYPE(arr) == NPY_FLOAT) {
2194 float* src = reinterpret_cast<float*>(PyArray_DATA(arr));
2195 npy_intp stride = strides[0] / sizeof(float);
2196 for (x = 0; x < dims[0]; x++) {
2197 float val = src[x * stride];
2198 setFloat8(val, var, index + x);
2199 }
2200 } else {
2201 throw(rogue::GeneralError::create("Block::setFloat8Py",
2202 "Passed nparray is not of type (float32) for %s",
2203 var->name_.c_str()));
2204 }
2205
2206 // Is passed value a list
2207 } else if (PyList_Check(value.ptr())) {
2208 bp::list vl = bp::extract<bp::list>(value);
2209 uint32_t vlen = len(vl);
2210
2211 if ((index + vlen) > var->numValues_)
2212 throw(rogue::GeneralError::create("Block::setFloat8Py",
2213 "Overflow error for passed array with length %" PRIu32
2214 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2215 vlen,
2216 index,
2217 var->numValues_,
2218 var->name_.c_str()));
2219
2220 for (x = 0; x < vlen; x++) {
2221 bp::extract<float> tmp(vl[x]);
2222
2223 if (!tmp.check())
2224 throw(rogue::GeneralError::create("Block::setFloat8Py",
2225 "Failed to extract value for %s.",
2226 var->name_.c_str()));
2227
2228 setFloat8(tmp, var, index + x);
2229 }
2230
2231 } else {
2232 bp::extract<float> tmp(value);
2233
2234 if (!tmp.check())
2235 throw(rogue::GeneralError::create("Block::setFloat8Py",
2236 "Failed to extract value for %s.",
2237 var->name_.c_str()));
2238
2239 setFloat8(tmp, var, index);
2240 }
2241}
2242
2243// Get data using float8
2244bp::object rim::Block::getFloat8Py(rim::Variable* var, int32_t index) {
2245 bp::object ret;
2246 uint32_t x;
2247
2248 // Unindexed with a list variable
2249 if (index < 0 && var->numValues_ > 0) {
2250 npy_intp dims[1] = {var->numValues_};
2251 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT);
2252 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2253 float* dst = reinterpret_cast<float*>(PyArray_DATA(arr));
2254
2255 for (x = 0; x < var->numValues_; x++) dst[x] = getFloat8(var, x);
2256
2257 boost::python::handle<> handle(obj);
2258 ret = bp::object(handle);
2259
2260 } else {
2261 PyObject* val = Py_BuildValue("f", getFloat8(var, index));
2262
2263 if (val == NULL) throw(rogue::GeneralError::create("Block::getFloat8Py", "Failed to generate Float8"));
2264
2265 bp::handle<> handle(val);
2266 ret = bp::object(handle);
2267 }
2268 return ret;
2269}
2270
2271#endif
2272
2273// Set data using float8
2274void rim::Block::setFloat8(const float& val, rim::Variable* var, int32_t index) {
2275 // Check range
2276 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2277 throw(rogue::GeneralError::create("Block::setFloat8",
2278 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2279 var->name_.c_str(),
2280 val,
2281 var->minValue_,
2282 var->maxValue_));
2283
2284 // Convert float to E4M3 and store as 1 byte
2285 uint8_t f8 = floatToFloat8(val);
2286 setBytes(reinterpret_cast<uint8_t*>(&f8), var, index);
2287}
2288
2289// Get data using float8
2290float rim::Block::getFloat8(rim::Variable* var, int32_t index) {
2291 uint8_t tmp = 0;
2292
2293 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
2294
2295 return float8ToFloat(tmp);
2296}
2297
2299// BFloat16 (Brain Float 16)
2301
2302#ifndef NO_PYTHON
2303
2304// Set data using bfloat16
2305void rim::Block::setBFloat16Py(bp::object& value, rim::Variable* var, int32_t index) {
2306 uint32_t x;
2307
2308 if (index == -1) index = 0;
2309
2310 // Passed value is a numpy value
2311 if (PyArray_Check(value.ptr())) {
2312 // Cast to an array object and check that the numpy array
2313 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2314 npy_intp ndims = PyArray_NDIM(arr);
2315 npy_intp* dims = PyArray_SHAPE(arr);
2316 npy_intp* strides = PyArray_STRIDES(arr);
2317
2318 if (ndims != 1)
2319 throw(rogue::GeneralError::create("Block::setBFloat16Py",
2320 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2321 ndims,
2322 var->name_.c_str()));
2323
2324 if ((index + dims[0]) > var->numValues_)
2325 throw(rogue::GeneralError::create("Block::setBFloat16Py",
2326 "Overflow error for passed array with length %" PRIu32
2327 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2328 dims[0],
2329 index,
2330 var->numValues_,
2331 var->name_.c_str()));
2332
2333 if (PyArray_TYPE(arr) == NPY_FLOAT) {
2334 float* src = reinterpret_cast<float*>(PyArray_DATA(arr));
2335 npy_intp stride = strides[0] / sizeof(float);
2336 for (x = 0; x < dims[0]; x++) {
2337 float val = src[x * stride];
2338 setBFloat16(val, var, index + x);
2339 }
2340 } else {
2341 throw(rogue::GeneralError::create("Block::setBFloat16Py",
2342 "Passed nparray is not of type (float32) for %s",
2343 var->name_.c_str()));
2344 }
2345
2346 // Is passed value a list
2347 } else if (PyList_Check(value.ptr())) {
2348 bp::list vl = bp::extract<bp::list>(value);
2349 uint32_t vlen = len(vl);
2350
2351 if ((index + vlen) > var->numValues_)
2352 throw(rogue::GeneralError::create("Block::setBFloat16Py",
2353 "Overflow error for passed array with length %" PRIu32
2354 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2355 vlen,
2356 index,
2357 var->numValues_,
2358 var->name_.c_str()));
2359
2360 for (x = 0; x < vlen; x++) {
2361 bp::extract<float> tmp(vl[x]);
2362
2363 if (!tmp.check())
2364 throw(rogue::GeneralError::create("Block::setBFloat16Py",
2365 "Failed to extract value for %s.",
2366 var->name_.c_str()));
2367
2368 setBFloat16(tmp, var, index + x);
2369 }
2370
2371 } else {
2372 bp::extract<float> tmp(value);
2373
2374 if (!tmp.check())
2375 throw(rogue::GeneralError::create("Block::setBFloat16Py",
2376 "Failed to extract value for %s.",
2377 var->name_.c_str()));
2378
2379 setBFloat16(tmp, var, index);
2380 }
2381}
2382
2383// Get data using bfloat16
2384bp::object rim::Block::getBFloat16Py(rim::Variable* var, int32_t index) {
2385 bp::object ret;
2386 uint32_t x;
2387
2388 // Unindexed with a list variable
2389 if (index < 0 && var->numValues_ > 0) {
2390 npy_intp dims[1] = {var->numValues_};
2391 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT);
2392 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2393 float* dst = reinterpret_cast<float*>(PyArray_DATA(arr));
2394
2395 for (x = 0; x < var->numValues_; x++) dst[x] = getBFloat16(var, x);
2396
2397 boost::python::handle<> handle(obj);
2398 ret = bp::object(handle);
2399
2400 } else {
2401 PyObject* val = Py_BuildValue("f", getBFloat16(var, index));
2402
2403 if (val == NULL) throw(rogue::GeneralError::create("Block::getBFloat16Py", "Failed to generate BFloat16"));
2404
2405 bp::handle<> handle(val);
2406 ret = bp::object(handle);
2407 }
2408 return ret;
2409}
2410
2411#endif
2412
2413// Set data using bfloat16
2414void rim::Block::setBFloat16(const float& val, rim::Variable* var, int32_t index) {
2415 // Check range
2416 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2417 throw(rogue::GeneralError::create("Block::setBFloat16",
2418 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2419 var->name_.c_str(),
2420 val,
2421 var->minValue_,
2422 var->maxValue_));
2423
2424 // Convert float to BFloat16 and store as 2 bytes
2425 uint16_t bf16 = floatToBFloat16(val);
2426 setBytes(reinterpret_cast<uint8_t*>(&bf16), var, index);
2427}
2428
2429// Get data using bfloat16
2430float rim::Block::getBFloat16(rim::Variable* var, int32_t index) {
2431 uint16_t tmp = 0;
2432
2433 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
2434
2435 return bfloat16ToFloat(tmp);
2436}
2437
2439// TensorFloat32 (NVIDIA TF32)
2441
2442#ifndef NO_PYTHON
2443
2444// Set data using TensorFloat32
2445void rim::Block::setTensorFloat32Py(bp::object& value, rim::Variable* var, int32_t index) {
2446 uint32_t x;
2447
2448 if (index == -1) index = 0;
2449
2450 // Passed value is a numpy value
2451 if (PyArray_Check(value.ptr())) {
2452 // Cast to an array object and check that the numpy array
2453 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2454 npy_intp ndims = PyArray_NDIM(arr);
2455 npy_intp* dims = PyArray_SHAPE(arr);
2456 npy_intp* strides = PyArray_STRIDES(arr);
2457
2458 if (ndims != 1)
2459 throw(rogue::GeneralError::create("Block::setTensorFloat32Py",
2460 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2461 ndims,
2462 var->name_.c_str()));
2463
2464 if ((index + dims[0]) > var->numValues_)
2465 throw(rogue::GeneralError::create("Block::setTensorFloat32Py",
2466 "Overflow error for passed array with length %" PRIu32
2467 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2468 dims[0],
2469 index,
2470 var->numValues_,
2471 var->name_.c_str()));
2472
2473 if (PyArray_TYPE(arr) == NPY_FLOAT) {
2474 float* src = reinterpret_cast<float*>(PyArray_DATA(arr));
2475 npy_intp stride = strides[0] / sizeof(float);
2476 for (x = 0; x < dims[0]; x++) {
2477 float val = src[x * stride];
2478 setTensorFloat32(val, var, index + x);
2479 }
2480 } else {
2481 throw(rogue::GeneralError::create("Block::setTensorFloat32Py",
2482 "Passed nparray is not of type (float32) for %s",
2483 var->name_.c_str()));
2484 }
2485
2486 // Is passed value a list
2487 } else if (PyList_Check(value.ptr())) {
2488 bp::list vl = bp::extract<bp::list>(value);
2489 uint32_t vlen = len(vl);
2490
2491 if ((index + vlen) > var->numValues_)
2492 throw(rogue::GeneralError::create("Block::setTensorFloat32Py",
2493 "Overflow error for passed array with length %" PRIu32
2494 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2495 vlen,
2496 index,
2497 var->numValues_,
2498 var->name_.c_str()));
2499
2500 for (x = 0; x < vlen; x++) {
2501 bp::extract<float> tmp(vl[x]);
2502
2503 if (!tmp.check())
2504 throw(rogue::GeneralError::create("Block::setTensorFloat32Py",
2505 "Failed to extract value for %s.",
2506 var->name_.c_str()));
2507
2508 setTensorFloat32(tmp, var, index + x);
2509 }
2510
2511 } else {
2512 bp::extract<float> tmp(value);
2513
2514 if (!tmp.check())
2515 throw(rogue::GeneralError::create("Block::setTensorFloat32Py",
2516 "Failed to extract value for %s.",
2517 var->name_.c_str()));
2518
2519 setTensorFloat32(tmp, var, index);
2520 }
2521}
2522
2523// Get data using TensorFloat32
2524bp::object rim::Block::getTensorFloat32Py(rim::Variable* var, int32_t index) {
2525 bp::object ret;
2526 uint32_t x;
2527
2528 // Unindexed with a list variable
2529 if (index < 0 && var->numValues_ > 0) {
2530 npy_intp dims[1] = {var->numValues_};
2531 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT);
2532 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2533 float* dst = reinterpret_cast<float*>(PyArray_DATA(arr));
2534
2535 for (x = 0; x < var->numValues_; x++) dst[x] = getTensorFloat32(var, x);
2536
2537 boost::python::handle<> handle(obj);
2538 ret = bp::object(handle);
2539
2540 } else {
2541 PyObject* val = Py_BuildValue("f", getTensorFloat32(var, index));
2542
2543 if (val == NULL) throw(rogue::GeneralError::create("Block::getTensorFloat32Py", "Failed to generate TensorFloat32"));
2544
2545 bp::handle<> handle(val);
2546 ret = bp::object(handle);
2547 }
2548 return ret;
2549}
2550
2551#endif
2552
2553// Set data using TensorFloat32
2554void rim::Block::setTensorFloat32(const float& val, rim::Variable* var, int32_t index) {
2555 // Check range
2556 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2557 throw(rogue::GeneralError::create("Block::setTensorFloat32",
2558 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2559 var->name_.c_str(),
2560 val,
2561 var->minValue_,
2562 var->maxValue_));
2563
2564 // Convert float to TensorFloat32 and store as 4 bytes
2565 uint32_t tf32 = floatToTensorFloat32(val);
2566 setBytes(reinterpret_cast<uint8_t*>(&tf32), var, index);
2567}
2568
2569// Get data using TensorFloat32
2570float rim::Block::getTensorFloat32(rim::Variable* var, int32_t index) {
2571 uint32_t tmp = 0;
2572
2573 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
2574
2575 return tensorFloat32ToFloat(tmp);
2576}
2577
2579// Float6 (E3M2)
2581
2582#ifndef NO_PYTHON
2583
2584// Set data using float6
2585void rim::Block::setFloat6Py(bp::object& value, rim::Variable* var, int32_t index) {
2586 uint32_t x;
2587
2588 if (index == -1) index = 0;
2589
2590 // Passed value is a numpy value
2591 if (PyArray_Check(value.ptr())) {
2592 // Cast to an array object and check that the numpy array
2593 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2594 npy_intp ndims = PyArray_NDIM(arr);
2595 npy_intp* dims = PyArray_SHAPE(arr);
2596 npy_intp* strides = PyArray_STRIDES(arr);
2597
2598 if (ndims != 1)
2599 throw(rogue::GeneralError::create("Block::setFloat6Py",
2600 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2601 ndims,
2602 var->name_.c_str()));
2603
2604 if ((index + dims[0]) > var->numValues_)
2605 throw(rogue::GeneralError::create("Block::setFloat6Py",
2606 "Overflow error for passed array with length %" PRIu32
2607 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2608 dims[0],
2609 index,
2610 var->numValues_,
2611 var->name_.c_str()));
2612
2613 if (PyArray_TYPE(arr) == NPY_FLOAT) {
2614 float* src = reinterpret_cast<float*>(PyArray_DATA(arr));
2615 npy_intp stride = strides[0] / sizeof(float);
2616 for (x = 0; x < dims[0]; x++) {
2617 float val = src[x * stride];
2618 setFloat6(val, var, index + x);
2619 }
2620 } else {
2621 throw(rogue::GeneralError::create("Block::setFloat6Py",
2622 "Passed nparray is not of type (float32) for %s",
2623 var->name_.c_str()));
2624 }
2625
2626 // Is passed value a list
2627 } else if (PyList_Check(value.ptr())) {
2628 bp::list vl = bp::extract<bp::list>(value);
2629 uint32_t vlen = len(vl);
2630
2631 if ((index + vlen) > var->numValues_)
2632 throw(rogue::GeneralError::create("Block::setFloat6Py",
2633 "Overflow error for passed array with length %" PRIu32
2634 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2635 vlen,
2636 index,
2637 var->numValues_,
2638 var->name_.c_str()));
2639
2640 for (x = 0; x < vlen; x++) {
2641 bp::extract<float> tmp(vl[x]);
2642
2643 if (!tmp.check())
2644 throw(rogue::GeneralError::create("Block::setFloat6Py",
2645 "Failed to extract value for %s.",
2646 var->name_.c_str()));
2647
2648 setFloat6(tmp, var, index + x);
2649 }
2650
2651 } else {
2652 bp::extract<float> tmp(value);
2653
2654 if (!tmp.check())
2655 throw(rogue::GeneralError::create("Block::setFloat6Py",
2656 "Failed to extract value for %s.",
2657 var->name_.c_str()));
2658
2659 setFloat6(tmp, var, index);
2660 }
2661}
2662
2663// Get data using float6
2664bp::object rim::Block::getFloat6Py(rim::Variable* var, int32_t index) {
2665 bp::object ret;
2666 uint32_t x;
2667
2668 // Unindexed with a list variable
2669 if (index < 0 && var->numValues_ > 0) {
2670 npy_intp dims[1] = {var->numValues_};
2671 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT);
2672 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2673 float* dst = reinterpret_cast<float*>(PyArray_DATA(arr));
2674
2675 for (x = 0; x < var->numValues_; x++) dst[x] = getFloat6(var, x);
2676
2677 boost::python::handle<> handle(obj);
2678 ret = bp::object(handle);
2679
2680 } else {
2681 PyObject* val = Py_BuildValue("f", getFloat6(var, index));
2682
2683 if (val == NULL) throw(rogue::GeneralError::create("Block::getFloat6Py", "Failed to generate Float6"));
2684
2685 bp::handle<> handle(val);
2686 ret = bp::object(handle);
2687 }
2688 return ret;
2689}
2690
2691#endif
2692
2693// Set data using float6
2694void rim::Block::setFloat6(const float& val, rim::Variable* var, int32_t index) {
2695 // Check range
2696 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2697 throw(rogue::GeneralError::create("Block::setFloat6",
2698 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2699 var->name_.c_str(),
2700 val,
2701 var->minValue_,
2702 var->maxValue_));
2703
2704 // Convert float to E3M2 and store as 1 byte
2705 uint8_t f6 = floatToFloat6(val);
2706 setBytes(reinterpret_cast<uint8_t*>(&f6), var, index);
2707}
2708
2709// Get data using float6
2710float rim::Block::getFloat6(rim::Variable* var, int32_t index) {
2711 uint8_t tmp = 0;
2712
2713 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
2714
2715 return float6ToFloat(tmp);
2716}
2717
2719// Float4 (E2M1)
2721
2722#ifndef NO_PYTHON
2723
2724// Set data using float4
2725void rim::Block::setFloat4Py(bp::object& value, rim::Variable* var, int32_t index) {
2726 uint32_t x;
2727
2728 if (index == -1) index = 0;
2729
2730 // Passed value is a numpy value
2731 if (PyArray_Check(value.ptr())) {
2732 // Cast to an array object and check that the numpy array
2733 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2734 npy_intp ndims = PyArray_NDIM(arr);
2735 npy_intp* dims = PyArray_SHAPE(arr);
2736 npy_intp* strides = PyArray_STRIDES(arr);
2737
2738 if (ndims != 1)
2739 throw(rogue::GeneralError::create("Block::setFloat4Py",
2740 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2741 ndims,
2742 var->name_.c_str()));
2743
2744 if ((index + dims[0]) > var->numValues_)
2745 throw(rogue::GeneralError::create("Block::setFloat4Py",
2746 "Overflow error for passed array with length %" PRIu32
2747 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2748 dims[0],
2749 index,
2750 var->numValues_,
2751 var->name_.c_str()));
2752
2753 if (PyArray_TYPE(arr) == NPY_FLOAT) {
2754 float* src = reinterpret_cast<float*>(PyArray_DATA(arr));
2755 npy_intp stride = strides[0] / sizeof(float);
2756 for (x = 0; x < dims[0]; x++) {
2757 float val = src[x * stride];
2758 setFloat4(val, var, index + x);
2759 }
2760 } else {
2761 throw(rogue::GeneralError::create("Block::setFloat4Py",
2762 "Passed nparray is not of type (float32) for %s",
2763 var->name_.c_str()));
2764 }
2765
2766 // Is passed value a list
2767 } else if (PyList_Check(value.ptr())) {
2768 bp::list vl = bp::extract<bp::list>(value);
2769 uint32_t vlen = len(vl);
2770
2771 if ((index + vlen) > var->numValues_)
2772 throw(rogue::GeneralError::create("Block::setFloat4Py",
2773 "Overflow error for passed array with length %" PRIu32
2774 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2775 vlen,
2776 index,
2777 var->numValues_,
2778 var->name_.c_str()));
2779
2780 for (x = 0; x < vlen; x++) {
2781 bp::extract<float> tmp(vl[x]);
2782
2783 if (!tmp.check())
2784 throw(rogue::GeneralError::create("Block::setFloat4Py",
2785 "Failed to extract value for %s.",
2786 var->name_.c_str()));
2787
2788 setFloat4(tmp, var, index + x);
2789 }
2790
2791 } else {
2792 bp::extract<float> tmp(value);
2793
2794 if (!tmp.check())
2795 throw(rogue::GeneralError::create("Block::setFloat4Py",
2796 "Failed to extract value for %s.",
2797 var->name_.c_str()));
2798
2799 setFloat4(tmp, var, index);
2800 }
2801}
2802
2803// Get data using float4
2804bp::object rim::Block::getFloat4Py(rim::Variable* var, int32_t index) {
2805 bp::object ret;
2806 uint32_t x;
2807
2808 // Unindexed with a list variable
2809 if (index < 0 && var->numValues_ > 0) {
2810 npy_intp dims[1] = {var->numValues_};
2811 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT);
2812 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2813 float* dst = reinterpret_cast<float*>(PyArray_DATA(arr));
2814
2815 for (x = 0; x < var->numValues_; x++) dst[x] = getFloat4(var, x);
2816
2817 boost::python::handle<> handle(obj);
2818 ret = bp::object(handle);
2819
2820 } else {
2821 PyObject* val = Py_BuildValue("f", getFloat4(var, index));
2822
2823 if (val == NULL) throw(rogue::GeneralError::create("Block::getFloat4Py", "Failed to generate Float4"));
2824
2825 bp::handle<> handle(val);
2826 ret = bp::object(handle);
2827 }
2828 return ret;
2829}
2830
2831#endif
2832
2833// Set data using float4
2834void rim::Block::setFloat4(const float& val, rim::Variable* var, int32_t index) {
2835 // Check range
2836 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2837 throw(rogue::GeneralError::create("Block::setFloat4",
2838 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2839 var->name_.c_str(),
2840 val,
2841 var->minValue_,
2842 var->maxValue_));
2843
2844 // Convert float to E2M1 and store as 1 byte
2845 uint8_t f4 = floatToFloat4(val);
2846 setBytes(reinterpret_cast<uint8_t*>(&f4), var, index);
2847}
2848
2849// Get data using float4
2850float rim::Block::getFloat4(rim::Variable* var, int32_t index) {
2851 uint8_t tmp = 0;
2852
2853 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
2854
2855 return float4ToFloat(tmp);
2856}
2857
2859// Double
2861
2862#ifndef NO_PYTHON
2863
2864// Set data using double
2865void rim::Block::setDoublePy(bp::object& value, rim::Variable* var, int32_t index) {
2866 uint32_t x;
2867
2868 if (index == -1) index = 0;
2869
2870 // Passed value is a numpy value
2871 if (PyArray_Check(value.ptr())) {
2872 // Cast to an array object and check that the numpy array
2873 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
2874 npy_intp ndims = PyArray_NDIM(arr);
2875 npy_intp* dims = PyArray_SHAPE(arr);
2876 npy_intp* strides = PyArray_STRIDES(arr);
2877
2878 if (ndims != 1)
2879 throw(rogue::GeneralError::create("Block::setDoublePy",
2880 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
2881 ndims,
2882 var->name_.c_str()));
2883
2884 if ((index + dims[0]) > var->numValues_)
2885 throw(rogue::GeneralError::create("Block::setDoublePy",
2886 "Overflow error for passed array with length %" PRIu32
2887 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2888 dims[0],
2889 index,
2890 var->numValues_,
2891 var->name_.c_str()));
2892
2893 if (PyArray_TYPE(arr) == NPY_FLOAT64) {
2894 double* src = reinterpret_cast<double*>(PyArray_DATA(arr));
2895 npy_intp stride = strides[0] / sizeof(double);
2896 for (x = 0; x < dims[0]; x++) {
2897 setDouble(src[x * stride], var, index + x);
2898 }
2899 } else {
2900 throw(rogue::GeneralError::create("Block::setFLoatPy",
2901 "Passed nparray is not of type (double) for %s",
2902 var->name_.c_str()));
2903 }
2904
2905 // Is passed value a list
2906 } else if (PyList_Check(value.ptr())) {
2907 bp::list vl = bp::extract<bp::list>(value);
2908 uint32_t vlen = len(vl);
2909
2910 if ((index + vlen) > var->numValues_)
2911 throw(rogue::GeneralError::create("Block::setDoublePy",
2912 "Overflow error for passed array with length %" PRIu32
2913 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
2914 vlen,
2915 index,
2916 var->numValues_,
2917 var->name_.c_str()));
2918
2919 for (x = 0; x < vlen; x++) {
2920 bp::extract<double> tmp(vl[x]);
2921
2922 if (!tmp.check())
2923 throw(rogue::GeneralError::create("Block::setDoublePy",
2924 "Failed to extract value for %s.",
2925 var->name_.c_str()));
2926
2927 setDouble(tmp, var, index + x);
2928 }
2929
2930 // Passed scalar numpy value
2931 } else if (PyArray_CheckScalar(value.ptr())) {
2932 if (PyArray_DescrFromScalar(value.ptr())->type_num == NPY_FLOAT64) {
2933 double val;
2934 PyArray_ScalarAsCtype(value.ptr(), &val);
2935 setDouble(val, var, index);
2936 } else {
2937 throw(rogue::GeneralError::create("Block::setDoublePy",
2938 "Failed to extract value for %s.",
2939 var->name_.c_str()));
2940 }
2941 } else {
2942 bp::extract<double> tmp(value);
2943
2944 if (!tmp.check())
2945 throw(rogue::GeneralError::create("Block::setDoublePy",
2946 "Failed to extract value for %s.",
2947 var->name_.c_str()));
2948
2949 setDouble(tmp, var, index);
2950 }
2951}
2952
2953// Get data using double
2954bp::object rim::Block::getDoublePy(rim::Variable* var, int32_t index) {
2955 bp::object ret;
2956 uint32_t x;
2957
2958 // Unindexed with a list variable
2959 if (index < 0 && var->numValues_ > 0) {
2960 // Create a numpy array to receive it and locate the destination data buffer
2961 npy_intp dims[1] = {var->numValues_};
2962 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT64);
2963 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
2964 double* dst = reinterpret_cast<double*>(PyArray_DATA(arr));
2965
2966 for (x = 0; x < var->numValues_; x++) dst[x] = getDouble(var, x);
2967
2968 boost::python::handle<> handle(obj);
2969 ret = bp::object(handle);
2970
2971 } else {
2972 PyObject* val = Py_BuildValue("d", getDouble(var, index));
2973
2974 if (val == NULL) throw(rogue::GeneralError::create("Block::getDoublePy", "Failed to generate Double"));
2975
2976 bp::handle<> handle(val);
2977 ret = bp::object(handle);
2978 }
2979 return ret;
2980}
2981
2982#endif
2983
2984// Set data using double
2985void rim::Block::setDouble(const double& val, rim::Variable* var, int32_t index) {
2986 // Check range
2987 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
2988 throw(rogue::GeneralError::create("Block::setDouble",
2989 "Value range error for %s. Value=%f, Min=%f, Max=%f",
2990 var->name_.c_str(),
2991 val,
2992 var->minValue_,
2993 var->maxValue_));
2994
2995 setBytes(reinterpret_cast<uint8_t*>(const_cast<double*>(&val)), var, index);
2996}
2997
2998// Get data using double
2999double rim::Block::getDouble(rim::Variable* var, int32_t index) {
3000 double tmp = 0;
3001
3002 getBytes(reinterpret_cast<uint8_t*>(&tmp), var, index);
3003
3004 return tmp;
3005}
3006
3008// Fixed Point
3010
3011#ifndef NO_PYTHON
3012
3013// Set data using fixed point
3014void rim::Block::setFixedPy(bp::object& value, rim::Variable* var, int32_t index) {
3015 uint32_t x;
3016
3017 // Dispatch to the signed or unsigned fixed-point scalar setter based on modelId
3018 auto setScalar = [this, var](const double& v, int32_t idx) {
3019 if (var->modelId_ == rim::UFixed)
3020 setUFixed(v, var, idx);
3021 else
3022 setFixed(v, var, idx);
3023 };
3024
3025 if (index == -1) index = 0;
3026
3027 // Passed value is a numpy value
3028 if (PyArray_Check(value.ptr())) {
3029 // Cast to an array object and check that the numpy array
3030 PyArrayObject* arr = reinterpret_cast<decltype(arr)>(value.ptr());
3031 npy_intp ndims = PyArray_NDIM(arr);
3032 npy_intp* dims = PyArray_SHAPE(arr);
3033 npy_intp* strides = PyArray_STRIDES(arr);
3034
3035 if (ndims != 1)
3036 throw(rogue::GeneralError::create("Block::setFixedPy",
3037 "Invalid number of dimensions (%" PRIu32 ") for passed ndarray for %s",
3038 ndims,
3039 var->name_.c_str()));
3040
3041 if ((index + dims[0]) > var->numValues_)
3042 throw(rogue::GeneralError::create("Block::setFixedPy",
3043 "Overflow error for passed array with length %" PRIu32
3044 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
3045 dims[0],
3046 index,
3047 var->numValues_,
3048 var->name_.c_str()));
3049
3050 if (PyArray_TYPE(arr) == NPY_FLOAT64) {
3051 double* src = reinterpret_cast<double*>(PyArray_DATA(arr));
3052 npy_intp stride = strides[0] / sizeof(double);
3053 for (x = 0; x < dims[0]; x++) {
3054 setScalar(src[x * stride], index + x);
3055 }
3056 } else {
3057 throw(rogue::GeneralError::create("Block::setFixedPy",
3058 "Passed nparray is not of type (double) for %s",
3059 var->name_.c_str()));
3060 }
3061
3062 // Is passed value a list
3063 } else if (PyList_Check(value.ptr())) {
3064 bp::list vl = bp::extract<bp::list>(value);
3065 uint32_t vlen = len(vl);
3066
3067 if ((index + vlen) > var->numValues_)
3068 throw(rogue::GeneralError::create("Block::setFixedPy",
3069 "Overflow error for passed array with length %" PRIu32
3070 " at index %" PRIi32 ". Variable length = %" PRIu32 " for %s",
3071 vlen,
3072 index,
3073 var->numValues_,
3074 var->name_.c_str()));
3075
3076 for (x = 0; x < vlen; x++) {
3077 bp::extract<double> tmp(vl[x]);
3078
3079 if (!tmp.check())
3080 throw(rogue::GeneralError::create("Block::setFixedPy",
3081 "Failed to extract value for %s.",
3082 var->name_.c_str()));
3083
3084 setScalar(tmp, index + x);
3085 }
3086
3087 // Passed scalar numpy value
3088 } else if (PyArray_CheckScalar(value.ptr())) {
3089 if (PyArray_DescrFromScalar(value.ptr())->type_num == NPY_FLOAT64) {
3090 double val;
3091 PyArray_ScalarAsCtype(value.ptr(), &val);
3092 setScalar(val, index);
3093 } else {
3094 throw(rogue::GeneralError::create("Block::setFixedPy",
3095 "Failed to extract value for %s.",
3096 var->name_.c_str()));
3097 }
3098 } else {
3099 bp::extract<double> tmp(value);
3100
3101 if (!tmp.check())
3102 throw(rogue::GeneralError::create("Block::setFixedPy",
3103 "Failed to extract value for %s.",
3104 var->name_.c_str()));
3105
3106 setScalar(tmp, index);
3107 }
3108}
3109
3110// Get data using fixed point
3111bp::object rim::Block::getFixedPy(rim::Variable* var, int32_t index) {
3112 bp::object ret;
3113 uint32_t x;
3114
3115 // Dispatch to the signed or unsigned fixed-point scalar getter based on modelId
3116 auto getScalar = [this, var](int32_t idx) -> double {
3117 return (var->modelId_ == rim::UFixed) ? getUFixed(var, idx) : getFixed(var, idx);
3118 };
3119
3120 // Unindexed with a list variable
3121 if (index < 0 && var->numValues_ > 0) {
3122 // Create a numpy array to receive it and locate the destination data buffer
3123 npy_intp dims[1] = {var->numValues_};
3124 PyObject* obj = PyArray_SimpleNew(1, dims, NPY_FLOAT64);
3125 PyArrayObject* arr = reinterpret_cast<PyArrayObject*>(obj);
3126 double* dst = reinterpret_cast<double*>(PyArray_DATA(arr));
3127
3128 for (x = 0; x < var->numValues_; x++) dst[x] = getScalar(x);
3129
3130 boost::python::handle<> handle(obj);
3131 ret = bp::object(handle);
3132
3133 } else {
3134 PyObject* val = Py_BuildValue("d", getScalar(index));
3135
3136 if (val == NULL) throw(rogue::GeneralError::create("Block::getFixedPy", "Failed to generate Fixed"));
3137
3138 bp::handle<> handle(val);
3139 ret = bp::object(handle);
3140 }
3141 return ret;
3142}
3143
3144#endif
3145
3146// Set data using fixed point
3147void rim::Block::setFixed(const double& val, rim::Variable* var, int32_t index) {
3148 // Check range
3149 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
3150 throw(rogue::GeneralError::create("Block::setFixed",
3151 "Value range error for %s. Value=%f, Min=%f, Max=%f",
3152 var->name_.c_str(),
3153 val,
3154 var->minValue_,
3155 var->maxValue_));
3156
3157 // Convert
3158 int64_t fPoint = static_cast<int64_t>(round(val * pow(2, var->binPoint_)));
3159
3160 // Compute representable range in integer domain (use 1ULL to avoid UB for 64-bit widths)
3161 int64_t maxInt = static_cast<int64_t>((1ULL << (var->valueBits_ - 1)) - 1);
3162 int64_t minInt = -maxInt - 1;
3163
3164 // Check for overflow (rounding may push value beyond representable range)
3165 if (fPoint > maxInt || fPoint < minInt)
3166 throw(rogue::GeneralError::create("Block::setFixed",
3167 "Fixed point overflow for %s. Value=%f, Min=%f, Max=%f",
3168 var->name_.c_str(),
3169 val,
3170 static_cast<double>(minInt) / pow(2, var->binPoint_),
3171 static_cast<double>(maxInt) / pow(2, var->binPoint_)));
3172
3173 setBytes(reinterpret_cast<uint8_t*>(&fPoint), var, index);
3174}
3175
3176// Get data using fixed point
3177double rim::Block::getFixed(rim::Variable* var, int32_t index) {
3178 int64_t fPoint = 0;
3179 double tmp;
3180
3181 getBytes(reinterpret_cast<uint8_t*>(&fPoint), var, index);
3182 // Sign-extend from valueBits_ to 64 bits. Use 1LL to avoid shifting a
3183 // plain int by >= 32 (UB) and guard the valueBits_ == 64 case, where
3184 // fPoint already holds the signed two's-complement value directly.
3185 if (var->valueBits_ < 64) {
3186 const int64_t signBit = 1LL << (var->valueBits_ - 1);
3187 const int64_t modulus = 1LL << var->valueBits_;
3188 if ((fPoint & signBit) != 0) fPoint -= modulus;
3189 }
3190
3191 // Convert to float
3192 tmp = static_cast<double>(fPoint);
3193 tmp = tmp / pow(2, var->binPoint_);
3194 return tmp;
3195}
3196
3197// Set data using unsigned fixed point
3198void rim::Block::setUFixed(const double& val, rim::Variable* var, int32_t index) {
3199 // Check range
3200 if ((var->minValue_ != 0 || var->maxValue_ != 0) && (val > var->maxValue_ || val < var->minValue_))
3201 throw(rogue::GeneralError::create("Block::setUFixed",
3202 "Value range error for %s. Value=%f, Min=%f, Max=%f",
3203 var->name_.c_str(),
3204 val,
3205 var->minValue_,
3206 var->maxValue_));
3207
3208 // Convert (unsigned; reject negatives explicitly before the cast)
3209 if (val < 0)
3210 throw(rogue::GeneralError::create("Block::setUFixed",
3211 "Unsigned fixed-point underflow for %s. Value=%f",
3212 var->name_.c_str(),
3213 val));
3214
3215 uint64_t fPoint = static_cast<uint64_t>(round(val * pow(2, var->binPoint_)));
3216
3217 // Compute representable unsigned range (cap at 64 bits to avoid UB)
3218 uint64_t maxUInt =
3219 (var->valueBits_ >= 64) ? UINT64_MAX : ((1ULL << var->valueBits_) - 1ULL);
3220
3221 // Check for overflow (rounding may push value beyond representable range)
3222 if (fPoint > maxUInt)
3223 throw(rogue::GeneralError::create("Block::setUFixed",
3224 "Unsigned fixed-point overflow for %s. Value=%f, Min=0, Max=%f",
3225 var->name_.c_str(),
3226 val,
3227 static_cast<double>(maxUInt) / pow(2, var->binPoint_)));
3228
3229 setBytes(reinterpret_cast<uint8_t*>(&fPoint), var, index);
3230}
3231
3232// Get data using unsigned fixed point
3233double rim::Block::getUFixed(rim::Variable* var, int32_t index) {
3234 uint64_t fPoint = 0;
3235
3236 getBytes(reinterpret_cast<uint8_t*>(&fPoint), var, index);
3237 // No sign extension — treat stored bits as unsigned
3238 return static_cast<double>(fPoint) / pow(2, var->binPoint_);
3239}
3240
3242// Custom
3244
3245// Custom Init function called after addVariables
3246void rim::Block::customInit() {}
3247
3248// Custom Clean function called before delete
3249void rim::Block::customClean() {}
3250
3251void rim::Block::rateTest() {
3252 uint32_t x;
3253
3254 struct timeval stime;
3255 struct timeval etime;
3256 struct timeval dtime;
3257
3258 uint64_t count = 1000000;
3259 double durr;
3260 double rate;
3261 uint32_t value;
3262
3263 gettimeofday(&stime, NULL);
3264 waitTransaction(0);
3265 for (x = 0; x < count; ++x) {
3266 reqTransaction(0, 4, &value, rim::Read);
3267 waitTransaction(0);
3268 }
3269 gettimeofday(&etime, NULL);
3270
3271 timersub(&etime, &stime, &dtime);
3272 durr = dtime.tv_sec + static_cast<float>(dtime.tv_usec) / 1.0e6;
3273 rate = count / durr;
3274
3275 printf("\nBlock c++ raw: Read %" PRIu64 " times in %f seconds. Rate = %f\n", count, durr, rate);
3276
3277 gettimeofday(&stime, NULL);
3278 waitTransaction(0);
3279 for (x = 0; x < count; ++x) {
3280 reqTransaction(0, 4, reinterpret_cast<uint8_t*>(&count), rim::Write);
3281 waitTransaction(0);
3282 }
3283 gettimeofday(&etime, NULL);
3284
3285 timersub(&etime, &stime, &dtime);
3286 durr = dtime.tv_sec + static_cast<float>(dtime.tv_usec) / 1.0e6;
3287 rate = count / durr;
3288
3289 printf("\nBlock c++ raw: Wrote %" PRIu64 " times in %f seconds. Rate = %f\n", count, durr, rate);
3290}
Generic Rogue exception type.
char const * what() const
Returns exception text for standard exception handling.
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
RAII helper that acquires the Python GIL for a scope.
Definition ScopedGil.h:35
uint32_t size()
Returns block size in bytes.
Definition Block.cpp:165
uint64_t offset()
Returns the local offset of this block.
Definition Block.cpp:155
Internal Boost.Python wrapper for rogue::interfaces::memory::Variable. Enables Python subclasses to o...
Definition Variable.h:1099
Memory variable descriptor and typed accessor facade.
Definition Variable.h:62
std::vector< uint32_t > bitSize_
Definition Variable.h:103
std::vector< uint32_t > bitOffset_
Definition Variable.h:100
std::shared_ptr< rogue::interfaces::memory::Block > BlockPtr
Shared pointer alias for Block.
Definition Block.h:1189
static const uint32_t Read
Memory read transaction type.
Definition Constants.h:36
static const uint32_t Write
Memory write transaction type.
Definition Constants.h:43
static const uint32_t Verify
Memory verify readback transaction type.
Definition Constants.h:57
static const uint8_t UFixed
Block access type for unsigned fixed-point numeric data.
Definition Constants.h:141
static const uint32_t Post
Memory posted write transaction type.
Definition Constants.h:50
std::shared_ptr< rogue::interfaces::memory::Variable > VariablePtr
Definition Variable.h:43