diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index bcca8c069..2867b28de 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -4,6 +4,7 @@ #include #include "rtds2gpu/xrtds2gpu.h" +#include "rtds2gpu/register_types.hpp" namespace villas { namespace fpga { @@ -17,11 +18,22 @@ public: bool init(); - void dump(); + bool start(); - bool startOnce(const MemoryBlock& mem, size_t frameSize); + void dump(spdlog::level::level_enum logLevel = spdlog::level::info); - bool isDone(); + bool startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOffset, size_t doorbellOffset); + + bool isFinished(); + + bool isReady(); + + size_t getMaxFrameSize(); + + void dumpDoorbell(uint32_t doorbellRegister) const; + +private: + bool updateStatus(); private: static constexpr const char* registerMemory = "Reg"; @@ -32,6 +44,11 @@ private: { return { registerMemory }; } XRtds2gpu xInstance; + + axilite_reg_status_t status; + size_t maxFrameSize; + + bool started; }; diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp new file mode 100644 index 000000000..b59a297c9 --- /dev/null +++ b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp @@ -0,0 +1,30 @@ +#ifndef REGISTER_TYPES_H +#define REGISTER_TYPES_H + +#include + +union axilite_reg_status_t { + uint32_t value; + struct { + uint32_t + last_seq_nr : 16, + last_count : 6, + max_frame_size : 6, + invalid_frame_size : 1, + frame_too_short : 1, + frame_too_long : 1, + is_running : 1; + }; +}; + +union reg_doorbell_t { + uint32_t value; + struct { + uint32_t + seq_nr : 16, + count : 6, + is_valid : 1; + }; +}; + +#endif // REGISTER_TYPES_H diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h index 38770aadb..87cb2b70a 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h @@ -93,11 +93,10 @@ void XRtds2gpu_Set_data_offset(XRtds2gpu *InstancePtr, u32 Data); u32 XRtds2gpu_Get_data_offset(XRtds2gpu *InstancePtr); void XRtds2gpu_Set_doorbell_offset(XRtds2gpu *InstancePtr, u32 Data); u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr); -void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data); -u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr); -u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr); void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data); u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_Get_status(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_Get_status_vld(XRtds2gpu *InstancePtr); void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr); void XRtds2gpu_InterruptGlobalDisable(XRtds2gpu *InstancePtr); diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h index 198963c7e..73bf1bce2 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h @@ -33,15 +33,14 @@ // 0x20 : Data signal of doorbell_offset // bit 31~0 - doorbell_offset[31:0] (Read/Write) // 0x24 : reserved -// 0x28 : Data signal of status_i -// bit 31~0 - status_i[31:0] (Read/Write) -// 0x2c : reserved -// 0x30 : Data signal of status_o -// bit 31~0 - status_o[31:0] (Read) -// 0x34 : reserved -// 0x38 : Data signal of frame_size +// 0x28 : Data signal of frame_size // bit 31~0 - frame_size[31:0] (Read/Write) -// 0x3c : reserved +// 0x2c : reserved +// 0x30 : Data signal of status +// bit 31~0 - status[31:0] (Read) +// 0x34 : Control signal of status +// bit 0 - status_ap_vld (Read/COR) +// others - reserved // (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake) #define XRTDS2GPU_CTRL_ADDR_AP_CTRL 0x00 @@ -54,10 +53,9 @@ #define XRTDS2GPU_CTRL_BITS_DATA_OFFSET_DATA 32 #define XRTDS2GPU_CTRL_ADDR_DOORBELL_OFFSET_DATA 0x20 #define XRTDS2GPU_CTRL_BITS_DOORBELL_OFFSET_DATA 32 -#define XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA 0x28 -#define XRTDS2GPU_CTRL_BITS_STATUS_I_DATA 32 -#define XRTDS2GPU_CTRL_ADDR_STATUS_O_DATA 0x30 -#define XRTDS2GPU_CTRL_BITS_STATUS_O_DATA 32 -#define XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA 0x38 +#define XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA 0x28 #define XRTDS2GPU_CTRL_BITS_FRAME_SIZE_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_STATUS_DATA 0x30 +#define XRTDS2GPU_CTRL_BITS_STATUS_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_STATUS_CTRL 0x34 diff --git a/fpga/lib/CMakeLists.txt b/fpga/lib/CMakeLists.txt index 10165cdd0..7159a63a9 100644 --- a/fpga/lib/CMakeLists.txt +++ b/fpga/lib/CMakeLists.txt @@ -29,6 +29,10 @@ set(SOURCES log_helper.c ) +# we don't have much influence on drivers generated by Xilinx, so ignore warnings +set_source_files_properties(ips/rtds2gpu/xrtds2gpu.c + PROPERTIES COMPILE_FLAGS -Wno-int-to-pointer-cast) + include(FindPkgConfig) pkg_check_modules(JANSSON jansson) diff --git a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp index 50bb34c90..b9ce32d13 100644 --- a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp +++ b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp @@ -20,44 +20,64 @@ bool Rtds2Gpu::init() // make sure IP is stopped for now XRtds2gpu_DisableAutoRestart(&xInstance); - dump(); + status.value = 0; + started = false; + + maxFrameSize = getMaxFrameSize(); + logger->info("Max. frame size supported: {}", maxFrameSize); return true; } -void Rtds2Gpu::dump() +bool Rtds2Gpu::start() +{ + XRtds2gpu_Start(&xInstance); + started = true; + + return true; +} + +void Rtds2Gpu::dump(spdlog::level::level_enum logLevel) { const auto baseaddr = XRtds2gpu_Get_baseaddr(&xInstance); const auto data_offset = XRtds2gpu_Get_data_offset(&xInstance); const auto doorbell_offset = XRtds2gpu_Get_doorbell_offset(&xInstance); const auto frame_size = XRtds2gpu_Get_frame_size(&xInstance); - const auto status = XRtds2gpu_Get_status_o(&xInstance); - logger->debug("Rtds2Gpu registers (IP base {:#x}):", xInstance.Ctrl_BaseAddress); - logger->debug(" Base address (bytes): {:#x}", baseaddr); - logger->debug(" Doorbell offset (bytes): {:#x}", doorbell_offset); - logger->debug(" Data offset (bytes): {:#x}", data_offset); - logger->debug(" Frame size (words): {:#x}", frame_size); - logger->debug(" Status: {:#x}", status); + logger->log(logLevel, "Rtds2Gpu registers (IP base {:#x}):", xInstance.Ctrl_BaseAddress); + logger->log(logLevel, " Base address (bytes): {:#x}", baseaddr); + logger->log(logLevel, " Doorbell offset (bytes): {:#x}", doorbell_offset); + logger->log(logLevel, " Data offset (bytes): {:#x}", data_offset); + logger->log(logLevel, " Frame size (words): {:#x}", frame_size); + logger->log(logLevel, " Status: {:#x}", status.value); + logger->log(logLevel, " Running: {}", (status.is_running ? "yes" : "no")); + logger->log(logLevel, " Frame too short: {}", (status.frame_too_short ? "yes" : "no")); + logger->log(logLevel, " Frame too long: {}", (status.frame_too_long ? "yes" : "no")); + logger->log(logLevel, " Frame size invalid: {}", (status.invalid_frame_size ? "yes" : "no")); + logger->log(logLevel, " Last count: {}", status.last_count); + logger->log(logLevel, " Last seq. number: {}", status.last_seq_nr); + logger->log(logLevel, " Max. frame size: {}", status.max_frame_size); } -bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize) +bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOffset, size_t doorbellOffset) { auto& mm = MemoryManager::get(); + if(frameSize > maxFrameSize) { + logger->error("Requested frame size of {} exceeds max. frame size of {}", + frameSize, maxFrameSize); + return false; + } + auto translationFromIp = mm.getTranslation( getMasterAddrSpaceByInterface(axiInterface), mem.getAddrSpaceId()); - // make sure IP is stopped for now - XRtds2gpu_DisableAutoRestart(&xInstance); -// while(not XRtds2gpu_IsIdle(&xInstance) and not XRtds2gpu_IsDone(&xInstance)); - // set address of memory block in HLS IP XRtds2gpu_Set_baseaddr(&xInstance, translationFromIp.getLocalAddr(0)); - XRtds2gpu_Set_doorbell_offset(&xInstance, 0); - XRtds2gpu_Set_data_offset(&xInstance, 4); + XRtds2gpu_Set_doorbell_offset(&xInstance, doorbellOffset); + XRtds2gpu_Set_data_offset(&xInstance, dataOffset); XRtds2gpu_Set_frame_size(&xInstance, frameSize); // prepare memory with all zeroes @@ -66,15 +86,61 @@ bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize) memset(memory, 0, mem.getSize()); // start IP -// XRtds2gpu_EnableAutoRestart(&xInstance); - XRtds2gpu_Start(&xInstance); + return start(); +} + +bool Rtds2Gpu::isFinished() +{ + if(started and isReady()) { + started = false; + + if(not updateStatus()) { + throw "IP is finished but status register invalid"; + } + } + + return !started; +} + +bool +Rtds2Gpu::isReady() +{ + // use the idle bit to indicate readiness, we don't care about the difference + // here + return XRtds2gpu_IsIdle(&xInstance); +} + +bool +Rtds2Gpu::updateStatus() +{ + if(not XRtds2gpu_Get_status_vld(&xInstance)) + return false; + + status.value = XRtds2gpu_Get_status(&xInstance); return true; } -bool Rtds2Gpu::isDone() +size_t +Rtds2Gpu::getMaxFrameSize() { - return XRtds2gpu_IsDone(&xInstance); + XRtds2gpu_Set_frame_size(&xInstance, 0); + + start(); + while(not isFinished()); + + return status.max_frame_size; +} + +void +Rtds2Gpu::dumpDoorbell(uint32_t doorbellRegister) const +{ + auto& doorbell = reinterpret_cast(doorbellRegister); + + logger->info("Doorbell register: {:#08x}", doorbell.value); + logger->info(" Valid: {}", (doorbell.is_valid ? "yes" : "no")); + logger->info(" Count: {}", doorbell.count); + logger->info(" Seq. number: {}", doorbell.seq_nr); } Rtds2GpuFactory::Rtds2GpuFactory() : diff --git a/fpga/lib/ips/rtds2gpu/xrtds2gpu.c b/fpga/lib/ips/rtds2gpu/xrtds2gpu.c index f7f1dadb6..26a5e4f34 100644 --- a/fpga/lib/ips/rtds2gpu/xrtds2gpu.c +++ b/fpga/lib/ips/rtds2gpu/xrtds2gpu.c @@ -127,33 +127,6 @@ u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr) { return Data; } -void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data) { - Xil_AssertVoid(InstancePtr != NULL); - Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); - - XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA, Data); -} - -u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr) { - u32 Data; - - Xil_AssertNonvoid(InstancePtr != NULL); - Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); - - Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA); - return Data; -} - -u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr) { - u32 Data; - - Xil_AssertNonvoid(InstancePtr != NULL); - Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); - - Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_O_DATA); - return Data; -} - void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); @@ -171,6 +144,26 @@ u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr) { return Data; } +u32 XRtds2gpu_Get_status(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_DATA); + return Data; +} + +u32 XRtds2gpu_Get_status_vld(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_CTRL); + return Data & 0x1; +} + void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index adc2603ae..a9bfe8400 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -35,9 +35,12 @@ static constexpr size_t SAMPLE_SIZE = 4; -static constexpr size_t SAMPLE_COUNT = 8; +static constexpr size_t SAMPLE_COUNT = 16; static constexpr size_t FRAME_SIZE = SAMPLE_COUNT * SAMPLE_SIZE; +static constexpr size_t DOORBELL_OFFSET = SAMPLE_COUNT; +static constexpr size_t DATA_OFFSET = 0; + Test(fpga, rtds2gpu, .description = "Rtds2Gpu") { @@ -49,60 +52,55 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") logger->info("Testing {}", *ip); + + /* Collect neccessary IPs */ + auto rtds2gpu = reinterpret_cast(*ip); - auto dmaMem0 = villas::HostDmaRam::getAllocator(0).allocate(FRAME_SIZE + 4); - auto dmaMem1 = villas::HostDmaRam::getAllocator(0).allocate(FRAME_SIZE + 4); - -// continue; - - - auto axiSwitch = reinterpret_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:"))); - cr_assert_not_null(axiSwitch); auto dma = reinterpret_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axi_dma:"))); - cr_assert_not_null(dma); - memset(&dmaMem0, 0x55, dmaMem0.getMemoryBlock().getSize()); - memset(&dmaMem1, 0x11, dmaMem1.getMemoryBlock().getSize()); + rtds2gpu.dump(spdlog::level::debug); - puts("Before:"); - for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) { - printf("0x%02x ", dmaMem0[i]); - } - puts(""); + cr_assert_not_null(axiSwitch, "No AXI switch IP found"); + cr_assert_not_null(dma, "No DMA IP found"); - rtds2gpu.dump(); - cr_assert(axiSwitch->connect(7, 6)); + /* Allocate and prepare memory */ + + // allocate space for all samples and doorbell register + auto dmaMemSrc = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); + auto dmaMemDst = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); + + memset(&dmaMemSrc, 0x11, dmaMemSrc.getMemoryBlock().getSize()); + memset(&dmaMemDst, 0x55, dmaMemDst.getMemoryBlock().getSize()); + + const uint32_t* dataSrc = &dmaMemSrc[DATA_OFFSET]; + const uint32_t* dataDst = &dmaMemDst[DATA_OFFSET]; + + // connect DMA to Rtds2Gpu IP + // TODO: this should be done automatically cr_assert(axiSwitch->connect(6, 7)); - - - cr_assert(rtds2gpu.startOnce(dmaMem0.getMemoryBlock(), SAMPLE_COUNT), + cr_assert(rtds2gpu.startOnce(dmaMemDst.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET*4, DOORBELL_OFFSET*4), "Preparing Rtds2Gpu IP failed"); - cr_assert(dma->write(dmaMem1.getMemoryBlock(), FRAME_SIZE)); + cr_assert(dma->write(dmaMemSrc.getMemoryBlock(), FRAME_SIZE), + "Starting DMA MM2S transfer failed"); -// cr_assert(axiSwitch->connect(6, 6)); // loopback -// cr_assert(dma->read(dmaMem1.getMemoryBlock(), FRAME_SIZE)); -// cr_assert(dma->readComplete()); + cr_assert(dma->writeComplete(), + "DMA failed"); - cr_assert(dma->writeComplete()); + while(not rtds2gpu.isFinished()); - puts("After:"); - for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) { - printf("0x%02x ", dmaMem0[i]); - } - puts(""); + const uint32_t* doorbellDst = &dmaMemDst[DOORBELL_OFFSET]; + rtds2gpu.dump(spdlog::level::info); + rtds2gpu.dumpDoorbell(*doorbellDst); - - rtds2gpu.dump(); - - cr_assert(rtds2gpu.isDone()); + cr_assert(memcmp(dataSrc, dataDst, FRAME_SIZE) == 0, "Memory not equal"); logger->info(TXT_GREEN("Passed")); }