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

fixed all major bugs in FPGA code

This commit is contained in:
Steffen Vogel 2016-06-19 19:23:19 +02:00
parent 98fb370e85
commit c67af15a2c
31 changed files with 1658 additions and 980 deletions

10
.gitignore vendored
View file

@ -3,10 +3,10 @@
*.so
*~
node
pipe
test
signal
fpga
/node
/pipe
/test
/signal
/fpga
thirdparty/

View file

@ -54,7 +54,7 @@ endif
######## Node types ########
# file node-type is always supported
LIB_OBJS += file.o
LIB_OBJS += file.o cbuilder.o
# Enable Socket node type when libnl3 is available
ifeq ($(shell pkg-config libnl-route-3.0; echo $$?),0)
@ -64,8 +64,8 @@ endif
# Enable VILLASfpga support when libpci is available
ifeq ($(shell pkg-config libpci; echo $$?),0)
LIB_OBJS += vfpga.o pci.o ip.o vfio.o
LIB_OBJS += dma.o model.o fifo.o switch.o rtds_axis.o
LIB_OBJS += fpga.o pci.o ip.o vfio.o
LIB_OBJS += dma.o model.o fifo.o switch.o rtds_axis.o intc.o
LDLIBS += -lxil
LDFLAGS += -Lthirdparty/xilinx -Wl,-rpath-link,'$$ORIGIN/thirdparty/xilinx'
CFLAGS += -Ithirdparty/xilinx/include
@ -113,7 +113,7 @@ all: $(LIBS) $(TARGETS)
fpga: LDLIBS += -lpci -lxil
node: server.o
fpga: fpga.o fpga-tests.o
fpga: fpga-main.o fpga-tests.o
pipe: pipe.o
test: test.o
signal: signal.o

View file

@ -24,10 +24,6 @@
* except RTDS AXI Stream bridge which runs at RTDS_HZ (100 Mhz) */
#define AXI_HZ 125000000 // 125 MHz
#define virt_to_axi(virt, map) ((char *) ((char *) virt - map))
#define virt_to_dma(virt, dma) ((char *) ((char *) virt - dma) + BASEADDR_HOST)
#define dma_to_virt(addr, dma) ((char *) ((char *) addr - BASEADDR_HOST) + dma)
#define PCI_VID_XILINX 0x10ee
#define PCI_PID_VFPGA 0x7022

View file

@ -1,5 +1,11 @@
fpga = {
reset = false;
/* Card identification */
id = "10ee:7022";
slot = "01:00.0";
intc = 0x5000;
reset = 0x2000;
do_reset = true;
ips = {
switch_0 = {
@ -14,13 +20,12 @@ fpga = {
},
dma_0 = {
vlnv = "xilinx.com:ip:axi_dma:7.1";
baseaddr = 0x0000;
baseaddr = 0x1000;
port = 2;
irq = 0
},
hls_dft_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.0";
baseaddr = 0x0000;
port = 1;
switch = "switch_0";
}
@ -34,7 +39,9 @@ fpga = {
}
nodes = {
fpga_dma = {
dma = {
datamover = "dma_0";
use_irqs = false;
}
}

104
etc/fpga.conf Normal file
View file

@ -0,0 +1,104 @@
fpga = {
/* Card identification */
id = "10ee:7022";
slot = "01:00.0";
do_reset = true;
ips = {
axi_pcie_intc_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:user:axi_pcie_intc:1.0";
baseaddr = 0xb000;
},
axi_reset_0 = {
vlnv = "xilinx.com:ip:axi_gpio:2.0";
baseaddr = 0x7000;
},
bram_0 = {
vlnv = "xilinx.com:ip:axi_bram_ctrl:4.0";
baseaddr = 0x0000;
size = 0x2000;
},
xsg_multiply_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:sysgen:xsg_multiply:1.0";
baseaddr = 0x2000;
port = 4;
parameters = {
factor = 2.0;
}
},
dma_0 = {
vlnv = "xilinx.com:ip:axi_dma:7.1";
baseaddr = 0x3000;
port = 1;
irq = 3; /* 3 - 4 */
},
timer_0 = {
vlnv = "xilinx.com:ip:axi_timer:2.0";
baseaddr = 0x4000;
irq = 0; /* 0 - 1 */
},
switch_0 = {
vlnv = "xilinx.com:ip:axis_interconnect:2.1"
baseaddr = 0x5000;
numports = 10;
},
fifo_mm_s_0 = {
vlnv = "xilinx.com:ip:axi_fifo_mm_s:4.1";
baseaddr = 0x6000;
baseaddr_axi4 = 0xC000;
port = 2;
irq = 2;
},
rtds_axis_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:user:rtds_axis:1.0";
baseaddr = 0x8000;
port = 5;
irq = 5; /* 5 -7 */
},
hls_multiply_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_multiply:1.1";
baseaddr = 0x9000;
port = 5;
},
dma_1 = {
vlnv = "xilinx.com:ip:axi_dma:7.1";
baseaddr = 0xA000;
port = 7;
irq = 3; /* 3 - 4 */
},
hls_decimate_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_decimate:1.0";
baseaddr = 0xE000;
port = 8;
},
hls_dft_0 = {
vlnv = "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.0";
baseaddr = 0xF000;
port = 9;
},
axis_data_fifo_0 = {
vlnv = "xilinx.com:ip:axis_data_fifo:1.1";
port = 3;
},
axis_data_fifo_1 = {
vlnv = "xilinx.com:ip:axis_data_fifo:1.1";
port = 6;
},
}
/* Configure switch */
paths = (
{ in = "dma", out = "hls_dft" },
{ in = "hls_dft", out = "dma" }
)
}
nodes = {
dma = {
datamover = "dma_0";
use_irqs = false;
}
}

View file

@ -20,23 +20,34 @@
#define XAXIDMA_SR_SGINCL_MASK 0x00000008
enum dma_mode {
DMA_MODE_SIMPLE,
DMA_MODE_SG
};
struct dma_mem {
uint32_t base_virt;
uint32_t base_phys;
size_t len;
};
int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem *bd, struct dma_mem *rx, size_t maxlen);
struct ip;
ssize_t dma_write(XAxiDma *xdma, char *buf, size_t len, int irq);
int dma_write(struct ip *c, char *buf, size_t len);
int dma_read(struct ip *c, char *buf, size_t len);
int dma_read_complete(struct ip *c, char **buf, size_t *len);
int dma_write_complete(struct ip *c, char **buf, size_t *len);
ssize_t dma_read(XAxiDma *xdma, char *buf, size_t len, int irq);
int dma_sg_write(struct ip *c, char *buf, size_t len);
int dma_sg_read(struct ip *c, char *buf, size_t len);
ssize_t dma_ping_pong(XAxiDma *xdma, char *src, char *dst, size_t len, int s2mm_irq);
int dma_sg_write_complete(struct ip *c, char **buf, size_t *len);
int dma_sg_read_complete(struct ip *c, char **buf, size_t *len);
int dma_simple_read(struct ip *c, char *buf, size_t len);
int dma_simple_write(struct ip *c, char *buf, size_t len);
int dma_simple_read_complete(struct ip *c, char **buf, size_t *len);
int dma_simple_write_complete(struct ip *c, char **buf, size_t *len);
int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len);
int dma_init(struct ip *c);
int dma_init_rings(struct ip *c, struct dma_mem *bd);
#endif /* _DMA_H_ */

View file

@ -17,10 +17,13 @@
#include <xilinx/xstatus.h>
#include <xilinx/xllfifo.h>
int fifo_init(XLlFifo *fifo, char *baseaddr, char *axi_baseaddr);
/* Forward declaration */
struct ip;
ssize_t fifo_write(XLlFifo *fifo, char *buf, size_t len, int irq);
int fifo_init(struct ip *c);
ssize_t fifo_read(XLlFifo *fifo, char *buf, size_t len, int irq);
ssize_t fifo_write(struct ip *c, char *buf, size_t len);
ssize_t fifo_read(struct ip *c, char *buf, size_t len);
#endif /* _FIFO_H_ */

View file

@ -0,0 +1,20 @@
/** AXI-PCIe Interrupt controller
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-2016, Steffen Vogel
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
#ifndef _INTC_H_
#define _INTC_H_
int intc_init(struct ip *c);
uint32_t intc_enable(struct ip *c, uint32_t mask);
void intc_disable(struct ip *c, uint32_t mask);
uint64_t intc_wait(struct fpga *f, int irq);
#endif /* _INTC_H_ */

75
include/villas/fpga/ip.h Normal file
View file

@ -0,0 +1,75 @@
#ifndef _IP_H_
#define _IP_H_
#include <stdint.h>
#include <xilinx/xtmrctr.h>
#include <xilinx/xintc.h>
#include <xilinx/xllfifo.h>
#include <xilinx/xaxis_switch.h>
#include <xilinx/xaxidma.h>
#include "fpga/dma.h"
#include "fpga/switch.h"
#include "fpga/fifo.h"
#include "fpga/rtds_axis.h"
#include "fpga/model.h"
#include "nodes/fpga.h"
enum ip_state {
IP_STATE_UNKNOWN,
IP_STATE_INITIALIZED
};
struct ip {
char *name;
struct {
char *vendor;
char *library;
char *name;
char *version;
} vlnv;
uintptr_t baseaddr;
uintptr_t baseaddr_axi4;
int irq;
int port;
enum ip_state state;
union {
struct model model;
struct bram {
int size;
} bram;
XTmrCtr timer;
XLlFifo fifo_mm;
XAxiDma dma;
XAxis_Switch sw;
};
struct fpga *card;
config_setting_t *cfg;
};
/** Return the first IP block in list \p l which matches the VLNV */
struct ip * ip_vlnv_lookup(struct list *l, const char *vendor, const char *library, const char *name, const char *version);
/** Check if IP block \p c matched VLNV. */
int ip_vlnv_match(struct ip *c, const char *vendor, const char *library, const char *name, const char *version);
/** Tokenizes VLNV \p vlnv and stores it into \p c */
int ip_vlnv_parse(struct ip *c, const char *vlnv);
int ip_init(struct ip *c);
void ip_destroy(struct ip *c);
void ip_dump(struct ip *c);
int ip_parse(struct ip *c, config_setting_t *cfg);
#endif

View file

