mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
major changes in the VILLASfpga code. Lots of smaller improvements and fixed
This commit is contained in:
parent
c67af15a2c
commit
68f2dbea76
21 changed files with 858 additions and 307 deletions
34
include/villas/fpga/dft.h
Normal file
34
include/villas/fpga/dft.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/** Moving window / Recursive DFT implementation based on HLS
|
||||
*
|
||||
* @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 _DFT_H_
|
||||
#define _DFT_H_
|
||||
|
||||
#include <xilinx/xhls_dft.h>
|
||||
|
||||
/* Forward declaration */
|
||||
struct ip;
|
||||
|
||||
struct dft {
|
||||
XHls_dft inst;
|
||||
|
||||
int period; /* in samples */
|
||||
int num_harmonics;
|
||||
float *fharmonics;
|
||||
int decimation;
|
||||
};
|
||||
|
||||
int dft_parse(struct ip *c);
|
||||
|
||||
int dft_init(struct ip *c);
|
||||
|
||||
void dft_destroy(struct ip *c);
|
||||
|
||||
|
||||
#endif /* _DFT_H_ */
|
|
@ -20,6 +20,10 @@
|
|||
|
||||
#define XAXIDMA_SR_SGINCL_MASK 0x00000008
|
||||
|
||||
struct dma {
|
||||
XAxiDma inst;
|
||||
};
|
||||
|
||||
struct dma_mem {
|
||||
uint32_t base_virt;
|
||||
uint32_t base_phys;
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
#include <xilinx/xstatus.h>
|
||||
#include <xilinx/xllfifo.h>
|
||||
|
||||
struct fifo {
|
||||
XLlFifo inst;
|
||||
|
||||
uint32_t baseaddr_axi4;
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
struct ip;
|
||||
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
#ifndef _INTC_H_
|
||||
#define _INTC_H_
|
||||
|
||||
#include <xilinx/xintc.h>
|
||||
|
||||
int intc_init(struct ip *c);
|
||||
|
||||
uint32_t intc_enable(struct ip *c, uint32_t mask);
|
||||
int intc_enable(struct ip *c, uint32_t mask, int poll);
|
||||
|
||||
void intc_disable(struct ip *c, uint32_t mask);
|
||||
int intc_disable(struct ip *c, uint32_t mask);
|
||||
|
||||
uint64_t intc_wait(struct fpga *f, int irq);
|
||||
uint64_t intc_wait(struct ip *c, int irq, int poll);
|
||||
|
||||
#endif /* _INTC_H_ */
|
|
@ -9,45 +9,69 @@
|
|||
#include <xilinx/xaxis_switch.h>
|
||||
#include <xilinx/xaxidma.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "fpga/dma.h"
|
||||
#include "fpga/switch.h"
|
||||
#include "fpga/fifo.h"
|
||||
#include "fpga/rtds_axis.h"
|
||||
#include "fpga/timer.h"
|
||||
#include "fpga/model.h"
|
||||
#include "fpga/dft.h"
|
||||
#include "nodes/fpga.h"
|
||||
|
||||
#define REGISTER_IP_TYPE(ip) \
|
||||
__attribute__((constructor)) static \
|
||||
void UNIQUE(__register_)() { \
|
||||
list_push(&ip_types, ip); \
|
||||
}
|
||||
|
||||
extern struct list ip_types; /**< Table of existing FPGA IP core drivers */
|
||||
|
||||
enum ip_state {
|
||||
IP_STATE_UNKNOWN,
|
||||
IP_STATE_INITIALIZED
|
||||
};
|
||||
|
||||
struct ip_vlnv {
|
||||
char *vendor;
|
||||
char *library;
|
||||
char *name;
|
||||
char *version;
|
||||
};
|
||||
|
||||
struct ip_type {
|
||||
struct ip_vlnv vlnv;
|
||||
|
||||
int (*parse)(struct ip *c);
|
||||
int (*init)(struct ip *c);
|
||||
void (*dump)(struct ip *c);
|
||||
void (*destroy)(struct ip *c);
|
||||
};
|
||||
|
||||
struct ip {
|
||||
char *name;
|
||||
|
||||
struct {
|
||||
char *vendor;
|
||||
char *library;
|
||||
char *name;
|
||||
char *version;
|
||||
} vlnv;
|
||||
|
||||
struct ip_vlnv vlnv;
|
||||
|
||||
uintptr_t baseaddr;
|
||||
uintptr_t baseaddr_axi4;
|
||||
int irq;
|
||||
int port;
|
||||
|
||||
int port, irq;
|
||||
|
||||
enum ip_state state;
|
||||
|
||||
struct ip_type *_vt;
|
||||
|
||||
union {
|
||||
struct model model;
|
||||
struct bram {
|
||||
struct {
|
||||
int size;
|
||||
} bram;
|
||||
|
||||
XTmrCtr timer;
|
||||
XLlFifo fifo_mm;
|
||||
XAxiDma dma;
|
||||
XAxis_Switch sw;
|
||||
struct timer timer;
|
||||
struct fifo fifo;
|
||||
struct dma dma;
|
||||
struct sw sw;
|
||||
struct dft dft;
|
||||
};
|
||||
|
||||
struct fpga *card;
|
||||
|
|
|
@ -54,7 +54,7 @@ union model_param_value {
|
|||
|
||||
struct model {
|
||||
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; /**< A list of key / value pairs with model details */
|
||||
|
||||
|
@ -91,6 +91,9 @@ struct model_param {
|
|||
/** Initialize a model */
|
||||
int model_init(struct ip *c);
|
||||
|
||||
/** Parse model */
|
||||
int model_parse(struct ip *c);
|
||||
|
||||
/** Destroy a model */
|
||||
void model_destroy(struct ip *c);
|
||||
|
||||
|
@ -118,4 +121,6 @@ int model_param_read(struct model_param *p, double *v);
|
|||
*/
|
||||
int model_param_write(struct model_param *p, double v);
|
||||
|
||||
int model_param_update(struct model_param *p, struct model_param *u);
|
||||
|
||||
#endif /* _MODEL_H_ */
|
|
@ -10,6 +10,9 @@
|
|||
#ifndef _RTDS_AXIS_H_
|
||||
#define _RTDS_AXIS_H_
|
||||
|
||||
/* Forward declaration */
|
||||
struct ip;
|
||||
|
||||
#define RTDS_HZ 100000000 // 100 MHz
|
||||
|
||||
#define RTDS_AXIS_MAX_TX 64 /**< The amount of values which is supported by the vfpga card */
|
||||
|
@ -23,8 +26,7 @@
|
|||
#define RTDS_AXIS_TS_PERIOD_OFFSET 0x10 /**< Period in clock cycles of previous timestep (read-only). */
|
||||
#define RTDS_AXIS_COALESC_OFFSET 0x14 /**< IRQ Coalescing register (read/write). */
|
||||
#define RTDS_AXIS_VERSION_OFFSET 0x18 /**< 16 bit version field passed back to the rack for version reporting (visible from “status” command, read/write). */
|
||||
#define RTDS_AXIS_MRATE_RTDS2AXIS 0x1C /**< */
|
||||
#define RTDS_AXIS_MRATE_AXIS2RTDS 0x20 /**< */
|
||||
#define RTDS_AXIS_MRATE 0x1C /**< Multi-rate register */
|
||||
|
||||
/* Status register bits */
|
||||
#define RTDS_AXIS_SR_CARDDETECTED (1 << 0)/**< ‘1’ when RTDS software has detected and configured card. */
|
||||
|
@ -36,8 +38,8 @@
|
|||
/* Control register bits */
|
||||
#define RTDS_AXIS_CR_DISABLE_LINK 0 /**< Disable SFP TX when set */
|
||||
|
||||
void rtds_axis_dump(char *baseaddr);
|
||||
void rtds_axis_dump(struct ip *c);
|
||||
|
||||
double rtds_axis_dt(char *baseaddr);
|
||||
double rtds_axis_dt(struct ip *c);
|
||||
|
||||
#endif /* _RTDS_AXIS_H_ */
|
|
@ -14,10 +14,33 @@
|
|||
|
||||
#include <xilinx/xaxis_switch.h>
|
||||
|
||||
#include "list.h"
|
||||
|
||||
/* Forward declaration */
|
||||
struct ip;
|
||||
|
||||
struct sw_path {
|
||||
const char *in;
|
||||
const char *out;
|
||||
};
|
||||
|
||||
struct sw {
|
||||
XAxis_Switch inst;
|
||||
|
||||
int num_ports;
|
||||
struct list paths;
|
||||
};
|
||||
|
||||
struct ip;
|
||||
|
||||
int switch_init(struct ip *c);
|
||||
|
||||
void switch_destroy(struct ip *c);
|
||||
|
||||
int switch_parse(struct ip *c);
|
||||
|
||||
int switch_connect(struct ip *c, struct ip *mi, struct ip *si);
|
||||
|
||||
int switch_disconnect(struct ip *c, struct ip *mi, struct ip *si);
|
||||
|
||||
#endif /* _SWITCH_H_ */
|
|
@ -12,4 +12,8 @@
|
|||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
struct timer {
|
||||
XTmrCtr inst;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -50,12 +50,15 @@ struct fpga {
|
|||
struct ip *intc;
|
||||
struct ip *reset;
|
||||
struct ip *sw;
|
||||
|
||||
config_setting_t *cfg;
|
||||
};
|
||||
|
||||
struct fpga_dm {
|
||||
struct ip *ip;
|
||||
const char *ip_name;
|
||||
|
||||
bool use_irqs;
|
||||
int use_irqs;
|
||||
|
||||
enum {
|
||||
FPGA_DM_DMA,
|
||||
|
|
32
lib/fpga/bram.c
Normal file
32
lib/fpga/bram.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/** Block RAM
|
||||
*
|
||||
* @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 "fpga/ip.h"
|
||||
#include "fpga/timer.h"
|
||||
|
||||
int bram_parse(struct ip *c)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (config_setting_lookup_int(c->cfg, "size", &size))
|
||||
c->bram.size = size;
|
||||
else
|
||||
cerror(c->cfg, "BRAM IP core requires 'size' setting");
|
||||
|
||||
if (size <= 0)
|
||||
error("BRAM IP core has invalid size: %d", size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_bram_ctrl", NULL },
|
||||
.parse = bram_parse
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
95
lib/fpga/dft.c
Normal file
95
lib/fpga/dft.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/** Moving window / Recursive DFT implementation based on HLS
|
||||
*
|
||||
* @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.
|
||||
**********************************************************************************/
|
||||
|
||||
#include "log.h"
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/dft.h"
|
||||
|
||||
int dft_parse(struct ip *c)
|
||||
{
|
||||
struct dft *dft = &c->dft;
|
||||
|
||||
config_setting_t *cfg_harms;
|
||||
|
||||
if (!config_setting_lookup_int(c->cfg, "period", &dft->period))
|
||||
cerror(c->cfg, "DFT IP core requires 'period' setting");
|
||||
|
||||
if (!config_setting_lookup_int(c->cfg, "decimation", &dft->decimation))
|
||||
cerror(c->cfg, "DFT IP core requires 'decimation' setting");
|
||||
|
||||
cfg_harms = config_setting_get_member(c->cfg, "harmonics");
|
||||
if (!cfg_harms)
|
||||
cerror(c->cfg, "DFT IP core requires 'harmonics' setting!");
|
||||
|
||||
if (!config_setting_is_array(cfg_harms))
|
||||
cerror(c->cfg, "DFT IP core requires 'harmonics' to be an array of integers!");
|
||||
|
||||
dft->num_harmonics = config_setting_length(cfg_harms);
|
||||
if (dft->num_harmonics <= 0)
|
||||
cerror(cfg_harms, "DFT IP core requires 'harmonics' to contain at least 1 integer!");
|
||||
|
||||
dft->fharmonics = alloc(sizeof(float) * dft->num_harmonics);
|
||||
|
||||
for (int i = 0; i < dft->num_harmonics; i++)
|
||||
dft->fharmonics[i] = (float) config_setting_get_int_elem(cfg_harms, i) / dft->period;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dft_init(struct ip *c)
|
||||
{
|
||||
int ret;
|
||||
struct dft *dft = &c->dft;
|
||||
XHls_dft *xdft = &dft->inst;
|
||||
XHls_dft_Config xdft_cfg = {
|
||||
.Ctrl_BaseAddress = (uintptr_t) c->card->map + c->baseaddr
|
||||
};
|
||||
|
||||
ret = XHls_dft_CfgInitialize(xdft, &xdft_cfg);
|
||||
if (ret != XST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
int max_harmonics = XHls_dft_Get_fharmonics_TotalBytes(xdft) / sizeof(dft->fharmonics[0]);
|
||||
|
||||
if (dft->num_harmonics > max_harmonics)
|
||||
error("DFT IP core supports a maximum of %u harmonics", max_harmonics);
|
||||
|
||||
XHls_dft_Set_num_harmonics_V(xdft, dft->num_harmonics);
|
||||
|
||||
XHls_dft_Set_decimation_V(xdft, dft->decimation);
|
||||
|
||||
memcpy((void *) (uintptr_t) XHls_dft_Get_fharmonics_BaseAddress(xdft), dft->fharmonics, dft->num_harmonics * sizeof(dft->fharmonics[0]));
|
||||
|
||||
XHls_dft_EnableAutoRestart(xdft);
|
||||
XHls_dft_Start(xdft);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dft_destroy(struct ip *c)
|
||||
{
|
||||
struct dft *dft = &c->dft;
|
||||
XHls_dft *xdft = &dft->inst;
|
||||
|
||||
XHls_dft_DisableAutoRestart(xdft);
|
||||
|
||||
if (dft->fharmonics) {
|
||||
free(dft->fharmonics);
|
||||
dft->fharmonics = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "acs.eonerc.rwth-aachen.de", "hls", "hls_dft", NULL },
|
||||
.init = dft_init,
|
||||
.destroy = dft_destroy,
|
||||
.parse = dft_parse
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
105
lib/fpga/dma.c
105
lib/fpga/dma.c
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <villas/log.h>
|
||||
|
||||
|
@ -42,7 +43,7 @@ int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len)
|
|||
|
||||
int dma_write(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_write(c, buf, len)
|
||||
|
@ -51,7 +52,7 @@ int dma_write(struct ip *c, char *buf, size_t len)
|
|||
|
||||
int dma_read(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_read(c, buf, len)
|
||||
|
@ -60,7 +61,7 @@ int dma_read(struct ip *c, char *buf, size_t len)
|
|||
|
||||
int dma_read_complete(struct ip *c, char **buf, size_t *len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_read_complete(c, buf, len)
|
||||
|
@ -69,7 +70,7 @@ int dma_read_complete(struct ip *c, char **buf, size_t *len)
|
|||
|
||||
int dma_write_complete(struct ip *c, char **buf, size_t *len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
return xdma->HasSg
|
||||
? dma_sg_write_complete(c, buf, len)
|
||||
|
@ -78,7 +79,7 @@ int dma_write_complete(struct ip *c, char **buf, size_t *len)
|
|||
|
||||
int dma_sg_write(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
|
||||
|
@ -129,7 +130,7 @@ int dma_sg_write(struct ip *c, char *buf, size_t len)
|
|||
|
||||
int dma_sg_read(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
|
||||
|
@ -180,22 +181,22 @@ int dma_sg_read(struct ip *c, char *buf, size_t len)
|
|||
|
||||
int dma_sg_write_complete(struct ip *c, char **buf, size_t *len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
|
||||
int processed, ret;
|
||||
|
||||
|
||||
/* Wait until the one BD TX transaction is done */
|
||||
while ((processed = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bd)) == 0) {
|
||||
// if (c->irq >= 0) {
|
||||
// intc_wait(c->card, c->irq);
|
||||
// XAxiDma_IntrAckIrq(xmda, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
// }
|
||||
// else
|
||||
__asm__ ("nop");
|
||||
}
|
||||
while ((processed = XAxiDma_BdRingFromHw(ring, XAXIDMA_ALL_BDS, &bd)) == 0)
|
||||
pthread_testcancel();
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
if (len != NULL)
|
||||
*len = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN);
|
||||
|
||||
if (buf != NULL)
|
||||
*buf = (char *) (uintptr_t) XAxiDma_BdGetBufAddr(bd);
|
||||
|
||||
/* Free all processed TX BDs for future transmission */
|
||||
ret = XAxiDma_BdRingFree(ring, processed, bd);
|
||||
|
@ -209,7 +210,7 @@ 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)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
XAxiDma_Bd *bd;
|
||||
|
||||
|
@ -218,14 +219,9 @@ int dma_sg_read_complete(struct ip *c, char **buf, size_t *len)
|
|||
if (!xdma->HasSg)
|
||||
return -1;
|
||||
|
||||
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");
|
||||
}
|
||||
while (XAxiDma_BdRingFromHw(ring, 1, &bd) == 0)
|
||||
pthread_testcancel();
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
if (len != NULL)
|
||||
*len = XAxiDma_BdGetActualLength(bd, XAXIDMA_MAX_TRANSFER_LEN);
|
||||
|
@ -243,7 +239,7 @@ 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)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
|
||||
|
||||
buf = virt_to_dma(buf, c->card->dma);
|
||||
|
@ -263,7 +259,7 @@ int dma_simple_read(struct ip *c, char *buf, size_t len)
|
|||
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;
|
||||
|
@ -281,7 +277,7 @@ int dma_simple_read(struct ip *c, char *buf, size_t len)
|
|||
|
||||
int dma_simple_write(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
|
||||
buf = virt_to_dma(buf, c->card->dma);
|
||||
|
@ -320,25 +316,42 @@ 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)
|
||||
{
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
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;
|
||||
// }
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK))
|
||||
pthread_testcancel();
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
if (len)
|
||||
*len = XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET);
|
||||
|
||||
if (buf) {
|
||||
*buf = (char *) (uintptr_t) XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_DESTADDR_OFFSET);
|
||||
if (xdma->AddrWidth > 32)
|
||||
*buf += XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_DESTADDR_MSB_OFFSET);
|
||||
}
|
||||
|
||||
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);
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
|
||||
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DEVICE_TO_DMA) & XAXIDMA_IRQ_IOC_MASK));
|
||||
while (!(XAxiDma_IntrGetIrq(xdma, XAXIDMA_DMA_TO_DEVICE) & XAXIDMA_IRQ_IOC_MASK))
|
||||
pthread_testcancel();
|
||||
XAxiDma_IntrAckIrq(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
|
||||
|
||||
if (len)
|
||||
*len = XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_BUFFLEN_OFFSET);
|
||||
|
||||
if (buf) {
|
||||
*buf = (char *) (uintptr_t) XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SRCADDR_OFFSET);
|
||||
if (xdma->AddrWidth > 32)
|
||||
*buf += XAxiDma_ReadReg(ring->ChanBase, XAXIDMA_SRCADDR_MSB_OFFSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -362,7 +375,7 @@ static int dma_setup_ring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
|
|||
|
||||
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);
|
||||
info("RX create BD ring failed (%d)", ret);
|
||||
return XST_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -386,8 +399,7 @@ static int dma_setup_ring(XAxiDma_BdRing *ring, struct dma_mem *bdbuf)
|
|||
int dma_init_rings(struct ip *c, struct dma_mem *bd)
|
||||
{
|
||||
int ret;
|
||||
XAxiDma *xdma = &c->dma;
|
||||
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
/* Split BD memory equally between Rx and Tx rings */
|
||||
struct dma_mem bd_rx = {
|
||||
|
@ -415,7 +427,7 @@ int dma_init_rings(struct ip *c, struct dma_mem *bd)
|
|||
int dma_init(struct ip *c)
|
||||
{
|
||||
int ret, sg;
|
||||
XAxiDma *xdma = &c->dma;
|
||||
XAxiDma *xdma = &c->dma.inst;
|
||||
|
||||
/* Guess DMA type */
|
||||
sg = (XAxiDma_In32((uintptr_t) c->card->map + c->baseaddr + XAXIDMA_TX_OFFSET+ XAXIDMA_SR_OFFSET) &
|
||||
|
@ -457,4 +469,11 @@ int dma_init(struct ip *c)
|
|||
XAxiDma_IntrEnable(xdma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_dma", NULL },
|
||||
.init = dma_init
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
|
@ -19,28 +19,34 @@
|
|||
|
||||
int fifo_init(struct ip *c)
|
||||
{
|
||||
XLlFifo *fifo = &c->fifo_mm;
|
||||
struct fifo *fifo = &c->fifo;
|
||||
XLlFifo *xfifo = &fifo->inst;
|
||||
|
||||
int ret;
|
||||
|
||||
XLlFifo_Config fifo_cfg = {
|
||||
.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 */
|
||||
.Axi4BaseAddress = (uintptr_t) c->card->map + fifo->baseaddr_axi4,
|
||||
.Datainterface = (fifo->baseaddr_axi4 != -1) ? 1 : 0 /* use AXI4 for Data, AXI4-Lite for control */
|
||||
};
|
||||
|
||||
ret = XLlFifo_CfgInitialize(fifo, &fifo_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
||||
ret = XLlFifo_CfgInitialize(xfifo, &fifo_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
XLlFifo_IntEnable(fifo, XLLF_INT_RC_MASK); /* Receive complete IRQ */
|
||||
XLlFifo_IntEnable(xfifo, XLLF_INT_RC_MASK); /* Receive complete IRQ */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t fifo_write(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XLlFifo *fifo = &c->fifo_mm;
|
||||
XLlFifo *fifo = &c->fifo.inst;
|
||||
uint32_t tdfv;
|
||||
|
||||
tdfv = XLlFifo_TxVacancy(fifo);
|
||||
if (tdfv < len)
|
||||
return -1;
|
||||
|
||||
XLlFifo_Write(fifo, buf, len);
|
||||
XLlFifo_TxSetLen(fifo, len);
|
||||
|
@ -50,24 +56,43 @@ ssize_t fifo_write(struct ip *c, char *buf, size_t len)
|
|||
|
||||
ssize_t fifo_read(struct ip *c, char *buf, size_t len)
|
||||
{
|
||||
XLlFifo *fifo = &c->fifo_mm;
|
||||
XLlFifo *fifo = &c->fifo.inst;
|
||||
|
||||
size_t nextlen = 0;
|
||||
uint32_t rdfo, rxlen;
|
||||
|
||||
while (XLlFifo_RxOccupancy(fifo) == 0) {
|
||||
if (c->irq >= 0)
|
||||
intc_wait(c->card, c->irq);
|
||||
else
|
||||
__asm__("nop");
|
||||
}
|
||||
while (!(rdfo = XLlFifo_RxOccupancy(fifo)))
|
||||
pthread_testcancel();
|
||||
XLlFifo_IntClear(fifo, XLLF_INT_RC_MASK);
|
||||
|
||||
/* Get length of next frame */
|
||||
nextlen = MIN(XLlFifo_RxGetLen(fifo), len);
|
||||
|
||||
rxlen = XLlFifo_RxGetLen(fifo);
|
||||
nextlen = MIN(rxlen, len);
|
||||
|
||||
/* Read from FIFO */
|
||||
XLlFifo_Read(fifo, buf, nextlen);
|
||||
|
||||
XLlFifo_IntClear(fifo, XLLF_INT_RC_MASK);
|
||||
|
||||
return nextlen;
|
||||
}
|
||||
|
||||
int fifo_parse(struct ip *c)
|
||||
{
|
||||
struct fifo *fifo = &c->fifo;
|
||||
|
||||
int baseaddr_axi4;
|
||||
|
||||
if (config_setting_lookup_int(c->cfg, "baseaddr_axi4", &baseaddr_axi4))
|
||||
fifo->baseaddr_axi4 = baseaddr_axi4;
|
||||
else
|
||||
fifo->baseaddr_axi4 = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_fifo_mm_s", NULL },
|
||||
.init = fifo_init,
|
||||
.parse = fifo_parse
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <xilinx/xintc.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "nodes/fpga.h"
|
||||
#include "kernel/vfio.h"
|
||||
|
@ -21,6 +19,9 @@ int intc_init(struct ip *c)
|
|||
struct fpga *f = c->card;
|
||||
int ret;
|
||||
|
||||
if (c != f->intc)
|
||||
error("There can be only one interrupt controller per FPGA");
|
||||
|
||||
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
|
||||
|
||||
/* Setup IRQs */
|
||||
|
@ -40,38 +41,78 @@ int intc_init(struct ip *c)
|
|||
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);
|
||||
|
||||
debug(4, "FPGA: enabled interrupts");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t intc_enable(struct ip *c, uint32_t mask)
|
||||
int intc_enable(struct ip *c, uint32_t mask, int poll)
|
||||
{
|
||||
struct fpga *f = c->card;
|
||||
|
||||
uint32_t ier, imr;
|
||||
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);
|
||||
/* Current state of INTC */
|
||||
ier = XIntc_In32(base + XIN_IER_OFFSET);
|
||||
imr = XIntc_In32(base + XIN_IMR_OFFSET);
|
||||
|
||||
return ier;
|
||||
/* Clear pending IRQs */
|
||||
XIntc_Out32(base + XIN_IAR_OFFSET, mask);
|
||||
|
||||
if (poll)
|
||||
XIntc_Out32(base + XIN_IMR_OFFSET, imr & ~mask);
|
||||
else
|
||||
XIntc_Out32(base + XIN_IER_OFFSET, ier | mask);
|
||||
|
||||
debug(8, "FPGA: Interupt enabled: %#x", mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intc_disable(struct ip *c, uint32_t mask)
|
||||
int 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t intc_wait(struct fpga *f, int irq)
|
||||
uint64_t intc_wait(struct ip *c, int irq, int poll)
|
||||
{
|
||||
ssize_t ret;
|
||||
uint64_t cnt;
|
||||
struct fpga *f = c->card;
|
||||
|
||||
ret = read(f->vd.msi_efds[irq], &cnt, sizeof(cnt));
|
||||
if (ret != sizeof(cnt))
|
||||
return 0;
|
||||
uintptr_t base = (uintptr_t) f->map + c->baseaddr;
|
||||
uint64_t cnt;
|
||||
|
||||
if (poll) {
|
||||
uint32_t mask = 1 << irq;
|
||||
uint32_t isr;
|
||||
|
||||
do { /* Wait for IRQ to occur */
|
||||
isr = XIntc_In32(base + XIN_ISR_OFFSET);
|
||||
} while (!(isr & mask));
|
||||
|
||||
/* Acknowlege */
|
||||
XIntc_Out32(base + XIN_IAR_OFFSET, mask);
|
||||
|
||||
cnt = 1;
|
||||
}
|
||||
else {
|
||||
ssize_t ret = read(f->vd.msi_efds[irq], &cnt, sizeof(cnt));
|
||||
if (ret != sizeof(cnt))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL },
|
||||
.init = intc_init
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
||||
|
|
105
lib/fpga/ip.c
105
lib/fpga/ip.c
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "config-fpga.h"
|
||||
|
||||
struct list ip_types; /**< Table of existing FPGA IP core drivers */
|
||||
|
||||
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) {
|
||||
|
@ -46,60 +48,24 @@ int ip_vlnv_parse(struct ip *c, const char *vlnv)
|
|||
|
||||
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);
|
||||
}
|
||||
ret = c->_vt && c->_vt->init ? c->_vt->init(c) : 0;
|
||||
if (ret)
|
||||
error("Failed to intialize IP core: %s", c->name);
|
||||
|
||||
if (ret == 0)
|
||||
c->state = IP_STATE_INITIALIZED;
|
||||
|
||||
debug(8, "IP Core %s initalized (%u)", c->name, ret);
|
||||
|
||||
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);
|
||||
if (c->_vt && c->_vt->destroy)
|
||||
c->_vt->destroy(c);
|
||||
|
||||
free(c->vlnv.vendor);
|
||||
free(c->vlnv.library);
|
||||
|
@ -113,16 +79,18 @@ void ip_dump(struct ip *c)
|
|||
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);
|
||||
if (c->_vt && c->_vt->dump)
|
||||
c->_vt->dump(c);
|
||||
}
|
||||
|
||||
int ip_parse(struct ip *c, config_setting_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
const char *vlnv;
|
||||
long long baseaddr;
|
||||
|
||||
c->cfg = cfg;
|
||||
|
||||
c->name = config_setting_name(cfg);
|
||||
if (!c->name)
|
||||
cerror(cfg, "IP is missing a name");
|
||||
|
@ -130,38 +98,16 @@ int ip_parse(struct ip *c, config_setting_t *cfg)
|
|||
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;
|
||||
ret = ip_vlnv_parse(c, vlnv);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to parse VLNV identifier");
|
||||
|
||||
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;
|
||||
/* Try to find matching IP type */
|
||||
list_foreach(struct ip_type *t, &ip_types) {
|
||||
if (ip_vlnv_match(c, t->vlnv.vendor, t->vlnv.library, t->vlnv.name, t->vlnv.version)) {
|
||||
c->_vt = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Common settings */
|
||||
|
@ -175,7 +121,10 @@ int ip_parse(struct ip *c, config_setting_t *cfg)
|
|||
if (!config_setting_lookup_int(cfg, "port", &c->port))
|
||||
c->port = -1;
|
||||
|
||||
c->cfg = cfg;
|
||||
/* Type sepecific settings */
|
||||
ret = c->_vt && c->_vt->parse ? c->_vt->parse(c) : 0;
|
||||
if (ret)
|
||||
error("Failed to parse settings for IP core '%s'", c->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter
|
|||
{
|
||||
#define copy_string(off) strndup((char *) (data + (off)), (length - (off)) * 4);
|
||||
int j;
|
||||
struct model_param *p;
|
||||
struct model_param p, *e;
|
||||
struct model_info *i;
|
||||
|
||||
/* Check magic */
|
||||
|
@ -59,17 +59,21 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter
|
|||
case XSG_BLOCK_GATEWAY_OUT:
|
||||
if (length < 4)
|
||||
break; /* block is to small to describe a gateway */
|
||||
|
||||
p = alloc(sizeof(*p));
|
||||
|
||||
p->name = copy_string(3);
|
||||
p->default_value.flt = *((float *) &data[1]);
|
||||
p->offset = data[2];
|
||||
p->direction = type & 0x1;
|
||||
p->type = (data[0] >> 0) & 0xFF;
|
||||
p->binpt = (data[0] >> 8) & 0xFF;
|
||||
memset(&p, 0, sizeof(p));
|
||||
|
||||
list_push(parameters, p);
|
||||
p.name = copy_string(3);
|
||||
p.default_value.flt = *((float *) &data[1]);
|
||||
p.offset = data[2];
|
||||
p.direction = type & 0x1;
|
||||
p.type = (data[0] >> 0) & 0xFF;
|
||||
p.binpt = (data[0] >> 8) & 0xFF;
|
||||
|
||||
e = list_lookup(parameters, p.name);
|
||||
if (e)
|
||||
model_param_update(e, &p);
|
||||
else
|
||||
list_push(parameters, memdup(&p, sizeof(p)));
|
||||
break;
|
||||
|
||||
case XSG_BLOCK_INFO:
|
||||
|
@ -125,13 +129,35 @@ static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr)
|
|||
return i;
|
||||
}
|
||||
|
||||
static int model_init_from_xml(struct ip *c)
|
||||
int model_parse(struct ip *c)
|
||||
{
|
||||
//struct model *m = &c->model;
|
||||
struct model *m = &c->model;
|
||||
struct model_param p;
|
||||
|
||||
config_setting_t *cfg_params, *cfg_param;
|
||||
|
||||
/** @todo Implement */
|
||||
|
||||
return -1;
|
||||
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(c->cfg, "Invalid model type: %s", c->vlnv.library);
|
||||
|
||||
cfg_params = config_setting_get_member(c->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);
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
|
||||
p.name = config_setting_name(cfg_param);
|
||||
p.default_value.flt = config_setting_get_float(cfg_param);
|
||||
|
||||
list_push(&m->parameters, memdup(&p, sizeof(p)));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int model_init_from_xsg_map(struct model *m, void *baseaddr)
|
||||
|
@ -169,18 +195,15 @@ int model_init(struct ip *c)
|
|||
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))
|
||||
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) {
|
||||
p->ip = c;
|
||||
|
||||
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);
|
||||
|
@ -316,3 +339,35 @@ int model_param_remove(struct ip *c, const char *name)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int model_param_update(struct model_param *p, struct model_param *u)
|
||||
{
|
||||
if (strcmp(p->name, u->name) != 0)
|
||||
return -1;
|
||||
|
||||
p->direction = u->direction;
|
||||
p->type = u->type;
|
||||
p->binpt = u->binpt;
|
||||
p->offset = u->offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip_hls = {
|
||||
.vlnv = { NULL, "hls", NULL, NULL },
|
||||
.init = model_init,
|
||||
.destroy = model_destroy,
|
||||
.dump = model_dump,
|
||||
.parse = model_parse
|
||||
};
|
||||
|
||||
static struct ip_type ip_xsg = {
|
||||
.vlnv = { NULL, "sysgen", NULL, NULL },
|
||||
.init = model_init,
|
||||
.destroy = model_destroy,
|
||||
.dump = model_dump,
|
||||
.parse = model_parse
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip_hls)
|
||||
REGISTER_IP_TYPE(&ip_xsg)
|
|
@ -11,14 +11,15 @@
|
|||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/rtds_axis.h"
|
||||
|
||||
void rtds_axis_dump(char *baseaddr)
|
||||
void rtds_axis_dump(struct ip *c)
|
||||
{
|
||||
/* Check RTDS_Axis registers */
|
||||
uint32_t *rtds = (uint32_t *) baseaddr;
|
||||
uint32_t *regs = (uint32_t *) (c->card->map + c->baseaddr);
|
||||
|
||||
uint32_t sr = rtds[RTDS_AXIS_SR_OFFSET/4];
|
||||
uint32_t sr = regs[RTDS_AXIS_SR_OFFSET/4];
|
||||
info("RTDS AXI Stream interface details");
|
||||
{ INDENT
|
||||
info("RTDS status: %#08x", sr);
|
||||
|
@ -30,20 +31,27 @@ void rtds_axis_dump(char *baseaddr)
|
|||
info("Case running: %s", sr & RTDS_AXIS_SR_CASE_RUNNING ? GRN("yes") : RED("no"));
|
||||
}
|
||||
|
||||
info("RTDS control: %#08x", rtds[RTDS_AXIS_CR_OFFSET/4]);
|
||||
info("RTDS IRQ coalesc: %u", rtds[RTDS_AXIS_COALESC_OFFSET/4]);
|
||||
info("RTDS IRQ version: %#06x", rtds[RTDS_AXIS_VERSION_OFFSET/4]);
|
||||
info("RTDS IRQ multi-rate RTDS2AXIS: %u", rtds[RTDS_AXIS_MRATE_RTDS2AXIS/4]);
|
||||
info("RTDS IRQ multi-rate AXIS2RTDS: %u", rtds[RTDS_AXIS_MRATE_AXIS2RTDS/4]);
|
||||
info("RTDS control: %#08x", regs[RTDS_AXIS_CR_OFFSET/4]);
|
||||
info("RTDS IRQ coalesc: %u", regs[RTDS_AXIS_COALESC_OFFSET/4]);
|
||||
info("RTDS IRQ version: %#06x", regs[RTDS_AXIS_VERSION_OFFSET/4]);
|
||||
info("RTDS IRQ multi-rate: %u", regs[RTDS_AXIS_MRATE/4]);
|
||||
|
||||
info("RTDS timestep counter: %lu", (uint64_t) rtds[RTDS_AXIS_TSCNT_LOW_OFFSET/4] | (uint64_t) rtds[RTDS_AXIS_TSCNT_HIGH_OFFSET/4] << 32);
|
||||
info("RTDS timestep period: %.3f uS", rtds_axis_dt(baseaddr) * 1e6);
|
||||
info("RTDS timestep counter: %lu", (uint64_t) regs[RTDS_AXIS_TSCNT_LOW_OFFSET/4] | (uint64_t) regs[RTDS_AXIS_TSCNT_HIGH_OFFSET/4] << 32);
|
||||
info("RTDS timestep period: %.3f uS", rtds_axis_dt(c) * 1e6);
|
||||
}
|
||||
}
|
||||
|
||||
double rtds_axis_dt(char *baseaddr)
|
||||
double rtds_axis_dt(struct ip *c)
|
||||
{
|
||||
uint32_t *rtds = (uint32_t *) baseaddr;
|
||||
uint32_t *regs = (uint32_t *) (c->card->map + c->baseaddr);
|
||||
uint16_t dt = regs[RTDS_AXIS_TS_PERIOD_OFFSET/4];
|
||||
|
||||
return (double) rtds[RTDS_AXIS_TS_PERIOD_OFFSET/4] / RTDS_HZ;
|
||||
}
|
||||
return (dt == 0xFFFF) ? -1.0 : (double) dt / RTDS_HZ;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL },
|
||||
.dump = rtds_axis_dump
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
|
@ -8,46 +8,134 @@
|
|||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "fpga/switch.h"
|
||||
#include "fpga/ip.h"
|
||||
|
||||
int switch_init(struct ip *c)
|
||||
{
|
||||
XAxis_Switch *sw = &c->sw;
|
||||
int ret;
|
||||
struct sw *sw = &c->sw;
|
||||
struct fpga *f = c->card;
|
||||
|
||||
if (c != f->sw)
|
||||
error("There can be only one AXI4-Stream interconnect per FPGA");
|
||||
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
/* Setup AXI-stream switch */
|
||||
XAxis_Switch_Config sw_cfg = {
|
||||
.BaseAddress = (uintptr_t) c->card->map + c->baseaddr,
|
||||
.MaxNumMI = sw->Config.MaxNumMI,
|
||||
.MaxNumSI = sw->Config.MaxNumSI
|
||||
.MaxNumMI = sw->num_ports,
|
||||
.MaxNumSI = sw->num_ports
|
||||
};
|
||||
|
||||
ret = XAxisScr_CfgInitialize(sw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
||||
ret = XAxisScr_CfgInitialize(xsw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
|
||||
#if 0
|
||||
ret = XAxisScr_SelfTest(sw);
|
||||
if (ret != TRUE)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/* Disable all masters */
|
||||
XAxisScr_RegUpdateDisable(sw);
|
||||
XAxisScr_MiPortDisableAll(sw);
|
||||
XAxisScr_RegUpdateEnable(sw);
|
||||
XAxisScr_RegUpdateDisable(xsw);
|
||||
XAxisScr_MiPortDisableAll(xsw);
|
||||
XAxisScr_RegUpdateEnable(xsw);
|
||||
|
||||
debug(8, "FPGA: Switch disabled all");
|
||||
|
||||
list_foreach(struct sw_path *p, &sw->paths) {
|
||||
struct ip *mi, *si;
|
||||
|
||||
mi = list_lookup(&c->card->ips, p->out);
|
||||
si = list_lookup(&c->card->ips, p->in);
|
||||
|
||||
if (!mi || !si || mi->port == -1 || si->port == -1)
|
||||
error("Invalid path configuration for FPGA");
|
||||
|
||||
ret = switch_connect(c, mi, si);
|
||||
if (ret)
|
||||
error("Failed to configure switch");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void switch_destroy(struct ip *c)
|
||||
{
|
||||
struct sw *sw = &c->sw;
|
||||
|
||||
list_destroy(&sw->paths, NULL, true);
|
||||
}
|
||||
|
||||
int switch_parse(struct ip *c)
|
||||
{
|
||||
struct sw *sw = &c->sw;
|
||||
|
||||
list_init(&sw->paths);
|
||||
|
||||
config_setting_t *cfg_sw, *cfg_path;
|
||||
|
||||
if (!config_setting_lookup_int(c->cfg, "num_ports", &sw->num_ports))
|
||||
cerror(c->cfg, "Switch IP '%s' requires 'num_ports' option", c->name);
|
||||
|
||||
cfg_sw = config_setting_get_member(c->card->cfg, "paths");
|
||||
if (!cfg_sw)
|
||||
return 0; /* no switch config available */
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_sw); i++) {
|
||||
cfg_path = config_setting_get_elem(cfg_sw, i);
|
||||
|
||||
struct sw_path path;
|
||||
if (!config_setting_lookup_string(cfg_path, "in", &path.in) &&
|
||||
!config_setting_lookup_string(cfg_path, "from", &path.in) &&
|
||||
!config_setting_lookup_string(cfg_path, "src", &path.in) &&
|
||||
!config_setting_lookup_string(cfg_path, "source", &path.in))
|
||||
cerror(cfg_path, "Path is missing 'in' setting");
|
||||
|
||||
if (!config_setting_lookup_string(cfg_path, "out", &path.out) &&
|
||||
!config_setting_lookup_string(cfg_path, "to", &path.out) &&
|
||||
!config_setting_lookup_string(cfg_path, "dst", &path.out) &&
|
||||
!config_setting_lookup_string(cfg_path, "dest", &path.out) &&
|
||||
!config_setting_lookup_string(cfg_path, "sink", &path.out))
|
||||
cerror(cfg_path, "Path is missing 'out' setting");
|
||||
|
||||
list_push(&sw->paths, memdup(&path, sizeof(path)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_connect(struct ip *c, struct ip *mi, struct ip *si)
|
||||
{
|
||||
XAxis_Switch *sw = &c->sw;
|
||||
|
||||
XAxisScr_RegUpdateDisable(sw);
|
||||
XAxisScr_MiPortEnable(sw, mi->port, si->port);
|
||||
XAxisScr_RegUpdateEnable(sw);
|
||||
struct sw *sw = &c->sw;
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
XAxisScr_RegUpdateDisable(xsw);
|
||||
XAxisScr_MiPortEnable(xsw, mi->port, si->port);
|
||||
XAxisScr_RegUpdateEnable(xsw);
|
||||
|
||||
debug(8, "FPGA: Switch connected %s (%u) to %s (%u)", mi->name, mi->port, si->name, si->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_disconnect(struct ip *c, struct ip *mi, struct ip *si)
|
||||
{
|
||||
struct sw *sw = &c->sw;
|
||||
XAxis_Switch *xsw = &sw->inst;
|
||||
|
||||
if (!XAxisScr_IsMiPortEnabled(xsw, mi->port, si->port))
|
||||
return -1;
|
||||
|
||||
XAxisScr_MiPortDisable(xsw, mi->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axis_interconnect", NULL },
|
||||
.init = switch_init,
|
||||
.destroy = switch_destroy,
|
||||
.parse = switch_parse
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
39
lib/fpga/timer.c
Normal file
39
lib/fpga/timer.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/** 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.
|
||||
**********************************************************************************/
|
||||
|
||||
#include "config-fpga.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/timer.h"
|
||||
|
||||
int timer_init(struct ip *c)
|
||||
{
|
||||
struct timer *tmr = &c->timer;
|
||||
struct fpga *f = c->card;
|
||||
|
||||
XTmrCtr *xtmr = &tmr->inst;
|
||||
XTmrCtr_Config xtmr_cfg = {
|
||||
.BaseAddress = (uintptr_t) f->map + c->baseaddr,
|
||||
.SysClockFreqHz = AXI_HZ
|
||||
};
|
||||
|
||||
XTmrCtr_CfgInitialize(xtmr, &xtmr_cfg, (uintptr_t) f->map + c->baseaddr);
|
||||
XTmrCtr_InitHw(xtmr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_type ip = {
|
||||
.vlnv = { "xilinx.com", "ip", "axi_timer", NULL },
|
||||
.init = timer_init
|
||||
};
|
||||
|
||||
REGISTER_IP_TYPE(&ip)
|
247
lib/nodes/fpga.c
247
lib/nodes/fpga.c
|
@ -18,6 +18,7 @@
|
|||
#include "nodes/fpga.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/intc.h"
|
||||
|
||||
#include "config-fpga.h"
|
||||
#include "utils.h"
|
||||
|
@ -38,7 +39,7 @@ int fpga_reset(struct fpga *f)
|
|||
|
||||
uint32_t *rst_reg = (uint32_t *) (f->map + f->reset->baseaddr);
|
||||
|
||||
info("Reset fpga");
|
||||
debug(3, "FPGA: reset");
|
||||
rst_reg[0] = 1;
|
||||
|
||||
usleep(100000);
|
||||
|
@ -48,9 +49,7 @@ int fpga_reset(struct fpga *f)
|
|||
if (ret != sizeof(state))
|
||||
return -1;
|
||||
|
||||
info("Reset status = %#x", *rst_reg);
|
||||
|
||||
return 0;
|
||||
return rst_reg[0];
|
||||
}
|
||||
|
||||
void fpga_dump(struct fpga *f)
|
||||
|
@ -88,27 +87,27 @@ struct fpga * fpga_get()
|
|||
return &fpga;
|
||||
}
|
||||
|
||||
int fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *cfg)
|
||||
int fpga_parse_card(struct fpga *f, int argc, char * argv[], config_setting_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
const char *slot, *id, *err;
|
||||
config_setting_t *cfg_fpga, *cfg_ips, *cfg_slot, *cfg_id;
|
||||
config_setting_t *cfg_ips, *cfg_slot, *cfg_id;
|
||||
|
||||
/* Default values */
|
||||
v->filter.vendor = PCI_VID_XILINX;
|
||||
v->filter.device = PCI_PID_VFPGA;
|
||||
f->filter.vendor = PCI_VID_XILINX;
|
||||
f->filter.device = PCI_PID_VFPGA;
|
||||
|
||||
cfg_fpga = config_setting_get_member(cfg, "fpga");
|
||||
if (!cfg_fpga)
|
||||
f->cfg = config_setting_get_member(cfg, "fpga");
|
||||
if (!f->cfg)
|
||||
cerror(cfg, "Config file is missing VILLASfpga configuration");
|
||||
|
||||
config_setting_lookup_bool(cfg_fpga, "do_reset", &v->do_reset);
|
||||
config_setting_lookup_bool(f->cfg, "do_reset", &f->do_reset);
|
||||
|
||||
cfg_slot = config_setting_get_member(cfg_fpga, "slot");
|
||||
cfg_slot = config_setting_get_member(f->cfg, "slot");
|
||||
if (cfg_slot) {
|
||||
slot = config_setting_get_string(cfg_slot);
|
||||
if (slot) {
|
||||
err = pci_filter_parse_slot(&v->filter, (char*) slot);
|
||||
err = pci_filter_parse_slot(&f->filter, (char*) slot);
|
||||
if (err)
|
||||
cerror(cfg_slot, "%s", err);
|
||||
}
|
||||
|
@ -116,11 +115,11 @@ int fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *c
|
|||
cerror(cfg_slot, "Invalid slot format");
|
||||
}
|
||||
|
||||
cfg_id = config_setting_get_member(cfg_fpga, "id");
|
||||
cfg_id = config_setting_get_member(f->cfg, "id");
|
||||
if (cfg_id) {
|
||||
id = config_setting_get_string(cfg_id);
|
||||
if (id) {
|
||||
err = pci_filter_parse_id(&v->filter, (char*) id);
|
||||
err = pci_filter_parse_id(&f->filter, (char*) id);
|
||||
if (err)
|
||||
cerror(cfg_id, "%s", err);
|
||||
}
|
||||
|
@ -128,22 +127,22 @@ int fpga_parse_card(struct fpga *v, int argc, char * argv[], config_setting_t *c
|
|||
cerror(cfg_slot, "Invalid id format");
|
||||
}
|
||||
|
||||
cfg_ips = config_setting_get_member(cfg_fpga, "ips");
|
||||
cfg_ips = config_setting_get_member(f->cfg, "ips");
|
||||
if (!cfg_ips)
|
||||
cerror(cfg_fpga, "FPGA configuration is missing ips section");
|
||||
cerror(f->cfg, "FPGA configuration is missing ips section");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_ips); i++) {
|
||||
struct ip *ip;
|
||||
config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
|
||||
|
||||
ip = alloc(sizeof(struct ip));
|
||||
ret = ip_parse(ip, cfg_ip);
|
||||
if (ret) {
|
||||
free(ip);
|
||||
cerror(cfg_ip, "Failed to parse VILLASfpga ip");
|
||||
}
|
||||
struct ip ip = {
|
||||
.card = f
|
||||
};
|
||||
|
||||
ret = ip_parse(&ip, cfg_ip);
|
||||
if (ret)
|
||||
cerror(cfg_ip, "Failed to parse VILLASfpga IP core");
|
||||
|
||||
list_push(&v->ips, ip);
|
||||
list_push(&f->ips, memdup(&ip, sizeof(ip)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -158,13 +157,22 @@ int fpga_init(int argc, char * argv[], config_setting_t *cfg)
|
|||
|
||||
/* For now we only support a single VILALSfpga card */
|
||||
f = fpga_get();
|
||||
list_init(&f->ips);
|
||||
|
||||
pacc = pci_get_handle();
|
||||
pci_filter_init(pacc, &f->filter);
|
||||
|
||||
/* Parse FPGA configuration */
|
||||
ret = fpga_parse_card(f, argc, argv, cfg);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to parse VILLASfpga config");
|
||||
|
||||
/* Check FPGA configuration */
|
||||
f->reset = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_gpio", NULL);
|
||||
if (!reset)
|
||||
if (!f->reset)
|
||||
error("FPGA is missing a reset controller");
|
||||
|
||||
f->intc = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_pcie_intc", NULL);
|
||||
f->intc = ip_vlnv_lookup(&f->ips, "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL);
|
||||
if (!f->intc)
|
||||
error("FPGA is missing a interrupt controller");
|
||||
|
||||
|
@ -172,22 +180,11 @@ int fpga_init(int argc, char * argv[], config_setting_t *cfg)
|
|||
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 = fpga_parse_card(f, argc, argv, cfg);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to parse VILLASfpga config");
|
||||
|
||||
/* Search for fpga card */
|
||||
/* Search for FPGA card */
|
||||
pdev = pci_find_device(pacc, &f->filter);
|
||||
if (!pdev)
|
||||
error("Failed to find PCI device");
|
||||
|
||||
if (pdev->vendor_id != PCI_VID_XILINX)
|
||||
error("This is not a Xilinx FPGA board!");
|
||||
|
||||
/* Get VFIO handles and details */
|
||||
ret = vfio_init(&vc);
|
||||
if (ret)
|
||||
|
@ -204,7 +201,7 @@ int fpga_init(int argc, char * argv[], config_setting_t *cfg)
|
|||
serror("Failed to mmap() BAR0");
|
||||
|
||||
/* Map DMA accessible memory */
|
||||
f->dma = vfio_map_dma(f->vd.group->container, 0x10000, 0x1000, 0x0);
|
||||
f->dma = vfio_map_dma(f->vd.group->container, 16 << 20, 0x1000, 0x0);
|
||||
if (f->dma == MAP_FAILED)
|
||||
serror("Failed to mmap() DMA");
|
||||
|
||||
|
@ -217,7 +214,7 @@ int fpga_init(int argc, char * argv[], config_setting_t *cfg)
|
|||
if (f->do_reset) {
|
||||
ret = fpga_reset(f);
|
||||
if (ret)
|
||||
serror("Failed to reset fpga card");
|
||||
error("Failed to reset FGPA card");
|
||||
|
||||
/* Reset / detect PCI device */
|
||||
ret = vfio_pci_reset(&f->vd);
|
||||
|
@ -227,8 +224,9 @@ int fpga_init(int argc, char * argv[], config_setting_t *cfg)
|
|||
|
||||
/* Initialize IP cores */
|
||||
list_foreach(struct ip *c, &f->ips) {
|
||||
c->card = f;
|
||||
ip_init(c);
|
||||
ret = ip_init(c);
|
||||
if (ret)
|
||||
error("Failed to initalize IP core: %s (%u)", c->name, ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -256,21 +254,11 @@ int fpga_parse(struct node *n, config_setting_t *cfg)
|
|||
/* 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))
|
||||
if (!config_setting_lookup_string(cfg, "datamover", &d->ip_name))
|
||||
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);
|
||||
if (!config_setting_lookup_bool(cfg, "use_irqs", &d->use_irqs))
|
||||
d->use_irqs = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -279,27 +267,92 @@ char * fpga_print(struct node *n)
|
|||
{
|
||||
struct fpga_dm *d = n->_vd;
|
||||
struct fpga *f = d->card;
|
||||
|
||||
if (d->ip)
|
||||
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);
|
||||
else
|
||||
return strf("dm=%s", d->ip_name);
|
||||
}
|
||||
|
||||
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 fpga_get_type(struct ip *c)
|
||||
{
|
||||
if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_dma", NULL))
|
||||
return FPGA_DM_DMA;
|
||||
else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_fifo_mm_s", NULL))
|
||||
return FPGA_DM_FIFO;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fpga_open(struct node *n)
|
||||
{
|
||||
// struct fpga *v = n->_vd;
|
||||
int ret;
|
||||
struct fpga_dm *d = n->_vd;
|
||||
struct fpga *f = d->card;
|
||||
|
||||
/** @todo Implement */
|
||||
d->ip = list_lookup(&d->card->ips, d->ip_name);
|
||||
if (!d->ip)
|
||||
cerror(n->cfg, "Datamover '%s' is unknown. Please specify it in the fpga.ips section", d->ip_name);
|
||||
|
||||
d->type = fpga_get_type(d->ip);
|
||||
if (d->type < 0)
|
||||
cerror(n->cfg, "IP '%s' is not a supported datamover", d->ip->name);
|
||||
|
||||
switch (d->type) {
|
||||
case FPGA_DM_DMA:
|
||||
XAxiDma_Reset(&d->ip->dma.inst);
|
||||
|
||||
if (d->ip->dma.inst.HasSg) {
|
||||
struct ip *bram = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_bram_ctrl", NULL);
|
||||
if (!bram)
|
||||
return -3;
|
||||
|
||||
/* 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(d->ip, &bd);
|
||||
if (ret)
|
||||
return -4;
|
||||
}
|
||||
|
||||
intc_enable(f->intc, (1 << d->ip->irq), !d->use_irqs); /* MM2S */
|
||||
intc_enable(f->intc, (1 << (d->ip->irq + 1)), !d->use_irqs); /* S2MM */
|
||||
break;
|
||||
|
||||
case FPGA_DM_FIFO:
|
||||
XLlFifo_Reset(&d->ip->fifo.inst);
|
||||
|
||||
intc_enable(f->intc, (1 << d->ip->irq), !d->use_irqs); /* MM2S & S2MM */
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_close(struct node *n)
|
||||
{
|
||||
// struct fpga *v = n->_vd;
|
||||
|
||||
/** @todo Implement */
|
||||
struct fpga_dm *d = n->_vd;
|
||||
struct fpga *f = d->card;
|
||||
|
||||
switch (d->type) {
|
||||
case FPGA_DM_DMA:
|
||||
if (d->use_irqs) {
|
||||
intc_disable(f->intc, d->ip->irq); /* MM2S */
|
||||
intc_disable(f->intc, d->ip->irq + 1); /* S2MM */
|
||||
}
|
||||
|
||||
case FPGA_DM_FIFO:
|
||||
if (d->use_irqs)
|
||||
intc_disable(f->intc, d->ip->irq); /* MM2S & S2MM */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -307,23 +360,39 @@ int fpga_close(struct node *n)
|
|||
int fpga_read(struct node *n, struct sample *smps[], unsigned cnt)
|
||||
{
|
||||
struct fpga_dm *d = n->_vd;
|
||||
struct fpga *f = d->card;
|
||||
struct sample *smp = smps[0];
|
||||
|
||||
char *addr = (char *) smp->values;
|
||||
size_t len = smp->length * sizeof(smp->values[0]);
|
||||
int ret;
|
||||
char *tmp = f->dma, *addr = (char *) smp->values;
|
||||
size_t recvlen;
|
||||
//size_t len = smp->length * sizeof(smp->values[0]);
|
||||
size_t len = 64 * sizeof(smp->values[0]);
|
||||
|
||||
/* We dont get a sequence no from the FPGA. Lets fake it */
|
||||
smp->sequence = n->received;
|
||||
smp->ts.origin = time_now();
|
||||
|
||||
/* 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;
|
||||
}
|
||||
ret = dma_read(d->ip, tmp, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dma_read_complete(d->ip, NULL, &recvlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(addr, tmp, recvlen);
|
||||
|
||||
smp->length = recvlen / 4;
|
||||
return 1;
|
||||
case FPGA_DM_FIFO:
|
||||
break;
|
||||
recvlen = fifo_read(d->ip, addr, len);
|
||||
|
||||
smp->length = recvlen / 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -331,18 +400,41 @@ int fpga_read(struct node *n, struct sample *smps[], unsigned cnt)
|
|||
|
||||
int fpga_write(struct node *n, struct sample *smps[], unsigned cnt)
|
||||
{
|
||||
int ret;
|
||||
struct fpga_dm *d = n->_vd;
|
||||
struct fpga *f = d->card;
|
||||
struct sample *smp = smps[0];
|
||||
|
||||
char *tmp = f->dma + 0x1000;
|
||||
char *addr = (char *) smp->values;
|
||||
size_t sentlen;
|
||||
size_t len = smp->length * sizeof(smp->values[0]);
|
||||
|
||||
//intc_wait(f->intc, 5, 1);
|
||||
|
||||
//if (n->received % 40000 == 0) {
|
||||
// struct timespec now = time_now();
|
||||
// info("proc time = %f", time_delta(&smp->ts.origin, &now));
|
||||
//}
|
||||
|
||||
/* Send data to RTDS */
|
||||
switch (d->type) {
|
||||
case FPGA_DM_DMA:
|
||||
len = dma_write(d->ip, addr, len);
|
||||
memcpy(tmp, addr, len);
|
||||
|
||||
ret = dma_write(d->ip, tmp, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dma_write_complete(d->ip, NULL, &sentlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
//info("Sent %u bytes to FPGA", sentlen);
|
||||
|
||||
return 1;
|
||||
case FPGA_DM_FIFO:
|
||||
sentlen = fifo_write(d->ip, addr, len);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -352,6 +444,7 @@ int fpga_write(struct node *n, struct sample *smps[], unsigned cnt)
|
|||
static struct node_type vt = {
|
||||
.name = "fpga",
|
||||
.description = "VILLASfpga PCIe card (libpci)",
|
||||
.size = sizeof(struct fpga_dm),
|
||||
.vectorize = 1,
|
||||
.parse = fpga_parse,
|
||||
.print = fpga_print,
|
||||
|
@ -363,4 +456,4 @@ static struct node_type vt = {
|
|||
.deinit = fpga_deinit
|
||||
};
|
||||
|
||||
REGISTER_NODE_TYPE(&vt)
|
||||
REGISTER_NODE_TYPE(&vt)
|
||||
|
|
Loading…
Add table
Reference in a new issue