1// vi:set ft=cpp: -*- Mode: C++ -*-
2/* SPDX-License-Identifier: GPL-2.0-only or License-Ref-kk-custom */
4 * (c) 2014-2021 Alexander Warg <alexander.warg@kernkonzept.com>
8#include <l4/sys/types.h>
9#include <l4/cxx/type_traits>
15 * \class Register_block
16 * \details Example usage:
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);
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);
30 // read a 16bit register at offset 8byte
31 unsigned short x = regs.r<16>(8);
32 unsigned short x1 = regs[8]; // alternative
34 // read an 8bit register at offset 0byte
35 unsigned v = regs.r<8>(0);
37 // do a 16bit write to register at offset 2byte (four variants)
41 regs.r<16>().write(22);
43 // do an 8bit write (two variants)
45 regs.r<8>(0).write(9);
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);
51 // do 8bit read-modify-write
52 regs.r<8>(0).modify(0xf, 3);
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)
64 * \brief Abstract register block interface
65 * \tparam MAX_BITS The maximum access width for the registers.
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.
70template< unsigned MAX_BITS = 32 >
71struct Register_block_base;
74struct Register_block_base<8>
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;
81inline Register_block_base<8>::~Register_block_base() {}
84struct Register_block_base<16> : Register_block_base<8>
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;
91struct Register_block_base<32> : Register_block_base<16>
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;
98struct Register_block_base<64> : Register_block_base<32>
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;
103#undef REGBLK_READ_TEMPLATE
104#undef REGBLK_WRITE_TEMPLATE
106template<typename CHILD>
107struct Register_block_modify_mixin
109 template< typename T >
110 T modify(T clear_bits, T set_bits, l4_addr_t reg) const
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);
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); }
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); }
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 \
132 union X { T t; l4_uint##sz##_t v; } m; \
133 m.v = _b->do_read_##sz (reg); \
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 \
141 union X { T t; l4_uint##sz##_t v; } m; \
143 _b->do_write_##sz(m.v, reg); \
147 * \brief Helper template that translates to the Register_block_base
149 * \tparam BLOCK The type of the Register_block_base interface to use.
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>.
154template< typename BLOCK >
155class Register_block_tmpl
156: public Register_block_modify_mixin<Register_block_tmpl<BLOCK> >
162 Register_block_tmpl(BLOCK *blk) : _b(blk) {}
163 Register_block_tmpl() = default;
165 operator BLOCK * () const { return _b; }
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)
178#undef REGBLK_READ_TEMPLATE
179#undef REGBLK_WRITE_TEMPLATE
181namespace __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; };
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.
197 * Allows simple read only access to a hardware register.
199template< unsigned BITS, typename BLOCK >
200class Ro_register_tmpl
207 typedef typename __Type_helper::Unsigned<BITS>::type value_type;
209 Ro_register_tmpl(BLOCK const &blk, unsigned offset) : _b(blk), _o(offset) {}
210 Ro_register_tmpl() = default;
213 * \brief read the value from the hardware register.
214 * \return value read from the hardware register.
216 operator value_type () const
217 { return _b.template read<value_type>(_o); }
220 * \brief read the value from the hardware register.
221 * \return value from the hardware register.
223 value_type read() const
224 { return _b.template read<value_type>(_o); }
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 must be used only in temporary contexts
233 * not in global, class, or object scope.
235template< unsigned BITS, typename BLOCK >
236class Register_tmpl : public Ro_register_tmpl<BITS, BLOCK>
239 typedef typename Ro_register_tmpl<BITS, BLOCK>::value_type value_type;
241 Register_tmpl(BLOCK const &blk, unsigned offset)
242 : Ro_register_tmpl<BITS, BLOCK>(blk, offset)
245 Register_tmpl() = default;
248 * \brief write \a val into the hardware register.
249 * \param val the value to write into the hardware register.
251 Register_tmpl &operator = (value_type val)
252 { this->_b.template write<value_type>(val, this->_o); return *this; }
255 * \brief write \a val into the hardware register.
256 * \param val the value to write into the hardware register.
258 void write(value_type val)
259 { this->_b.template write<value_type>(val, this->_o); }
262 * \brief set bits in \a set_bits in the hardware register.
263 * \param set_bits bits to be set within the hardware register.
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.
269 * unsigned old_value = read();
270 * write(old_value | set_bits);
273 value_type set(value_type set_bits)
274 { return this->_b.template set<value_type>(set_bits, this->_o); }
277 * \brief clears bits in \a clear_bits in the hardware register.
278 * \param clear_bits bits to be cleared within the hardware register.
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
285 * unsigned old_value = read();
286 * write(old_value & ~clear_bits);
289 value_type clear(value_type clear_bits)
290 { return this->_b.template clear<value_type>(clear_bits, this->_o); }
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.
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.
303 * unsigned old_value = read();
304 * write((old_value & ~clear_bits) | set_bits);
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); }
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
317 * \tparam BLOCK Type implementing the register accesses (`read<>()`,
318 * `write<>()`, `modify<>()`, `set<>()`, and `clear<>()`).
320 * Provides access to registers in this block via r<WIDTH>() and
325 typename BLOCK = Register_block_tmpl<
326 Register_block_base<MAX_BITS>
332 template< unsigned B, typename BLK > friend class Register_block;
333 template< unsigned B, typename BLK > friend class Ro_register_block;
338 Register_block() = default;
339 Register_block(Block const &blk) : _b(blk) {}
340 Register_block &operator = (Block const &blk)
341 { _b = blk; return *this; }
343 template< unsigned BITS >
344 Register_block(Register_block<BITS> blk) : _b(blk._b) {}
346 typedef Register_tmpl<MAX_BITS, Block> Register;
347 typedef Ro_register_tmpl<MAX_BITS, Block> Ro_register;
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.
355 template< unsigned BITS >
356 Ro_register_tmpl<BITS, Block> r(unsigned offset) const
357 { return Ro_register_tmpl<BITS, Block>(this->_b, offset); }
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.
364 Ro_register operator [] (unsigned offset) const
365 { return this->r<MAX_BITS>(offset); }
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.
374 template< unsigned BITS >
375 Register_tmpl<BITS, Block> r(unsigned offset)
376 { return Register_tmpl<BITS, Block>(this->_b, offset); }
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
384 Register operator [] (unsigned offset)
385 { return this->r<MAX_BITS>(offset); }
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<>()),
394 * Provides read only access to registers in this block via r<WIDTH>()
399 typename BLOCK = Register_block_tmpl<
400 Register_block_base<MAX_BITS> const
403class Ro_register_block
406 template< unsigned B, typename BLK > friend class Ro_register_block;
411 Ro_register_block() = default;
412 Ro_register_block(BLOCK const &blk) : _b(blk) {}
414 template< unsigned BITS >
415 Ro_register_block(Register_block<BITS> const &blk) : _b(blk._b) {}
417 typedef Ro_register_tmpl<MAX_BITS, Block> Ro_register;
418 typedef Ro_register Register;
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.
425 Ro_register operator [] (unsigned offset) const
426 { return Ro_register(this->_b, offset); }
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.
434 template< unsigned BITS >
435 Ro_register_tmpl<BITS, Block> r(unsigned offset) const
436 { return Ro_register_tmpl<BITS, Block>(this->_b, offset); }
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.
449 * This template allows easy implementation of register files by providing
450 * read<> and write<> template functions, see Mmio_register_block
453template< typename BASE, unsigned MAX_BITS = 32 >
454struct Register_block_impl;
456#define REGBLK_IMPL_RW_TEMPLATE(sz, ...) \
457 l4_uint##sz##_t do_read_##sz(l4_addr_t reg) const override \
458 { return static_cast<BASE const *>(this)->template read<l4_uint##sz##_t>(reg); } \
460 void do_write_##sz(l4_uint##sz##_t value, l4_addr_t reg) override \
461 { static_cast<BASE*>(this)->template write<l4_uint##sz##_t>(value, reg); }
464template< typename BASE >
465struct Register_block_impl<BASE, 8> : public Register_block_base<8>
467 REGBLK_IMPL_RW_TEMPLATE(8);
470template< typename BASE >
471struct Register_block_impl<BASE, 16> : public Register_block_base<16>
473 REGBLK_IMPL_RW_TEMPLATE(8);
474 REGBLK_IMPL_RW_TEMPLATE(16);
477template< typename BASE >
478struct Register_block_impl<BASE, 32> : public Register_block_base<32>
480 REGBLK_IMPL_RW_TEMPLATE(8);
481 REGBLK_IMPL_RW_TEMPLATE(16);
482 REGBLK_IMPL_RW_TEMPLATE(32);
485template< typename BASE >
486struct Register_block_impl<BASE, 64> : public Register_block_base<64>
488 REGBLK_IMPL_RW_TEMPLATE(8);
489 REGBLK_IMPL_RW_TEMPLATE(16);
490 REGBLK_IMPL_RW_TEMPLATE(32);
491 REGBLK_IMPL_RW_TEMPLATE(64);
494#undef REGBLK_IMPL_RW_TEMPLATE