blob: 15737691b8f9f9aa006c1692f402bdc52970fdcc [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_SW_DEVICE_LIB_BASE_BITFIELD_H_
#define OPENTITAN_SW_DEVICE_LIB_BASE_BITFIELD_H_
#include <stdbool.h>
#include <stdint.h>
// Header Extern Guard (so header can be used from C and C++)
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* @file
* @brief Bitfield Manipulation Functions
*/
/**
* All the bitfield functions are pure (they do not modify their arguments), so
* the result must be used. We enable warnings to ensure this happens.
*/
#define BITFIELD_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
/**
* A field of a 32-bit bitfield.
*
* The following field definition: `{ .mask = 0b11, .index = 12 }`
*
* Denotes the X-marked bits in the following 32-bit bitfield:
*
* field: 0b--------'--------'--XX----'--------
* index: 31 0
*
* Restrictions: The index plus the width of the mask must not be greater than
* 31.
*/
typedef struct bitfield_field32 {
/** The field mask. Usually all ones. */
uint32_t mask;
/** The field position in the bitfield, counting from the zero-bit. */
uint32_t index;
} bitfield_field32_t;
/**
* Reads a value from `field` in `bitfield`.
*
* This function uses the `field` parameter to read the value from `bitfield`.
* The resulting value will be shifted right and zero-extended so the field's
* zero-bit is the return value's zero-bit.
*
* @param bitfield Bitfield to get the field from.
* @param field Field to read out from.
* @return Zero-extended `field` from `bitfield`.
*/
BITFIELD_WARN_UNUSED_RESULT
inline uint32_t bitfield_field32_read(uint32_t bitfield,
bitfield_field32_t field) {
return (bitfield >> field.index) & field.mask;
}
/**
* Writes `value` to `field` in `bitfield`.
*
* This function uses the `field` parameter to set specific bits in `bitfield`.
* The relevant portion of `bitfield` is zeroed before the bits are set to
* `value`.
*
* @param bitfield Bitfield to set the field in.
* @param field Field within bitfield to be set.
* @param value Value for the new field.
* @return `bitfield` with `field` set to `value`.
*/
BITFIELD_WARN_UNUSED_RESULT
inline uint32_t bitfield_field32_write(uint32_t bitfield,
bitfield_field32_t field,
uint32_t value) {
bitfield &= ~(field.mask << field.index);
bitfield |= (value & field.mask) << field.index;
return bitfield;
}
/**
* A single bit in a 32-bit bitfield.
*
* This denotes the position of a single bit, counting from the zero-bit.
*
* For instance, `(bitfield_bit_index_t)4` denotes the X-marked bit in the
* following 32-bit bitfield:
*
* field: 0b--------'--------'--------'---X----
* index: 31 0
*
* Restrictions: The value must not be greater than 31.
*/
typedef uint32_t bitfield_bit32_index_t;
/**
* Turns a `bitfield_bit32_index_t` into a `bitfield_field32_t` (which is more
* general).
*
* @param bit_index The corresponding single bit to turn into a field.
* @return A 1-bit field that corresponds to `bit_index`.
*/
BITFIELD_WARN_UNUSED_RESULT
inline bitfield_field32_t bitfield_bit32_to_field32(
bitfield_bit32_index_t bit_index) {
return (bitfield_field32_t){
.mask = 0x1, .index = bit_index,
};
}
/**
* Reads the `bit_index`th bit in `bitfield`.
*
* @param bitfield Bitfield to get the bit from.
* @param bit_index Bit to read.
* @return `true` if the bit was one, `false` otherwise.
*/
BITFIELD_WARN_UNUSED_RESULT
inline bool bitfield_bit32_read(uint32_t bitfield,
bitfield_bit32_index_t bit_index) {
return bitfield_field32_read(bitfield,
bitfield_bit32_to_field32(bit_index)) == 0x1u;
}
/**
* Writes `value` to the `bit_index`th bit in `bitfield`.
*
* @param bitfield Bitfield to update the bit in.
* @param bit_index Bit to update.
* @param value Bit value to write to `bitfield`.
* @return `bitfield` with the `bit_index`th bit set to `value`.
*/
BITFIELD_WARN_UNUSED_RESULT
inline uint32_t bitfield_bit32_write(uint32_t bitfield,
bitfield_bit32_index_t bit_index,
bool value) {
return bitfield_field32_write(bitfield, bitfield_bit32_to_field32(bit_index),
value ? 0x1u : 0x0u);
}
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // OPENTITAN_SW_DEVICE_LIB_BASE_BITFIELD_H_