//
// Copyright 2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#ifndef INCLUDED_SOFT_REG_H
#define INCLUDED_SOFT_REG_H
#include
#include
#include
/* Keeps track of all metadata associated with a soft register.
* Use this struct when you need to manage a hardware register that needs
* to be accessed from different sections of software. If a register contains
* several unrelated bitfields, this object can be used to ensure coherency.
* It is recommended that the client hold this as a global/static object.
*/
typedef struct
{
uint32_t wr_addr;
uint32_t rd_addr;
uint32_t soft_copy;
} soft_reg_t;
/* A register field is defined as a tuple of the mask and the shift.
* It can be used to make read-modify-write operations more convenient
* For efficiency reasons, it is recommended to always use a constant
* of this type because it will get optimized out by the compiler and
* will result in zero memory overhead
*/
typedef struct
{
uint8_t num_bits;
uint8_t shift;
} soft_reg_field_t;
/*!
* Initialize the soft_reg_t struct as a read-write register.
* Params:
* - reg: Pointer to the soft_reg struct
* - wr_addr: The address used to flush the register to HW
* - rd_addr: The address used to read the register from HW
*/
static inline void initialize_readwrite_soft_reg(soft_reg_t* reg, uint32_t wr_addr, uint32_t rd_addr)
{
reg->wr_addr = wr_addr;
reg->rd_addr = rd_addr;
reg->soft_copy = 0;
}
/*!
* Initialize the soft_reg_t struct as a write-only register.
* Params:
* - reg: Pointer to the soft_reg struct
* - addr: The address used to flush the register to HW
*/
static inline void initialize_writeonly_soft_reg(soft_reg_t* reg, uint32_t addr)
{
reg->wr_addr = addr;
reg->rd_addr = 0;
reg->soft_copy = 0;
}
/*!
* Update specified field in the soft-copy with the arg value.
* Performs a read-modify-write operation so all other field are preserved.
* NOTE: This does not write the value to hardware.
*/
static inline void soft_reg_set(soft_reg_t* reg, const soft_reg_field_t field, const uint32_t field_value)
{
const uint32_t mask = ((1<soft_copy = (reg->soft_copy & ~mask) | ((field_value << field.shift) & mask);
}
/*!
* Write the contents of the soft-copy to hardware.
*/
static inline void soft_reg_flush(const soft_reg_t* reg)
{
wb_poke32(reg->wr_addr, reg->soft_copy);
}
/*!
* Shortcut for a set and a flush.
*/
static inline void soft_reg_write(soft_reg_t* reg, const soft_reg_field_t field, const uint32_t field_value)
{
soft_reg_set(reg, field, field_value);
soft_reg_flush(reg);
}
/*!
* Get the value of the specified field from the soft-copy.
* NOTE: This does not read anything from hardware.
*/
static inline uint32_t soft_reg_get(const soft_reg_t* reg, const soft_reg_field_t field)
{
const uint32_t mask = ((1<soft_copy & mask) >> field.shift;
}
/*!
* Read the contents of the register from hardware and update the soft copy.
*/
static inline void soft_reg_refresh(soft_reg_t* reg)
{
if (reg->rd_addr) {
reg->soft_copy = wb_peek32(reg->rd_addr);
}
}
/*!
* Shortcut for refresh and get
*/
static inline uint32_t soft_reg_read(soft_reg_t* reg, const soft_reg_field_t field)
{
soft_reg_refresh(reg);
return soft_reg_get(reg, field);
}
#endif /* INCLUDED_SOFT_REG_H */