1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

remove old C code

This commit is contained in:
Steffen Vogel 2022-10-28 02:18:13 -04:00
parent 72cfade589
commit 7ccb23d8b4
15 changed files with 0 additions and 1799 deletions

View file

@ -1,52 +0,0 @@
/** Moving window / Recursive DFT implementation based on HLS
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
/** @addtogroup fpga VILLASfpga
* @{
*/
#pragma once
#include <xilinx/xhls_dft.h>
// Forward declaration
struct ip;
struct dft {
XHls_dft inst;
int period; // in samples
int num_harmonics;
float *fharmonics;
int decimation;
};
int dft_parse(struct fpga_ip *c, json_t *cfg);
int dft_start(struct fpga_ip *c);
int dft_stop(struct fpga_ip *c);
int dft_destroy(struct fpga_ip *c);
/** @} */

View file

@ -1,153 +0,0 @@
/** Interface to Xilinx System Generator Models via PCIe
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
/** @addtogroup fpga VILLASfpga
* @{
*/
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include "list.h"
#define XSG_MAPLEN 0x1000
#define XSG_MAGIC 0xDEADBABE
// Forward declaration
struct ip;
enum model_type {
MODEL_TYPE_HLS,
MODEL_TYPE_XSG
};
enum model_xsg_block_type {
XSG_BLOCK_GATEWAY_IN = 0x1000,
XSG_BLOCK_GATEWAY_OUT = 0x1001,
XSG_BLOCK_INFO = 0x2000
};
enum model_parameter_type {
MODEL_PARAMETER_TYPE_UFIX,
MODEL_PARAMETER_TYPE_FIX,
MODEL_PARAMETER_TYPE_FLOAT,
MODEL_PARAMETER_TYPE_BOOLEAN
};
enum model_parameter_direction {
MODEL_PARAMETER_IN,
MODEL_PARAMETER_OUT,
MODEL_PARAMETER_INOUT
};
union model_parameter_value {
uint32_t ufix;
int32_t fix;
float flt;
bool bol;
};
struct xsg_model {
uint32_t *map;
ssize_t maplen;
};
struct hls_model {
};
struct model {
enum model_type type; // Either HLS or XSG model
struct list parameters; // List of model parameters.
struct list infos; // A list of key / value pairs with model details
union {
struct xsg_model xsg; // XSG specific model data
struct hls_model hls; // HLS specific model data
};
};
struct model_info {
char *field;
char *value;
};
struct model_parameter {
// Name of the parameter
char *name;
// Read / Write / Read-write?
enum model_parameter_direction direction;
// Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0
enum model_parameter_type type;
// Binary point for type == MODEL_GW_TYPE_(U)FIX
int binpt;
// Register offset to model::baseaddress
uintptr_t offset;
union model_parameter_value default_value;
// A pointer to the model structure to which this parameters belongs to.
struct fpga_ip *ip;
};
// Initialize a model
int model_init(struct fpga_ip *c);
// Parse model
int model_parse(struct fpga_ip *c, json_t *cfg);
// Destroy a model
int model_destroy(struct fpga_ip *c);
// Print detailed information about the model to the screen.
void model_dump(struct fpga_ip *c);
// Add a new parameter to the model
void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type);
// Remove an existing parameter by its name
int model_parameter_remove(struct fpga_ip *c, const char *name);
/** Read a model parameter.
*
* Note: the data type of the register is taken into account.
* All datatypes are converted to double.
*/
int model_parameter_read(struct model_parameter *p, double *v);
/** Update a model parameter.
*
* Note: the data type of the register is taken into account.
* The double argument will be converted to the respective data type of the
* GatewayIn/Out block.
*/
int model_parameter_write(struct model_parameter *p, double v);
int model_parameter_update(struct model_parameter *p, struct model_parameter *u);
/** @} */

View file

