diff --git a/fpga/include/villas/fpga/ips/register.hpp b/fpga/include/villas/fpga/ips/register.hpp new file mode 100644 index 000000000..713bddd2a --- /dev/null +++ b/fpga/include/villas/fpga/ips/register.hpp @@ -0,0 +1,47 @@ +/* Driver for register interface 'registerif' + * + * Author: Niklas Eiling + * SPDX-FileCopyrightText: 2024 Niklas Eiling + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +namespace villas { +namespace fpga { +namespace ip { + +class Register : public Node { +public: + Register(); + virtual ~Register(); + virtual bool init() override; + virtual bool check() override; + void setRegister(size_t reg, uint32_t value); + void setRegister(size_t reg, float value); + uint32_t getRegister(size_t reg); + float getRegisterFloat(size_t reg); + void resetRegister(size_t reg); + void resetAllRegisters(); + +protected: + const size_t registerNum = 4; + const size_t registerSize = 32; + static constexpr char registerMemory[] = "reg0"; + std::list getMemoryBlocks() const { + return {registerMemory}; + } +}; + +} // namespace ip +} // namespace fpga +} // namespace villas + +#ifndef FMT_LEGACY_OSTREAM_FORMATTER +template <> +class fmt::formatter + : public fmt::ostream_formatter {}; +template <> +#endif diff --git a/fpga/lib/CMakeLists.txt b/fpga/lib/CMakeLists.txt index 34d65d4cd..e1c2040c7 100644 --- a/fpga/lib/CMakeLists.txt +++ b/fpga/lib/CMakeLists.txt @@ -27,6 +27,7 @@ set(SOURCES ips/switch.cpp ips/timer.cpp ips/i2c.cpp + ips/register.cpp ips/rtds2gpu/rtds2gpu.cpp ips/rtds2gpu/xrtds2gpu.c diff --git a/fpga/lib/ips/register.cpp b/fpga/lib/ips/register.cpp new file mode 100644 index 000000000..995f1d74d --- /dev/null +++ b/fpga/lib/ips/register.cpp @@ -0,0 +1,106 @@ +/* Driver for register interface 'registerif' + * + * Author: Niklas Eiling + * SPDX-FileCopyrightText: 2024 Niklas Eiling + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +using namespace villas::fpga::ip; + +#define REGISTER_RESET (512) +#define REGISTER_OUT(NUM) (4 * NUM) + +Register::Register() : Node() {} + +bool Register::init() { return true; } + +bool Register::check() { + + logger->debug("Checking register interface: Base address: 0x{:08x}", + getBaseAddr(registerMemory)); + uint32_t buf; + // we shouldn't change the rate register, because this can lead to hardware fault, so start at 1 + for (size_t i = 1; i < registerNum; i++) { + setRegister(i, static_cast(i)); + } + + for (size_t i = 1; i < registerNum; i++) { + buf = getRegister(i); + if (buf != i) { + logger->error("Register {}: 0x{:08x} != 0x{:08x}", i, buf, i); + return false; + } + } + + resetAllRegisters(); + + for (size_t i = 0; i < registerNum; i++) { + logger->trace("Register {}: 0x{:08x}", i, getRegister(i)); + } + + // This is Dino specific for now - we should possibly move this to Dino in the future + uint32_t rate = getRegister(0); + float scale = getRegisterFloat(1); + float offset = getRegisterFloat(2); + logger->info("Check: Register configuration: Rate: {}, Scale: {}, Offset: {}", + rate, scale, offset); + + return true; +} + +void Register::setRegister(size_t reg, uint32_t value) { + if (reg >= registerNum) { + logger->error("Register index out of range: {}/{}", reg, registerNum); + throw std::out_of_range("Register index out of range"); + } + Xil_Out32(getBaseAddr(registerMemory) + REGISTER_OUT(reg), value); +} + +void Register::setRegister(size_t reg, float value) { + if (reg >= registerNum) { + logger->error("Register index out of range: {}/{}", reg, registerNum); + throw std::out_of_range("Register index out of range"); + } + Xil_Out32(getBaseAddr(registerMemory) + REGISTER_OUT(reg), + reinterpret_cast(value)); +} + +uint32_t Register::getRegister(size_t reg) { + if (reg >= registerNum) { + logger->error("Register index out of range: {}/{}", reg, registerNum); + throw std::out_of_range("Register index out of range"); + } + return Xil_In32(getBaseAddr(registerMemory) + REGISTER_OUT(reg)); +} + +float Register::getRegisterFloat(size_t reg) { + if (reg >= registerNum) { + logger->error("Register index out of range: {}/{}", reg, registerNum); + throw std::out_of_range("Register index out of range"); + } + uint32_t value = Xil_In32(getBaseAddr(registerMemory) + REGISTER_OUT(reg)); + return reinterpret_cast(value); +} + +void Register::resetRegister(size_t reg) { + if (reg >= registerNum) { + logger->error("Register index out of range: {}/{}", reg, registerNum); + throw std::out_of_range("Register index out of range"); + } + Xil_Out32(getBaseAddr(registerMemory) + REGISTER_RESET, (1 << reg)); +} + +void Register::resetAllRegisters() { + Xil_Out32(getBaseAddr(registerMemory) + REGISTER_RESET, 0xFFFFFFFF); +} + +Register::~Register() {} + +static char n[] = "register"; +static char d[] = "Register interface VHDL module 'registerif'"; +static char v[] = "xilinx.com:module_ref:registerif:"; +static CorePlugin f;