]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/hw_register_block.h
update
[l4.git] / l4 / pkg / io / server / src / hw_register_block.h
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 class 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 }