S
shaun roe
For a bit of seasonal festive fun, I thought I'd try making a bitfield
function, i.e. a function returning, for example, the value of bits 1 to
5 of a word as an integer, when the exact bits are known at compile
time.
The data word is always 32 bit unsigned integer (its a data stream from
some embedded controller).
The legacy code I have has lines like:
errNum = (dataWord>>1) & 31; //bits 1 to 5 is an error code
and what I would aim for is something like:
errNum=errBits(word);
the catch is that speed is all important, so I thought maybe templates
could help me to compile in the bitfields. My feeble attempts are below;
they are both about 40 times slower than the existing code (using gcc 4
on a mac).
Can anyone show me a better solution, not using macros (I am considering
using a union of a bitfield struct and an unsigned int, though I might
have to worry about endianness and what happens when I go to a 64 bit
machine) ?
attempt a)
template <int BIT1, int BIT2, typename T>
inline
T getBitField2( const T word){
static const unsigned int bitLen = BIT2 - BIT1 + 1;
static const unsigned int mask = (1<<bitLen) -1;
return (word >> BIT1) & mask;
}
used like:
errNum = getBitField2<1,5>(word);
attempt b)
template <int MASKLENGTH>
inline
const int maskit(){
return (1<<MASKLENGTH)-1;
}
template<class NumericalType>
inline
NumericalType getBitField(const NumericalType thisNumber, unsigned int
bitStart, unsigned int bitEnd){
const unsigned int bitLength = bitEnd-bitStart+1;
const NumericalType bitMask = (1<<bitLength) -1;
return (thisNumber>>bitStart) & bitMask;
}
template <unsigned int BIT1, unsigned int BIT2>
class BitField{
private:
const unsigned int mask;
public:
BitField():mask(maskit<BIT2>()){
}
inline int
operator()(const unsigned int word) const{
return (word>> BIT1) & mask;
}
};
(b) is used like:
BitField<1,5> errBits;
errNum = errBits(word);
surprisingly (for me) both (a) and the function call in using (b) have
approximately the same dismal timing, when I thought that instantiating
the class first (in b) would hardwire the bit numbers, so that the
function call would be much quicker.
function, i.e. a function returning, for example, the value of bits 1 to
5 of a word as an integer, when the exact bits are known at compile
time.
The data word is always 32 bit unsigned integer (its a data stream from
some embedded controller).
The legacy code I have has lines like:
errNum = (dataWord>>1) & 31; //bits 1 to 5 is an error code
and what I would aim for is something like:
errNum=errBits(word);
the catch is that speed is all important, so I thought maybe templates
could help me to compile in the bitfields. My feeble attempts are below;
they are both about 40 times slower than the existing code (using gcc 4
on a mac).
Can anyone show me a better solution, not using macros (I am considering
using a union of a bitfield struct and an unsigned int, though I might
have to worry about endianness and what happens when I go to a 64 bit
machine) ?
attempt a)
template <int BIT1, int BIT2, typename T>
inline
T getBitField2( const T word){
static const unsigned int bitLen = BIT2 - BIT1 + 1;
static const unsigned int mask = (1<<bitLen) -1;
return (word >> BIT1) & mask;
}
used like:
errNum = getBitField2<1,5>(word);
attempt b)
template <int MASKLENGTH>
inline
const int maskit(){
return (1<<MASKLENGTH)-1;
}
template<class NumericalType>
inline
NumericalType getBitField(const NumericalType thisNumber, unsigned int
bitStart, unsigned int bitEnd){
const unsigned int bitLength = bitEnd-bitStart+1;
const NumericalType bitMask = (1<<bitLength) -1;
return (thisNumber>>bitStart) & bitMask;
}
template <unsigned int BIT1, unsigned int BIT2>
class BitField{
private:
const unsigned int mask;
public:
BitField():mask(maskit<BIT2>()){
}
inline int
operator()(const unsigned int word) const{
return (word>> BIT1) & mask;
}
};
(b) is used like:
BitField<1,5> errBits;
errNum = errBits(word);
surprisingly (for me) both (a) and the function call in using (b) have
approximately the same dismal timing, when I thought that instantiating
the class first (in b) would hardwire the bit numbers, so that the
function call would be much quicker.