2012-01-09 21:05:49 +01:00
|
|
|
/*
|
2012-02-22 16:14:41 +01:00
|
|
|
* \brief Generic accessor framework for highly structured memory regions
|
2012-01-09 21:05:49 +01:00
|
|
|
* \author Martin stein
|
|
|
|
* \date 2011-11-10
|
|
|
|
*/
|
|
|
|
|
2012-01-10 12:56:45 +01:00
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2011-2013 Genode Labs GmbH
|
2012-01-10 12:56:45 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2012-07-10 10:23:05 +02:00
|
|
|
#ifndef _INCLUDE__UTIL__REGISTER_H_
|
|
|
|
#define _INCLUDE__UTIL__REGISTER_H_
|
2012-01-09 21:05:49 +01:00
|
|
|
|
2012-07-10 10:23:05 +02:00
|
|
|
/* Genode includes */
|
2012-01-09 21:05:49 +01:00
|
|
|
#include <base/stdint.h>
|
2013-05-29 20:12:29 +02:00
|
|
|
#include <base/printf.h>
|
2012-01-09 21:05:49 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
namespace Genode {
|
|
|
|
|
|
|
|
template <unsigned long> struct Register;
|
|
|
|
template <typename, typename> struct Bitset_2;
|
|
|
|
template <typename, typename, typename> struct Bitset_3;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace Genode { namespace Trait {
|
|
|
|
|
2013-08-23 00:50:08 +02:00
|
|
|
/**
|
|
|
|
* Round bit width up to an appropriate uint width or 0 if not feasible
|
|
|
|
*/
|
|
|
|
template <unsigned _WIDTH>
|
|
|
|
struct Raise_to_uint_width
|
|
|
|
{
|
|
|
|
enum { WIDTH = _WIDTH < 2 ? 1 :
|
|
|
|
_WIDTH < 9 ? 8 :
|
|
|
|
_WIDTH < 17 ? 16 :
|
|
|
|
_WIDTH < 33 ? 32 :
|
|
|
|
_WIDTH < 65 ? 64 : 0, };
|
|
|
|
};
|
2012-01-17 18:55:24 +01:00
|
|
|
|
|
|
|
/**
|
2012-02-22 16:14:41 +01:00
|
|
|
* Properties of integer types with a given bitwidth
|
2012-01-17 18:55:24 +01:00
|
|
|
*/
|
2013-05-29 20:12:29 +02:00
|
|
|
template <unsigned long _WIDTH> struct Uint_width;
|
2012-01-17 18:55:24 +01:00
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_width<1>
|
2012-01-17 18:55:24 +01:00
|
|
|
{
|
2012-05-24 11:56:54 +02:00
|
|
|
typedef bool Type;
|
|
|
|
enum { WIDTH_LOG2 = 0 };
|
2012-01-17 18:55:24 +01:00
|
|
|
|
|
|
|
/**
|
2013-05-29 20:12:29 +02:00
|
|
|
* Access widths wich are dividers to the compound type width
|
2012-01-17 18:55:24 +01:00
|
|
|
*/
|
|
|
|
template <unsigned long _DIVISOR_WIDTH> struct Divisor;
|
2013-05-29 20:12:29 +02:00
|
|
|
|
|
|
|
static inline void print_hex(bool const v) {
|
|
|
|
printf("%01x", v); }
|
2012-01-17 18:55:24 +01:00
|
|
|
};
|
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_width<8> : Uint_width<1>
|
2012-05-24 11:56:54 +02:00
|
|
|
{
|
|
|
|
typedef uint8_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 3 };
|
2013-05-29 20:12:29 +02:00
|
|
|
|
|
|
|
static inline void print_hex(uint8_t const v) {
|
|
|
|
printf("%02x", v); }
|
2012-05-24 11:56:54 +02:00
|
|
|
};
|
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_width<16> : Uint_width<8>
|
2012-01-17 18:55:24 +01:00
|
|
|
{
|
|
|
|
typedef uint16_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 4 };
|
2013-05-29 20:12:29 +02:00
|
|
|
|
|
|
|
static inline void print_hex(uint16_t const v) {
|
|
|
|
printf("%04x", v); }
|
2012-01-17 18:55:24 +01:00
|
|
|
};
|
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_width<32> : Uint_width<16>
|
2012-01-17 18:55:24 +01:00
|
|
|
{
|
|
|
|
typedef uint32_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 5 };
|
2013-05-29 20:12:29 +02:00
|
|
|
|
|
|
|
static inline void print_hex (uint32_t const v) {
|
|
|
|
printf("%08x", v); }
|
2012-01-17 18:55:24 +01:00
|
|
|
};
|
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_width<64> : Uint_width<32>
|
2012-01-17 18:55:24 +01:00
|
|
|
{
|
2012-07-25 17:50:44 +02:00
|
|
|
typedef uint64_t Type;
|
2012-01-17 18:55:24 +01:00
|
|
|
enum { WIDTH_LOG2 = 6 };
|
2013-05-29 20:12:29 +02:00
|
|
|
|
|
|
|
static inline void print_hex(uint64_t const v) {
|
|
|
|
printf("%016llx", v); }
|
2012-01-17 18:55:24 +01:00
|
|
|
};
|
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_width<1>::Divisor<1> { enum { WIDTH_LOG2 = 0 }; };
|
|
|
|
template <> struct Uint_width<8>::Divisor<2> { enum { WIDTH_LOG2 = 1 }; };
|
|
|
|
template <> struct Uint_width<8>::Divisor<4> { enum { WIDTH_LOG2 = 2 }; };
|
|
|
|
template <> struct Uint_width<8>::Divisor<8> { enum { WIDTH_LOG2 = 3 }; };
|
|
|
|
template <> struct Uint_width<16>::Divisor<16> { enum { WIDTH_LOG2 = 4 }; };
|
|
|
|
template <> struct Uint_width<32>::Divisor<32> { enum { WIDTH_LOG2 = 5 }; };
|
|
|
|
template <> struct Uint_width<64>::Divisor<64> { enum { WIDTH_LOG2 = 6 }; };
|
2012-02-22 16:14:41 +01:00
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
/**
|
|
|
|
* Reference 'Uint_width' through typenames
|
|
|
|
*/
|
|
|
|
template <typename _TYPE> struct Uint_type;
|
2012-02-22 16:14:41 +01:00
|
|
|
|
2013-05-29 20:12:29 +02:00
|
|
|
template <> struct Uint_type<bool> : Uint_width<1> { };
|
|
|
|
template <> struct Uint_type<uint8_t> : Uint_width<8> { };
|
|
|
|
template <> struct Uint_type<uint16_t> : Uint_width<16> { };
|
|
|
|
template <> struct Uint_type<uint32_t> : Uint_width<32> { };
|
|
|
|
template <> struct Uint_type<uint64_t> : Uint_width<64> { };
|
2012-01-17 18:55:24 +01:00
|
|
|
}
|
2015-03-04 21:12:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An integer like highly structured memory region
|
|
|
|
*
|
|
|
|
* \param _ACCESS_WIDTH bit width of the region
|
|
|
|
*
|
|
|
|
* The register can contain multiple bitfields. Bitfields that are
|
|
|
|
* partially exceed the register range are read and written also partially.
|
|
|
|
* Bitfields that are completely out of the register range are read as '0'
|
|
|
|
* and trying to overwrite them has no effect.
|
|
|
|
*/
|
|
|
|
template <unsigned long _ACCESS_WIDTH>
|
|
|
|
struct Genode::Register
|
|
|
|
{
|
|
|
|
enum {
|
|
|
|
ACCESS_WIDTH = _ACCESS_WIDTH,
|
|
|
|
ACCESS_WIDTH_LOG2 = Trait::Uint_width<ACCESS_WIDTH>::WIDTH_LOG2,
|
|
|
|
BITFIELD_WIDTH = ACCESS_WIDTH,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef typename Trait::Uint_width<ACCESS_WIDTH>::Type access_t;
|
2012-01-17 18:55:24 +01:00
|
|
|
|
2012-01-09 21:05:49 +01:00
|
|
|
/**
|
2015-03-04 21:12:14 +01:00
|
|
|
* A bitregion within a register
|
2012-01-17 18:55:24 +01:00
|
|
|
*
|
2015-03-04 21:12:14 +01:00
|
|
|
* \param _SHIFT bit shift of first bit within the compound register
|
|
|
|
* \param _WIDTH bit width of the region
|
2012-01-17 18:55:24 +01:00
|
|
|
*
|
2015-03-04 21:12:14 +01:00
|
|
|
* Bitfields are read and written according to their range,
|
|
|
|
* so if we have a 'Bitfield<2,3>' and write '0b11101' to it
|
|
|
|
* only '0b101' (shiftet by 2 bits) is written.
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2015-03-04 21:12:14 +01:00
|
|
|
template <unsigned long _SHIFT, unsigned long _WIDTH>
|
|
|
|
struct Bitfield
|
2012-01-09 21:05:49 +01:00
|
|
|
{
|
2012-01-17 18:55:24 +01:00
|
|
|
enum {
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Fetch template parameters
|
|
|
|
*/
|
|
|
|
SHIFT = _SHIFT,
|
|
|
|
WIDTH = _WIDTH,
|
|
|
|
BITFIELD_WIDTH = WIDTH,
|
|
|
|
};
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
/**
|
2015-03-04 21:12:14 +01:00
|
|
|
* Get an unshifted mask of this field
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2015-03-18 17:18:00 +01:00
|
|
|
static constexpr access_t mask() { return ((access_t)1 << WIDTH) - 1; }
|
2012-01-17 18:55:24 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get a mask of this field shifted by its shift in the register
|
|
|
|
*/
|
2015-03-18 17:18:00 +01:00
|
|
|
static constexpr access_t reg_mask() { return mask() << SHIFT; }
|
2012-01-09 21:05:49 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get the bitwise negation of 'reg_mask'
|
|
|
|
*/
|
2015-03-18 17:18:00 +01:00
|
|
|
static constexpr access_t clear_mask() { return ~reg_mask(); }
|
2012-07-10 10:23:05 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Back reference to containing register
|
|
|
|
*/
|
|
|
|
typedef Register<ACCESS_WIDTH> Compound_reg;
|
2012-07-10 10:23:05 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get register with this bitfield set to 'value' and rest left 0
|
|
|
|
*
|
|
|
|
* Useful to combine successive access to multiple
|
|
|
|
* bitfields into one operation.
|
|
|
|
*/
|
|
|
|
static inline access_t bits(access_t const value) {
|
|
|
|
return (value & mask()) << SHIFT; }
|
2012-07-25 17:50:44 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get a register value 'reg' masked according to this bitfield
|
|
|
|
*
|
|
|
|
* E.g. '0x1234' masked according to a
|
|
|
|
* 'Register<16>::Bitfield<5,7>' returns '0x0220'.
|
|
|
|
*/
|
|
|
|
static inline access_t masked(access_t const reg)
|
|
|
|
{ return reg & reg_mask(); }
|
2012-01-09 21:05:49 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get value of this bitfield from 'reg'
|
|
|
|
*/
|
|
|
|
static inline access_t get(access_t const reg)
|
|
|
|
{ return (reg >> SHIFT) & mask(); }
|
2012-01-09 21:05:49 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get register value 'reg' with this bitfield set to zero
|
|
|
|
*/
|
|
|
|
static inline void clear(access_t & reg) { reg &= clear_mask(); }
|
2012-05-24 11:56:54 +02:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Get register value 'reg' with this bitfield set to 'value'
|
|
|
|
*/
|
|
|
|
static inline void set(access_t & reg, access_t const value = ~0)
|
|
|
|
{
|
|
|
|
clear(reg);
|
|
|
|
reg |= (value & mask()) << SHIFT;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Bitfield that is composed of 2 separate parts
|
|
|
|
*
|
|
|
|
* \param _BITS_X Register, bitfield or/and bitset types the
|
|
|
|
* bitset is composed of. The order of arguments
|
|
|
|
* is also the order of bit significance starting
|
|
|
|
* with the least.
|
|
|
|
*/
|
|
|
|
template <typename _BITS_0, typename _BITS_1>
|
|
|
|
struct Genode::Bitset_2
|
|
|
|
{
|
|
|
|
typedef _BITS_0 Bits_0;
|
|
|
|
typedef _BITS_1 Bits_1;
|
|
|
|
enum {
|
|
|
|
WIDTH = Bits_0::BITFIELD_WIDTH +
|
|
|
|
Bits_1::BITFIELD_WIDTH,
|
|
|
|
BITFIELD_WIDTH = WIDTH,
|
|
|
|
ACCESS_WIDTH = Trait::Raise_to_uint_width<WIDTH>::WIDTH,
|
2012-01-09 21:05:49 +01:00
|
|
|
};
|
2015-03-04 21:12:14 +01:00
|
|
|
typedef typename Trait::Uint_width<ACCESS_WIDTH>::Type access_t;
|
|
|
|
typedef Bitset_2<Bits_0, Bits_1> Bitset_2_base;
|
2013-08-23 00:50:08 +02:00
|
|
|
|
|
|
|
/**
|
2015-03-04 21:12:14 +01:00
|
|
|
* Convert bitset value to register representation
|
2013-08-23 00:50:08 +02:00
|
|
|
*
|
2015-03-04 21:12:14 +01:00
|
|
|
* \param T access type of register
|
|
|
|
* \param v bitset value
|
2013-08-23 00:50:08 +02:00
|
|
|
*/
|
2015-03-04 21:12:14 +01:00
|
|
|
template <typename T>
|
|
|
|
static inline T bits(T const v)
|
2013-08-23 00:50:08 +02:00
|
|
|
{
|
2015-03-04 21:12:14 +01:00
|
|
|
return Bits_0::bits(v) | Bits_1::bits(v >> Bits_0::WIDTH);
|
|
|
|
}
|
2013-12-20 02:12:07 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Override bitset in a given register value
|
|
|
|
*
|
|
|
|
* \param T access type of register
|
|
|
|
* \param reg register value
|
|
|
|
* \param value new bitset value
|
|
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
static inline void set(T & reg, access_t const value)
|
|
|
|
{
|
|
|
|
Bits_0::clear(reg);
|
|
|
|
Bits_1::clear(reg);
|
|
|
|
Bits_0::set(reg, value);
|
|
|
|
Bits_1::set(reg, value >> Bits_0::WIDTH);
|
2013-08-23 00:50:08 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2015-03-04 21:12:14 +01:00
|
|
|
* Read bitset from a given register value
|
2013-08-23 00:50:08 +02:00
|
|
|
*
|
2015-03-04 21:12:14 +01:00
|
|
|
* \param T access type of register
|
|
|
|
* \param reg register value
|
|
|
|
*
|
|
|
|
* \return bitset value
|
2013-08-23 00:50:08 +02:00
|
|
|
*/
|
2015-03-04 21:12:14 +01:00
|
|
|
template <typename T>
|
|
|
|
static inline access_t get(T const reg)
|
2013-08-23 00:50:08 +02:00
|
|
|
{
|
2015-03-04 21:12:14 +01:00
|
|
|
return Bits_0::get(reg) | (Bits_1::get(reg) << Bits_0::WIDTH);
|
|
|
|
}
|
|
|
|
};
|
2013-12-19 17:31:56 +01:00
|
|
|
|
2013-12-20 02:12:07 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Bitfield that is composed of 3 separate parts
|
|
|
|
*
|
|
|
|
* \param _BITS_X Register, bitfield or/and bitset types the
|
|
|
|
* bitset is composed of. The order of arguments
|
|
|
|
* is also the order of bit significance starting
|
|
|
|
* with the least.
|
|
|
|
*/
|
|
|
|
template <typename _BITS_0, typename _BITS_1, typename _BITS_2>
|
|
|
|
struct Genode::Bitset_3
|
|
|
|
{
|
|
|
|
typedef _BITS_0 Bits_0;
|
|
|
|
typedef _BITS_1 Bits_1;
|
|
|
|
typedef _BITS_2 Bits_2;
|
|
|
|
typedef Bitset_2<Bits_0, Bits_1> Bits_0_1;
|
|
|
|
enum {
|
|
|
|
WIDTH = Bits_0::BITFIELD_WIDTH +
|
|
|
|
Bits_1::BITFIELD_WIDTH +
|
|
|
|
Bits_2::BITFIELD_WIDTH,
|
|
|
|
BITFIELD_WIDTH = WIDTH,
|
|
|
|
ACCESS_WIDTH = Trait::Raise_to_uint_width<WIDTH>::WIDTH,
|
|
|
|
};
|
|
|
|
typedef typename Trait::Uint_width<ACCESS_WIDTH>::Type access_t;
|
|
|
|
typedef Bitset_3<Bits_0, Bits_1, Bits_2> Bitset_3_base;
|
2013-12-20 02:12:07 +01:00
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Convert bitset value to register representation
|
|
|
|
*
|
|
|
|
* \param T access type of register
|
|
|
|
* \param v bitset value
|
|
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
static inline T bits(T const v)
|
|
|
|
{
|
|
|
|
return Bits_0_1::bits(v) | Bits_2::bits(v >> Bits_0_1::WIDTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Override bitset in a given register value
|
|
|
|
*
|
|
|
|
* \param T access type of register
|
|
|
|
* \param reg register value
|
|
|
|
* \param value new bitset value
|
|
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
static inline void set(T & reg, access_t const value)
|
|
|
|
{
|
|
|
|
Bits_0::clear(reg);
|
|
|
|
Bits_1::clear(reg);
|
|
|
|
Bits_2::clear(reg);
|
|
|
|
Bits_0_1::set(reg, value);
|
|
|
|
Bits_2::set(reg, value >> Bits_0_1::WIDTH);
|
2013-08-23 00:50:08 +02:00
|
|
|
};
|
2015-03-04 21:12:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Read bitset from a given register value
|
|
|
|
*
|
|
|
|
* \param T access type of register
|
|
|
|
* \param reg register value
|
|
|
|
*
|
|
|
|
* \return bitset value
|
|
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
static inline access_t get(T const reg)
|
|
|
|
{
|
|
|
|
return Bits_0_1::get(reg) | (Bits_2::get(reg) << Bits_0_1::WIDTH);
|
|
|
|
}
|
|
|
|
};
|
2012-01-09 21:05:49 +01:00
|
|
|
|
2012-07-10 10:23:05 +02:00
|
|
|
#endif /* _INCLUDE__UTIL__REGISTER_H_ */
|
2012-01-09 21:05:49 +01:00
|
|
|
|