2016-06-14 01:19:17 +02:00
|
|
|
/** Test procedures for VILLASfpga
|
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
|
|
|
* @copyright 2016, Steffen Vogel
|
|
|
|
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
|
|
|
|
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
|
|
|
*********************************************************************************/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
#include <xilinx/xtmrctr.h>
|
|
|
|
#include <xilinx/xintc.h>
|
|
|
|
#include <xilinx/xllfifo.h>
|
|
|
|
#include <xilinx/xaxis_switch.h>
|
|
|
|
#include <xilinx/xaxidma.h>
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
#include <villas/utils.h>
|
|
|
|
#include <villas/nodes/vfpga.h>
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
#include <villas/fpga/ip.h>
|
|
|
|
|
|
|
|
//#include <villas/fpga/cbmodel.h>
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
#include "config.h"
|
|
|
|
#include "config-fpga.h"
|
|
|
|
|
|
|
|
//#include "cbuilder/cbmodel.h"
|
|
|
|
|
|
|
|
#define TEST_LEN 0x1000
|
|
|
|
|
|
|
|
#define CPU_HZ 3392389000
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
/* Declarations */
|
|
|
|
int fpga_test_intc(struct vfpga *f);
|
|
|
|
int fpga_test_timer(struct vfpga *f);
|
|
|
|
int fpga_test_fifo(struct vfpga *f);
|
|
|
|
int fpga_test_dma(struct vfpga *f);
|
|
|
|
int fpga_test_xsg(struct vfpga *f);
|
|
|
|
int fpga_test_rtds_rtt(struct vfpga *f);
|
|
|
|
int fpga_test_rtds_cbuilder(struct vfpga *f);
|
|
|
|
|
|
|
|
int fpga_tests(struct vfpga *f)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
const char *name;
|
|
|
|
int (*func)(struct vfpga *f);
|
|
|
|
} tests[] = {
|
|
|
|
{ "Interrupt Controller", fpga_test_intc },
|
|
|
|
{ "Timer Counter", fpga_test_timer },
|
|
|
|
{ "FIFO", fpga_test_fifo },
|
|
|
|
{ "DMA", fpga_test_dma },
|
|
|
|
{ "XSG: multiply_add", fpga_test_xsg },
|
|
|
|
{ "RTDS: RTT Test", fpga_test_rtds_rtt },
|
|
|
|
{ "RTDS: CBuilder", fpga_test_rtds_cbuilder }
|
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAY_LEN(tests); i++) {
|
|
|
|
ret = tests[i].func(f);
|
|
|
|
|
|
|
|
info("%s: %s", tests[i].name, (ret == 0) ? GRN("passed") : RED("failed"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fpga_test_intc(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
|
|
|
uint32_t ier, isr;
|
|
|
|
|
|
|
|
/* Save old IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
|
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | 0xFF00);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_ISR_OFFSET, 0xFF00);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
debug(3, "Wait for 8 SW triggerd interrupts");
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
wait_irq(f->vd.msi_efds[i+8]);
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
isr = XIntc_In32(f->baseaddr.intc + XIN_ISR_OFFSET);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Restore IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
return (isr & 0xFF00) ? -1 : 0; /* ISR should get cleared by MSI_Grant_signal */
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
int fpga_test_xsg(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-15 20:05:09 +02:00
|
|
|
struct ip *xsg, *dma, *sw;
|
|
|
|
|
|
|
|
xsg = ip_vlnv_lookup(&f->ips, NULL, "xsg", "xsg_multiply_add", NULL);
|
|
|
|
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
|
|
|
|
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
/* Check if required IP is available on FPGA */
|
|
|
|
if (!dma || !xsg || !dma)
|
|
|
|
return -1;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
ip_dump(xsg);
|
|
|
|
|
|
|
|
list_foreach(struct model_param *p, &xsg->model.parameters) {
|
|
|
|
if (p->direction == MODEL_PARAM_IN) {
|
|
|
|
model_param_write(p, p->default_value.flt);
|
|
|
|
info("Param '%s' updated to: %f", p->name, p->default_value.flt);
|
2016-06-14 01:19:17 +02:00
|
|
|
}
|
2016-06-15 20:05:09 +02:00
|
|
|
}
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
switch_connect(&sw->sw, dma->port, xsg->port);
|
|
|
|
switch_connect(&sw->sw, xsg->port, dma->port);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
float *src = (float *) f->dma;
|
|
|
|
float *dst = (float *) f->dma + TEST_LEN;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
src[i] = 1.1 * (i+1);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
ssize_t len = dma_ping_pong(&dma->dma, virt_to_dma(src, f->dma), virt_to_dma(dst, f->dma), 6 * sizeof(float), -1);
|
|
|
|
if (len != 6 * sizeof(float))
|
|
|
|
error("Failed to to ping pong DMA transfer: %zd", len);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
info("src[%d] = %f", i, src[i]);
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
info("dst[%d] = %f", i, dst[i]);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
int fpga_test_hls_dft(struct vfpga *f)
|
|
|
|
{
|
|
|
|
struct ip *hls, *sw, *dma;
|
|
|
|
|
|
|
|
hls = ip_vlnv_lookup(&f->ips, NULL, "hls", NULL, NULL);
|
|
|
|
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
|
|
|
|
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
|
|
|
|
|
|
|
|
/* Check if required IP is available on FPGA */
|
|
|
|
if (!dma || !hls || !dma)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fpga_test_fifo(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
ssize_t len;
|
|
|
|
char src[255], dst[255];
|
2016-06-15 20:05:09 +02:00
|
|
|
struct ip *fifo, *sw;
|
2016-06-14 01:19:17 +02:00
|
|
|
uint32_t ier;
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm", NULL);
|
|
|
|
if (!fifo)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
|
|
|
|
if (!sw)
|
|
|
|
return -1;
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
/* Save old IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
|
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << fifo->irq));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Get some random data to compare */
|
|
|
|
memset(dst, 0, sizeof(dst));
|
|
|
|
ret = read_random((char *) src, sizeof(src));
|
|
|
|
if (ret)
|
|
|
|
error("Failed to get random data");
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
ret = switch_connect(&sw->sw, fifo->port, fifo->port);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (ret)
|
|
|
|
error("Failed to configure switch");
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
len = fifo_write(&fifo->fifo_mm, (char *) src, sizeof(src), f->vd.msi_efds[fifo->irq]);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != sizeof(src))
|
|
|
|
error("Failed to send to FIFO");
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
len = fifo_read(&fifo->fifo_mm, (char *) dst, sizeof(dst), f->vd.msi_efds[fifo->irq]);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != sizeof(dst))
|
|
|
|
error("Failed to read from FIFO");
|
|
|
|
|
|
|
|
/* Restore IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Compare data */
|
|
|
|
return memcmp(src, dst, sizeof(src));
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
int fpga_test_dma(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-15 20:05:09 +02:00
|
|
|
struct ip *dma, *sw;
|
2016-06-14 01:19:17 +02:00
|
|
|
ssize_t len;
|
2016-06-15 20:05:09 +02:00
|
|
|
int ret;
|
2016-06-14 01:19:17 +02:00
|
|
|
uint32_t ier;
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
|
|
|
|
if (!dma)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
|
|
|
|
if (!sw)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int irq_mm2s = dma->irq;
|
|
|
|
int irq_s2mm = dma->irq + 1;
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
/* Save old IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
|
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << irq_mm2s) | (1 << irq_s2mm));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
ret = switch_connect(&sw->sw, dma->port, dma->port);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (ret)
|
|
|
|
error("Failed to configure switch");
|
|
|
|
|
|
|
|
#ifdef HAS_DMA_SG
|
|
|
|
/* Memory for buffer descriptors and RX */
|
|
|
|
struct dma_mem bd = {
|
|
|
|
.base_virt = (uintptr_t) f->map + BASEADDR_BRAM,
|
|
|
|
.base_phys = BASEADDR_BRAM,
|
|
|
|
.len = 8 * 1024
|
|
|
|
};
|
|
|
|
|
|
|
|
struct dma_mem rx = {
|
|
|
|
.base_virt = (uintptr_t) f->dma + TEST_LEN,
|
|
|
|
.base_phys = BASEADDR_HOST + TEST_LEN,
|
|
|
|
.len = TEST_LEN
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Get some random data to compare */
|
2016-06-15 20:05:09 +02:00
|
|
|
char *src = (char *) f->dma;
|
|
|
|
char *dst = (char *) f->dma + TEST_LEN;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
ret = read_random(src, TEST_LEN);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to get random data");
|
|
|
|
|
|
|
|
#if 0
|
2016-06-15 20:05:09 +02:00
|
|
|
len = dma_write(&f->dma_simple, virt_to_dma(src, f->dma), TEST_LEN, -1);//f->vd.msi_efds[irq_mm2s]);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != TEST_LEN)
|
|
|
|
error("Failed to send to DMAC: %zd", len);
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
len = dma_read(&f->dma_simple, virt_to_dma(dst, f->dma), TEST_LEN, -1);//f->vd.msi_efds[irq_s2mm]);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != TEST_LEN)
|
|
|
|
error("Failed to send to DMAC: %zd", len);
|
|
|
|
#else
|
2016-06-15 20:05:09 +02:00
|
|
|
len = dma_ping_pong(&dma->dma, virt_to_dma(src, f->dma), virt_to_dma(dst, f->dma), TEST_LEN, f->vd.msi_efds[irq_s2mm]);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (len != TEST_LEN)
|
|
|
|
error("Failed to to ping pong DMA transfer: %zd", len);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Restore IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Check received data */
|
|
|
|
return memcmp(src, dst, TEST_LEN);
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
int fpga_test_timer(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
|
|
|
int ret;
|
2016-06-15 20:05:09 +02:00
|
|
|
struct ip *timer;
|
2016-06-14 01:19:17 +02:00
|
|
|
uint32_t ier;
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
timer = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_timer", NULL);
|
|
|
|
if (!timer)
|
|
|
|
return -1;
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
/* Save old IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
|
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << timer->irq));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
XTmrCtr_SetOptions(&timer->timer, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
|
|
|
|
XTmrCtr_SetResetValue(&timer->timer, 0, AXI_HZ / 125);
|
|
|
|
XTmrCtr_Start(&timer->timer, 0);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
struct pollfd pfd = {
|
2016-06-15 20:05:09 +02:00
|
|
|
.fd = f->vd.msi_efds[timer->irq],
|
2016-06-14 01:19:17 +02:00
|
|
|
.events = POLLIN
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = poll(&pfd, 1, 1000);
|
|
|
|
if (ret == 1) {
|
2016-06-15 20:05:09 +02:00
|
|
|
uint64_t counter = wait_irq(f->vd.msi_efds[timer->irq]);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
info("Got IRQ: counter = %ju", counter);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
if (counter == 1)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
warn("Counter was not 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
int fpga_test_rtds_cbuilder(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-15 20:05:09 +02:00
|
|
|
#if 0
|
2016-06-14 01:19:17 +02:00
|
|
|
int ret;
|
|
|
|
int values_tx = 1;
|
|
|
|
int values_rx;
|
|
|
|
uint32_t tsc = 0, ovfl = 0;
|
|
|
|
ssize_t len;
|
|
|
|
uint32_t ier;
|
2016-06-15 20:05:09 +02:00
|
|
|
struct ip *rtds, *dma;
|
|
|
|
|
|
|
|
int irq_rtds_ovf = rtds->irq + 1;
|
|
|
|
|
|
|
|
rtds = ip_vlnv_lookup(&f->ips, "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL);
|
|
|
|
if (!rtds)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
|
|
|
|
if (!dma)
|
|
|
|
return -1;
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Save old IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
|
|
|
|
// XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
|
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << irq_rtds_ovf);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Dump RTDS AXI Stream state */
|
2016-06-15 20:05:09 +02:00
|
|
|
rtds_axis_dump(f->map + rtds->baseaddr);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Get some random data to compare */
|
|
|
|
float *data_rx = (uint32_t *) (f->dma);
|
|
|
|
float *data_tx = (uint32_t *) (f->dma + 0x1000);
|
|
|
|
|
|
|
|
/* Setup crossbar switch */
|
2016-06-15 20:05:09 +02:00
|
|
|
switch_connect(&sw->sw, rtds->port, dma->port);
|
|
|
|
switch_connect(&sw->sw, dma->port, rtds->port);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Disable blocking Overflow status */
|
2016-06-15 20:05:09 +02:00
|
|
|
int flags = fcntl(f->vd.msi_efds[irq_rtds_ovf], F_GETFL, 0);
|
|
|
|
fcntl(f->vd.msi_efds[irq_rtds_ovf], F_SETFL, flags | O_NONBLOCK);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Initialize CBuilder model */
|
|
|
|
double mdl_dt = rtds_axis_dt(f->map + BASEADDR_RTDS);
|
|
|
|
double mdl_params[] = {
|
|
|
|
1, /**< R2 = 1 Ohm */
|
|
|
|
0.001 /**< C2 = 1000 uF */
|
|
|
|
};
|
|
|
|
double mdl_inputs[1];
|
|
|
|
double mdl_outputs[1];
|
|
|
|
|
|
|
|
cbmodel_init(&mdl_params, mdl_dt);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
/* Check for overflow */
|
|
|
|
ovfl += wait_irq(f->vd.msi_efds[MSI_RTDS_OVF]);
|
|
|
|
if (tsc % (int) (1.0 / mdl_dt) == 0)
|
|
|
|
warn("Missed %u timesteps", ovfl);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read data from RTDS */
|
2016-06-15 20:05:09 +02:00
|
|
|
len = dma_read(&dma->dma, virt_to_dma(data_rx, f->dma), 0x1000, -1);
|
|
|
|
XAxiDma_IntrAckIrq(&dma->dma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
values_rx = len / sizeof(uint32_t);
|
|
|
|
|
|
|
|
mdl_inputs[0] = data_rx[0]; /* cast to double */
|
|
|
|
|
|
|
|
/* Run CBuilder model */
|
|
|
|
cbmodel_step(mdl_inputs, mdl_outputs);
|
2016-06-15 20:05:09 +02:00
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
data_tx[0] = mdl_outputs[0]; /* cast to float */
|
|
|
|
|
|
|
|
/* Send data to RTDS */
|
2016-06-15 20:05:09 +02:00
|
|
|
len = dma_write(&dma->dma, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, -1);
|
|
|
|
XAxiDma_IntrAckIrq(&dma->dma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
2016-06-14 01:19:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
|
|
|
|
#endif
|
2016-06-14 01:19:17 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-15 20:05:09 +02:00
|
|
|
int fpga_test_rtds_rtt(struct vfpga *f)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2016-06-15 20:05:09 +02:00
|
|
|
#if 0
|
|
|
|
uint32_t tsc = 0;
|
2016-06-14 01:19:17 +02:00
|
|
|
ssize_t len;
|
|
|
|
uint32_t ier;
|
|
|
|
|
|
|
|
/* Save old IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
|
|
|
|
// XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Dump RTDS AXI Stream state */
|
|
|
|
rtds_axis_dump(f->map + BASEADDR_RTDS);
|
|
|
|
|
|
|
|
/* Get some random data to compare */
|
|
|
|
uint32_t *data_rx = (uint32_t *) (f->dma);
|
|
|
|
uint32_t *data_tx = (uint32_t *) (f->dma + 0x1000);
|
|
|
|
|
|
|
|
int switch_port;
|
|
|
|
#if DATAMOVER == RTDS_DM_FIFO
|
|
|
|
switch_port = AXIS_SWITCH_FIFO_MM;
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SIMPLE
|
|
|
|
switch_port = AXIS_SWITCH_DMA_SIMPLE;
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SG
|
|
|
|
switch_port = AXIS_SWITCH_DMA_SG;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Setup crossbar switch */
|
|
|
|
switch_connect(&f->sw, AXIS_SWITCH_RTDS, switch_port);
|
|
|
|
switch_connect(&f->sw, switch_port, AXIS_SWITCH_RTDS);
|
|
|
|
|
|
|
|
/* Disable blocking Overflow status */
|
|
|
|
int flags = fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_GETFL, 0);
|
|
|
|
fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_SETFL, flags | O_NONBLOCK);
|
|
|
|
|
|
|
|
int irq_fifo = f->vd.msi_efds[MSI_FIFO_MM];
|
|
|
|
int rtt2_prev, rtt2;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
#if 0 /* Wait for TS */
|
|
|
|
tsc += wait_irq(f->vd.msi_efds[MSI_RTDS_TS]);
|
|
|
|
#else
|
|
|
|
tsc++;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0 /* Check for overflow */
|
|
|
|
ovfl += wait_irq(f->vd.msi_efds[MSI_RTDS_OVF]);
|
|
|
|
if (tsc % 20000 == 0)
|
|
|
|
warn("Missed %u timesteps", ovfl);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if DATAMOVER == RTDS_DM_FIFO
|
|
|
|
retry: len = fifo_read(&f->fifo, (char *) data_rx, 0x1000, irq_fifo);
|
|
|
|
if (XLlFifo_RxOccupancy(&f->fifo) > 0 )
|
|
|
|
goto retry;
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SIMPLE
|
|
|
|
len = dma_read(&f->dma_simple, virt_to_dma(data_rx, f->dma), 0x1000, -1);//f->vd.msi_efds[MSI_DMA_S2MM]);
|
|
|
|
uint64_t start = rdtscp();
|
|
|
|
XAxiDma_IntrAckIrq(&f->dma_simple, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SG
|
|
|
|
len = dma_read(&f->dma_sg, virt_to_dma(data_rx, f->dma), 0x1000, f->vd.msi_efds[MSI_DMA_S2MM]);
|
|
|
|
#endif
|
|
|
|
values_rx = len / sizeof(uint32_t);
|
|
|
|
|
|
|
|
for (int i = 0; i < values_tx; i++)
|
|
|
|
data_tx[i] = data_rx[i];
|
|
|
|
|
|
|
|
data_tx[3] = tsc;
|
|
|
|
|
|
|
|
if (data_rx[3] == 0)
|
|
|
|
tsc = 0;
|
|
|
|
|
|
|
|
int rtt = tsc - data_rx[3];
|
|
|
|
|
|
|
|
rtt2_prev = rtt2;
|
|
|
|
rtt2 = tsc - data_rx[0];
|
|
|
|
|
|
|
|
rdtsc_sleep(30000, start);
|
|
|
|
|
|
|
|
#if DATAMOVER == RTDS_DM_FIFO
|
|
|
|
len = fifo_write(&f->fifo, (char *) data_tx, sizeof(uint32_t) * values_tx, irq_fifo);
|
|
|
|
if (len != sizeof(uint32_t) * values_tx)
|
|
|
|
error("Failed to send to FIFO");
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SIMPLE
|
|
|
|
len = dma_write(&f->dma_simple, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, -1);//f->vd.msi_efds[MSI_DMA_MM2S]);
|
|
|
|
XAxiDma_IntrAckIrq(&f->dma_simple, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
|
|
|
#elif DATAMOVER == RTDS_DM_DMA_SG
|
|
|
|
len = dma_write(&f->dma_sg, virt_to_dma(data_tx, f->dma), sizeof(uint32_t) * values_tx, f->vd.msi_efds[MSI_DMA_MM2S]);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore IER */
|
2016-06-15 20:05:09 +02:00
|
|
|
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
|
|
|
|
#endif
|
2016-06-14 01:19:17 +02:00
|
|
|
return 0;
|
|
|
|
}
|