Files
Upsilon/ion/src/device/regs/register.h
Émilie Feral 3f0328f5b5 Add assertions for dangerous bit shift that could trigger undefined
behaviour

Change-Id: I051ed229d407eafcae1ea4b5fc745176a751e036
2017-12-01 11:53:55 +01:00

62 lines
2.3 KiB
C++

#ifndef REGS_REGISTER_H
#define REGS_REGISTER_H
#include <stdint.h>
#include <assert.h>
template <typename T>
class Register {
public:
Register() = delete;
Register(T v) : m_value(v) {}
void set(Register<T> value) volatile {
m_value = value.m_value;
}
void set(T value) volatile {
m_value = value;
}
T get() volatile {
return m_value;
}
void setBitRange(uint8_t high, uint8_t low, T value) volatile {
m_value = bit_range_set_value(high, low, m_value, value);
}
T getBitRange(uint8_t high, uint8_t low) volatile {
/* "Shift behavior is undefined if the right operand is negative, or greater
* than or equal to the length in bits of the promoted left operand" according
* to C++ spec. */
assert(low < 8*sizeof(T));
return (m_value & bit_range_mask(high,low)) >> low;
}
protected:
static constexpr T bit_range_mask(uint8_t high, uint8_t low) {
// Same comment as for getBitRange: we should assert (high-low+1) < 8*sizeof(T)
return ((((T)1)<<(high-low+1))-1)<<low;
}
static constexpr T bit_range_value(T value, uint8_t high, uint8_t low) {
// Same comment as for getBitRange: we should assert low < 8*sizeof(T))
return (value<<low) & bit_range_mask(high,low);
}
static constexpr T bit_range_set_value(uint8_t high, uint8_t low, T originalValue, T targetValue) {
return (originalValue & ~bit_range_mask(high,low))|bit_range_value(targetValue, high, low);
}
private:
T m_value;
};
typedef Register<uint8_t> Register8;
typedef Register<uint16_t> Register16;
typedef Register<uint32_t> Register32;
typedef Register<uint64_t> Register64;
#define REGS_FIELD_R(name,type,high,low) type get##name() volatile { return (type)getBitRange(high,low); };
#define REGS_FIELD_W(name,type,high,low) void set##name(type v) volatile { setBitRange(high, low, (uint8_t)v); };
#define REGS_FIELD(name,type,high,low) REGS_FIELD_R(name,type,high,low); REGS_FIELD_W(name,type,high,low);
#define REGS_TYPE_FIELD(name,high,low) REGS_FIELD(name,name,high,low)
#define REGS_BOOL_FIELD(name,bit) REGS_FIELD(name,bool,bit,bit)
#define REGS_BOOL_FIELD_R(name,bit) REGS_FIELD_R(name,bool,bit,bit)
#define REGS_BOOL_FIELD_W(name,bit) REGS_FIELD_W(name,bool,bit,bit)
#define REGS_REGISTER_AT(name, offset) volatile name * name() const { return (class name *)(Base() + offset); };
#endif