@ -1,140 +0,0 @@
/** Moving window / Recursive DFT implementation based on HLS
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/log.h>
#include <villas/log_config.h>
#include <villas/plugin.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/card.h>
#include <villas/fpga/ips/dft.h>
int dft_parse(struct fpga_ip *c, json_t *cfg)
{
struct dft *dft = (struct dft *) c->_vd;
int ret;
json_t *json_harms;
json_error_t err;
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: o }",
"period", &dft->period,
"decimation", &dft->decimation,
"harmonics", &json_harms
);
if (ret)
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
if (!json_is_array(json_harms))
error("DFT IP core requires 'harmonics' to be an array of integers!");
dft->num_harmonics = json_array_size(json_harms);
if (dft->num_harmonics <= 0)
error("DFT IP core requires 'harmonics' to contain at least 1 value!");
dft->fharmonics = alloc(sizeof(float) * dft->num_harmonics);
size_t index;
json_t *json_harm;
json_array_foreach(json_harms, index, json_harm) {
if (!json_is_real(json_harm))
error("DFT IP core requires all 'harmonics' values to be of floating point type");
dft->fharmonics[index] = (float) json_number_value(json_harm) / dft->period;
}
return 0;
}
int dft_start(struct fpga_ip *c)
{
int ret;
struct fpga_card *f = c->card;
struct dft *dft = (struct dft *) c->_vd;
XHls_dft *xdft = &dft->inst;
XHls_dft_Config xdft_cfg = {
.Ctrl_BaseAddress = (uintptr_t) f->map + c->baseaddr
};
ret = XHls_dft_CfgInitialize(xdft, &xdft_cfg);
if (ret != XST_SUCCESS)
return ret;
int max_harmonics = XHls_dft_Get_fharmonics_TotalBytes(xdft) / sizeof(dft->fharmonics[0]);
if (dft->num_harmonics > max_harmonics)
error("DFT IP core supports a maximum of %u harmonics", max_harmonics);
XHls_dft_Set_num_harmonics_V(xdft, dft->num_harmonics);
XHls_dft_Set_decimation_V(xdft, dft->decimation);
memcpy((void *) (uintptr_t) XHls_dft_Get_fharmonics_BaseAddress(xdft), dft->fharmonics, dft->num_harmonics * sizeof(dft->fharmonics[0]));
XHls_dft_EnableAutoRestart(xdft);
XHls_dft_Start(xdft);
return 0;
}
int dft_stop(struct fpga_ip *c)
{
struct dft *dft = (struct dft *) c->_vd;
XHls_dft *xdft = &dft->inst;
XHls_dft_DisableAutoRestart(xdft);
return 0;
}
int dft_destroy(struct fpga_ip *c)
{
struct dft *dft = (struct dft *) c->_vd;
if (dft->fharmonics) {
free(dft->fharmonics);
dft->fharmonics = NULL;
}
return 0;
}
static struct plugin p = {
.name = "Discrete Fourier Transform",
.description = "Perfom Discrete Fourier Transforms with variable number of harmonics on the FPGA",
.type = PLUGIN_TYPE_FPGA_IP,
.ip = {
.vlnv = { "acs.eonerc.rwth-aachen.de", "hls", "hls_dft", NULL },
.type = FPGA_IP_TYPE_MATH,
.start = dft_start,
.stop = dft_stop,
.destroy = dft_destroy,
.parse = dft_parse,
.size = sizeof(struct dft)
}
};
REGISTER_PLUGIN(&p)

View file

@ -1,427 +0,0 @@
/** Interface to Xilinx System Generator Models via PCIe
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <villas/utils.hpp>
#include <villas/log.h>
#include <villas/log_config.h>
#include <villas/plugin.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/card.h>
#include <villas/fpga/ips/model.h>
static int model_parameter_destroy(struct model_parameter *p)
{
free(p->name);
return 0;
}
static int model_info_destroy(struct model_info *i)
{
free(i->field);
free(i->value);
return 0;
}
static uint32_t model_xsg_map_checksum(uint32_t *map, size_t len)
{
uint32_t chks = 0;
for (int i = 2; i < len-1; i++)
chks += map[i];
return chks; // Moduluo 2^32 because of overflow
}
static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos)
{
#define copy_string(off) strndup((char *) (data + (off)), (length - (off)) * 4);
int j;
struct model_info *i;
// Check magic
if (map[0] != XSG_MAGIC)
error("Invalid magic: %#x", map[0]);
for (j = 2; j < len-1;) {
uint16_t type = map[j] & 0xFFFF;
uint16_t length = map[j] >> 16;
uint32_t *data = &map[j+1];
switch (type) {
case XSG_BLOCK_GATEWAY_IN:
case XSG_BLOCK_GATEWAY_OUT:
if (length < 4)
break; // Block is to small to describe a gateway
struct model_parameter *e, *p = (struct model_parameter *) alloc(sizeof(struct model_parameter));
p->name = copy_string(3);
p->default_value.flt = *((float *) &data[1]);
p->offset = data[2];
p->direction = type & 0x1;
p->type = (data[0] >> 0) & 0xFF;
p->binpt = (data[0] >> 8) & 0xFF;
e = list_lookup(parameters, p->name);
if (e)
model_parameter_update(e, p);
else
list_push(parameters, p);
break;
case XSG_BLOCK_INFO:
i = alloc(sizeof(struct model_info));
i->field = copy_string(0);
i->value = copy_string((int) ceil((double) (strlen(i->field) + 1) / 4))
list_push(infos, i);
break;
default:
warn("Unknown block type: %#06x", type);
}
j += length + 1;
}
return 0;
#undef copy_string
}
static uint32_t model_xsg_map_read_word(uint32_t offset, void *baseaddr)
{
volatile uint32_t *addr = baseaddr + 0x00;
volatile uint32_t *data = baseaddr + 0x04;
*addr = offset; // Update addr reg
return *data; // Read data reg
}
static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr)
{
size_t maplen;
uint32_t magic;
// Check magic
magic = model_xsg_map_read_word(0, baseaddr);
if (magic != XSG_MAGIC)
return -1;
maplen = model_xsg_map_read_word(1, baseaddr);
if (maplen < 3)
return -2;
// Read Data
int i;
for (i = 0; i < MIN(maplen, len); i++)
map[i] = model_xsg_map_read_word(i, baseaddr);
return i;
}
int model_parse(struct fpga_ip *c, json_t *cfg)
{
struct model *m = (struct model *) c->_vd;
int ret;
json_t *json_params;
json_error_t err;
if (strcmp(c->vlnv.library, "hls") == 0)
m->type = MODEL_TYPE_HLS;
else if (strcmp(c->vlnv.library, "sysgen") == 0)
m->type = MODEL_TYPE_XSG;
else
error("Unsupported model type: %s", c->vlnv.library);
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "parameters", &json_params);
if (ret)
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
if (json_params) {
if (!json_is_object(json_params))
error("Setting 'parameters' must be a JSON object");
const char *name;
json_t *value;
json_object_foreach(json_params, name, value) {
if (!json_is_real(value))
error("Parameters of FPGA IP '%s' must be of type floating point", c->name);
struct model_parameter *p = (struct model_parameter *) alloc(sizeof(struct model_parameter));
p->name = strdup(name);
p->default_value.flt = json_real_value(value);
list_push(&m->parameters, p);
}
}
return 0;
}
static int model_init_from_xsg_map(struct model *m, void *baseaddr)
{
int ret, chks;
if (baseaddr == (void *) -1)
return -1;
m->xsg.map = alloc(XSG_MAPLEN);
m->xsg.maplen = model_xsg_map_read(m->xsg.map, XSG_MAPLEN, baseaddr);
if (m->xsg.maplen < 0)
return -1;
debug(5, "XSG: memory map length = %#zx", m->xsg.maplen);
chks = m->xsg.map[m->xsg.maplen - 1];
if (chks != model_xsg_map_checksum(m->xsg.map, m->xsg.maplen))
return -2;
ret = model_xsg_map_parse(m->xsg.map, m->xsg.maplen, &m->parameters, &m->infos);
if (ret)
return -3;
debug(5, "XSG: Parsed %zu parameters and %zu model infos", list_length(&m->parameters), list_length(&m->infos));
return 0;
}
int model_init(struct fpga_ip *c)
{
int ret;
struct model *m = (struct model *) c->_vd;
list_init(&m->parameters);
list_init(&m->infos);
if (!fpga_vlnv_cmp(&c->vlnv, &(struct fpga_vlnv) { NULL, "sysgen", NULL, NULL }))
ret = model_init_from_xsg_map(m, c->card->map + c->baseaddr);
else
ret = 0;
// Set default values for parameters
for (size_t i = 0; i < list_length(&m->parameters); i++) {
struct model_parameter *p = (struct model_parameter *) list_at(&m->parameters, i);
p->ip = c;
if (p->direction == MODEL_PARAMETER_IN) {
model_parameter_write(p, p->default_value.flt);
info("Set parameter '%s' updated to default value: %f", p->name, p->default_value.flt);
}
}
if (ret)
error("Failed to init XSG model: %d", ret);
return 0;
}
int model_destroy(struct fpga_ip *c)
{
struct model *m = (struct model *) c->_vd;
list_destroy(&m->parameters, (dtor_cb_t) model_parameter_destroy, true);
list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true);
if (m->xsg.map != NULL)
free(m->xsg.map);
return 0;
}
void model_dump(struct fpga_ip *c)
{
struct model *m = (struct model *) c->_vd;
const char *param_type[] = { "UFix", "Fix", "Float", "Boolean" };
const char *parameter_dirs[] = { "In", "Out", "In/Out" };
{ INDENT
info("Parameters:");
for (size_t i = 0; i < list_length(&m->parameters); i++) { INDENT
struct model_parameter *p = (struct model_parameter *) list_at(&m->parameters, i);
if (p->direction == MODEL_PARAMETER_IN)
info("%#jx: %s (%s) = %.3f %s %u",
p->offset,
p->name,
parameter_dirs[p->direction],
p->default_value.flt,
param_type[p->type],
p->binpt
);
else if (p->direction == MODEL_PARAMETER_OUT)
info("%#jx: %s (%s)",
p->offset,
p->name,
parameter_dirs[p->direction]
);
}
info("Infos:");
for (size_t j = 0; j < list_length(&m->infos); j++) { INDENT
struct model_info *i = (struct model_info *) list_at(&m->infos, j);
info("%s: %s", i->field, i->value);
}
}
}
int model_parameter_read(struct model_parameter *p, double *v)
{
struct fpga_ip *c = p->ip;
union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset);
switch (p->type) {
case MODEL_PARAMETER_TYPE_UFIX:
*v = (double) ptr->ufix / (1 << p->binpt);
break;
case MODEL_PARAMETER_TYPE_FIX:
*v = (double) ptr->fix / (1 << p->binpt);
break;
case MODEL_PARAMETER_TYPE_FLOAT:
*v = (double) ptr->flt;
break;
case MODEL_PARAMETER_TYPE_BOOLEAN:
*v = (double) ptr->ufix ? 1 : 0;
}
return 0;
}
int model_parameter_write(struct model_parameter *p, double v)
{
struct fpga_ip *c = p->ip;
union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset);
switch (p->type) {
case MODEL_PARAMETER_TYPE_UFIX:
ptr->ufix = (uint32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAMETER_TYPE_FIX:
ptr->fix = (int32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAMETER_TYPE_FLOAT:
ptr->flt = (float) v;
break;
case MODEL_PARAMETER_TYPE_BOOLEAN:
ptr->bol = (bool) v;
break;
}
return 0;
}
void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type)
{
struct model *m = (struct model *) c->_vd;
struct model_parameter *p = (struct model_parameter *) alloc(sizeof(struct model_parameter));
p->name = strdup(name);
p->type = type;
p->direction = dir;
list_push(&m->parameters, p);
}
int model_parameter_remove(struct fpga_ip *c, const char *name)
{
struct model *m = (struct model *) c->_vd;
struct model_parameter *p;
p = list_lookup(&m->parameters, name);
if (!p)
return -1;
list_remove(&m->parameters, p);
return 0;
}
int model_parameter_update(struct model_parameter *p, struct model_parameter *u)
{
if (strcmp(p->name, u->name) != 0)
return -1;
p->direction = u->direction;
p->type = u->type;
p->binpt = u->binpt;
p->offset = u->offset;
return 0;
}
static struct plugin p_hls = {
.name = "Xilinx High Level Synthesis (HLS) model",
.description = "",
.type = PLUGIN_TYPE_FPGA_IP,
.ip = {
.vlnv = { NULL, "hls", NULL, NULL },
.type = FPGA_IP_TYPE_MODEL,
.init = model_init,
.destroy = model_destroy,
.dump = model_dump,
.parse = model_parse
}
};
REGISTER_PLUGIN(&p_hls)
static struct plugin p_sysgen = {
.name = "Xilinx System Generator for DSP (XSG) model",
.description = "",
.type = PLUGIN_TYPE_FPGA_IP,
.ip = {
.vlnv = { NULL, "sysgen", NULL, NULL },
.type = FPGA_IP_TYPE_MODEL,
.init = model_init,
.destroy = model_destroy,
.dump = model_dump,
.parse = model_parse,
.size = sizeof(struct model)
}
};
REGISTER_PLUGIN(&p_sysgen)

View file

@ -1,141 +0,0 @@
/** Data mover benchmarks.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/utils.hpp>
#include <villas/log.h>
#include <villas/fpga/card.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/ips/dma.h>
#include <villas/fpga/ips/switch.h>
#include <villas/fpga/ips/intc.h>
#include "bench.h"
int fpga_benchmark_datamover(struct fpga_card *c)
{
int ret;
struct fpga_ip *dm;
struct dma_mem mem, src, dst;
#if BENCH_DM == 1
char *dm_name = "fifo_mm_s_0";
#elif BENCH_DM == 2
char *dm_name = "dma_0";
#elif BENCH_DM == 3
char *dm_name = "dma_1";
#else
#error "Invalid DM selected"
#endif
dm = list_lookup(&c->ips, dm_name);
if (!dm)
error("Unknown datamover");
ret = switch_connect(c->sw, dm, dm);
if (ret)
error("Failed to configure switch");
ret = intc_enable(c->intc, (1 << dm->irq) | (1 << (dm->irq + 1)), intc_flags);
if (ret)
error("Failed to enable interrupt");
// Allocate DMA memory
ret = dma_alloc(dm, &mem, 2 * (1 << BENCH_DM_EXP_MAX), 0);
if (ret)
error("Failed to allocate DMA memory");
ret = dma_mem_split(&mem, &src, &dst);
if (ret)
return -1;
// Open file for results
char fn[256];
snprintf(fn, sizeof(fn), "results/datamover_%s_%s_%s.dat", dm_name, intc_flags & INTC_POLLING ? "polling" : "irq", uts.release);
FILE *g = fopen(fn, "w");
for (int exp = BENCH_DM_EXP_MIN; exp <= BENCH_DM_EXP_MAX; exp++) {
uint64_t start, stop, total = 0, len = 1 << exp;
#if BENCH_DM == 1
if (exp > 11)
break; // FIFO and Simple DMA are limited to 4kb
#elif BENCH_DM == 3
if (exp >= 12)
break; // FIFO and Simple DMA are limited to 4kb
#endif
read_random(src.base_virt, len);
memset(dst.base_virt, 0, len);
info("Start DM bench: len=%#jx", len);
uint64_t runs = BENCH_RUNS >> exp;
for (int i = 0; i < runs + BENCH_WARMUP; i++) {
start = rdtsc();
#if BENCH_DM == 1
ssize_t ret;
ret = fifo_write(dm, src.base_virt, len);
if (ret < 0)
error("Failed write to FIFO with len = %zu", len);
ret = fifo_read(dm, dst.base_virt, dst.len);
if (ret < 0)
error("Failed read from FIFO with len = %zu", len);
#else
ret = dma_ping_pong(dm, src.base_phys, dst.base_phys, len);
if (ret)
error("DMA ping pong failed");
#endif
stop = rdtsc();
if (memcmp(src.base_virt, dst.base_virt, len))
warn("Compare failed");
if (i > BENCH_WARMUP)
total += stop - start;
}
info("exp %u avg %lu", exp, total / runs);
fprintf(g, "%lu %lu\n", len, total / runs);
}
fclose(g);
ret = switch_disconnect(c->sw, dm, dm);
if (ret)
error("Failed to configure switch");
ret = dma_free(dm, &mem);
if (ret)
error("Failed to release DMA memory");
ret = intc_disable(c->intc, (1 << dm->irq) | (1 << (dm->irq + 1)));
if (ret)
error("Failed to enable interrupt");
return 0;
}

View file

@ -1,87 +0,0 @@
/** Jitter benchmarks.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/utils.hpp>
#include <villas/fpga/card.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/ips/timer.h>
#include "bench.h"
int fpga_benchmark_jitter(struct fpga_card *c)
{
int ret;
struct fpga_ip *ip = list_lookup(&c->ips, "timer_0");
if (!ip || !c->intc)
return -1;
struct timer *tmr = (struct timer *) ip->_vd;
XTmrCtr *xtmr = &tmr->inst;
ret = intc_enable(c->intc, (1 << ip->irq), intc_flags);
if (ret)
error("Failed to enable interrupt");
float period = 50e-6;
int runs = 300.0 / period;
int *hist = alloc(8 << 20);
XTmrCtr_SetOptions(xtmr, 0, XTC_INT_MODE_OPTION | XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION | XTC_AUTO_RELOAD_OPTION);
XTmrCtr_SetResetValue(xtmr, 0, period * FPGA_AXI_HZ);
XTmrCtr_Start(xtmr, 0);
uint64_t end, start = rdtsc();
for (int i = 0; i < runs; i++) {
uint64_t cnt = intc_wait(c->intc, ip->irq);
if (cnt != 1)
warn("fail");
// Ackowledge IRQ
XTmrCtr_WriteReg((uintptr_t) c->map + ip->baseaddr, 0, XTC_TCSR_OFFSET, XTmrCtr_ReadReg((uintptr_t) c->map + ip->baseaddr, 0, XTC_TCSR_OFFSET));
end = rdtsc();
hist[i] = end - start;
start = end;
}
XTmrCtr_Stop(xtmr, 0);
char fn[256];
snprintf(fn, sizeof(fn), "results/jitter_%s_%s.dat", intc_flags & INTC_POLLING ? "polling" : "irq", uts.release);
FILE *g = fopen(fn, "w");
for (int i = 0; i < runs; i++)
fprintf(g, "%u\n", hist[i]);
fclose(g);
free(hist);
ret = intc_disable(c->intc, (1 << ip->irq));
if (ret)
error("Failed to disable interrupt");
return 0;
}

View file

@ -1,71 +0,0 @@
/** Latency benchmarks.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <stdio.h>
#include <villas/log.h>
#include <villas/utils.hpp>
#include <villas/fpga/card.h>
#include <villas/fpga/ip.h>
#include "bench.h"
int fpga_benchmark_latency(struct fpga_card *c)
{
int ret;
uint64_t start, end;
if (!c->intc)
return -1;
int runs = 1000000;
int hist[runs];
ret = intc_enable(c->intc, 0x100, intc_flags);
if (ret)
error("Failed to enable interrupts");
for (int i = 0; i < runs; i++) {
start = rdtsc();
XIntc_Out32((uintptr_t) c->map + c->intc->baseaddr + XIN_ISR_OFFSET, 0x100);
intc_wait(c->intc, 8);
end = rdtsc();
hist[i] = end - start;
}
char fn[256];
snprintf(fn, sizeof(fn), "results/latency_%s_%s.dat", intc_flags & INTC_POLLING ? "polling" : "irq", uts.release);
FILE *g = fopen(fn, "w");
for (int i = 0; i < runs; i++)
fprintf(g, "%u\n", hist[i]);
fclose(g);
ret = intc_disable(c->intc, 0x100);
if (ret)
error("Failed to disable interrupt");
return 0;
}

View file

@ -1,68 +0,0 @@
/** Memcpy benchmarks.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/utils.hpp>
#include <villas/fpga/card.h>
#include <villas/fpga/ips/intc.h>
#include "bench.h"
int fpga_benchmark_memcpy(struct fpga_card *c)
{
char *map = c->map + 0x200000;
uint32_t *mapi = (uint32_t *) map;
char fn[256];
snprintf(fn, sizeof(fn), "results/bar0_%s_%s.dat", intc_flags & INTC_POLLING ? "polling" : "irq", uts.release);
FILE *g = fopen(fn, "w");
fprintf(g, "# bytes cycles\n");
uint32_t dummy = 0;
for (int exp = BENCH_DM_EXP_MIN; exp <= BENCH_DM_EXP_MAX; exp++) {
uint64_t len = 1 << exp;
uint64_t start, end, total = 0;
uint64_t runs = (BENCH_RUNS << 2) >> exp;
for (int i = 0; i < runs + BENCH_WARMUP; i++) {
start = rdtsc();
for (int j = 0; j < len / 4; j++)
// mapi[j] = j; // Write
dummy += mapi[j]; // Read
end = rdtsc();
if (i > BENCH_WARMUP)
total += end - start;
}
info("exp = %u\truns = %ju\ttotal = %ju\tavg = %ju\tavgw = %ju", exp, runs, total, total / runs, total / (runs * len));
fprintf(g, "%zu %lu %ju\n", len, total / runs, runs);
}
fclose(g);
return 0;
}

View file

@ -1,168 +0,0 @@
/** Benchmarks for VILLASfpga: LAPACK & BLAS
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <stdio.h>
#include <sys/utsname.h>
#include <fpga/card.h>
#include <fpga/ip.h>
#include <fpga/ips/switch.h>
#include <fpga/ips/intc.h>
#include <utils.h>
#include <villas/log.h>
#include "bench.h"
// Some hard-coded configuration for the FPGA benchmarks
#define BENCH_WARMUP 100
// Declared in fpga-bench.c
extern int intc_flags;
extern struct utsname uts;
// LAPACK & BLAS Fortran prototypes
extern int dgemm_(char *transa, char *transb, int *m, int *n, int *k, double *alpha, double *a, int *lda, double *b, int *ldb, double *beta, double *c, int *ldc);
extern int dgetrf_(int *m, int *n, double *a, int *lda, int *ipiv, int *info);
extern int dgetri_(int *n, double *a, int *lda, int *ipiv, double *work, int *lwork, int *info);
static int lapack_generate_workload(int N, double *C)
{
double *A = alloc(N * N * sizeof(double));
srand(time(NULL));
for (int i = 0; i < N * N; i++)
A[i] = 100 * (double) rand() / RAND_MAX + 1;
char transA = 'T';
char transB = 'N';
double alpha = 1;
double beta = 1;
// C = A' * A, to get an invertible matrix
dgemm_(&transA, &transB, &N, &N, &N, &alpha, A, &N, A, &N, &beta, C, &N);
free(A);
return 0;
}
static int lapack_workload(int N, double *A)
{
int info = 0;
int lworkspace = N;
int ipiv[N];
double workspace[N];
dgetrf_(&N, &N, A, &N, ipiv, &info);
if (info > 0)
error("Failed to pivot matrix");
dgetri_(&N, A, &N, ipiv, workspace, &lworkspace, &info);
if (info > 0)
error("Failed to LU factorized matrix");
return 0;
}
int fpga_benchmark_overruns(struct fpga_card *c)
{
struct fpga_ip *rtds, *dm;
dm = list_lookup(&c->ips, "dma_1");
rtds = list_lookup(&c->ips, "rtds_axis_0");
if (!rtds || !c->intc)
return -1;
int ret;
float period = 50e-6;
int runs = 1.0 / period;
int overruns;
info("runs = %u", runs);
switch_connect(c->sw, dm, rtds);
switch_connect(c->sw, rtds, dm);
intc_enable(c->intc, (1 << (dm->irq + 1 )), intc_flags);
// Dump results
char fn[256];
snprintf(fn, sizeof(fn), "results/overruns_lu_rtds_axis_%s_%s.dat", intc_flags & INTC_POLLING ? "polling" : "irq", uts.release);
FILE *g = fopen(fn, "w");
fprintf(g, "# period = %f\n", period);
fprintf(g, "# runs = %u\n", runs);
struct dma_mem mem;
ret = dma_alloc(dm, &mem, 0x1000, 0);
if (ret)
error("Failed to allocate DMA memory");
uint32_t *data_rx = (uint32_t *) mem.base_virt;
uint32_t *data_tx = (uint32_t *) mem.base_virt + 0x200;
uint64_t total, start, stop;
for (int p = 3; p < 45; p++) {
double *A = alloc(p*p*sizeof(double));
lapack_generate_workload(p, A);
overruns = 0;
total = 0;
for (int i = 0; i < 2000; i++) {
dma_read(dm, mem.base_phys, 0x200);
dma_read_complete(dm, NULL, NULL);
}
for (int i = 0; i < runs + BENCH_WARMUP; i++) {
dma_read(dm, mem.base_phys, 0x200);
start = rdtsc();
lapack_workload(p, A);
stop = rdtsc();
dma_read_complete(dm, NULL, NULL);
// Send data to rtds
data_tx[0] = i;
dma_write(dm, mem.base_phys + 0x200, 64 * sizeof(data_tx[0]));
if (i < BENCH_WARMUP)
continue;
if (i - data_rx[0] > 2)
overruns++;
total += stop - start;
}
free(A);
info("iter = %u clks = %ju overruns = %u", p, total / runs, overruns);
fprintf(g, "%u %ju %u\n", p, total / runs, overruns);
if (overruns >= runs)
break;
}
fclose(g);
return 0;
}

View file

@ -1,90 +0,0 @@
/** Benchmarks for VILLASfpga
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <villas/utils.hpp>
#include <villas/log.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/card.h>
#include <villas/fpga/ips/intc.h>
#include <villas/fpga/ips/timer.h>
#include "bench.h"
#ifdef WITH_LAPACK
int fpga_benchmark_overruns(struct fpga_card *c);
#endif
int intc_flags = 0;
struct utsname uts;
int fpga_benchmarks(int argc, char *argv[], struct fpga_card *c)
{
int ret;
struct bench {
const char *name;
int (*func)(struct fpga_card *c);
} benchmarks[] = {
{ "datamover", fpga_benchmark_datamover },
{ "jitter", fpga_benchmark_jitter },
{ "memcpy", fpga_benchmark_memcpy },
#ifdef WITH_LAPACK
{ "overruns", fpga_benchmark_overruns },
#endif
{ "latency", fpga_benchmark_latency }
};
if (argc < 2)
error("Usage: fpga benchmark (bench)");
struct bench *bench = NULL;
for (int i = 0; i < ARRAY_LEN(benchmarks); i++) {
if (strcmp(benchmarks[i].name, argv[1]) == 0) {
bench = &benchmarks[i];
break;
}
}
if (bench == NULL)
error("There is no benchmark named: %s", argv[1]);
ret = uname(&uts);
if (ret)
return -1;
again: ret = bench->func(c);
if (ret)
error("Benchmark %s failed", bench->name);
// Rerun test with polling
if (intc_flags == 0) {
intc_flags |= INTC_POLLING;
getchar();
goto again;
}
return -1;
}

View file

@ -1,44 +0,0 @@
/** Benchmarks for VILLASfpga
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <sys/utsname.h>
#include "config.h"
// Some hard-coded configuration for the FPGA benchmarks
#define BENCH_DM 3
// 1 FIFO
// 2 DMA SG
// 3 DMA Simple
#define BENCH_RUNS 3000000
#define BENCH_WARMUP 100
#define BENCH_DM_EXP_MIN 0
#define BENCH_DM_EXP_MAX 20
int fpga_benchmark_datamover(struct fpga_card *c);
int fpga_benchmark_jitter(struct fpga_card *c);
int fpga_benchmark_memcpy(struct fpga_card *c);
int fpga_benchmark_latency(struct fpga_card *c);
extern int intc_flags;
extern struct utsname uts;

View file

@ -1,124 +0,0 @@
/** VILLASfpga utility for tests and benchmarks
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <villas/log.h>
#include <villas/utils.hpp>
#include <villas/kernel/pci.hpp>
#include <villas/kernel/kernel.hpp>
#include <villas/fpga/card.h>
// Declarations
int fpga_benchmarks(int argc, char *argv[], struct fpga_card *c);
void usage()
{
printf("Usage: villas-fpga [OPTIONS] CONFIG CARD\n\n");
printf(" CONFIG path to a configuration file\n");
printf(" CARD name of the FPGA card\n");
printf(" OPTIONS is one or more of the following options:\n");
printf(" -h show this help\n");
printf(" -V show the version of the tool\n");
printf("\n");
print_copyright();
}
int main(int argc, char *argv[])
{
int ret;
struct list cards;
struct vfio_container vc;
struct fpga_card *card;
// Parse arguments
char c, *endptr;
while ((c = getopt(argc, argv, "Vh")) != -1) {
switch (c) {
case 'V':
print_version();
exit(EXIT_SUCCESS);
case 'h':
case '?':
default:
usage();
exit(EXIT_SUCCESS);
}
check: if (optarg == endptr)
error("Failed to parse parse option argument '-%c %s'", c, optarg);
}
if (argc != optind + 2) {
usage();
exit(EXIT_FAILURE);
}
char *configfile = argv[optind];
char *cardname = argv[optind+1];
FILE *f;
json_error_t err;
json_t *json;
auto pciDevices = std::make_shared<kernel::pci::DeviceList>();
ret = vfio_init(&vc);
if (ret)
return -1;
// Parse FPGA configuration
f = fopen(configfile, "r");
if (!f)
return -1;
json = json_loadf(f, 0, &err);
if (!json)
return -1;
fclose(f);
list_init(&cards);
ret = fpga_card_parse_list(&cards, json);
if (ret)
return -1;
json_decref(json);
card = list_lookup(&cards, cardname);
if (!card)
return -1;
fpga_card_dump(card);
// Run benchmarks
fpga_benchmarks(argc-optind-1, argv+optind+1, card);
return 0;
}

View file

@ -1,80 +0,0 @@
/** HLS unit test.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <unistd.h>
#include <criterion/criterion.h>
#include <villas/fpga/card.hpp>
#include <villas/fpga/vlnv.hpp>
#include <villas/fpga/core.hpp>
extern struct fpga_card *card;
// cppcheck-suppress unknownMacro
Test(fpga, hls_dft, .description = "HLS: hls_dft")
{
int ret;
struct fpga_ip *hls, *rtds;
rtds = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL });
hls = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { NULL, "hls", "hls_dft", NULL });
// Check if required IP is available on FPGA
cr_assert(hls && rtds);
ret = intc_enable(card->intc, (1 << rtds->irq), 0);
cr_assert_eq(ret, 0, "Failed to enable interrupt");
ret = switch_connect(card->sw, rtds, hls);
cr_assert_eq(ret, 0, "Failed to configure switch");
ret = switch_connect(card->sw, hls, rtds);
cr_assert_eq(ret, 0, "Failed to configure switch");
while (1) {
// Dump RTDS AXI Stream state
rtds_axis_dump(rtds);
sleep(1);
}
#if 0
int len = 2000;
int NSAMPLES = 400;
float src[len], dst[len];
for (int i = 0; i < len; i++) {
src[i] = 4 + 5.0 * sin(2.0 * M_PI * 1 * i / NSAMPLES) +
2.0 * sin(2.0 * M_PI * 2 * i / NSAMPLES) +
1.0 * sin(2.0 * M_PI * 5 * i / NSAMPLES) +
0.5 * sin(2.0 * M_PI * 9 * i / NSAMPLES) +
0.2 * sin(2.0 * M_PI * 15 * i / NSAMPLES);
fifo_write()
}
#endif
ret = switch_disconnect(card->sw, rtds, hls);
cr_assert_eq(ret, 0, "Failed to configure switch");
ret = switch_disconnect(card->sw, hls, rtds);
cr_assert_eq(ret, 0, "Failed to configure switch");
}

View file

@ -1,57 +0,0 @@
/** Intc unit test.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <criterion/criterion.h>
#include <villas/fpga/card.hpp>
#include <villas/fpga/core.hpp>
#include <villas/fpga/ips/intc.hpp>
extern struct fpga_card *card;
// cppcheck-suppress unknownMacro
Test(fpga, intc, .description = "Interrupt Controller")
{
int ret;
uint32_t isr;
cr_assert(card->intc);
ret = intc_enable(card->intc, 0xFF00, 0);
cr_assert_eq(ret, 0, "Failed to enable interrupt");
// Fake IRQs in software by writing to ISR
XIntc_Out32((uintptr_t) card->map + card->intc->baseaddr + XIN_ISR_OFFSET, 0xFF00);
// Wait for 8 SW triggered IRQs
for (int i = 0; i < 8; i++)
intc_wait(card->intc, i+8);
// Check ISR if all SW IRQs have been deliverd
isr = XIntc_In32((uintptr_t) card->map + card->intc->baseaddr + XIN_ISR_OFFSET);
ret = intc_disable(card->intc, 0xFF00);
cr_assert_eq(ret, 0, "Failed to disable interrupt");
cr_assert_eq(isr & 0xFF00, 0); // ISR should get cleared by MSI_Grant_signal
}

View file

@ -1,97 +0,0 @@
/** System Generator unit test.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017-2022, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <math.h>
#include <criterion/criterion.h>
#include <villas/log.h>
#include <villas/fpga/card.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/vlnv.h>
#include <villas/fpga/ips/dma.h>
extern struct fpga_card *card;
// cppcheck-suppress unknownMacro
Test(fpga, xsg, .description = "XSG: multiply_add")
{
int ret;
double factor, err = 0;
struct fpga_ip *ip, *dma;
struct model_parameter *p;
struct dma_mem mem;
ip = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { NULL, "sysgen", "xsg_multiply", NULL });
cr_assert(ip);
dma = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_dma", NULL });
cr_assert(dma);
struct model *model = (struct model *) ip->_vd;
p = list_lookup(&model->parameters, "factor");
if (!p)
error("Missing parameter 'factor' for model '%s'", ip->name);
ret = model_parameter_read(p, &factor);
cr_assert_eq(ret, 0, "Failed to read parameter 'factor' from model '%s'", ip->name);
info("Model param: factor = %f", factor);
ret = switch_connect(card->sw, dma, ip);
cr_assert_eq(ret, 0, "Failed to configure switch");
ret = switch_connect(card->sw, ip, dma);
cr_assert_eq(ret, 0, "Failed to configure switch");
ret = dma_alloc(dma, &mem, 0x1000, 0);
cr_assert_eq(ret, 0, "Failed to allocate DMA memory");
float *src = (float *) mem.base_virt;
float *dst = (float *) mem.base_virt + 0x800;
for (int i = 0; i < 6; i++)
src[i] = 1.1 * (i+1);
ret = dma_ping_pong(dma, (char *) src, (char *) dst, 6 * sizeof(float));
cr_assert_eq(ret, 0, "Failed to to ping pong DMA transfer: %d", ret);
for (int i = 0; i < 6; i++)
err += fabs(factor * src[i] - dst[i]);
info("Error after FPGA operation: err = %f", err);
ret = switch_disconnect(card->sw, dma, ip);
cr_assert_eq(ret, 0, "Failed to configure switch");
ret = switch_disconnect(card->sw, ip, dma);
cr_assert_eq(ret, 0, "Failed to configure switch");
ret = dma_free(dma, &mem);
cr_assert_eq(ret, 0, "Failed to release DMA memory");
cr_assert(err < 1e-3);
}