Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/tl/include/utils
2025-09-12 15:55:45 +02:00

81 lines
2.1 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2013 Technische Universität Dresden.
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
/**
* Read the value at an address at most once.
*
* The read might be omitted if the result is not used by any code unless
* `typename` contains `volatile`. If the read operation has side effects and
* must not be omitted, use different means like L4drivers::Mmio_register_block
* or similar.
*
* The compiler is disallowed to reuse a previous read at the same address, for
* example:
* ```
* val1 = *a;
* val2 = access_once(a); // compiler may not replace this by val2 = val1;
* ```
*
* The compiler is also disallowed to repeat the read, for example:
* ```
* val1 = access_once(a);
* val2 = val1; // compiler may not replace this by val2 = *a;
* ```
*
* The above implies that the compiler is also disallowed to move the read out
* of or into loops.
*
* \note The read might still be moved relative to other code.
* \note The value might be read from a hardware cache, not from RAM.
*/
template< typename T > inline
T access_once(T const *a)
{
#if 1
__asm__ __volatile__ ( "" : "=m"(*const_cast<T*>(a)));
T tmp = *a;
__asm__ __volatile__ ( "" : "=m"(*const_cast<T*>(a)));
return tmp;
#else
return *static_cast<T const volatile *>(a);
#endif
}
/**
* Write a value at an address exactly once.
*
* The compiler is disallowed to skip the write, for example:
* ```
* *a = val;
* write_now(a, val); // compiler may not skip this line
* ```
*
* The compiler is also disallowed to repeat the write.
*
* The above implies that the compiler is also disallowed to move the write out
* of or into loops.
*
* \note The write might still be moved relative to other code.
* \note The value might be written just to a hardware cache for the moment, not
* immediately to RAM.
*/
template< typename T, typename VAL > inline
void write_now(T *a, VAL &&val)
{
__asm__ __volatile__ ( "" : "=m"(*a));
*a = val;
__asm__ __volatile__ ( "" : : "m"(*a));
}
}