paul@0 | 1 | /* |
paul@0 | 2 | * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com> |
paul@0 | 3 | * |
paul@0 | 4 | * This file is part of TUD:OS and distributed under the terms of the |
paul@0 | 5 | * GNU General Public License 2. |
paul@0 | 6 | * Please see the COPYING-GPL-2 file for details. |
paul@0 | 7 | */ |
paul@0 | 8 | #pragma once |
paul@0 | 9 | |
paul@0 | 10 | #include <l4/sys/types.h> |
paul@0 | 11 | #include <l4/cxx/type_traits> |
paul@0 | 12 | |
paul@0 | 13 | namespace Hw { |
paul@0 | 14 | |
paul@0 | 15 | |
paul@0 | 16 | /* EXAMPLE usage: |
paul@0 | 17 | |
paul@0 | 18 | \code |
paul@0 | 19 | |
paul@0 | 20 | void test() |
paul@0 | 21 | { |
paul@0 | 22 | // create a register block reference for max. 16bit accesses, using a |
paul@0 | 23 | // MMIO register block implementation (at address 0x1000). |
paul@0 | 24 | Hw::Register_block<16> regs = new Hw::Mmio_register_block<16>(0x1000); |
paul@0 | 25 | |
paul@0 | 26 | // Alternatively it is allowed to use an implementation that allows |
paul@0 | 27 | // wider access than actually needed. |
paul@0 | 28 | Hw::Register_block<16> regs = new Hw::Mmio_register_block<32>(0x1000); |
paul@0 | 29 | |
paul@0 | 30 | // read a 16bit register at offset 8byte |
paul@0 | 31 | unsigned short x = regs.r<16>(8); |
paul@0 | 32 | unsigned short x1 = regs[8]; // alternative |
paul@0 | 33 | |
paul@0 | 34 | // read an 8bit register at offset 0byte |
paul@0 | 35 | unsigned v = regs.r<8>(0); |
paul@0 | 36 | |
paul@0 | 37 | // do a 16bit write to register at offset 2byte (four variants) |
paul@0 | 38 | regs[2] = 22; |
paul@0 | 39 | regs.r<16>(2) = 22; |
paul@0 | 40 | regs[2].write(22); |
paul@0 | 41 | regs.r<16>().write(22); |
paul@0 | 42 | |
paul@0 | 43 | // do an 8bit write (two variants) |
paul@0 | 44 | regs.r<8>(0) = 9; |
paul@0 | 45 | regs.r<8>(0).write(9); |
paul@0 | 46 | |
paul@0 | 47 | // do 16bit read-modify-write (two variants) |
paul@0 | 48 | regs[4].modify(0xf, 3); // clear 4 lowest bits and set them to 3 |
paul@0 | 49 | regs.r<16>(4).modify(0xf, 3); |
paul@0 | 50 | |
paul@0 | 51 | // do 8bit read-modify-write |
paul@0 | 52 | regs.r<8>(0).modify(0xf, 3); |
paul@0 | 53 | |
paul@0 | 54 | // fails to compile, because of too wide access |
paul@0 | 55 | // (32 bit access but regs is Hw::Register_block<16>) |
paul@0 | 56 | unsigned long v = regs.r<32>(4) |
paul@0 | 57 | } |
paul@0 | 58 | |
paul@0 | 59 | \endcode |
paul@0 | 60 | */ |
paul@0 | 61 | |
paul@0 | 62 | |
paul@0 | 63 | /** |
paul@0 | 64 | * \brief Abstract register block interface |
paul@0 | 65 | * \tparam MAX_BITS The maximum access width for the registers. |
paul@0 | 66 | * |
paul@0 | 67 | * This interfaces is based on virtual do_read_<xx> and do_write_<xx> |
paul@0 | 68 | * methods that have to be implemented up to the maximum access width. |
paul@0 | 69 | */ |
paul@0 | 70 | template< unsigned MAX_BITS = 32 > |
paul@0 | 71 | struct Register_block_base; |
paul@0 | 72 | |
paul@0 | 73 | template<> |
paul@0 | 74 | struct Register_block_base<8> |
paul@0 | 75 | { |
paul@0 | 76 | virtual l4_uint8_t do_read_8(l4_addr_t reg) const = 0; |
paul@0 | 77 | virtual void do_write_8(l4_uint8_t value, l4_addr_t reg) = 0; |
paul@0 | 78 | virtual ~Register_block_base() = 0; |
paul@0 | 79 | }; |
paul@0 | 80 | |
paul@0 | 81 | inline Register_block_base<8>::~Register_block_base() {} |
paul@0 | 82 | |
paul@0 | 83 | template<> |
paul@0 | 84 | struct Register_block_base<16> : Register_block_base<8> |
paul@0 | 85 | { |
paul@0 | 86 | virtual l4_uint16_t do_read_16(l4_addr_t reg) const = 0; |
paul@0 | 87 | virtual void do_write_16(l4_uint16_t value, l4_addr_t reg) = 0; |
paul@0 | 88 | }; |
paul@0 | 89 | |
paul@0 | 90 | template<> |
paul@0 | 91 | struct Register_block_base<32> : Register_block_base<16> |
paul@0 | 92 | { |
paul@0 | 93 | virtual l4_uint32_t do_read_32(l4_addr_t reg) const = 0; |
paul@0 | 94 | virtual void do_write_32(l4_uint32_t value, l4_addr_t reg) = 0; |
paul@0 | 95 | }; |
paul@0 | 96 | |
paul@0 | 97 | template<> |
paul@0 | 98 | struct Register_block_base<64> : Register_block_base<32> |
paul@0 | 99 | { |
paul@0 | 100 | virtual l4_uint64_t do_read_64(l4_addr_t reg) const = 0; |
paul@0 | 101 | virtual void do_write_64(l4_uint64_t value, l4_addr_t reg) = 0; |
paul@0 | 102 | }; |
paul@0 | 103 | #undef REGBLK_READ_TEMPLATE |
paul@0 | 104 | #undef REGBLK_WRITE_TEMPLATE |
paul@0 | 105 | |
paul@0 | 106 | template<typename CHILD> |
paul@0 | 107 | struct Register_block_modify_mixin |
paul@0 | 108 | { |
paul@0 | 109 | template< typename T > |
paul@0 | 110 | T modify(T clear_bits, T set_bits, l4_addr_t reg) const |
paul@0 | 111 | { |
paul@0 | 112 | CHILD const *c = static_cast<CHILD const *>(this); |
paul@0 | 113 | T r = (c->template read<T>(reg) & ~clear_bits) | set_bits; |
paul@0 | 114 | c->template write<T>(r, reg); |
paul@0 | 115 | return r; |
paul@0 | 116 | } |
paul@0 | 117 | |
paul@0 | 118 | template< typename T > |
paul@0 | 119 | T set(T set_bits, l4_addr_t reg) const |
paul@0 | 120 | { return this->template modify<T>(T(0), set_bits, reg); } |
paul@0 | 121 | |
paul@0 | 122 | template< typename T > |
paul@0 | 123 | T clear(T clear_bits, l4_addr_t reg) const |
paul@0 | 124 | { return this->template modify<T>(clear_bits, T(0), reg); } |
paul@0 | 125 | }; |
paul@0 | 126 | |
paul@0 | 127 | |
paul@0 | 128 | #define REGBLK_READ_TEMPLATE(sz) \ |
paul@0 | 129 | template< typename T > \ |
paul@0 | 130 | typename cxx::enable_if<sizeof(T) == (sz / 8), T>::type read(l4_addr_t reg) const \ |
paul@0 | 131 | { \ |
paul@0 | 132 | union X { T t; l4_uint##sz##_t v; } m; \ |
paul@0 | 133 | m.v = _b->do_read_##sz (reg); \ |
paul@0 | 134 | return m.t; \ |
paul@0 | 135 | } |
paul@0 | 136 | |
paul@0 | 137 | #define REGBLK_WRITE_TEMPLATE(sz) \ |
paul@0 | 138 | template< typename T > \ |
paul@0 | 139 | void write(T value, l4_addr_t reg, typename cxx::enable_if<sizeof(T) == (sz / 8), T>::type = T()) const \ |
paul@0 | 140 | { \ |
paul@0 | 141 | union X { T t; l4_uint##sz##_t v; } m; \ |
paul@0 | 142 | m.t = value; \ |
paul@0 | 143 | _b->do_write_##sz(m.v, reg); \ |
paul@0 | 144 | } |
paul@0 | 145 | |
paul@0 | 146 | /** |
paul@0 | 147 | * \brief Helper template that translates to the Register_block_base |
paul@0 | 148 | * interface. |
paul@0 | 149 | * \tparam BLOCK The type of the Register_block_base interface to use. |
paul@0 | 150 | * |
paul@0 | 151 | * This helper translates read<T>(), write<T>(), set<T>(), clear<T>(), |
paul@0 | 152 | * and modify<T>() calls to BLOCK::do_read_<xx> and BLOCK::do_write_<xx>. |
paul@0 | 153 | */ |
paul@0 | 154 | template< typename BLOCK > |
paul@0 | 155 | class Register_block_tmpl |
paul@0 | 156 | : public Register_block_modify_mixin<Register_block_tmpl<BLOCK> > |
paul@0 | 157 | { |
paul@0 | 158 | private: |
paul@0 | 159 | BLOCK *_b; |
paul@0 | 160 | |
paul@0 | 161 | public: |
paul@0 | 162 | Register_block_tmpl(BLOCK *blk) : _b(blk) {} |
paul@0 | 163 | Register_block_tmpl() = default; |
paul@0 | 164 | |
paul@0 | 165 | operator BLOCK * () const { return _b; } |
paul@0 | 166 | |
paul@0 | 167 | REGBLK_READ_TEMPLATE(8) |
paul@0 | 168 | REGBLK_WRITE_TEMPLATE(8) |
paul@0 | 169 | REGBLK_READ_TEMPLATE(16) |
paul@0 | 170 | REGBLK_WRITE_TEMPLATE(16) |
paul@0 | 171 | REGBLK_READ_TEMPLATE(32) |
paul@0 | 172 | REGBLK_WRITE_TEMPLATE(32) |
paul@0 | 173 | REGBLK_READ_TEMPLATE(64) |
paul@0 | 174 | REGBLK_WRITE_TEMPLATE(64) |
paul@0 | 175 | }; |
paul@0 | 176 | |
paul@0 | 177 | |
paul@0 | 178 | #undef REGBLK_READ_TEMPLATE |
paul@0 | 179 | #undef REGBLK_WRITE_TEMPLATE |
paul@0 | 180 | |
paul@0 | 181 | namespace __Type_helper { |
paul@0 | 182 | template<unsigned> struct Unsigned; |
paul@0 | 183 | template<> struct Unsigned<8> { typedef l4_uint8_t type; }; |
paul@0 | 184 | template<> struct Unsigned<16> { typedef l4_uint16_t type; }; |
paul@0 | 185 | template<> struct Unsigned<32> { typedef l4_uint32_t type; }; |
paul@0 | 186 | template<> struct Unsigned<64> { typedef l4_uint64_t type; }; |
paul@0 | 187 | }; |
paul@0 | 188 | |
paul@0 | 189 | |
paul@0 | 190 | /** |
paul@0 | 191 | * \brief Single read only register inside a Register_block_base interface. |
paul@0 | 192 | * \tparam BITS The access with of the register in bits. |
paul@0 | 193 | * \tparam BLOCK The type for the Register_block_base interface. |
paul@0 | 194 | * \note Objects of this type must be used only in temporary contexts |
paul@0 | 195 | * not in global, class, or object scope. |
paul@0 | 196 | * |
paul@0 | 197 | * Allows simple read only access to a hardware register. |
paul@0 | 198 | */ |
paul@0 | 199 | template< unsigned BITS, typename BLOCK > |
paul@0 | 200 | class Ro_register_tmpl |
paul@0 | 201 | { |
paul@0 | 202 | protected: |
paul@0 | 203 | BLOCK _b; |
paul@0 | 204 | unsigned _o; |
paul@0 | 205 | |
paul@0 | 206 | public: |
paul@0 | 207 | typedef typename __Type_helper::Unsigned<BITS>::type value_type; |
paul@0 | 208 | |
paul@0 | 209 | Ro_register_tmpl(BLOCK const &blk, unsigned offset) : _b(blk), _o(offset) {} |
paul@0 | 210 | Ro_register_tmpl() = default; |
paul@0 | 211 | |
paul@0 | 212 | /** |
paul@0 | 213 | * \brief read the value from the hardware register. |
paul@0 | 214 | * \return value read from the hardware register. |
paul@0 | 215 | */ |
paul@0 | 216 | operator value_type () const |
paul@0 | 217 | { return _b.template read<value_type>(_o); } |
paul@0 | 218 | |
paul@0 | 219 | /** |
paul@0 | 220 | * \brief read the value from the hardware register. |
paul@0 | 221 | * \return value from the hardware register. |
paul@0 | 222 | */ |
paul@0 | 223 | value_type read() const |
paul@0 | 224 | { return _b.template read<value_type>(_o); } |
paul@0 | 225 | }; |
paul@0 | 226 | |
paul@0 | 227 | |
paul@0 | 228 | /** |
paul@0 | 229 | * \brief Single hardware register inside a Register_block_base interface. |
paul@0 | 230 | * \tparam BITS The access width for the register in bits. |
paul@0 | 231 | * \tparam BLOCK the type of the Register_block_base interface. |
paul@0 | 232 | * \note Objects of this type msut be used only in temporary contexts |
paul@0 | 233 | * not in global, class, or object scope. |
paul@0 | 234 | */ |
paul@0 | 235 | template< unsigned BITS, typename BLOCK > |
paul@0 | 236 | class Register_tmpl : public Ro_register_tmpl<BITS, BLOCK> |
paul@0 | 237 | { |
paul@0 | 238 | public: |
paul@0 | 239 | typedef typename Ro_register_tmpl<BITS, BLOCK>::value_type value_type; |
paul@0 | 240 | |
paul@0 | 241 | Register_tmpl(BLOCK const &blk, unsigned offset) |
paul@0 | 242 | : Ro_register_tmpl<BITS, BLOCK>(blk, offset) |
paul@0 | 243 | {} |
paul@0 | 244 | |
paul@0 | 245 | Register_tmpl() = default; |
paul@0 | 246 | |
paul@0 | 247 | /** |
paul@0 | 248 | * \brief write \a val into the hardware register. |
paul@0 | 249 | * \param val the value to write into the hardware register. |
paul@0 | 250 | */ |
paul@0 | 251 | Register_tmpl &operator = (value_type val) |
paul@0 | 252 | { this->_b.template write<value_type>(val, this->_o); return *this; } |
paul@0 | 253 | |
paul@0 | 254 | /** |
paul@0 | 255 | * \brief write \a val into the hardware register. |
paul@0 | 256 | * \param val the value to write into the hardware register. |
paul@0 | 257 | */ |
paul@0 | 258 | void write(value_type val) |
paul@0 | 259 | { this->_b.template write<value_type>(val, this->_o); } |
paul@0 | 260 | |
paul@0 | 261 | /** |
paul@0 | 262 | * \brief set bits in \a set_bits in the hardware register. |
paul@0 | 263 | * \param set_bits bits to be set within the hardware register. |
paul@0 | 264 | * |
paul@0 | 265 | * This is a read-modify-write function that does a logical or |
paul@0 | 266 | * of the old value from the register with \a set_bits. |
paul@0 | 267 | * |
paul@0 | 268 | * \code |
paul@0 | 269 | * unsigned old_value = read(); |
paul@0 | 270 | * write(old_value | set_bits); |
paul@0 | 271 | * \endcode |
paul@0 | 272 | */ |
paul@0 | 273 | value_type set(value_type set_bits) |
paul@0 | 274 | { return this->_b.template set<value_type>(set_bits, this->_o); } |
paul@0 | 275 | |
paul@0 | 276 | /** |
paul@0 | 277 | * \brief clears bits in \a clear_bits in the hardware register. |
paul@0 | 278 | * \param clear_bits bits to be cleared within the hardware register. |
paul@0 | 279 | * |
paul@0 | 280 | * This is a read-modify-write function that does a logical and |
paul@0 | 281 | * of the old value from the register with the negated value of |
paul@0 | 282 | * \a clear_bits. |
paul@0 | 283 | * |
paul@0 | 284 | * \code |
paul@0 | 285 | * unsigned old_value = read(); |
paul@0 | 286 | * write(old_value & ~clear_bits); |
paul@0 | 287 | * \endcode |
paul@0 | 288 | */ |
paul@0 | 289 | value_type clear(value_type clear_bits) |
paul@0 | 290 | { return this->_b.template clear<value_type>(clear_bits, this->_o); } |
paul@0 | 291 | |
paul@0 | 292 | /** |
paul@0 | 293 | * \brief clears bits in \a clear_bits and sets bits in \a set_bits |
paul@0 | 294 | * in the hardware register. |
paul@0 | 295 | * \param clear_bits bits to be cleared within the hardware register. |
paul@0 | 296 | * \param set_bits bits to set in the hardware register. |
paul@0 | 297 | * |
paul@0 | 298 | * This is a read-modify-write function that first does a logical and |
paul@0 | 299 | * of the old value from the register with the negated value of |
paul@0 | 300 | * \a clear_bits and then does a logical or with \a set_bits. |
paul@0 | 301 | * |
paul@0 | 302 | * \code{.c} |
paul@0 | 303 | * unsigned old_value = read(); |
paul@0 | 304 | * write((old_value & ~clear_bits) | set_bits); |
paul@0 | 305 | * \endcode |
paul@0 | 306 | */ |
paul@0 | 307 | value_type modify(value_type clear_bits, value_type set_bits) |
paul@0 | 308 | { return this->_b.template modify<value_type>(clear_bits, set_bits, this->_o); } |
paul@0 | 309 | }; |
paul@0 | 310 | |
paul@0 | 311 | |
paul@0 | 312 | /** |
paul@0 | 313 | * \brief Handles a reference to a register block of the given |
paul@0 | 314 | * maximum access width. |
paul@0 | 315 | * \tparam MAX_BITS Maximum access width for the registers in this |
paul@0 | 316 | * block. |
paul@0 | 317 | * \tparam BLOCK Type implementing the register accesses (read<>(), write<>(), |
paul@0 | 318 | * modify<>(), set<>(), and clear<>()). |
paul@0 | 319 | * |
paul@0 | 320 | * Provides access to registers in this block via r<WIDTH>() and |
paul@0 | 321 | * operator[](). |
paul@0 | 322 | */ |
paul@0 | 323 | template< |
paul@0 | 324 | unsigned MAX_BITS, |
paul@0 | 325 | typename BLOCK = Register_block_tmpl< |
paul@0 | 326 | Register_block_base<MAX_BITS> |
paul@0 | 327 | > |
paul@0 | 328 | > |
paul@0 | 329 | class Register_block |
paul@0 | 330 | { |
paul@0 | 331 | private: |
paul@0 | 332 | template< unsigned B, typename BLK > friend class Register_block; |
paul@0 | 333 | template< unsigned B, typename BLK > friend class Ro_register_block; |
paul@0 | 334 | typedef BLOCK Block; |
paul@0 | 335 | Block _b; |
paul@0 | 336 | |
paul@0 | 337 | public: |
paul@0 | 338 | Register_block() = default; |
paul@0 | 339 | Register_block(Block const &blk) : _b(blk) {} |
paul@0 | 340 | Register_block &operator = (Block const &blk) |
paul@0 | 341 | { _b = blk; return *this; } |
paul@0 | 342 | |
paul@0 | 343 | template< unsigned BITS > |
paul@0 | 344 | Register_block(Register_block<BITS> blk) : _b(blk._b) {} |
paul@0 | 345 | |
paul@0 | 346 | typedef Register_tmpl<MAX_BITS, Block> Register; |
paul@0 | 347 | typedef Ro_register_tmpl<MAX_BITS, Block> Ro_register; |
paul@0 | 348 | |
paul@0 | 349 | /** |
paul@0 | 350 | * \brief Read only access to register at offset \a offset. |
paul@0 | 351 | * \tparam BITS the access width in bits for the register. |
paul@0 | 352 | * \param offset The offset of the register within the register file. |
paul@0 | 353 | * \return register object allowing read only access with width \a BITS. |
paul@0 | 354 | */ |
paul@0 | 355 | template< unsigned BITS > |
paul@0 | 356 | Ro_register_tmpl<BITS, Block> r(unsigned offset) const |
paul@0 | 357 | { return Ro_register_tmpl<BITS, Block>(this->_b, offset); } |
paul@0 | 358 | |
paul@0 | 359 | /** |
paul@0 | 360 | * \brief Read only access to register at offset \a offset. |
paul@0 | 361 | * \param offset The offset of the register within the register file. |
paul@0 | 362 | * \return register object allowing read only access with width \a MAX_BITS. |
paul@0 | 363 | */ |
paul@0 | 364 | Ro_register operator [] (unsigned offset) const |
paul@0 | 365 | { return this->r<MAX_BITS>(offset); } |
paul@0 | 366 | |
paul@0 | 367 | |
paul@0 | 368 | /** |
paul@0 | 369 | * \brief Read/write access to register at offset \a offset. |
paul@0 | 370 | * \tparam BITS the access width in bits for the register. |
paul@0 | 371 | * \param offset The offset of the register within the register file. |
paul@0 | 372 | * \return register object allowing read and write access with width \a BITS. |
paul@0 | 373 | */ |
paul@0 | 374 | template< unsigned BITS > |
paul@0 | 375 | Register_tmpl<BITS, Block> r(unsigned offset) |
paul@0 | 376 | { return Register_tmpl<BITS, Block>(this->_b, offset); } |
paul@0 | 377 | |
paul@0 | 378 | /** |
paul@0 | 379 | * \brief Read/write access to register at offset \a offset. |
paul@0 | 380 | * \param offset The offset of the register within the register file. |
paul@0 | 381 | * \return register object allowing read and write access with |
paul@0 | 382 | * width \a MAX_BITS. |
paul@0 | 383 | */ |
paul@0 | 384 | Register operator [] (unsigned offset) |
paul@0 | 385 | { return this->r<MAX_BITS>(offset); } |
paul@0 | 386 | }; |
paul@0 | 387 | |
paul@0 | 388 | /** |
paul@0 | 389 | * \brief Handles a reference to a read only register block of the given |
paul@0 | 390 | * maximum access width. |
paul@0 | 391 | * \tparam MAX_BITS Maximum access width for the registers in this block. |
paul@0 | 392 | * \tparam BLOCK Type implementing the register accesses (read<>()), |
paul@0 | 393 | * |
paul@0 | 394 | * Provides read only access to registers in this block via r<WIDTH>() |
paul@0 | 395 | * and operator[](). |
paul@0 | 396 | */ |
paul@0 | 397 | template< |
paul@0 | 398 | unsigned MAX_BITS, |
paul@0 | 399 | typename BLOCK = Register_block_tmpl< |
paul@0 | 400 | Register_block_base<MAX_BITS> const |
paul@0 | 401 | > |
paul@0 | 402 | > |
paul@0 | 403 | class Ro_register_block |
paul@0 | 404 | { |
paul@0 | 405 | private: |
paul@0 | 406 | template< unsigned B, typename BLK > friend class Ro_register_block; |
paul@0 | 407 | typedef BLOCK Block; |
paul@0 | 408 | Block _b; |
paul@0 | 409 | |
paul@0 | 410 | public: |
paul@0 | 411 | Ro_register_block() = default; |
paul@0 | 412 | Ro_register_block(BLOCK const &blk) : _b(blk) {} |
paul@0 | 413 | |
paul@0 | 414 | template< unsigned BITS > |
paul@0 | 415 | Ro_register_block(Register_block<BITS> const &blk) : _b(blk._b) {} |
paul@0 | 416 | |
paul@0 | 417 | typedef Ro_register_tmpl<MAX_BITS, Block> Ro_register; |
paul@0 | 418 | typedef Ro_register Register; |
paul@0 | 419 | |
paul@0 | 420 | /** |
paul@0 | 421 | * \brief Read only access to register at offset \a offset. |
paul@0 | 422 | * \param offset The offset of the register within the register file. |
paul@0 | 423 | * \return register object allowing read only access with width \a MAX_BITS. |
paul@0 | 424 | */ |
paul@0 | 425 | Ro_register operator [] (unsigned offset) const |
paul@0 | 426 | { return Ro_register(this->_b, offset); } |
paul@0 | 427 | |
paul@0 | 428 | /** |
paul@0 | 429 | * \brief Read only access to register at offset \a offset. |
paul@0 | 430 | * \tparam BITS the access width in bits for the register. |
paul@0 | 431 | * \param offset The offset of the register within the register file. |
paul@0 | 432 | * \return register object allowing read only access with width \a BITS. |
paul@0 | 433 | */ |
paul@0 | 434 | template< unsigned BITS > |
paul@0 | 435 | Ro_register_tmpl<BITS, Block> r(unsigned offset) const |
paul@0 | 436 | { return Ro_register_tmpl<BITS, Block>(this->_b, offset); } |
paul@0 | 437 | }; |
paul@0 | 438 | |
paul@0 | 439 | |
paul@0 | 440 | /** |
paul@0 | 441 | * \brief Implementation helper for register blocks. |
paul@0 | 442 | * \param BASE The class implementing read<> and write<> template functions |
paul@0 | 443 | * for accessing the registers. This class must inherit from |
paul@0 | 444 | * Register_block_impl. |
paul@0 | 445 | * \param MAX_BITS The maximum access width for the register file. |
paul@0 | 446 | * Supported values are 8, 16, 32, or 64. |
paul@0 | 447 | * |
paul@0 | 448 | * |
paul@0 | 449 | * This template allows easy implementation of register files by providing |
paul@0 | 450 | * read<> and write<> template functions, see Mmio_register_block |
paul@0 | 451 | * as an example. |
paul@0 | 452 | */ |
paul@0 | 453 | template< typename BASE, unsigned MAX_BITS = 32 > |
paul@0 | 454 | struct Register_block_impl; |
paul@0 | 455 | |
paul@0 | 456 | #define REGBLK_IMPL_RW_TEMPLATE(sz, ...) \ |
paul@0 | 457 | l4_uint##sz##_t do_read_##sz(l4_addr_t reg) const \ |
paul@0 | 458 | { return static_cast<BASE const *>(this)->template read<l4_uint##sz##_t>(reg); } \ |
paul@0 | 459 | \ |
paul@0 | 460 | void do_write_##sz(l4_uint##sz##_t value, l4_addr_t reg) \ |
paul@0 | 461 | { return static_cast<BASE*>(this)->template write<l4_uint##sz##_t>(value, reg); } |
paul@0 | 462 | |
paul@0 | 463 | |
paul@0 | 464 | template< typename BASE > |
paul@0 | 465 | struct Register_block_impl<BASE, 8> : public Register_block_base<8> |
paul@0 | 466 | { |
paul@0 | 467 | REGBLK_IMPL_RW_TEMPLATE(8); |
paul@0 | 468 | }; |
paul@0 | 469 | |
paul@0 | 470 | template< typename BASE > |
paul@0 | 471 | struct Register_block_impl<BASE, 16> : public Register_block_base<16> |
paul@0 | 472 | { |
paul@0 | 473 | REGBLK_IMPL_RW_TEMPLATE(8); |
paul@0 | 474 | REGBLK_IMPL_RW_TEMPLATE(16); |
paul@0 | 475 | }; |
paul@0 | 476 | |
paul@0 | 477 | template< typename BASE > |
paul@0 | 478 | struct Register_block_impl<BASE, 32> : public Register_block_base<32> |
paul@0 | 479 | { |
paul@0 | 480 | REGBLK_IMPL_RW_TEMPLATE(8); |
paul@0 | 481 | REGBLK_IMPL_RW_TEMPLATE(16); |
paul@0 | 482 | REGBLK_IMPL_RW_TEMPLATE(32); |
paul@0 | 483 | }; |
paul@0 | 484 | |
paul@0 | 485 | template< typename BASE > |
paul@0 | 486 | struct Register_block_impl<BASE, 64> : public Register_block_base<64> |
paul@0 | 487 | { |
paul@0 | 488 | REGBLK_IMPL_RW_TEMPLATE(8); |
paul@0 | 489 | REGBLK_IMPL_RW_TEMPLATE(16); |
paul@0 | 490 | REGBLK_IMPL_RW_TEMPLATE(32); |
paul@0 | 491 | REGBLK_IMPL_RW_TEMPLATE(64); |
paul@0 | 492 | }; |
paul@0 | 493 | |
paul@0 | 494 | #undef REGBLK_IMPL_RW_TEMPLATE |
paul@0 | 495 | |
paul@0 | 496 | /** \brief Dummy register block to be used as a placeholder */ |
paul@0 | 497 | extern Register_block<64> dummy_register_block; |
paul@0 | 498 | |
paul@0 | 499 | } |