2012-01-09 21:05:49 +01:00
|
|
|
/*
|
2012-01-14 02:42:45 +01:00
|
|
|
* \brief Generic access 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
|
|
|
/*
|
|
|
|
* Copyright (C) 2011-2012 Genode Labs GmbH
|
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2012-01-09 21:05:49 +01:00
|
|
|
#ifndef _BASE__INCLUDE__UTIL__REGISTER_H_
|
|
|
|
#define _BASE__INCLUDE__UTIL__REGISTER_H_
|
|
|
|
|
|
|
|
#include <base/stdint.h>
|
|
|
|
|
|
|
|
namespace Genode
|
|
|
|
{
|
2012-01-17 18:55:24 +01:00
|
|
|
namespace Trait {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get unsigned integer type for a given access width
|
|
|
|
*/
|
|
|
|
template <unsigned long _WIDTH> struct Uint_type;
|
|
|
|
|
|
|
|
template <> struct Uint_type<8>
|
|
|
|
{
|
|
|
|
typedef uint8_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 3 };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Declare dividers of the compound type width
|
|
|
|
*/
|
|
|
|
template <unsigned long _DIVISOR_WIDTH> struct Divisor;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <> struct Uint_type<16> : Uint_type<8>
|
|
|
|
{
|
|
|
|
typedef uint16_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 4 };
|
|
|
|
};
|
|
|
|
|
|
|
|
template <> struct Uint_type<32> : Uint_type<16>
|
|
|
|
{
|
|
|
|
typedef uint32_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 5 };
|
|
|
|
};
|
|
|
|
|
|
|
|
template <> struct Uint_type<64> : Uint_type<32>
|
|
|
|
{
|
|
|
|
typedef uint32_t Type;
|
|
|
|
enum { WIDTH_LOG2 = 6 };
|
|
|
|
};
|
|
|
|
|
|
|
|
template <> struct Uint_type<8>::Divisor<1> { enum { WIDTH_LOG2 = 0 }; };
|
|
|
|
template <> struct Uint_type<8>::Divisor<2> { enum { WIDTH_LOG2 = 1 }; };
|
|
|
|
template <> struct Uint_type<8>::Divisor<4> { enum { WIDTH_LOG2 = 2 }; };
|
|
|
|
template <> struct Uint_type<8>::Divisor<8> { enum { WIDTH_LOG2 = 3 }; };
|
|
|
|
template <> struct Uint_type<16>::Divisor<16> { enum { WIDTH_LOG2 = 4 }; };
|
|
|
|
template <> struct Uint_type<32>::Divisor<32> { enum { WIDTH_LOG2 = 5 }; };
|
|
|
|
template <> struct Uint_type<64>::Divisor<64> { enum { WIDTH_LOG2 = 6 }; };
|
|
|
|
}
|
|
|
|
|
2012-01-09 21:05:49 +01:00
|
|
|
/**
|
2012-01-17 18:55:24 +01:00
|
|
|
* An integer like highly structured memory region
|
|
|
|
*
|
|
|
|
* \param _ACCESS_WIDTH Bit width of the region
|
|
|
|
*
|
|
|
|
* \detail 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.
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
template <unsigned long _ACCESS_WIDTH>
|
2012-01-09 21:05:49 +01:00
|
|
|
struct Register
|
|
|
|
{
|
2012-01-17 18:55:24 +01:00
|
|
|
enum {
|
|
|
|
ACCESS_WIDTH = _ACCESS_WIDTH,
|
|
|
|
|
|
|
|
ACCESS_WIDTH_LOG2 = Trait::Uint_type<ACCESS_WIDTH>::WIDTH_LOG2,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef typename Trait::Uint_type<ACCESS_WIDTH>::Type access_t;
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A bitregion within a register
|
2012-01-17 18:55:24 +01:00
|
|
|
*
|
|
|
|
* \param _SHIFT Bit shift of the first bit within the compound register
|
|
|
|
* \param _WIDTH Bit width of the region
|
|
|
|
*
|
|
|
|
* \detail 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
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
template <unsigned long _SHIFT, unsigned long _WIDTH>
|
2012-01-17 09:47:23 +01:00
|
|
|
struct Bitfield
|
2012-01-09 21:05:49 +01:00
|
|
|
{
|
|
|
|
enum {
|
2012-01-17 18:55:24 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch template parameters
|
|
|
|
*/
|
|
|
|
SHIFT = _SHIFT,
|
|
|
|
WIDTH = _WIDTH,
|
|
|
|
|
2012-01-14 02:42:45 +01:00
|
|
|
MASK = (1 << WIDTH) - 1,
|
|
|
|
REG_MASK = MASK << SHIFT,
|
|
|
|
CLEAR_MASK = ~REG_MASK,
|
2012-01-09 21:05:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Back reference to containing register
|
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
typedef Register<ACCESS_WIDTH> Compound_reg;
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
/**
|
2012-01-17 09:47:23 +01:00
|
|
|
* Get a register value with this bitfield set to 'value' and the rest left zero
|
2012-01-10 12:56:45 +01:00
|
|
|
*
|
2012-01-17 09:47:23 +01:00
|
|
|
* \detail Useful to combine successive access to multiple bitfields
|
2012-01-10 12:56:45 +01:00
|
|
|
* into one operation
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
static inline access_t bits(access_t const value) { return (value & MASK) << SHIFT; }
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
/**
|
2012-01-17 09:47:23 +01:00
|
|
|
* Get value of this bitfield from 'reg'
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
static inline access_t get(access_t const reg) { return (reg >> SHIFT) & MASK; }
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
/**
|
2012-01-17 09:47:23 +01:00
|
|
|
* Get registervalue 'reg' with this bitfield set to zero
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
static inline void clear(access_t & reg) { reg &= CLEAR_MASK; }
|
2012-01-09 21:05:49 +01:00
|
|
|
|
|
|
|
/**
|
2012-01-17 09:47:23 +01:00
|
|
|
* Get registervalue 'reg' with this bitfield set to 'value'
|
2012-01-09 21:05:49 +01:00
|
|
|
*/
|
2012-01-17 18:55:24 +01:00
|
|
|
static inline void set(access_t & reg, access_t const value = ~0)
|
2012-01-09 21:05:49 +01:00
|
|
|
{
|
2012-01-10 12:56:45 +01:00
|
|
|
clear(reg);
|
2012-01-09 21:05:49 +01:00
|
|
|
reg |= (value & MASK) << SHIFT;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-01-10 12:56:45 +01:00
|
|
|
#endif /* _BASE__INCLUDE__UTIL__REGISTER_H_ */
|
2012-01-09 21:05:49 +01:00
|
|
|
|