@ -11,12 +11,16 @@
#define _MODEL_H_
#include <stdlib.h>
#include <inttypes.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
@ -49,18 +53,15 @@ union model_param_value {
};
struct model {
char *xml; /**< Path to a XML file which describes this model */
enum model_type type;
enum model_type type; /**< Either HLS or XSG model */
char *xml; /**< An optional path to a XML file which describes this model */
struct list parameters; /**< List of model parameters. */
struct list infos;
char *map;
size_t maplen;
struct list infos; /**< A list of key / value pairs with model details */
union {
struct xsg_model {
char *map;
size_t maplen;
uint32_t *map;
ssize_t maplen;
} xsg; /**< XSG specific model data */
struct hls_model {
@ -84,20 +85,23 @@ struct model_param {
union model_param_value default_value;
struct model *model; /**< A pointer to the model structure to which this parameters belongs to. */
struct ip *ip; /**< A pointer to the model structure to which this parameters belongs to. */
};
int model_init(struct model *m, uintptr_t baseaddr);
/** Initialize a model */
int model_init(struct ip *c);
int model_init_from_xsg_map(struct model *m, uintptr_t baseaddr);
/** Destroy a model */
void model_destroy(struct ip *c);
int model_init_from_xml(struct model *m);
/** Print detailed information about the model to the screen. */
void model_dump(struct ip *c);
void model_destroy(struct model *m);
/** Add a new parameter to the model */
void model_param_add(struct ip *c, const char *name, enum model_param_direction dir, enum model_param_type type);
void model_dump(struct model *m);
void model_param_add(struct model *m, const char *name, enum model_param_direction dir, enum model_param_type type);
/** Remove an existing parameter by its name */
int model_param_remove(struct ip *c, const char *name);
/** Read a model parameter.
*
@ -114,10 +118,4 @@ int model_param_read(struct model_param *p, double *v);
*/
int model_param_write(struct model_param *p, double v);
/** Read the XSG model information from ROM */
int model_xsg_map_read(void *offset, void *dst, size_t len);
/** Parse binary model information from ROM */
int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos);
#endif /* _MODEL_H_ */

View file

@ -14,8 +14,10 @@
#include <xilinx/xaxis_switch.h>
int switch_init(XAxis_Switch *sw, char *baseaddr, int micnt, int sicnt);
struct ip;
int switch_connect(XAxis_Switch *sw, int mi, int si);
int switch_init(struct ip *c);
int switch_connect(struct ip *c, struct ip *mi, struct ip *si);
#endif /* _SWITCH_H_ */

View file

@ -0,0 +1,15 @@
/** Timer related helper functions
*
* These functions present a simpler interface to Xilinx' Timer Counter driver (XTmrCtr_*)
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-2016, Steffen Vogel
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
#ifndef _TIMER_H_
#define _TIMER_H_
#endif

View file

@ -12,6 +12,10 @@
#include <pci/pci.h>
struct pci_access * pci_get_handle();
void pci_release_handle();
struct pci_dev * pci_find_device(struct pci_access *pacc, struct pci_filter *f);
int pci_attach_driver(struct pci_dev *d, const char *driver);

View file

@ -13,6 +13,8 @@
#include <stdarg.h>
#include <libconfig.h>
#include "utils.h"
#ifdef __GNUC__
#define INDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_indent(1);
#else
@ -21,7 +23,7 @@
/* The log level which is passed as first argument to print() */
#define LOG_LVL_DEBUG GRY("Debug")
#define LOG_LVL_INFO ""
#define LOG_LVL_INFO WHT("Info ")
#define LOG_LVL_WARN YEL("Warn ")
#define LOG_LVL_ERROR RED("Error")
#define LOG_LVL_STATS MAG("Stats")
@ -40,7 +42,7 @@ enum debug_facilities {
/* Node-types */
DBG_SOCKET = (1 << 16),
DBG_FILE = (1 << 17),
DBG_GTFPGA = (1 << 18),
DBG_FPGA = (1 << 18),
DBG_NGSI = (1 << 19),
DBG_WEBSOCKET = (1 << 20),
DBG_OPAL = (1 << 21),

104
include/villas/nodes/fpga.h Normal file
View file

@ -0,0 +1,104 @@
/** Node type: VILLASfpga
*
* This file implements the fpga node-type.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-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.
*/
/**
* @addtogroup fpga VILLASnode
* @ingroup node
* @{
*********************************************************************************/
#ifndef _FPGA_H_
#define _FPGA_H_
#include "kernel/vfio.h"
#include <pci/pci.h>
#include "nodes/fpga.h"
#include "node.h"
#include "list.h"
#define BASEADDR_HOST 0x80000000
#define FPGA_BAR 0 /**< The Base Address Register which is mmap()ed to the User Space */
#define virt_to_axi(virt, map) ((char *) ((char *) virt - map))
#define virt_to_dma(virt, dma) ((char *) ((char *) virt - dma) + BASEADDR_HOST)
#define dma_to_virt(addr, dma) ((char *) ((char *) addr - BASEADDR_HOST) + dma)
struct fpga {
struct pci_filter filter; /**< Filter for libpci with device id & slot */
struct vfio_dev vd; /**< VFIO device handle. */
int do_reset; /**< Reset VILLASfpga during startup? */
struct list ips; /**< List of IP components on FPGA. */
char *map; /**< PCI BAR0 mapping for register access */
char *dma; /**< DMA mapped memory */
size_t maplen;
size_t dmalen;
/* Some IP cores are special and referenced here */
struct ip *intc;
struct ip *reset;
struct ip *sw;
};
struct fpga_dm {
struct ip *ip;
bool use_irqs;
enum {
FPGA_DM_DMA,
FPGA_DM_FIFO
} type;
struct fpga *card;
};
/** @see node_vtable::init */
int fpga_init(int argc, char * argv[], config_setting_t *cfg);
/** @see node_vtable::deinit */
int fpga_deinit();
/** @see node_vtable::parse */
int fpga_parse(struct node *n, config_setting_t *cfg);
/** Parse the 'fpga' section in the configuration file */
int fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *cfg);
/** @see node_vtable::print */
char * fpga_print(struct node *n);
/** @see node_vtable::open */
int fpga_open(struct node *n);
/** @see node_vtable::close */
int fpga_close(struct node *n);
/** @see node_vtable::read */
int fpga_read(struct node *n, struct sample *smps[], unsigned cnt);
/** @see node_vtable::write */
int fpga_write(struct node *n, struct sample *smps[], unsigned cnt);
/** Get pointer to internal VILLASfpga datastructure */
struct fpga * fpga_get();
/** Reset VILLASfpga */
int fpga_reset(struct fpga *f);
/** Dump some details about the fpga card */
void fpga_dump(struct fpga *f);
#endif /** _FPGA_H_ @} */

View file

@ -1,87 +0,0 @@
/** Node type: VILLASfpga
*
* This file implements the vfpga node-type.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-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.
*/
/**
* @addtogroup vfpga VILLASnode
* @ingroup node
* @{
*********************************************************************************/
#ifndef _VFPGA_H_
#define _VFPGA_H_
#include "kernel/vfio.h"
#include <pci/pci.h>
#include "nodes/vfpga.h"
#include "node.h"
#include "list.h"
#define BASEADDR_HOST 0x8000000
#define VFPGA_BAR 0 /**< The Base Address Register which is mmap()ed to the User Space */
struct vfpga {
struct pci_filter filter; /**< Filter for libpci with device id & slot */
struct vfio_dev vd; /**< VFIO device handle. */
int reset; /**< Reset VILLASfpga during startup? */
struct list ips; /**< List of IP components on FPGA. */
char *map; /**< PCI BAR0 mapping for register access */
char *dma; /**< DMA mapped memory */
size_t maplen;
size_t dmalen;
/** Base addresses for internal IP blocks */
struct {
uintptr_t reset;
uintptr_t intc;
} baseaddr;
};
/** @see node_vtable::init */
int vfpga_init(int argc, char * argv[], config_setting_t *cfg);
/** @see node_vtable::deinit */
int vfpga_deinit();
/** @see node_vtable::parse */
int vfpga_parse_node(struct node *n, config_setting_t *cfg);
int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg);
/** @see node_vtable::print */
char * vfpga_print(struct node *n);
/** @see node_vtable::open */
int vfpga_open(struct node *n);
/** @see node_vtable::close */
int vfpga_close(struct node *n);
/** @see node_vtable::read */
int vfpga_read(struct node *n, struct sample *smps[], unsigned cnt);
/** @see node_vtable::write */
int vfpga_write(struct node *n, struct sample *smps[], unsigned cnt);
/** Get pointer to internal VILLASfpga datastructure */
struct vfpga * vfpga_get();
/** Reset VILLASfpga */
int vfpga_reset(struct vfpga *f);
/** Dump some details about the fpga card */
void vfpga_dump(struct vfpga *f);
#endif /** _VFPGA_H_ @} */

View file

@ -57,4 +57,4 @@ int websocket_read(struct node *n, struct sample *smps[], unsigned cnt);
/** @see node_vtable::write */
int websocket_write(struct node *n, struct sample *smps[], unsigned cnt);
#endif /* _WEBSOCKET_H_ */
#endif /** _WEBSOCKET_H_ @} */

View file

@ -119,6 +119,7 @@ char * vstrcatf(char **dest, const char *fmt, va_list va)
/** Format string like strcatf() just starting with empty string */
#define strf(fmt, ...) strcatf(&(char *) { NULL }, fmt, ##__VA_ARGS__)
#define vstrf(fmt, va) vstrcatf(&(char *) { NULL }, fmt, va)
/** Format a struct timespec date similar to strftime() */
int strftimespec(char *s, size_t max, const char *format, struct timespec *ts)
@ -169,9 +170,6 @@ int version_parse(const char *s, struct version *v);
} while (0)
#endif
/** Wait on eventfd */
uint64_t wait_irq(int irq);
/** Fill buffer with random data */
int read_random(char *buf, size_t len);

View file

@ -21,7 +21,7 @@ int config_parse(const char *filename, config_t *cfg, struct settings *set,
struct list *nodes, struct list *paths)
{
int ret;
char *filename_cpy, include_dir;
char *filename_cpy, *include_dir;
filename_cpy = strdup(filename);
include_dir = dirname(filename_cpy);

View file

@ -15,18 +15,186 @@
#include "utils.h"
#include "fpga/dma.h"
#include "fpga/ip.h"
int dma_write_complete(XAxiDma *xdma, int irq)
int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len)
{
int ret;
ret = dma_read(c, dst, len);
if (ret)
return ret;
ret = dma_write(c, src, len);
if (ret)
return ret;
ret = dma_read_complete(c, NULL, NULL);
if (ret)
return ret;
ret = dma_write_complete(c, NULL, NULL);
if (ret)
return ret;
return 0;
}
int dma_write(struct ip *c, char *buf, size_t len)
{
XAxiDma *xdma = &c->dma;
return xdma->HasSg
? dma_sg_write(c, buf, len)
: dma_simple_write(c, buf, len);
}
int dma_read(struct ip *c, char *buf, size_t len)
{
XAxiDma *xdma = &c->dma;
return xdma->HasSg
? dma_sg_read(c, buf, len)
: dma_simple_read(c, buf, len);
}
int dma_read_complete(struct ip *c, char **buf, size_t *len)
{
XAxiDma *xdma = &c->dma;
return xdma->HasSg
? dma_sg_read_complete(c, buf, len)
: dma_simple_read_complete(c, buf, len);
}
int dma_write_complete(struct ip *c, char **buf, size_t *len)
{
XAxiDma *xdma = &c->dma;
return xdma->HasSg
? dma_sg_write_complete(c, buf, len)
: dma_simple_write_complete(c, buf, len);
}
int dma_sg_write(struct ip *c, char *buf, size_t len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
XAxiDma_Bd *bd;
int ret;
buf = virt_to_dma(buf, c->card->dma);
/* Checks */
if (!xdma->HasSg)
return -1;
if ((len < 1) || (len > ring->MaxTransferLen))
return -2;
if (!xdma->HasMm2S)
return -3;
if (!ring->HasDRE) {
uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1;
if ((uintptr_t) buf & mask)
return -4;
}
ret = XAxiDma_BdRingAlloc(ring, 1, &bd);
if (ret != XST_SUCCESS)
return -5;
/* Set up the BD using the information of the packet to transmit */
ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf);
if (ret != XST_SUCCESS)
return -6;
ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen);
if (ret != XST_SUCCESS)
return -7;
/* Set SOF / EOF / ID */
XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXEOF_MASK | XAXIDMA_BD_CTRL_TXSOF_MASK);
XAxiDma_BdSetId(bd, (uintptr_t) buf);
/* Give the BD to DMA to kick off the transmission. */
ret = XAxiDma_BdRingToHw(ring, 1, bd);
if (ret != XST_SUCCESS)
return -8;
return 0;
}
int dma_sg_read(struct ip *c, char *buf, size_t len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
XAxiDma_Bd *bd;
int ret;
buf = virt_to_dma(buf, c->card->dma);
/* Checks */
if (!xdma->HasSg)
return -1;
if ((len < 1) || (len > ring->MaxTransferLen))
return -2;
if (!xdma->HasS2Mm)
return -3;
if (!ring->HasDRE) {
uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1;
if ((uintptr_t) buf & mask)
return -4;
}
ret = XAxiDma_BdRingAlloc(ring, 1, &bd);
if (ret != XST_SUCCESS)
return -5;
ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf);
if (ret != XST_SUCCESS)
return -6;
ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen);
if (ret != XST_SUCCESS)
return -7;
/* Receive BDs do not need to set anything for the control
* The hardware will set the SOF/EOF bits per stream ret */
XAxiDma_BdSetCtrl(bd, 0);
XAxiDma_BdSetId(bd, (uintptr_t) buf);
ret = XAxiDma_BdRingToHw(ring, 1, bd);
if (ret != XST_SUCCESS)
return -8;
return 0;
}
int dma_sg_write_complete(struct ip *c, char **buf, size_t *len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
XAxiDma_Bd *bd;
int processed, ret;
XAxiDma_Bd *bd;
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
/* Wait until the one BD TX transaction is done */
while ((processed = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bd)) == 0) {
if (irq >= 0)
wait_irq(irq);
// if (c->irq >= 0) {
// intc_wait(c->card, c->irq);
// XAxiDma_IntrAckIrq(xmda, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
// }
// else
__asm__ ("nop");
}
/* Free all processed TX BDs for future transmission */
@ -36,177 +204,146 @@ int dma_write_complete(XAxiDma *xdma, int irq)
return -1;
}
return processed;
}
int dma_read_complete(XAxiDma *xdma, int irq)
{
return 0;
}
ssize_t dma_write(XAxiDma *xdma, char *buf, size_t len, int irq)
int dma_sg_read_complete(struct ip *c, char **buf, size_t *len)
{
int ret;
if (xdma->HasSg) {
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
XAxiDma_Bd *bd;
XAxiDma_BdRing *ring;
XAxiDma_Bd *bd;
ring = XAxiDma_GetTxRing(xdma);
ret = XAxiDma_BdRingAlloc(ring, 1, &bd);
if (ret != XST_SUCCESS)
return -1;
/* Set up the BD using the information of the packet to transmit */
ret = XAxiDma_BdSetBufAddr(bd, (uintptr_t) buf);
if (ret != XST_SUCCESS) {
info("Tx set buffer addr %p on BD %p failed %d", buf, bd, ret);
return -1;
}
ret = XAxiDma_BdSetLength(bd, len, ring->MaxTransferLen);
if (ret != XST_SUCCESS) {
info("Tx set length %zu on BD %p failed %d", len, bd, ret);
return -1;
}
/* Set SOF / EOF / ID */
XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXEOF_MASK | XAXIDMA_BD_CTRL_TXSOF_MASK);
XAxiDma_BdSetId(bd, (uintptr_t) buf);
/* Give the BD to DMA to kick off the transmission. */
ret = XAxiDma_BdRingToHw(ring, 1, bd);
if (ret != XST_SUCCESS) {
info("to hw failed %d", ret);
return -1;
}
dma_write_complete(xdma, irq);
}
else {
ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) buf, len, XAXIDMA_DMA_TO_DEVICE);
if (ret != XST_SUCCESS) {
warn("Failed DMA transfer");
return -1;
}
if (irq >= 0) {
wait_irq(irq);
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
}
else {
while (XAxiDma_Busy(xdma, XAXIDMA_DMA_TO_DEVICE))
__asm__("nop");
}
}
return len;
}
ssize_t dma_read(XAxiDma *xdma, char *buf, size_t len, int irq)
{
int ret;
if (xdma->HasSg) {
int freecnt, processed;
XAxiDma_BdRing *ring;
XAxiDma_Bd *bd;
ring = XAxiDma_GetRxRing(xdma);
processed = 0;
do {
/* Wait until the data has been received by the Rx channel */
while (XAxiDma_BdRingFromHw(ring, 1, &bd) == 0) {
if (irq >= 0)
wait_irq(irq);
}
//char *bdbuf = XAxiDma_BdGetBufAddr(bd);
//size_t bdlen = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN);
//memcpy(buf, bdbuf, bdlen);
//buf += bdlen;
processed++;
} while (XAxiDma_BdGetSts(bd) & XAXIDMA_BD_STS_RXEOF_MASK);
/* Free all processed RX BDs for future transmission */
ret = XAxiDma_BdRingFree(ring, processed, bd);
if (ret != XST_SUCCESS) {
info("Failed to free %d rx BDs %d", processed, ret);
return XST_FAILURE;
}
/* Return processed BDs to RX channel so we are ready to receive new
* packets:
* - Allocate all free RX BDs
* - Pass the BDs to RX channel
*/
freecnt = XAxiDma_BdRingGetFreeCnt(ring);
ret = XAxiDma_BdRingAlloc(ring, freecnt, &bd);
if (ret != XST_SUCCESS) {
info("bd alloc failed");
return -1;
}
ret = XAxiDma_BdRingToHw(ring, freecnt, bd);
if (ret != XST_SUCCESS) {
info("Submit %d rx BDs failed %d", freecnt, ret);
return -1;
}
}
else {
ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) buf, len, XAXIDMA_DEVICE_TO_DMA);
if (ret != XST_SUCCESS)
warn("Failed DMA transfer");
if (irq >= 0) {
wait_irq(irq);
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
}
else {
while (XAxiDma_Busy(xdma, XAXIDMA_DEVICE_TO_DMA))
__asm__("nop");
}
}
return len;
}
ssize_t dma_ping_pong(XAxiDma *xdma, char *src, char *dst, size_t len, int s2mm_irq)
{
int ret;
/* Prepare S2MM transfer */
ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) dst, len, XAXIDMA_DEVICE_TO_DMA);
if (ret != XST_SUCCESS)
warn("Failed DMA transfer");
/* Start MM2S transfer */
ret = XAxiDma_SimpleTransfer(xdma, (uintptr_t) src, len, XAXIDMA_DMA_TO_DEVICE);
if (ret != XST_SUCCESS) {
warn("Failed DMA transfer");
if (!xdma->HasSg)
return -1;
}
/* Wait for completion */
if (s2mm_irq >= 0) {
wait_irq(s2mm_irq);
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
}
else {
while (XAxiDma_Busy(xdma, XAXIDMA_DEVICE_TO_DMA))
while (XAxiDma_BdRingFromHw(ring, 1, &bd) == 0) {
// if (irq >= 0) {
// intc_wait(c->card, c->irq + 1);
// XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
// }
// else
__asm__("nop");
}
if (len != NULL)
*len = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN);
return XAxiDma_ReadReg(xdma->RegBase + XAXIDMA_RX_OFFSET, XAXIDMA_BUFFLEN_OFFSET);
if (buf != NULL)
*buf = (char *) (uintptr_t) XAxiDma_BdGetBufAddr(bd);
/* Free all processed RX BDs for future transmission */
ret = XAxiDma_BdRingFree(ring, 1, bd);
if (ret != XST_SUCCESS)
return -3;
return 0;
}
static int dma_setup_bdring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
int dma_simple_read(struct ip *c, char *buf, size_t len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
buf = virt_to_dma(buf, c->card->dma);
/* Checks */
if (xdma->HasSg)
return -1;
if ((len < 1) || (len > ring->MaxTransferLen))
return -2;
if (!xdma->HasS2Mm)
return -3;
if (!ring->HasDRE) {
uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1;
if ((uintptr_t) buf & mask)
return -4;
}
if(!(XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) {
if (XAxiDma_Busy(xdma, XAXIDMA_DEVICE_TO_DMA))
return -5;
}
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_DESTADDR_OFFSET, LOWER_32_BITS((uintptr_t) buf));
if (xdma->AddrWidth > 32)
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_DESTADDR_MSB_OFFSET, UPPER_32_BITS((uintptr_t) buf));
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_CR_OFFSET) | XAXIDMA_CR_RUNSTOP_MASK);
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET, len);
return XST_SUCCESS;
}
int dma_simple_write(struct ip *c, char *buf, size_t len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
buf = virt_to_dma(buf, c->card->dma);
/* Checks */
if (xdma->HasSg)
return -1;
if ((len < 1) || (len > ring->MaxTransferLen))
return -2;
if (!xdma->HasMm2S)
return -3;
if (!ring->HasDRE) {
uint32_t mask = xdma->MicroDmaMode ? XAXIDMA_MICROMODE_MIN_BUF_ALIGN : ring->DataWidth - 1;
if ((uintptr_t) buf & mask)
return -4;
}
/* If the engine is doing transfer, cannot submit */
if(!(XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) {
if (XAxiDma_Busy(xdma, XAXIDMA_DMA_TO_DEVICE))
return -5;
}
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_SRCADDR_OFFSET, LOWER_32_BITS((uintptr_t) buf));
if (xdma->AddrWidth > 32)
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_SRCADDR_MSB_OFFSET, UPPER_32_BITS((uintptr_t) buf));
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_CR_OFFSET, XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_CR_OFFSET) | XAXIDMA_CR_RUNSTOP_MASK);
XAxiDma_WriteReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET, len);
return XST_SUCCESS;
}
int dma_simple_read_complete(struct ip *c, char **buf, size_t *len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK));
// if(!(XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) {
// if (XAxiDma_Busy(xdma, XAXIDMA_DMA_TO_DEVICE))
// return -5;
// }
return 0;
}
int dma_simple_write_complete(struct ip *c, char **buf, size_t *len)
{
XAxiDma *xdma = &c->dma;
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK));
return 0;
}
static int dma_setup_ring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
{
int delay = 0;
int coalesce = 1;
@ -222,16 +359,13 @@ static int dma_setup_bdring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
/* Setup Rx BD space */
cnt = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, bdbuf->len);
ret = XAxiDma_BdRingCreate(ring, bdbuf->base_phys, bdbuf->base_virt, XAXIDMA_BD_MINIMUM_ALIGNMENT, cnt);
ret = XAxiDma_BdRingCreate(ring, bdbuf->base_phys, bdbuf->base_virt, XAXIDMA_BD_MINIMUM_ALIGNMENT, cnt);
if (ret != XST_SUCCESS) {
info("RX create BD ring failed %d", ret);
return XST_FAILURE;
}
/*
* Setup an all-zero BD as the template for the Rx channel.
*/
XAxiDma_BdClear(&clearbd);
ret = XAxiDma_BdRingClone(ring, &clearbd);
if (ret != XST_SUCCESS) {
@ -239,113 +373,64 @@ static int dma_setup_bdring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
return XST_FAILURE;
}
return XST_SUCCESS;
}
static int dma_setup_rx(XAxiDma *AxiDmaInstPtr, struct dma_mem *bdbuf, struct dma_mem *rxbuf, size_t maxlen)
{
int ret;
XAxiDma_BdRing *ring;
XAxiDma_Bd *bd, *curbd;
uint32_t freecnt;
uintptr_t rxptr;
ring = XAxiDma_GetRxRing(AxiDmaInstPtr);
ret = dma_setup_bdring(ring, bdbuf);
if (ret != XST_SUCCESS)
return -1;
/* Attach buffers to RxBD ring so we are ready to receive packets */
freecnt = XAxiDma_BdRingGetFreeCnt(ring);
ret = XAxiDma_BdRingAlloc(ring, freecnt, &bd);
if (ret != XST_SUCCESS) {
info("RX alloc BD failed %d", ret);
return XST_FAILURE;
}
curbd = bd;
rxptr = rxbuf->base_phys;
for (int i = 0; i < freecnt; i++) {
ret = XAxiDma_BdSetBufAddr(curbd, rxptr);
if (ret != XST_SUCCESS) {
info("Set buffer addr %#lx on BD %p failed %d", rxptr, curbd, ret);
return XST_FAILURE;
}
ret = XAxiDma_BdSetLength(curbd, maxlen, ring->MaxTransferLen);
if (ret != XST_SUCCESS) {
info("Rx set length %zu on BD %p failed %d", maxlen, curbd, ret);
return XST_FAILURE;
}
/* Receive BDs do not need to set anything for the control
* The hardware will set the SOF/EOF bits per stream ret */
XAxiDma_BdSetCtrl(curbd, 0);
XAxiDma_BdSetId(curbd, rxptr);
rxptr += maxlen;
curbd = (XAxiDma_Bd *) XAxiDma_BdRingNext(ring, curbd);
}
/* Clear the receive buffer, so we can verify data */
memset((void *) (uintptr_t) rxbuf->base_virt, 0, rxbuf->len);
ret = XAxiDma_BdRingToHw(ring, freecnt, bd);
if (ret != XST_SUCCESS) {
info("RX submit hw failed %d", ret);
return XST_FAILURE;
}
/* Start RX DMA channel */
ret = XAxiDma_BdRingStart(ring);
if (ret != XST_SUCCESS) {
info("RX start hw failed %d", ret);
return XST_FAILURE;
}
return XST_SUCCESS;
}
static int dma_setup_tx(XAxiDma *AxiDmaInstPtr, struct dma_mem *bd)
{
int ret;
XAxiDma_BdRing *ring;
ring = XAxiDma_GetTxRing(AxiDmaInstPtr);
ret = dma_setup_bdring(ring, bd);
if (ret != XST_SUCCESS)
return -1;
/* Start the TX channel */
/* Start the channel */
ret = XAxiDma_BdRingStart(ring);
if (ret != XST_SUCCESS) {
info("failed start bdring txsetup %d", ret);
return XST_FAILURE;
}
return XST_SUCCESS;
}
int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem *bd, struct dma_mem *rx, size_t maxlen)
int dma_init_rings(struct ip *c, struct dma_mem *bd)
{
int ret, sgincld;
int ret;
XAxiDma *xdma = &c->dma;
/* Split BD memory equally between Rx and Tx rings */
struct dma_mem bd_rx = {
.base_virt = bd->base_virt,
.base_phys = bd->base_phys,
.len = bd->len / 2
};
struct dma_mem bd_tx = {
.base_virt = bd->base_virt + bd_rx.len,
.base_phys = bd->base_phys + bd_rx.len,
.len = bd->len - bd_rx.len
};
ret = dma_setup_ring(XAxiDma_GetRxRing(xdma), &bd_rx);
if (ret != XST_SUCCESS)
return -1;
ret = dma_setup_ring(XAxiDma_GetTxRing(xdma), &bd_tx);
if (ret != XST_SUCCESS)
return -1;
return 0;
}
int dma_init(struct ip *c)
{
int ret, sg;
XAxiDma *xdma = &c->dma;
/* Guess DMA type */
sg = (XAxiDma_In32((uintptr_t) c->card->map + c->baseaddr + XAXIDMA_TX_OFFSET+ XAXIDMA_SR_OFFSET) &
XAxiDma_In32((uintptr_t) c->card->map + c->baseaddr + XAXIDMA_RX_OFFSET+ XAXIDMA_SR_OFFSET) & XAXIDMA_SR_SGINCL_MASK) ? 1 : 0;
XAxiDma_Config xdma_cfg = {
.BaseAddr = (uintptr_t) baseaddr,
.BaseAddr = (uintptr_t) c->card->map + c->baseaddr,
.HasStsCntrlStrm = 0,
.HasMm2S = 1,
.HasMm2SDRE = 0,
.Mm2SDataWidth = 32,
.HasMm2SDRE = 1,
.Mm2SDataWidth = 128,
.HasS2Mm = 1,
.HasS2MmDRE = 0, /* Data Realignment Engine */
.S2MmDataWidth = 32,
.HasSg = (mode == DMA_MODE_SG) ? 1 : 0,
.HasS2MmDRE = 1, /* Data Realignment Engine */
.HasSg = sg,
.S2MmDataWidth = 128,
.Mm2sNumChannels = 1,
.S2MmNumChannels = 1,
.Mm2SBurstSize = 64,
@ -360,17 +445,6 @@ int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem *
return -1;
}
/* Check if correct DMA type */
sgincld = XAxiDma_In32((uintptr_t) baseaddr + XAXIDMA_TX_OFFSET+ XAXIDMA_SR_OFFSET) &
XAxiDma_In32((uintptr_t) baseaddr + XAXIDMA_RX_OFFSET+ XAXIDMA_SR_OFFSET) &
XAXIDMA_SR_SGINCL_MASK;
if ((mode == DMA_MODE_SIMPLE && sgincld == XAXIDMA_SR_SGINCL_MASK) ||
(mode == DMA_MODE_SG && sgincld != XAXIDMA_SR_SGINCL_MASK)) {
info("This is not a %s DMA controller", (mode == DMA_MODE_SG) ? "SG" : "Simple");
return -1;
}
/* Perform selftest */
ret = XAxiDma_Selftest(xdma);
if (ret != XST_SUCCESS) {
@ -378,29 +452,6 @@ int dma_init(XAxiDma *xdma, char *baseaddr, enum dma_mode mode, struct dma_mem *
return -1;
}
/* Setup Buffer Descriptor rings for SG DMA */
if (mode == DMA_MODE_SG) {
/* Split BD memory equally between Rx and Tx rings */
struct dma_mem bd_rx = {
.base_virt = bd->base_virt,
.base_phys = bd->base_phys,
.len = bd->len / 2
};
struct dma_mem bd_tx = {
.base_virt = bd->base_virt + bd_rx.len,
.base_phys = bd->base_phys + bd_rx.len,
.len = bd->len - bd_rx.len
};
ret = dma_setup_rx(xdma, &bd_rx, rx, maxlen);
if (ret != XST_SUCCESS)
return -1;
ret = dma_setup_tx(xdma, &bd_tx);
if (ret != XST_SUCCESS)
return -1;
}
/* Enable completion interrupts for both channels */
XAxiDma_IntrEnable(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);

View file

@ -13,42 +13,50 @@
#include <villas/utils.h>
#include "utils.h"
#include "fpga/ip.h"
#include "fpga/fifo.h"
#include "fpga/intc.h"
int fifo_init(XLlFifo *fifo, char *baseaddr, char *axi_baseaddr)
int fifo_init(struct ip *c)
{
XLlFifo *fifo = &c->fifo_mm;
int ret;
XLlFifo_Config fifo_cfg = {
.BaseAddress = (uintptr_t) baseaddr,
.Axi4BaseAddress = (uintptr_t) axi_baseaddr,
.Datainterface = (axi_baseaddr == NULL) ? 0 : 1 /* use AXI4 for Data, AXI4-Lite for control */
.BaseAddress = (uintptr_t) c->card->map + c->baseaddr,
.Axi4BaseAddress = (uintptr_t) c->card->map + c->baseaddr_axi4,
.Datainterface = ((c->baseaddr_axi4) && (c->baseaddr_axi4 != -1)) ? 1 : 0 /* use AXI4 for Data, AXI4-Lite for control */
};
ret = XLlFifo_CfgInitialize(fifo, &fifo_cfg, (uintptr_t) baseaddr);
ret = XLlFifo_CfgInitialize(fifo, &fifo_cfg, (uintptr_t) c->card->map + c->baseaddr);
if (ret != XST_SUCCESS)
return -1;
XLlFifo_IntEnable(fifo, XLLF_INT_RC_MASK);
XLlFifo_IntEnable(fifo, XLLF_INT_RC_MASK); /* Receive complete IRQ */
return 0;
}
ssize_t fifo_write(XLlFifo *fifo, char *buf, size_t len, int irq)
ssize_t fifo_write(struct ip *c, char *buf, size_t len)
{
XLlFifo *fifo = &c->fifo_mm;
XLlFifo_Write(fifo, buf, len);
XLlFifo_TxSetLen(fifo, len);
return len;
}
ssize_t fifo_read(XLlFifo *fifo, char *buf, size_t len, int irq)
ssize_t fifo_read(struct ip *c, char *buf, size_t len)
{
XLlFifo *fifo = &c->fifo_mm;
size_t nextlen = 0;
while (XLlFifo_RxOccupancy(fifo) == 0) {
if (irq >= 0)
wait_irq(irq);
if (c->irq >= 0)
intc_wait(c->card, c->irq);
else
__asm__("nop");
}

77
lib/fpga/intc.c Normal file
View file

@ -0,0 +1,77 @@
/** AXI-PCIe Interrupt controller
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-2016, Steffen Vogel
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
#include <unistd.h>
#include <xilinx/xintc.h>
#include "log.h"
#include "nodes/fpga.h"
#include "kernel/vfio.h"
#include "fpga/ip.h"
#include "fpga/intc.h"
int intc_init(struct ip *c)
{
struct fpga *f = c->card;
int ret;
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
/* Setup IRQs */
for (int i = 0; i < f->vd.irqs[VFIO_PCI_MSI_IRQ_INDEX].count; i++) {
/* Setup vector */
XIntc_Out32(base + XIN_IVAR_OFFSET + i * 4, i);
/* Register eventfd with VFIO */
ret = vfio_pci_msi_fd(&f->vd, (1 << i));
if (ret < 0)
serror("Failed to create eventfd for IRQ: ret=%d", f->vd.msi_efds[i]);
}
XIntc_Out32(base + XIN_IMR_OFFSET, 0); /* Use manual acknowlegement for all IRQs */
XIntc_Out32(base + XIN_IAR_OFFSET, 0xFFFFFFFF); /* Acknowlege all pending IRQs manually */
XIntc_Out32(base + XIN_IMR_OFFSET, 0xFFFFFFFF); /* Use fast acknowlegement for all IRQs */
XIntc_Out32(base + XIN_IER_OFFSET, 0x00000000); /* Disable all IRQs by default */
XIntc_Out32(base + XIN_MER_OFFSET, XIN_INT_HARDWARE_ENABLE_MASK | XIN_INT_MASTER_ENABLE_MASK);
return 0;
}
uint32_t intc_enable(struct ip *c, uint32_t mask)
{
struct fpga *f = c->card;
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
uint32_t ier = XIntc_In32(base + XIN_IER_OFFSET);
XIntc_Out32(base + XIN_IER_OFFSET, ier | mask);
return ier;
}
void intc_disable(struct ip *c, uint32_t mask)
{
struct fpga *f = c->card;
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
XIntc_Out32(base + XIN_IER_OFFSET, XIntc_In32(base + XIN_IER_OFFSET) & ~mask);
}
uint64_t intc_wait(struct fpga *f, int irq)
{
ssize_t ret;
uint64_t cnt;
ret = read(f->vd.msi_efds[irq], &cnt, sizeof(cnt));
if (ret != sizeof(cnt))
return 0;
return cnt;
}

181
lib/fpga/ip.c Normal file
View file

@ -0,0 +1,181 @@
#include <string.h>
#include <unistd.h>
#include <libconfig.h>
#include "log.h"
#include "fpga/ip.h"
#include "fpga/intc.h"
#include "fpga/fifo.h"
#include "nodes/fpga.h"
#include "config-fpga.h"
struct ip * ip_vlnv_lookup(struct list *l, const char *vendor, const char *library, const char *name, const char *version)
{
list_foreach(struct ip *c, l) {
if (ip_vlnv_match(c, vendor, library, name, version))
return c;
}
return NULL;
}
int ip_vlnv_match(struct ip *c, const char *vendor, const char *library, const char *name, const char *version)
{
return ((vendor && strcmp(c->vlnv.vendor, vendor)) ||
(library && strcmp(c->vlnv.library, library)) ||
(name && strcmp(c->vlnv.name, name)) ||
(version && strcmp(c->vlnv.version, version))) ? 0 : 1;
}
int ip_vlnv_parse(struct ip *c, const char *vlnv)
{
char *tmp = strdup(vlnv);
c->vlnv.vendor = strdup(strtok(tmp, ":"));
c->vlnv.library = strdup(strtok(NULL, ":"));
c->vlnv.name = strdup(strtok(NULL, ":"));
c->vlnv.version = strdup(strtok(NULL, ":"));
free(tmp);
return 0;
}
int ip_init(struct ip *c)
{
struct fpga *f = c->card;
int ret;
if (ip_vlnv_match(c, "xilinx.com", "ip", "axis_interconnect", NULL)) {
if (c != f->sw)
error("There can be only one AXI4-Stream interconnect per FPGA");
ret = switch_init(c);
}
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_fifo_mm_s", NULL)) {
ret = fifo_init(c);
}
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_dma", NULL)) {
ret = dma_init(c);
}
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_timer", NULL)) {
XTmrCtr_Config tmr_cfg = {
.BaseAddress = (uintptr_t) c->card->map + c->baseaddr,
.SysClockFreqHz = AXI_HZ
};
XTmrCtr_CfgInitialize(&c->timer, &tmr_cfg, (uintptr_t) c->card->map + c->baseaddr);
XTmrCtr_InitHw(&c->timer);
}
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_gpio", NULL)) {
if (strstr(c->name, "reset")) {
if (f->reset)
error("There can be only one reset controller per FPGA");
f->reset = c;
}
}
else if (ip_vlnv_match(c, "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL)) {
if (c != f->intc)
error("There can be only one interrupt controller per FPGA");
ret = intc_init(c);
}
else if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) ||
ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) {
ret = model_init(c);
}
if (ret == 0)
c->state = IP_STATE_INITIALIZED;
return ret;
}
void ip_destroy(struct ip *c)
{
if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) ||
ip_vlnv_match(c, NULL, "sysgen", NULL, NULL))
model_destroy(c);
free(c->vlnv.vendor);
free(c->vlnv.library);
free(c->vlnv.name);
free(c->vlnv.version);
}
void ip_dump(struct ip *c)
{
info("IP %s: vlnv=%s:%s:%s:%s baseaddr=%#jx, irq=%d, port=%d",
c->name, c->vlnv.vendor, c->vlnv.library, c->vlnv.name, c->vlnv.version,
c->baseaddr, c->irq, c->port);
if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) ||
ip_vlnv_match(c, NULL, "sysgen", NULL, NULL))
model_dump(c);
}
int ip_parse(struct ip *c, config_setting_t *cfg)
{
const char *vlnv;
long long baseaddr;
c->name = config_setting_name(cfg);
if (!c->name)
cerror(cfg, "IP is missing a name");
if (!config_setting_lookup_string(cfg, "vlnv", &vlnv))
cerror(cfg, "IP %s is missing the VLNV identifier", c->name);
ip_vlnv_parse(c, vlnv);
if (ip_vlnv_match(c, "xilinx.com", "ip", "axis_interconnect", NULL)) {
int numports;
if (!config_setting_lookup_int(cfg, "numports", &numports))
cerror(cfg, "Switch IP '%s' requires 'numports' option", c->name);
c->sw.Config.MaxNumSI = c->sw.Config.MaxNumMI = numports;
}
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_bram_ctrl", NULL)) {
if (!config_setting_lookup_int(cfg, "size", &c->bram.size))
cerror(cfg, "Block RAM requires 'size' option");
}
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_fifo_mm_s", NULL)) {
if (config_setting_lookup_int64(cfg, "baseaddr_axi4", &baseaddr))
c->baseaddr_axi4 = baseaddr;
else
c->baseaddr_axi4 = -1;
}
else if (ip_vlnv_match(c, NULL, "hls", NULL, NULL) ||
ip_vlnv_match(c, NULL, "sysgen", NULL, NULL)) {
if (strcmp(c->vlnv.library, "hls") == 0)
c->model.type = MODEL_TYPE_HLS;
else if (strcmp(c->vlnv.library, "sysgen") == 0)
c->model.type = MODEL_TYPE_XSG;
else
cerror(cfg, "Invalid model type: %s", c->vlnv.library);
if (!config_setting_lookup_string(cfg, "xml", (const char **) &c->model.xml))
c->model.xml = NULL;
}
/* Common settings */
if (config_setting_lookup_int64(cfg, "baseaddr", &baseaddr))
c->baseaddr = baseaddr;
else
c->baseaddr = -1;
if (!config_setting_lookup_int(cfg, "irq", &c->irq))
c->irq = -1;
if (!config_setting_lookup_int(cfg, "port", &c->port))
c->port = -1;
c->cfg = cfg;
return 0;
}

View file

@ -14,24 +14,9 @@
#include <villas/utils.h>
#include <villas/log.h>
#include "fpga/ip.h"
#include "fpga/model.h"
int model_init(struct model *m, uintptr_t baseaddr)
{
int ret;
/** @todo: Currently only XSG models are supported */
list_init(&m->parameters);
list_init(&m->infos);
ret = model_init_from_xsg_map(m, baseaddr);
if (ret)
error("Failed to init XSG model: %d", ret);
return 0;
}
static void model_param_destroy(struct model_param *p)
{
free(p->name);
@ -43,146 +28,24 @@ static void model_info_destroy(struct model_info *i)
free(i->value);
}
void model_destroy(struct model *m)
{
list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true);
list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true);
free(m->map);
}
void model_dump(struct model *m)
{
const char *param_type[] = { "UFix", "Fix", "Float", "Boolean" };
const char *model_types[] = { "HLS", "XSG" };
const char *parameter_dirs[] = { "In", "Out", "In/Out" };
info("Model: (type=%s)", model_types[m->type]);
{ INDENT
info("Parameters:");
list_foreach(struct model_param *p, &m->parameters) { INDENT
if (p->direction == MODEL_PARAM_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_PARAM_OUT)
info("%#jx: %s (%s)",
p->offset,
p->name,
parameter_dirs[p->direction]
);
}
info("Infos:");
list_foreach(struct model_info *i, &m->infos) { INDENT
info("%s: %s", i->field, i->value);
}
}
}
int model_param_read(struct model_param *p, double *v)
{
union model_param_value *ptr = p->offset;// TODO: + p->model->baseaddr;
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
*v = (double) ptr->ufix / (1 << p->binpt);
break;
case MODEL_PARAM_TYPE_FIX:
*v = (double) ptr->fix / (1 << p->binpt);
break;
case MODEL_PARAM_TYPE_FLOAT:
*v = (double) ptr->flt;
break;
case MODEL_PARAM_TYPE_BOOLEAN:
*v = (double) ptr->ufix ? 1 : 0;
}
return 0;
}
int model_param_write(struct model_param *p, double v)
{
union model_param_value *ptr = p->offset;// TODO: + p->model->baseaddr;
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
ptr->ufix = (uint32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAM_TYPE_FIX:
ptr->fix = (int32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAM_TYPE_FLOAT:
ptr->flt = (float) v;
break;
case MODEL_PARAM_TYPE_BOOLEAN:
ptr->bol = (bool) v;
break;
}
return 0;
}
void model_param_add(struct model *m, const char *name, enum model_param_direction dir, enum model_param_type type)
{
struct model_param *p = alloc(sizeof(struct model_param));
p->name = strdup(name);
p->type = type;
p->direction = dir;
list_push(&m->parameters, p);
}
int model_init_from_xsg_map(struct model *m, uintptr_t baseaddr)
{
int ret;
list_init(&m->infos);
m->map = alloc(1024);
m->maplen = model_xsg_map_read(baseaddr, m->map, 1024 / 4);
if (m->maplen < 0)
return -1;
debug(5, "XSG: memory map length = %#zx", m->maplen);
ret = model_xsg_map_parse((uint32_t *) m->map, m->maplen, &m->parameters, &m->infos);
if (ret)
return -2;
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 */
}
int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, struct list *infos)
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_param *p;
struct model_info *i;
int j;
/* Check magic */
if (map[0] != XSG_MAGIC)
error("Invalid magic: %#x", map[0]);
@ -224,40 +87,232 @@ int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameters, stru
j += length + 1;
}
if (model_xsg_map_checksum(map, len) != map[j])
error("XSG: Invalid checksum");
return 0;
#undef copy_string
}
int model_xsg_map_read(void *baseaddr, void *dst, size_t len)
static uint32_t model_xsg_map_read_word(uint32_t offset, void *baseaddr)
{
#define get_word(a) ({ *addr = a; *data; })
volatile uint32_t *addr = baseaddr + 0x00;
volatile uint32_t *data = baseaddr + 0x04;
uint32_t *map = dst;
uint32_t maplen, magic;
*addr = offset; /* Update addr reg */
/* Check start DW */
magic = get_word(0);
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 = get_word(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] = get_word(i);
map[i] = model_xsg_map_read_word(i, baseaddr);
return i;
}
#undef get_word
}
static int model_init_from_xml(struct ip *c)
{
//struct model *m = &c->model;
/** @todo Implement */
return -1;
}
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 ip *c)
{
int ret;
struct model *m = &c->model;
list_init(&m->parameters);
list_init(&m->infos);
if (m->xml)
ret = model_init_from_xml(c);
else if (ip_vlnv_match(c, NULL, "sysgen", NULL, NULL))
ret = model_init_from_xsg_map(m, c->card->map + c->baseaddr);
else
ret = 0;
list_foreach(struct model_param *p, &m->parameters)
p->ip = c;
/* Set default values for parameters */
list_foreach(struct model_param *p, &m->parameters) {
if (p->direction == MODEL_PARAM_IN) {
model_param_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;
}
void model_destroy(struct ip *c)
{
struct model *m = &c->model;
list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true);
list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true);
if (m->xsg.map != NULL)
free(m->xsg.map);
}
void model_dump(struct ip *c)
{
struct model *m = &c->model;
const char *param_type[] = { "UFix", "Fix", "Float", "Boolean" };
const char *parameter_dirs[] = { "In", "Out", "In/Out" };
{ INDENT
info("Parameters:");
list_foreach(struct model_param *p, &m->parameters) { INDENT
if (p->direction == MODEL_PARAM_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_PARAM_OUT)
info("%#jx: %s (%s)",
p->offset,
p->name,
parameter_dirs[p->direction]
);
}
info("Infos:");
list_foreach(struct model_info *i, &m->infos) { INDENT
info("%s: %s", i->field, i->value);
}
}
}
int model_param_read(struct model_param *p, double *v)
{
struct ip *c = p->ip;
union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
*v = (double) ptr->ufix / (1 << p->binpt);
break;
case MODEL_PARAM_TYPE_FIX:
*v = (double) ptr->fix / (1 << p->binpt);
break;
case MODEL_PARAM_TYPE_FLOAT:
*v = (double) ptr->flt;
break;
case MODEL_PARAM_TYPE_BOOLEAN:
*v = (double) ptr->ufix ? 1 : 0;
}
return 0;
}
int model_param_write(struct model_param *p, double v)
{
struct ip *c = p->ip;
union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
switch (p->type) {
case MODEL_PARAM_TYPE_UFIX:
ptr->ufix = (uint32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAM_TYPE_FIX:
ptr->fix = (int32_t) (v * (1 << p->binpt));
break;
case MODEL_PARAM_TYPE_FLOAT:
ptr->flt = (float) v;
break;
case MODEL_PARAM_TYPE_BOOLEAN:
ptr->bol = (bool) v;
break;
}
return 0;
}
void model_param_add(struct ip *c, const char *name, enum model_param_direction dir, enum model_param_type type)
{
struct model *m = &c->model;
struct model_param *p = alloc(sizeof(struct model_param));
p->name = strdup(name);
p->type = type;
p->direction = dir;
list_push(&m->parameters, p);
}
int model_param_remove(struct ip *c, const char *name)
{
struct model *m = &c->model;
struct model_param *p;
p = list_lookup(&m->parameters, name);
if (!p)
return -1;
list_remove(&m->parameters, p);
return 0;
}

View file

@ -9,19 +9,21 @@
**********************************************************************************/
#include "fpga/switch.h"
#include "fpga/ip.h"
int switch_init(XAxis_Switch *sw, char *baseaddr, int micnt, int sicnt)
int switch_init(struct ip *c)
{
XAxis_Switch *sw = &c->sw;
int ret;
/* Setup AXI-stream switch */
XAxis_Switch_Config sw_cfg = {
.BaseAddress = (uintptr_t) baseaddr,
.MaxNumMI = micnt,
.MaxNumSI = sicnt
.BaseAddress = (uintptr_t) c->card->map + c->baseaddr,
.MaxNumMI = sw->Config.MaxNumMI,
.MaxNumSI = sw->Config.MaxNumSI
};
ret = XAxisScr_CfgInitialize(sw, &sw_cfg, (uintptr_t) baseaddr);
ret = XAxisScr_CfgInitialize(sw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr);
if (ret != XST_SUCCESS)
return -1;
@ -39,10 +41,12 @@ int switch_init(XAxis_Switch *sw, char *baseaddr, int micnt, int sicnt)
return 0;
}
int switch_connect(XAxis_Switch *sw, int mi, int si)
int switch_connect(struct ip *c, struct ip *mi, struct ip *si)
{
XAxis_Switch *sw = &c->sw;
XAxisScr_RegUpdateDisable(sw);
XAxisScr_MiPortEnable(sw, mi, si);
XAxisScr_MiPortEnable(sw, mi->port, si->port);
XAxisScr_RegUpdateEnable(sw);
return 0;

View file

@ -8,6 +8,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
@ -16,6 +17,49 @@
#include "kernel/pci.h"
#include "config.h"
static struct pci_access *pacc;
static void pci_log(char *msg, ...)
{
char *tmp = strdup(msg);
va_list ap;
va_start(ap, msg);
log_vprint("PCI ", strtok(tmp, "\n"), ap);
va_end(ap);
free(tmp);
}
struct pci_access * pci_get_handle()
{
if (pacc)
return pacc; /* Singleton */
pacc = pci_alloc(); /* Get the pci_access structure */
if (!pacc)
error("Failed to allocate PCI access structure");
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
pacc->error = pci_log; /* Replace logging and debug functions */
pacc->warning = pci_log;
pacc->debug = pci_log;
pacc->debugging = 1;
pci_scan_bus(pacc); /* We want to get the list of devices */
return pacc;
}
void pci_release_handle()
{
if (pacc) {
//pci_cleanup(pacc);
//pacc = NULL;
}
}
struct pci_dev * pci_find_device(struct pci_access *pacc, struct pci_filter *f)
{
struct pci_dev *d;

82
lib/nodes/cbuilder.c Normal file
View file

@ -0,0 +1,82 @@
/** Node type: Wrapper around RSCAD CBuilder model
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-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 "node.h"
/* Constants from RSCAD */
#define PI 3.1415926535897932384626433832795 // definition of PI
#define TWOPI 6.283185307179586476925286766559 // definition of 2.0*PI
#define E 2.71828182845904523536028747135266 // definition of E
#define EINV 0.36787944117144232159552377016147 // definition of E Inverse (1/E)
#define RT2 1.4142135623730950488016887242097 // definition of square root 2.0
#define RT3 1.7320508075688772935274463415059 // definition of square root 3.0
#define INV_ROOT2 0.70710678118654752440084436210485
double TimeStep;
/* Add your inputs and outputs here */
double IntfIn;
double IntfOut;
/* Add your parameters here */
double R2; // Resistor [Ohm] in SS2
double C2; // Capacitance [F] in SS2
#include "cbuilder/static.h"
#include "cbuilder/ram_functions.h"
static double getTimeStep() {
return TimeStep;
}
int cbuilder_open(struct node *n)
{
/* Initialize parameters */
R2 = 1; /**< R2 = 1 Ohm */
C2 = 0.001; /**< C2 = 1000 uF */
TimeStep = 50e-6;
#include "cbuilder/ram.h"
return 0;
}
int cbuilder_read(struct node *n, struct sample *smps[], unsigned cnt)
{
struct sample *smp = smps[0];
smp->values[0].f = IntfOut;
return 1;
}
int cbuilder_write(struct node *n, struct sample *smps[], unsigned cnt)
{
struct sample *smp = smps[0];
/* Update inputs */
IntfIn = smp->values[0].f;
/* Start calculation of 1 step */
#include "cbuilder/code.h"
return 1;
}
static struct node_type vt = {
.name = "cbuilder",
.description = "RTDS CBuilder model",
.vectorize = 1,
.size = 0,
.open = cbuilder_open,
.read = cbuilder_read,
.write = cbuilder_write,
};
REGISTER_NODE_TYPE(&vt)

View file

@ -7,7 +7,7 @@
*********************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
@ -15,7 +15,7 @@
#include "kernel/kernel.h"
#include "kernel/pci.h"
#include "nodes/vfpga.h"
#include "nodes/fpga.h"
#include "fpga/ip.h"
@ -23,13 +23,10 @@
#include "utils.h"
#include "timing.h"
struct vfpga fpga;
struct fpga fpga;
struct vfio_container vc;
static struct pci_access *pacc;
typedef void(*log_cb_t)(char *, ...);
int vfpga_reset(struct vfpga *f)
int fpga_reset(struct fpga *f)
{
int ret;
char state[4096];
@ -39,7 +36,7 @@ int vfpga_reset(struct vfpga *f)
if (ret != sizeof(state))
return -1;
uint32_t *rst_reg = (uint32_t *) (f->map + f->baseaddr.reset);
uint32_t *rst_reg = (uint32_t *) (f->map + f->reset->baseaddr);
info("Reset fpga");
rst_reg[0] = 1;
@ -56,11 +53,14 @@ int vfpga_reset(struct vfpga *f)
return 0;
}
void vfpga_dump(struct vfpga *f)
void fpga_dump(struct fpga *f)
{
char namebuf[128];
char *name;
struct pci_access *pacc;
pacc = pci_get_handle();
name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, fpga.vd.pdev->vendor_id, fpga.vd.pdev->device_id);
pci_fill_info(fpga.vd.pdev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
@ -73,7 +73,7 @@ void vfpga_dump(struct vfpga *f)
info("BAR0 mapped at %p", fpga.map);
info("DMA mapped at %p", fpga.dma);
info("IP blocks:");
list_foreach(struct ip *i, &f->ips) { INDENT
ip_dump(i);
@ -83,20 +83,12 @@ void vfpga_dump(struct vfpga *f)
vfio_dump(fpga.vd.group->container);
}
struct vfpga * vfpga_get()
struct fpga * fpga_get()
{
return &fpga;
}
static void vfpga_debug(char *msg, ...) {
va_list ap;
va_start(ap, msg);
log_vprint(LOG_LVL_DEBUG, msg, ap);
va_end(ap);
}
int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg)
int fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *cfg)
{
int ret;
const char *slot, *id, *err;
@ -105,13 +97,12 @@ int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg)
/* Default values */
v->filter.vendor = PCI_VID_XILINX;
v->filter.device = PCI_PID_VFPGA;
v->reset = false;
cfg_fpga = config_setting_get_member(cfg, "fpga");
if (!cfg_fpga)
cerror(cfg, "Config file is missing VILLASfpga configuration");
config_setting_lookup_bool(cfg_fpga, "reset", &v->reset);
config_setting_lookup_bool(cfg_fpga, "do_reset", &v->do_reset);
cfg_slot = config_setting_get_member(cfg_fpga, "slot");
if (cfg_slot) {
@ -142,59 +133,50 @@ int vfpga_parse(struct vfpga *v, int argc, char * argv[], config_setting_t *cfg)
cerror(cfg_fpga, "FPGA configuration is missing ips section");
for (int i = 0; i < config_setting_length(cfg_ips); i++) {
struct ip ip;
struct ip *ip;
config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
ret = ip_parse(&ip, cfg_ip);
if (ret)
ip = alloc(sizeof(struct ip));
ret = ip_parse(ip, cfg_ip);
if (ret) {
free(ip);
cerror(cfg_ip, "Failed to parse VILLASfpga ip");
}
list_push(&v->ips, memdup(&ip, sizeof(struct ip)));
list_push(&v->ips, ip);
}
return 0;
}
struct pci_access * vfpga_init_pci()
{
struct pci_access *pacc;
pacc = pci_alloc(); /* Get the pci_access structure */
if (!pacc)
error("Failed to allocate PCI access structure");
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
pacc->error = (log_cb_t) error; /* Replace logging and debug functions */
pacc->warning = (log_cb_t) warn;
pacc->debug = vfpga_debug;
pci_scan_bus(pacc); /* We want to get the list of devices */
return pacc;
}
int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
int fpga_init(int argc, char * argv[], config_setting_t *cfg)
{
int ret;
struct pci_access *pacc;
struct pci_dev *pdev;
struct vfpga *f;
struct fpga *f;
/* For now we only support a single VILALSfpga card */
f = vfpga_get();
f = fpga_get();
/* Check FPGA configuration */
f->reset = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_gpio", NULL);
if (!reset)
error("FPGA is missing a reset controller");
/* Some hardcoded addresses for internal IP blocks */
f->baseaddr.reset = 0x2000;
f->baseaddr.intc = 0x5000;
f->intc = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_pcie_intc", NULL);
if (!f->intc)
error("FPGA is missing a interrupt controller");
pacc = vfpga_init_pci();
f->sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
if (!f->sw)
warn("FPGA is missing an AXI4-Stream switch");
pacc = pci_get_handle();
pci_filter_init(pacc, &f->filter);
list_init(&f->ips);
ret = vfpga_parse(f, argc, argv, cfg);
ret = fpga_parse_card(f, argc, argv, cfg);
if (ret)
cerror(cfg, "Failed to parse VILLASfpga config");
@ -216,13 +198,6 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
if (ret)
error("Failed to attach VFIO device");
/* Setup IRQs */
for (int i = 0; i < f->vd.irqs[VFIO_PCI_MSI_IRQ_INDEX].count; i++) {
ret = vfio_pci_msi_fd(&f->vd, (1 << i));
if (ret < 0)
serror("Failed to create eventfd for IRQ: ret=%d", f->vd.msi_efds[i]);
}
/* Map PCIe BAR */
f->map = vfio_map_region(&f->vd, VFIO_PCI_BAR0_REGION_INDEX);
if (f->map == MAP_FAILED)
@ -238,9 +213,9 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
if (ret)
serror("Failed to enable PCI device");
/* Trigger internal reset of fpga card / PCIe endpoint */
if (f->reset) {
ret = vfpga_reset(f);
/* Reset system ? */
if (f->do_reset) {
ret = fpga_reset(f);
if (ret)
serror("Failed to reset fpga card");
@ -250,6 +225,7 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
serror("Failed to reset PCI device");
}
/* Initialize IP cores */
list_foreach(struct ip *c, &f->ips) {
c->card = f;
ip_init(c);
@ -258,13 +234,13 @@ int vfpga_init(int argc, char * argv[], config_setting_t *cfg)
return 0;
}
int vfpga_deinit()
int fpga_deinit()
{
int ret;
list_destroy(&fpga.ips, (dtor_cb_t) ip_destroy, true);
pci_cleanup(pacc);
pci_release_handle();
ret = vfio_destroy(&vc);
if (ret)
@ -273,76 +249,118 @@ int vfpga_deinit()
return 0;
}
int vfpga_parse_node(struct node *n, config_setting_t *cfg)
int fpga_parse(struct node *n, config_setting_t *cfg)
{
// struct vfpga *v = n->_vd;
struct fpga_dm *d = n->_vd;
/* There is currently only support for a single FPGA card */
d->card = fpga_get();
const char *dm;
if (!config_setting_lookup_string(cfg, "datamover", &dm))
cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n));
d->ip = list_lookup(&d->card->ips, dm);
if (!d->ip)
cerror(cfg, "Datamover '%s' is unknown. Please specify it in the fpga.ips section", dm);
if (ip_vlnv_match(d->ip, "xilinx.com", "ip", "axi_dma", NULL))
d->type = FPGA_DM_DMA;
else if (ip_vlnv_match(d->ip, "xilinx.com", "ip", "axi_fifo_mm", NULL))
d->type = FPGA_DM_FIFO;
else
cerror(cfg, "IP '%s' is not a supported datamover", dm);
return 0;
}
char * vfpga_print(struct node *n)
char * fpga_print(struct node *n)
{
struct vfpga *v = n->_vd;
struct fpga_dm *d = n->_vd;
struct fpga *f = d->card;
return strf("slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16,
v->filter.bus, v->filter.device, v->filter.func,
v->filter.vendor, v->filter.device);
return strf("dm=%s (%s:%s:%s:%s) baseaddr=%#jx port=%u slot=%02"PRIx8":%02"PRIx8".%"PRIx8" id=%04"PRIx16":%04"PRIx16,
d->ip->name, d->ip->vlnv.vendor, d->ip->vlnv.library, d->ip->vlnv.name, d->ip->vlnv.version, d->ip->baseaddr, d->ip->port,
f->filter.bus, f->filter.device, f->filter.func,
f->filter.vendor, f->filter.device);
}
int vfpga_open(struct node *n)
int fpga_open(struct node *n)
{
struct vfpga *v = n->_vd;
struct pci_dev *dev;
// struct fpga *v = n->_vd;
dev = pci_find_device(pacc, &v->filter);
if (!dev)
error("No vfpga card found");
/* @todo */
/** @todo Implement */
return 0;
}
int vfpga_close(struct node *n)
int fpga_close(struct node *n)
{
// struct vfpga *v = n->_vd;
// struct fpga *v = n->_vd;
/* @todo */
/** @todo Implement */
return 0;
}
int vfpga_read(struct node *n, struct sample *smps[], unsigned cnt)
int fpga_read(struct node *n, struct sample *smps[], unsigned cnt)
{
// struct vfpga *v = n->_vd;
struct fpga_dm *d = n->_vd;
struct sample *smp = smps[0];
/** @todo */
char *addr = (char *) smp->values;
size_t len = smp->length * sizeof(smp->values[0]);
return 0;
/* Read data from RTDS */
switch (d->type) {
case FPGA_DM_DMA:
if (d->ip->dma.HasSg)
return -1; /* Currently not supported */
else {
len = dma_read(d->ip, addr, len);
XAxiDma_IntrAckIrq(&d->ip->dma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
return 1;
}
case FPGA_DM_FIFO:
break;
}
return -1;
}
/** @todo implement */
int vfpga_write(struct node *n, struct sample *smps[], unsigned cnt)
int fpga_write(struct node *n, struct sample *smps[], unsigned cnt)
{
// struct vfpga *v = n->_vd;
struct fpga_dm *d = n->_vd;
struct sample *smp = smps[0];
/** @todo */
char *addr = (char *) smp->values;
size_t len = smp->length * sizeof(smp->values[0]);
return 0;
/* Send data to RTDS */
switch (d->type) {
case FPGA_DM_DMA:
len = dma_write(d->ip, addr, len);
return 1;
case FPGA_DM_FIFO:
break;
}
return -1;
}
static struct node_type vt = {
.name = "vfpga",
.name = "fpga",
.description = "VILLASfpga PCIe card (libpci)",
.vectorize = 1,
.parse = vfpga_parse_node,
.print = vfpga_print,
.open = vfpga_open,
.close = vfpga_close,
.read = vfpga_read,
.write = vfpga_write,
.init = vfpga_init,
.deinit = vfpga_deinit
.parse = fpga_parse,
.print = fpga_print,
.open = fpga_open,
.close = fpga_close,
.read = fpga_read,
.write = fpga_write,
.init = fpga_init,
.deinit = fpga_deinit
};
REGISTER_NODE_TYPE(&vt)

View file

@ -6,14 +6,17 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <signal.h>
#include <pthread.h>
#include <fcntl.h>
#include <ctype.h>
#include "config.h"
#include "cfg.h"
@ -204,26 +207,6 @@ void * memdup(const void *src, size_t bytes)
return dst;
}
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include "utils.h"
uint64_t wait_irq(int irq)
{
ssize_t ret;
uint64_t cnt;
ret = read(irq, &cnt, sizeof(cnt));
if (ret != sizeof(cnt))
return 0;
return cnt;
}
int read_random(char *buf, size_t len)
{
int ret, fd;

View file

@ -17,7 +17,7 @@
#include <villas/log.h>
#include <villas/timing.h>
#include <villas/utils.h>
#include <villas/nodes/vfpga.h>
#include <villas/nodes/fpga.h>
#include <villas/kernel/pci.h>
#include <villas/kernel/kernel.h>
@ -25,8 +25,8 @@
#include "config-fpga.h"
/* Declarations */
int fpga_bench(struct vfpga *f);
int fpga_tests(struct vfpga *f);
int fpga_bench(struct fpga *f);
int fpga_tests(struct fpga *f);
void usage(char *name)
{
@ -45,7 +45,7 @@ void usage(char *name)
int main(int argc, char *argv[])
{
int ret;
struct vfpga *fpga;
struct fpga *fpga;
enum {
FPGA_TESTS,
FPGA_BENCH
@ -89,13 +89,13 @@ int main(int argc, char *argv[])
/* Initialize VILLASfpga card */
config_setting_t *cfg_root = config_root_setting(&config);
ret = vfpga_init(argc, argv, cfg_root);
ret = fpga_init(argc, argv, cfg_root);
if (ret)
error("Failed to initialize fpga card");
fpga = vfpga_get();
fpga = fpga_get();
vfpga_dump(fpga);
fpga_dump(fpga);
/* Setup scheduler */
cpu_set_t set = integer_to_cpuset(AFFINITY);
@ -121,7 +121,7 @@ int main(int argc, char *argv[])
}
/* Shutdown */
ret = vfpga_deinit(&fpga);
ret = fpga_deinit(&fpga);
if (ret)
error("Failed to de-initialize fpga card");

View file

@ -20,9 +20,10 @@
#include <xilinx/xaxidma.h>
#include <villas/utils.h>
#include <villas/nodes/vfpga.h>
#include <villas/nodes/fpga.h>
#include <villas/fpga/ip.h>
#include <villas/fpga/intc.h>
//#include <villas/fpga/cbmodel.h>
@ -35,30 +36,28 @@
#define CPU_HZ 3392389000
/* 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);
/* Forward Declarations */
int fpga_test_intc(struct fpga *f);
int fpga_test_timer(struct fpga *f);
int fpga_test_fifo(struct fpga *f);
int fpga_test_dma(struct fpga *f);
int fpga_test_xsg(struct fpga *f);
int fpga_test_rtds_rtt(struct fpga *f);
int fpga_tests(struct vfpga *f)
int fpga_tests(struct fpga *f)
{
int ret;
struct {
const char *name;
int (*func)(struct vfpga *f);
int (*func)(struct fpga *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 }
{ "RTDS: RTT Test", fpga_test_rtds_rtt }
};
for (int i = 0; i < ARRAY_LEN(tests); i++) {
@ -70,34 +69,42 @@ int fpga_tests(struct vfpga *f)
return 0;
}
int fpga_test_intc(struct vfpga *f)
int fpga_test_intc(struct fpga *f)
{
uint32_t ier, isr;
uint32_t isr;
/* Save old IER */
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | 0xFF00);
if (!f->intc)
return -1;
XIntc_Out32(f->baseaddr.intc + XIN_ISR_OFFSET, 0xFF00);
intc_enable(f->intc, 0xFF00);
debug(3, "Wait for 8 SW triggerd interrupts");
info("ISR %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET));
info("IER %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_IER_OFFSET));
info("IMR %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_IMR_OFFSET));
info("MER %#x", XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_MER_OFFSET));
/* Fake IRQs in software by writing to ISR */
XIntc_Out32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET, 0xFF00);
/* Wait for 8 SW triggered IRQs */
for (int i = 0; i < 8; i++)
wait_irq(f->vd.msi_efds[i+8]);
intc_wait(f, i+8);
isr = XIntc_In32(f->baseaddr.intc + XIN_ISR_OFFSET);
/* Restore IER */
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
/* Check ISR if all SW IRQs have been deliverd */
isr = XIntc_In32((uintptr_t) f->map + f->intc->baseaddr + XIN_ISR_OFFSET);
intc_disable(f->intc, 0xFF00);
return (isr & 0xFF00) ? -1 : 0; /* ISR should get cleared by MSI_Grant_signal */
}
int fpga_test_xsg(struct vfpga *f)
int fpga_test_xsg(struct fpga *f)
{
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);
struct ip *xsg, *dma;
int ret;
double factor, err = 0;
xsg = ip_vlnv_lookup(&f->ips, NULL, "sysgen", "xsg_multiply", NULL);
dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
/* Check if required IP is available on FPGA */
@ -106,69 +113,85 @@ int fpga_test_xsg(struct vfpga *f)
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);
config_setting_t *cfg_params, *cfg_param;
struct model_param *p;
cfg_params = config_setting_get_member(xsg->cfg, "parameters");
if (cfg_params) {
for (int i = 0; i < config_setting_length(cfg_params); i++) {
cfg_param = config_setting_get_elem(cfg_params, i);
const char *name = config_setting_name(cfg_param);
double value = config_setting_get_float(cfg_param);
p = list_lookup(&xsg->model.parameters, name);
if (!p)
cerror(cfg_param, "Model %s has no parameter named %s", xsg->name, name);
model_param_write(p, value);
info("Param '%s' updated to: %f", p->name, value);
}
}
switch_connect(&sw->sw, dma->port, xsg->port);
switch_connect(&sw->sw, xsg->port, dma->port);
p = list_lookup(&xsg->model.parameters, "factor");
if (!p)
error("Missing parameter 'factor' for model '%s'", xsg->name);
ret = model_param_read(p, &factor);
if (ret)
error("Failed to read parameter 'factor' from model '%s'", xsg->name);
info("Model param: factor = %f", factor);
switch_connect(f->sw, dma, xsg);
switch_connect(f->sw, xsg, dma);
float *src = (float *) f->dma;
float *dst = (float *) f->dma + TEST_LEN;
for (int i = 0; i < 6; i++)
src[i] = 1.1 * (i+1);
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);
ret = dma_ping_pong(dma, (char *) src, (char *) dst, 6 * sizeof(float));
if (ret)
error("Failed to to ping pong DMA transfer: %d", ret);
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]);
err += abs(factor * src[i] - dst[i]);
info("Error after FPGA operation: err = %f", err);
return 0;
return err > 1e-3;
}
int fpga_test_hls_dft(struct vfpga *f)
int fpga_test_hls_dft(struct fpga *f)
{
struct ip *hls, *sw, *dma;
#if 0
struct ip *hls, *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;
#endif
return 0;
}
int fpga_test_fifo(struct vfpga *f)
int fpga_test_fifo(struct fpga *f)
{
int ret;
ssize_t len;
char src[255], dst[255];
struct ip *fifo, *sw;
uint32_t ier;
struct ip *fifo;
fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm", NULL);
fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm_s", NULL);
if (!fifo)
return -1;
sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
if (!sw)
return -1;
/* Save old IER */
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << fifo->irq));
intc_enable(f->intc, (1 << fifo->irq));
/* Get some random data to compare */
memset(dst, 0, sizeof(dst));
@ -176,108 +199,106 @@ int fpga_test_fifo(struct vfpga *f)
if (ret)
error("Failed to get random data");
ret = switch_connect(&sw->sw, fifo->port, fifo->port);
ret = switch_connect(f->sw, fifo, fifo);
if (ret)
error("Failed to configure switch");
len = fifo_write(&fifo->fifo_mm, (char *) src, sizeof(src), f->vd.msi_efds[fifo->irq]);
len = fifo_write(fifo, (char *) src, sizeof(src));
if (len != sizeof(src))
error("Failed to send to FIFO");
len = fifo_read(&fifo->fifo_mm, (char *) dst, sizeof(dst), f->vd.msi_efds[fifo->irq]);
len = fifo_read(fifo, (char *) dst, sizeof(dst));
if (len != sizeof(dst))
error("Failed to read from FIFO");
/* Restore IER */
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
intc_disable(f->intc, (1 << fifo->irq));
/* Compare data */
return memcmp(src, dst, sizeof(src));
}
int fpga_test_dma(struct vfpga *f)
int fpga_test_dma(struct fpga *f)
{
struct ip *dma, *sw;
ssize_t len;
struct ip *bram;
ssize_t len = 0x100;
int ret;
uint32_t ier;
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;
/* Save old IER */
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << irq_mm2s) | (1 << irq_s2mm));
ret = switch_connect(&sw->sw, dma->port, dma->port);
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 */
char *src = (char *) f->dma;
char *dst = (char *) f->dma + TEST_LEN;
char *dst = (char *) f->dma + len;
ret = read_random(src, TEST_LEN);
ret = read_random(src, len);
if (ret)
error("Failed to get random data");
#if 0
len = dma_write(&f->dma_simple, virt_to_dma(src, f->dma), TEST_LEN, -1);//f->vd.msi_efds[irq_mm2s]);
if (len != TEST_LEN)
error("Failed to send to DMAC: %zd", len);
list_foreach(struct ip *dma, &f->ips) { INDENT
if (!ip_vlnv_match(dma, "xilinx.com", "ip", "axi_dma", NULL))
continue; /* skip non DMA IP cores */
len = dma_read(&f->dma_simple, virt_to_dma(dst, f->dma), TEST_LEN, -1);//f->vd.msi_efds[irq_s2mm]);
if (len != TEST_LEN)
error("Failed to send to DMAC: %zd", len);
#else
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]);
if (len != TEST_LEN)
error("Failed to to ping pong DMA transfer: %zd", len);
#endif
int irq_mm2s = dma->irq;
int irq_s2mm = dma->irq + 1;
intc_enable(f->intc, (1 << irq_mm2s) | (1 << irq_s2mm));
/* Restore IER */
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
ret = switch_connect(f->sw, dma, dma);
if (ret)
error("Failed to configure switch");
if (dma->dma.HasSg) {
/* Init BD rings */
bram = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_bram_ctrl", NULL);
if (!bram)
return -3;
/* Check received data */
return memcmp(src, dst, TEST_LEN);
/* Memory for buffer descriptors */
struct dma_mem bd = {
.base_virt = (uintptr_t) f->map + bram->baseaddr,
.base_phys = bram->baseaddr,
.len = bram->bram.size
};
ret = dma_init_rings(dma, &bd);
if (ret)
return -4;
}
/* Start transfer */
ret = dma_read(dma, dst, len);
if (ret)
error("Failed to start DMA read: %d", ret);
ret = dma_write(dma, src, len);
if (ret)
error("Failed to start DMA write: %d", ret);
ret = dma_read_complete(dma, NULL, NULL);
if (ret)
error("Failed to complete DMA read");
ret = dma_write_complete(dma, NULL, NULL);
if (ret)
error("Failed to complete DMA write");
ret = memcmp(src, dst, len);
info("DMA %s (%s): %s", dma->name, dma->dma.HasSg ? "sg" : "simple", ret ? RED("failed") : GRN("passed"));
intc_disable(f->intc, (1 << irq_mm2s) | (1 << irq_s2mm));
}
return ret;
}
int fpga_test_timer(struct vfpga *f)
int fpga_test_timer(struct fpga *f)
{
int ret;
struct ip *timer;
uint32_t ier;
timer = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_timer", NULL);
if (!timer)
return -1;
/* Save old IER */
ier = XIntc_In32(f->baseaddr.intc + XIN_IER_OFFSET);
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier | (1 << timer->irq));
intc_enable(f->intc, (1 << timer->irq));
XTmrCtr_SetOptions(&timer->timer, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
XTmrCtr_SetResetValue(&timer->timer, 0, AXI_HZ / 125);
@ -290,7 +311,7 @@ int fpga_test_timer(struct vfpga *f)
ret = poll(&pfd, 1, 1000);
if (ret == 1) {
uint64_t counter = wait_irq(f->vd.msi_efds[timer->irq]);
uint64_t counter = intc_wait(f, timer->irq);
info("Got IRQ: counter = %ju", counter);
@ -300,106 +321,18 @@ int fpga_test_timer(struct vfpga *f)
warn("Counter was not 1");
}
/* Restore IER */
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
intc_disable(f->intc, (1 << timer->irq));
return -1;
}
int fpga_test_rtds_cbuilder(struct vfpga *f)
{
#if 0
int ret;
int values_tx = 1;
int values_rx;
uint32_t tsc = 0, ovfl = 0;
ssize_t len;
uint32_t ier;
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;
/* Save old IER */
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);
/* Dump RTDS AXI Stream state */
rtds_axis_dump(f->map + rtds->baseaddr);
/* Get some random data to compare */
float *data_rx = (uint32_t *) (f->dma);
float *data_tx = (uint32_t *) (f->dma + 0x1000);
/* Setup crossbar switch */
switch_connect(&sw->sw, rtds->port, dma->port);
switch_connect(&sw->sw, dma->port, rtds->port);
/* Disable blocking Overflow status */
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);
/* 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 */
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);
values_rx = len / sizeof(uint32_t);
mdl_inputs[0] = data_rx[0]; /* cast to double */
/* Run CBuilder model */
cbmodel_step(mdl_inputs, mdl_outputs);
data_tx[0] = mdl_outputs[0]; /* cast to float */
/* Send data to RTDS */
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);
}
/* Restore IER */
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
#endif
return 0;
}
int fpga_test_rtds_rtt(struct vfpga *f)
int fpga_test_rtds_rtt(struct fpga *f)
{
#if 0
uint32_t tsc = 0;
ssize_t len;
uint32_t ier;
/* Save old IER */
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));
intc_enable(f->intc, (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
/* Dump RTDS AXI Stream state */
rtds_axis_dump(f->map + BASEADDR_RTDS);
@ -408,18 +341,9 @@ int fpga_test_rtds_rtt(struct vfpga *f)
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);
switch_connect(sw, AXIS_SWITCH_RTDS, switch_port);
switch_connect(sw, switch_port, AXIS_SWITCH_RTDS);
/* Disable blocking Overflow status */
int flags = fcntl(f->vd.msi_efds[MSI_RTDS_OVF], F_GETFL, 0);
@ -430,13 +354,13 @@ int fpga_test_rtds_rtt(struct vfpga *f)
while (1) {
#if 0 /* Wait for TS */
tsc += wait_irq(f->vd.msi_efds[MSI_RTDS_TS]);
tsc += intc_wait(f->intc, MSI_RTDS_TS);
#else
tsc++;
#endif
#if 0 /* Check for overflow */
ovfl += wait_irq(f->vd.msi_efds[MSI_RTDS_OVF]);
ovfl += intc_wait(f->intc, MSI_RTDS_OVF);
if (tsc % 20000 == 0)
warn("Missed %u timesteps", ovfl);
#endif
@ -481,8 +405,7 @@ retry: len = fifo_read(&f->fifo, (char *) data_rx, 0x1000, irq_fifo);
#endif
}
/* Restore IER */
XIntc_Out32(f->baseaddr.intc + XIN_IER_OFFSET, ier);
intc_disable(f->intc, (1 << MSI_DMA_MM2S) | (1 << MSI_DMA_S2MM));
#endif
return 0;
}