L4Re Operating System Framework – Interface and Usage Documentation
Loading...
Searching...
No Matches
hw_register_block
1// vi:set ft=cpp: -*- Mode: C++ -*-
2/* SPDX-License-Identifier: GPL-2.0-only or License-Ref-kk-custom */
3/*
4 * (c) 2014-2021 Alexander Warg <alexander.warg@kernkonzept.com>
5 */
6#pragma once
7
8#include <l4/sys/types.h>
9#include <l4/cxx/type_traits>
10
11namespace L4drivers {
12
13
14/**
15 * \class Register_block
16 * \details Example usage:
17
18\code{.cpp}
19
20void 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 */
70template< unsigned MAX_BITS = 32 >
71struct Register_block_base;
72
73template<>
74struct 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
81inline Register_block_base<8>::~Register_block_base() {}
82
83template<>
84struct 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
90template<>
91struct 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
97template<>
98struct 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
106template<typename CHILD>
107struct 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 */
154template< typename BLOCK >
155class Register_block_tmpl
156: public Register_block_modify_mixin<Register_block_tmpl<BLOCK> >
157{
158private:
159 BLOCK *_b;
160
161public:
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
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; };
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 */
199template< unsigned BITS, typename BLOCK >
200class Ro_register_tmpl
201{
202protected:
203 BLOCK _b;
204 unsigned _o;
205
206public:
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 must be used only in temporary contexts
233 * not in global, class, or object scope.
234 */
235template< unsigned BITS, typename BLOCK >
236class Register_tmpl : public Ro_register_tmpl<BITS, BLOCK>
237{
238public:
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<>()`,
318 * `write<>()`, `modify<>()`, `set<>()`, and `clear<>()`).
319 *
320 * Provides access to registers in this block via r<WIDTH>() and
321 * operator[]().
322 */
323template<
324 unsigned MAX_BITS,
325 typename BLOCK = Register_block_tmpl<
326 Register_block_base<MAX_BITS>
327 >
328>
329class Register_block
330{
331private:
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
337public:
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 */
397template<
398 unsigned MAX_BITS,
399 typename BLOCK = Register_block_tmpl<
400 Register_block_base<MAX_BITS> const
401 >
402>
403class Ro_register_block
404{
405private:
406 template< unsigned B, typename BLK > friend class Ro_register_block;
407 typedef BLOCK Block;
408 Block _b;
409
410public:
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 */
453template< typename BASE, unsigned MAX_BITS = 32 >
454struct Register_block_impl;
455
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); } \
459 \
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); }
462
463
464template< typename BASE >
465struct Register_block_impl<BASE, 8> : public Register_block_base<8>
466{
467 REGBLK_IMPL_RW_TEMPLATE(8);
468};
469
470template< typename BASE >
471struct 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
477template< typename BASE >
478struct 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
485template< typename BASE >
486struct 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}