aboutsummaryrefslogtreecommitdiffstats
path: root/backends
diff options
context:
space:
mode:
authorwhitequark <whitequark@whitequark.org>2020-06-18 21:51:30 +0000
committerwhitequark <whitequark@whitequark.org>2020-06-19 02:31:35 +0000
commit962a2f3bff9da3ae1ccf0bf05fabdbecf30f15c8 (patch)
treeaf91ada1c50ac0e40e5495135f9bcfd71a5bb009 /backends
parentdfde1cf1c540d5580d7bc7d24f9f59a004202d60 (diff)
downloadyosys-962a2f3bff9da3ae1ccf0bf05fabdbecf30f15c8.tar.gz
yosys-962a2f3bff9da3ae1ccf0bf05fabdbecf30f15c8.tar.bz2
yosys-962a2f3bff9da3ae1ccf0bf05fabdbecf30f15c8.zip
cxxrtl: add .get() and .set() accessors on value<> and wire<>.
For several reasons: * They're more convenient than accessing .data. * They accommodate variably-sized types like size_t transparently. * They statically ensure that no out of range conversions happen. For now these are only provided for unsigned integers, but eventually they should be provided for signed integers too. (Annoyingly this affects conversions to/from `char` at the moment.) Fixes #2127.
Diffstat (limited to 'backends')
-rw-r--r--backends/cxxrtl/cxxrtl.h53
1 files changed, 47 insertions, 6 deletions
diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h
index 85f45ac7f..f0d7b9fc7 100644
--- a/backends/cxxrtl/cxxrtl.h
+++ b/backends/cxxrtl/cxxrtl.h
@@ -111,6 +111,35 @@ struct value : public expr_base<value<Bits>> {
return ss.str();
}
+ // Conversion operations.
+ //
+ // These functions ensure that a conversion is never out of range, and should be always used, if at all
+ // possible, instead of direct manipulation of the `data` member. For very large types, .slice() and
+ // .concat() can be used to split them into more manageable parts.
+ template<class IntegerT>
+ CXXRTL_ALWAYS_INLINE
+ IntegerT get() const {
+ static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
+ "get<T>() requires T to be an unsigned integral type");
+ static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
+ "get<T>() requires T to be at least as wide as the value is");
+ IntegerT result = 0;
+ for (size_t n = 0; n < chunks; n++)
+ result |= IntegerT(data[n]) << (n * chunk::bits);
+ return result;
+ }
+
+ template<class IntegerT>
+ CXXRTL_ALWAYS_INLINE
+ void set(IntegerT other) {
+ static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
+ "set<T>() requires T to be an unsigned integral type");
+ static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
+ "set<T>() requires the value to be at least as wide as T is");
+ for (size_t n = 0; n < chunks; n++)
+ data[n] = (other >> (n * chunk::bits)) & chunk::mask;
+ }
+
// Operations with compile-time parameters.
//
// These operations are used to implement slicing, concatenation, and blitting.
@@ -274,6 +303,10 @@ struct value : public expr_base<value<Bits>> {
data[offset_chunks] |= value ? 1 << offset_bits : 0;
}
+ explicit operator bool() const {
+ return !is_zero();
+ }
+
bool is_zero() const {
for (size_t n = 0; n < chunks; n++)
if (data[n] != 0)
@@ -281,10 +314,6 @@ struct value : public expr_base<value<Bits>> {
return true;
}
- explicit operator bool() const {
- return !is_zero();
- }
-
bool is_neg() const {
return data[chunks - 1] & (1 << ((Bits - 1) % chunk::bits));
}
@@ -621,6 +650,18 @@ struct wire {
wire(wire<Bits> &&) = default;
wire<Bits> &operator=(const wire<Bits> &) = delete;
+ template<class IntegerT>
+ CXXRTL_ALWAYS_INLINE
+ IntegerT get() const {
+ return curr.template get<IntegerT>();
+ }
+
+ template<class IntegerT>
+ CXXRTL_ALWAYS_INLINE
+ void set(IntegerT other) {
+ next.template set<IntegerT>(other);
+ }
+
bool commit() {
if (curr != next) {
curr = next;
@@ -967,13 +1008,13 @@ value<BitsY> logic_not(const value<BitsA> &a) {
template<size_t BitsY, size_t BitsA, size_t BitsB>
CXXRTL_ALWAYS_INLINE
value<BitsY> logic_and(const value<BitsA> &a, const value<BitsB> &b) {
- return value<BitsY> { (bool(a) & bool(b)) ? 1u : 0u };
+ return value<BitsY> { (bool(a) && bool(b)) ? 1u : 0u };
}
template<size_t BitsY, size_t BitsA, size_t BitsB>
CXXRTL_ALWAYS_INLINE
value<BitsY> logic_or(const value<BitsA> &a, const value<BitsB> &b) {
- return value<BitsY> { (bool(a) | bool(b)) ? 1u : 0u };
+ return value<BitsY> { (bool(a) || bool(b)) ? 1u : 0u };
}
// Reduction operations