81 lines
2.1 KiB
C++
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));
|
|
}
|
|
|
|
|
|
}
|
|
|