mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
update rtds2gpu HLS IP to v1.1
- better tested IP (testbenches) - detect invalid frame sizes - more status reporting
This commit is contained in:
parent
bf286568dd
commit
28458fdf8a
8 changed files with 207 additions and 102 deletions
|
@ -4,6 +4,7 @@
|
|||
#include <villas/fpga/ip_node.hpp>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
|
|
30
fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp
Normal file
30
fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef REGISTER_TYPES_H
|
||||
#define REGISTER_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<reg_doorbell_t&>(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() :
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<villas::fpga::ip::Rtds2Gpu&>(*ip);
|
||||
|
||||
auto dmaMem0 = villas::HostDmaRam::getAllocator(0).allocate<char>(FRAME_SIZE + 4);
|
||||
auto dmaMem1 = villas::HostDmaRam::getAllocator(0).allocate<char>(FRAME_SIZE + 4);
|
||||
|
||||
// continue;
|
||||
|
||||
|
||||
|
||||
auto axiSwitch = reinterpret_cast<villas::fpga::ip::AxiStreamSwitch*>(
|
||||
state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:")));
|
||||
cr_assert_not_null(axiSwitch);
|
||||
|
||||
auto dma = reinterpret_cast<villas::fpga::ip::Dma*>(
|
||||
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<uint32_t>(SAMPLE_COUNT + 1);
|
||||
auto dmaMemDst = villas::HostDmaRam::getAllocator(0).allocate<uint32_t>(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"));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue