Commit 16297efe authored by Daniel Krebs's avatar Daniel Krebs
Browse files

update rtds2gpu HLS IP to v1.1

 - better tested IP (testbenches)
 - detect invalid frame sizes
 - more status reporting
parent 2f00d736
......@@ -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;
};
......
#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;
}
bool Rtds2Gpu::start()
{
XRtds2gpu_Start(&xInstance);
started = true;
return true;
}
void Rtds2Gpu::dump()
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,48 +127,41 @@ u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr) {
return Data;
}
void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data) {
void XRtds2gpu_Set_frame_size(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);
XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA, Data);
}
u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr) {
u32 XRtds2gpu_Get_frame_size(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);
Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA);
return Data;
}
u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr) {
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_O_DATA);
Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_DATA);
return Data;
}
void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA, Data);
}
u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr) {
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_FRAME_SIZE_DATA);
return Data;
Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_CTRL);
return Data & 0x1;
}
void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr) {
......
......@@ -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);
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;
/* Collect neccessary IPs */
auto rtds2gpu = reinterpret_cast<villas::fpga::ip::Rtds2Gpu&>(*ip);
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));
cr_assert(axiSwitch->connect(6, 7));
/* 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());
cr_assert(rtds2gpu.startOnce(dmaMem0.getMemoryBlock(), SAMPLE_COUNT),
"Preparing Rtds2Gpu IP failed");
const uint32_t* dataSrc = &dmaMemSrc[DATA_OFFSET];
const uint32_t* dataDst = &dmaMemDst[DATA_OFFSET];
cr_assert(dma->write(dmaMem1.getMemoryBlock(), FRAME_SIZE));
// connect DMA to Rtds2Gpu IP
// TODO: this should be done automatically
cr_assert(axiSwitch->connect(6, 7));
// cr_assert(axiSwitch->connect(6, 6)); // loopback
// cr_assert(dma->read(dmaMem1.getMemoryBlock(), FRAME_SIZE));
// cr_assert(dma->readComplete());
cr_assert(rtds2gpu.startOnce(dmaMemDst.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET*4, DOORBELL_OFFSET*4),
"Preparing Rtds2Gpu IP failed");
cr_assert(dma->writeComplete());
cr_assert(dma->write(dmaMemSrc.getMemoryBlock(), FRAME_SIZE),
"Starting DMA MM2S transfer failed");
puts("After:");
for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) {
printf("0x%02x ", dmaMem0[i]);
}
puts("");
cr_assert(dma->writeComplete(),
"DMA failed");
while(not rtds2gpu.isFinished());
rtds2gpu.dump();
const uint32_t* doorbellDst = &dmaMemDst[DOORBELL_OFFSET];
rtds2gpu.dump(spdlog::level::info);
rtds2gpu.dumpDoorbell(*doorbellDst);
cr_assert(rtds2gpu.isDone());
cr_assert(memcmp(dataSrc, dataDst, FRAME_SIZE) == 0, "Memory not equal");
logger->info(TXT_GREEN("Passed"));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment