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:
parent
98fb370e85
commit
c67af15a2c
31 changed files with 1658 additions and 980 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -3,10 +3,10 @@
|
|||
*.so
|
||||
*~
|
||||
|
||||
node
|
||||
pipe
|
||||
test
|
||||
signal
|
||||
fpga
|
||||
/node
|
||||
/pipe
|
||||
/test
|
||||
/signal
|
||||
/fpga
|
||||
|
||||
thirdparty/
|
||||
|
|
8
Makefile
8
Makefile
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
104
etc/fpga.conf
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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_ */
|
|
@ -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_ */
|
20
include/villas/fpga/intc.h
Normal file
20
include/villas/fpga/intc.h
Normal 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
75
include/villas/fpga/ip.h
Normal 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
|
|
@ -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_ */
|
|
@ -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_ */
|
15
include/villas/fpga/timer.h
Normal file
15
include/villas/fpga/timer.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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
104
include/villas/nodes/fpga.h
Normal 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_ @} */
|
|
@ -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_ @} */
|
|
@ -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_ @} */
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
637
lib/fpga/dma.c
637
lib/fpga/dma.c
|
@ -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);
|
||||
|
|
|
@ -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
77
lib/fpga/intc.c
Normal 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
181
lib/fpga/ip.c
Normal 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;
|
||||
}
|
369
lib/fpga/model.c
369
lib/fpga/model.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
82
lib/nodes/cbuilder.c
Normal 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)
|
|
@ -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)
|
27
lib/utils.c
27
lib/utils.c
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
387
src/fpga-tests.c
387
src/fpga-tests.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue