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