diff --git a/fpga/include/villas/fpga/ips/axis_cache.hpp b/fpga/include/villas/fpga/ips/axis_cache.hpp new file mode 100644 index 000000000..de5551d1b --- /dev/null +++ b/fpga/include/villas/fpga/ips/axis_cache.hpp @@ -0,0 +1,47 @@ +/* Driver for AXI Stream read cache. This module is used to lower latency of + * a DMA Scatter Gather engine's descriptor fetching. The driver allows for + * invalidating the cache. + * + * Author: Niklas Eiling + * SPDX-FileCopyrightText: 2024 Niklas Eiling + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +namespace villas { +namespace fpga { +namespace ip { + +class AxisCache : public Node { +public: + AxisCache(); + virtual ~AxisCache(); + virtual bool init() override; + virtual bool check() override; + void invalidate(); + +protected: + const size_t registerNum = 1; + const size_t registerSize = 32; + static constexpr char registerMemory[] = "reg0"; + std::list getMemoryBlocks() const override { + return {registerMemory}; + } + void setRegister(size_t reg, uint32_t value); + uint32_t getRegister(size_t reg); + void resetRegister(size_t reg); + void resetAllRegisters(); +}; + +} // namespace ip +} // namespace fpga +} // namespace villas + +#ifndef FMT_LEGACY_OSTREAM_FORMATTER +template <> +class fmt::formatter + : public fmt::ostream_formatter {}; +#endif diff --git a/fpga/lib/ips/axis_cache.cpp b/fpga/lib/ips/axis_cache.cpp new file mode 100644 index 000000000..3d24676d1 --- /dev/null +++ b/fpga/lib/ips/axis_cache.cpp @@ -0,0 +1,79 @@ +/* Driver for AXI Stream read cache. This module is used to lower latency of + * a DMA Scatter Gather engine's descriptor fetching. The driver allows for + * invalidating the cache. + * + * Author: Niklas Eiling + * SPDX-FileCopyrightText: 2024 Niklas Eiling + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +using namespace villas::fpga::ip; + +#define REGISTER_OUT(NUM) (4 * NUM) + +AxisCache::AxisCache() : Node() {} + +bool AxisCache::init() { return true; } + +bool AxisCache::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(0x00FF00FF)); + } + + for (size_t i = 1; i < registerNum; i++) { + buf = getRegister(i); + if (buf != 0x00FF00FF) { + logger->error("Register {}: 0x{:08x} != 0x{:08x}", i, buf, i); + return false; + } + } + + // Reset Registers + resetAllRegisters(); + + for (size_t i = 0; i < registerNum; i++) { + logger->debug("Register {}: 0x{:08x}", i, getRegister(i)); + } + + return true; +} + +void AxisCache::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); +} + +uint32_t AxisCache::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)); +} + +void AxisCache::resetRegister(size_t reg) { setRegister(reg, 0); } + +void AxisCache::resetAllRegisters() { + for (size_t i = 1; i < registerNum; i++) { + resetRegister(i); + } +} + +AxisCache::~AxisCache() {} + +static char n[] = "axis_cache"; +static char d[] = "Register interface VHDL module 'axi_read_cache'"; +static char v[] = "xilinx.com:module_ref:axi_read_cache:"; +static CorePlugin f;