From 7de25683d744d168148d70138fd395199045fd47 Mon Sep 17 00:00:00 2001
From: Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
Date: Sat, 18 Feb 2017 10:43:58 -0500
Subject: [PATCH] fpga: refactored VILLASfpga node type

---
 include/villas/fpga/card.h                |  63 ++++
 include/villas/fpga/dma.h                 |  68 -----
 include/villas/fpga/ip.h                  | 128 ++++----
 include/villas/fpga/{ => ips}/dft.h       |  20 +-
 include/villas/fpga/ips/dma.h             |  74 +++++
 include/villas/fpga/{ => ips}/fifo.h      |  17 +-
 include/villas/fpga/{ => ips}/intc.h      |  21 +-
 include/villas/fpga/{ => ips}/model.h     |  27 +-
 include/villas/fpga/{ => ips}/rtds_axis.h |  17 +-
 include/villas/fpga/{ => ips}/switch.h    |  23 +-
 include/villas/fpga/{ => ips}/timer.h     |  13 +-
 include/villas/fpga/vlnv.h                |  39 +++
 lib/fpga/Makefile.inc                     |   6 +-
 lib/fpga/card.c                           | 184 ++++++++++++
 lib/fpga/ip.c                             |  61 +---
 lib/fpga/ips/Makefile.inc                 |   6 +
 lib/fpga/{ => ips}/dft.c                  |  23 +-
 lib/fpga/{ => ips}/dma.c                  |  50 ++--
 lib/fpga/{ => ips}/fifo.c                 |  33 ++-
 lib/fpga/{ => ips}/intc.c                 |  30 +-
 lib/fpga/{ => ips}/model.c                |  49 ++--
 lib/fpga/{ => ips}/rtds_axis.c            |  12 +-
 lib/fpga/{ => ips}/switch.c               |  36 ++-
 lib/fpga/{ => ips}/timer.c                |  12 +-
 lib/fpga/vlnv.c                           |  45 +++
 lib/nodes/fpga.c                          | 337 +++++++---------------
 src/fpga-bench-overruns.c                 |   2 +-
 src/fpga-bench.c                          |   6 +-
 src/fpga-tests.c                          |  32 +-
 29 files changed, 839 insertions(+), 595 deletions(-)
 create mode 100644 include/villas/fpga/card.h
 delete mode 100644 include/villas/fpga/dma.h
 rename include/villas/fpga/{ => ips}/dft.h (68%)
 create mode 100644 include/villas/fpga/ips/dma.h
 rename include/villas/fpga/{ => ips}/fifo.h (65%)
 rename include/villas/fpga/{ => ips}/intc.h (63%)
 rename include/villas/fpga/{ => ips}/model.h (82%)
 rename include/villas/fpga/{ => ips}/rtds_axis.h (88%)
 rename include/villas/fpga/{ => ips}/switch.h (63%)
 rename include/villas/fpga/{ => ips}/timer.h (73%)
 create mode 100644 include/villas/fpga/vlnv.h
 create mode 100644 lib/fpga/card.c
 create mode 100644 lib/fpga/ips/Makefile.inc
 rename lib/fpga/{ => ips}/dft.c (87%)
 rename lib/fpga/{ => ips}/dma.c (89%)
 rename lib/fpga/{ => ips}/fifo.c (78%)
 rename lib/fpga/{ => ips}/intc.c (86%)
 rename lib/fpga/{ => ips}/model.c (89%)
 rename lib/fpga/{ => ips}/rtds_axis.c (88%)
 rename lib/fpga/{ => ips}/switch.c (85%)
 rename lib/fpga/{ => ips}/timer.c (82%)
 create mode 100644 lib/fpga/vlnv.c

diff --git a/include/villas/fpga/card.h b/include/villas/fpga/card.h
new file mode 100644
index 000000000..8fa9815d4
--- /dev/null
+++ b/include/villas/fpga/card.h
@@ -0,0 +1,63 @@
+/** FPGA card
+ *
+ * This class represents a FPGA device.
+ *
+ * @file
+ * @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
+ * @copyright 2017, 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 VILLASfpga
+ * @{
+ */
+
+#pragma once
+
+enum fpga_card_state {
+	FPGA_CARD_STATE_UNKOWN,
+	FPGA_CARD_STATE_RESETTED,
+	FPGA_CARD_STATE_INITIALIZED
+};
+
+struct fpga_card {
+	char *name;			/**< The name of the FPGA card */
+
+	enum fpga_card_state state;	/**< The state of this FPGA card. */
+
+	struct pci_dev filter;		/**< Filter for PCI device. */
+	struct vfio_dev vd;		/**< VFIO device handle. */
+
+	int do_reset;			/**< Reset VILLASfpga during startup? */
+	int affinity;			/**< Affinity for MSI interrupts */
+
+	struct list ips;		/**< List of IP components on FPGA. */
+
+	char *map;			/**< PCI BAR0 mapping for register access */
+
+	size_t maplen;
+	size_t dmalen;
+
+	/* Some IP cores are special and referenced here */
+	struct fpga_ip *intc;
+	struct fpga_ip *reset;
+	struct fpga_ip *sw;
+	
+	config_setting_t *cfg;
+};
+
+int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg);
+
+/** Initialize FPGA card and its IP components. */
+int fpga_card_init(struct fpga_card *c);
+
+int fpga_card_destroy(struct fpga_card *c);
+
+/** Check if the FPGA card configuration is plausible. */
+int fpga_card_check(struct fpga_card *c);
+
+/** Reset the FPGA to a known state */
+int fpga_card_reset(struct fpga_card *c);
+
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/dma.h b/include/villas/fpga/dma.h
deleted file mode 100644
index 172d80dba..000000000
--- a/include/villas/fpga/dma.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/** DMA related helper functions
- *
- * These functions present a simpler interface to Xilinx' DMA driver (XAxiDma_*)
- *
- * @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 _FPGA_DMA_H_
-#define _FPGA_DMA_H_
- 
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <xilinx/xaxidma.h>
-
-#define FPGA_DMA_BASEADDR	0x00000000
-#define FPGA_DMA_BOUNDARY	0x1000
-#define FPGA_DMA_BD_OFFSET	0xC0000000
-#define FPGA_DMA_BD_SIZE	(32 << 20) // 32 MB
-
-#define XAXIDMA_SR_SGINCL_MASK	0x00000008
-
-struct dma_mem {
-	char *base_virt;
-	char *base_phys;
-	size_t len;
-};
-
-struct dma {
-	XAxiDma inst;
-
-	struct dma_mem bd;
-};
-
-struct ip;
-
-int dma_mem_split(struct dma_mem *o, struct dma_mem *a, struct dma_mem *b);
-
-int dma_alloc(struct ip *c, struct dma_mem *mem, size_t len, int flags);
-int dma_free(struct ip *c, struct dma_mem *mem);
-
-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);
-
-int dma_sg_write(struct ip *c, char *buf, size_t len);
-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);
-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);
-
-#endif /* _FPGA_DMA_H_ */
\ No newline at end of file
diff --git a/include/villas/fpga/ip.h b/include/villas/fpga/ip.h
index 72a7cda7d..fb0e94a88 100644
--- a/include/villas/fpga/ip.h
+++ b/include/villas/fpga/ip.h
@@ -1,62 +1,73 @@
-#ifndef _FPGA_IP_H_
-#define _FPGA_IP_H_
+/** Interlectual Property component.
+ *
+ * This class represents a module within the FPGA.
+ *
+ * @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 VILLASfpga
+ * @{
+ */
+
+#pragma once
 
 #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 "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 "fpga/intc.h"
+
 #include "nodes/fpga.h"
 
-extern struct list ip_types;	/**< Table of existing FPGA IP core drivers */
+#include "fpga/vlnv.h"
 
-enum ip_state {
+#include "fpga/ips/dma.h"
+#include "fpga/ips/switch.h"
+#include "fpga/ips/fifo.h"
+#include "fpga/ips/rtds_axis.h"
+#include "fpga/ips/timer.h"
+#include "fpga/ips/model.h"
+#include "fpga/ips/dft.h"
+#include "fpga/ips/intc.h"
+
+enum fpga_ip_state {
 	IP_STATE_UNKNOWN,
 	IP_STATE_INITIALIZED
 };
 
-struct ip_vlnv {
-	char *vendor;
-	char *library;
-	char *name;
-	char *version;
+struct fpga_ip_type {
+	struct fpga_vlnv vlnv;
+
+	enum {
+		FPGA_IP_TYPE_DATAMOVER,	/**< A datamover IP exchanges streaming data between the FPGA and the CPU. */
+		FPGA_IP_TYPE_MODEL,	/**< A model IP simulates a system on the FPGA. */
+		FPGA_IP_TYPE_MATH,	/**< A math IP performs some kind of mathematical operation on the streaming data */
+		FPGA_IP_TYPE_MISC,	/**< Other IP components like timer, counters, interrupt conctrollers or routing. */
+		FPGA_IP_TYPE_INTERFACE	/**< A interface IP connects the FPGA to another system or controller. */
+	} type;
+
+	int (*parse)(struct fpga_ip *c);
+	int (*init)(struct fpga_ip *c);
+	int (*reset)(struct fpga_ip *c);
+	void (*dump)(struct fpga_ip *c);
+	void (*destroy)(struct fpga_ip *c);
 };
 
-struct ip_type {
-	struct ip_vlnv vlnv;
+struct fpga_ip {
+	char *name;			/**< Name of the FPGA IP component. */
+	struct fpga_vlnv vlnv;		/**< The Vendor, Library, Name, Version tag of the FPGA IP component. */
 
-	int (*parse)(struct ip *c);
-	int (*init)(struct ip *c);
-	int (*reset)(struct ip *c);
-	void (*dump)(struct ip *c);
-	void (*destroy)(struct ip *c);
-};
+	enum fpga_ip_state state;	/**< The current state of the FPGA IP component. */
 
-struct ip {
-	char *name;
+	struct fpga_ip_type *_vt;	/**< Vtable containing FPGA IP type function pointers. */
 
-	struct ip_vlnv vlnv;
+	uintptr_t baseaddr;		/**< The baseadress of this FPGA IP component */
+	uintptr_t baseaddr_axi4;	/**< Used by AXI4 FIFO DM */
 
-	uintptr_t baseaddr;
-	uintptr_t baseaddr_axi4;
-
-	int port, irq;
-
-	enum ip_state state;
-
-	struct ip_type *_vt;
+	int port;			/**< The port of the AXI4-Stream switch to which this FPGA IP component is connected. */
+	int irq;			/**< The interrupt number of the FPGA IP component. */
 
 	union {
 		struct model model;
@@ -66,33 +77,26 @@ struct ip {
 		struct sw sw;
 		struct dft dft;
 		struct intc intc;
-	};
+	};				/**< Specific private date per FPGA IP type. Depends on fpga_ip::_vt */
 	
-	struct fpga *card;
+	struct fpga_card *card;		/**< The FPGA to which this IP instance belongs to. */
 
 	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);
+/** Initialize IP instance. */
+int fpga_ip_init(struct fpga_ip *c);
 
-/** Check if IP block \p c matched VLNV. */
-int ip_vlnv_cmp(struct ip_vlnv *a, struct ip_vlnv *b);
+/** Release dynamic memory allocated by this IP instance. */
+int fpga_ip_destroy(struct fpga_ip *c);
 
-/** Tokenizes VLNV \p vlnv and stores it into \p c */
-int ip_vlnv_parse(struct ip_vlnv *c, const char *vlnv);
+/** Dump details about this IP instance to stdout. */
+void fpga_ip_dump(struct fpga_ip *c);
 
-/** Release memory allocated by ip_vlnv_parse(). */
-void ip_vlnv_destroy(struct ip_vlnv *v);
+/** Reset IP component to its initial state. */
+int fpga_ip_reset(struct fpga_ip *c);
 
-int ip_init(struct ip *c);
+/** Parse IP configuration from configuration file */
+int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg);
 
-void ip_destroy(struct ip *c);
-
-void ip_dump(struct ip *c);
-
-int ip_reset(struct ip *c);
-
-int ip_parse(struct ip *c, config_setting_t *cfg);
-
-#endif /* _FPGA_IP_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/dft.h b/include/villas/fpga/ips/dft.h
similarity index 68%
rename from include/villas/fpga/dft.h
rename to include/villas/fpga/ips/dft.h
index 52edfb37b..95edb9abf 100644
--- a/include/villas/fpga/dft.h
+++ b/include/villas/fpga/ips/dft.h
@@ -5,10 +5,13 @@
  * @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 _FPGA_DFT_H_
-#define _FPGA_DFT_H_
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
+
+#pragma once
 
 #include <xilinx/xhls_dft.h>
 
@@ -24,11 +27,10 @@ struct dft {
 	int decimation;
 };
 
-int dft_parse(struct ip *c);
+int dft_parse(struct fpga_ip *c);
 
-int dft_init(struct ip *c);
+int dft_init(struct fpga_ip *c);
 
-void dft_destroy(struct ip *c);
+int dft_destroy(struct fpga_ip *c);
 
-
-#endif /* _FPGA_DFT_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/ips/dma.h b/include/villas/fpga/ips/dma.h
new file mode 100644
index 000000000..ab6fffb10
--- /dev/null
+++ b/include/villas/fpga/ips/dma.h
@@ -0,0 +1,74 @@
+/** DMA related helper functions.
+ *
+ * These functions present a simpler interface to Xilinx' DMA driver (XAxiDma_*).
+ *
+ * @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.
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
+
+#pragma once
+ 
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <xilinx/xaxidma.h>
+
+/* Forward declarations */
+struct fpga_ip;
+
+#define FPGA_DMA_BASEADDR	0x00000000
+#define FPGA_DMA_BOUNDARY	0x1000
+#define FPGA_DMA_BD_OFFSET	0xC0000000
+#define FPGA_DMA_BD_SIZE	(32 << 20) // 32 MB
+
+#define XAXIDMA_SR_SGINCL_MASK	0x00000008
+
+struct dma_mem {
+	char *base_virt;
+	char *base_phys;
+	size_t len;
+};
+
+struct dma {
+	XAxiDma inst;
+
+	struct dma_mem bd;
+};
+
+struct ip;
+
+int dma_mem_split(struct dma_mem *o, struct dma_mem *a, struct dma_mem *b);
+
+int dma_alloc(struct fpga_ip *c, struct dma_mem *mem, size_t len, int flags);
+int dma_free(struct fpga_ip *c, struct dma_mem *mem);
+
+int dma_write(struct fpga_ip *c, char *buf, size_t len);
+int dma_read(struct fpga_ip *c, char *buf, size_t len);
+int dma_read_complete(struct fpga_ip *c, char **buf, size_t *len);
+int dma_write_complete(struct fpga_ip *c, char **buf, size_t *len);
+
+int dma_sg_write(struct fpga_ip *c, char *buf, size_t len);
+int dma_sg_read(struct fpga_ip *c, char *buf, size_t len);
+
+int dma_sg_write_complete(struct fpga_ip *c, char **buf, size_t *len);
+int dma_sg_read_complete(struct fpga_ip *c, char **buf, size_t *len);
+
+int dma_simple_read(struct fpga_ip *c, char *buf, size_t len);
+int dma_simple_write(struct fpga_ip *c, char *buf, size_t len);
+
+int dma_simple_read_complete(struct fpga_ip *c, char **buf, size_t *len);
+int dma_simple_write_complete(struct fpga_ip *c, char **buf, size_t *len);
+
+int dma_ping_pong(struct fpga_ip *c, char *src, char *dst, size_t len);
+
+int dma_init(struct fpga_ip *c);
+
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/fifo.h b/include/villas/fpga/ips/fifo.h
similarity index 65%
rename from include/villas/fpga/fifo.h
rename to include/villas/fpga/ips/fifo.h
index 1872fa488..4602ed36f 100644
--- a/include/villas/fpga/fifo.h
+++ b/include/villas/fpga/ips/fifo.h
@@ -7,10 +7,13 @@
  * @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.
- **********************************************************************************/
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
 
-#ifndef _FPGA_FIFO_H_
-#define _FPGA_FIFO_H_
+#pragma once
 
 #include <sys/types.h>
 
@@ -26,10 +29,10 @@ struct fifo {
 /* Forward declaration */
 struct ip;
 
-int fifo_init(struct ip *c);
+int fifo_init(struct fpga_ip *c);
 
-ssize_t fifo_write(struct ip *c, char *buf, size_t len);
+ssize_t fifo_write(struct fpga_ip *c, char *buf, size_t len);
 
-ssize_t fifo_read(struct ip *c, char *buf, size_t len);
+ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len);
 
-#endif /* _FPGA_FIFO_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/intc.h b/include/villas/fpga/ips/intc.h
similarity index 63%
rename from include/villas/fpga/intc.h
rename to include/villas/fpga/ips/intc.h
index 626fe07d6..2449259b9 100644
--- a/include/villas/fpga/intc.h
+++ b/include/villas/fpga/ips/intc.h
@@ -4,10 +4,13 @@
  * @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.
- **********************************************************************************/
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
 
-#ifndef _FPGA_INTC_H_
-#define _FPGA_INTC_H_
+#pragma once
 
 #include <xilinx/xintc.h>
 
@@ -25,14 +28,14 @@ struct intc {
 	int flags[32];		/**< Mask of intc_flags */
 };
 
-int intc_init(struct ip *c);
+int intc_init(struct fpga_ip *c);
 
-void intc_destroy(struct ip *c);
+int intc_destroy(struct fpga_ip *c);
 
-int intc_enable(struct ip *c, uint32_t mask, int poll);
+int intc_enable(struct fpga_ip *c, uint32_t mask, int poll);
 
-int intc_disable(struct ip *c, uint32_t mask);
+int intc_disable(struct fpga_ip *c, uint32_t mask);
 
-uint64_t intc_wait(struct ip *c, int irq);
+uint64_t intc_wait(struct fpga_ip *c, int irq);
 
-#endif /* _FPGA_INTC_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/model.h b/include/villas/fpga/ips/model.h
similarity index 82%
rename from include/villas/fpga/model.h
rename to include/villas/fpga/ips/model.h
index 5270d626a..a5387e6c7 100644
--- a/include/villas/fpga/model.h
+++ b/include/villas/fpga/ips/model.h
@@ -5,10 +5,13 @@
  * @copyright 2016, Steffen Vogel
  *   This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
  *   Unauthorized copying of this file, via any medium is strictly prohibited.
- *********************************************************************************/
- 
-#ifndef _FPGA_MODEL_H_
-#define _FPGA_MODEL_H_
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
+
+#pragma once
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -85,26 +88,26 @@ struct model_param {
 
 	union model_param_value default_value;
 
-	struct ip *ip;				/**< A pointer to the model structure to which this parameters belongs to. */
+	struct fpga_ip *ip;				/**< A pointer to the model structure to which this parameters belongs to. */
 };
 
 /** Initialize a model */
-int model_init(struct ip *c);
+int model_init(struct fpga_ip *c);
 
 /** Parse model */
-int model_parse(struct ip *c);
+int model_parse(struct fpga_ip *c);
 
 /** Destroy a model */
-void model_destroy(struct ip *c);
+int model_destroy(struct fpga_ip *c);
 
 /** Print detailed information about the model to the screen. */
-void model_dump(struct ip *c);
+void model_dump(struct fpga_ip *c);
 
 /** 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_param_add(struct fpga_ip *c, 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);
+int model_param_remove(struct fpga_ip *c, const char *name);
 
 /** Read a model parameter.
  *
@@ -123,4 +126,4 @@ int model_param_write(struct model_param *p, double v);
 
 int model_param_update(struct model_param *p, struct model_param *u);
 
-#endif /* _FPGA_MODEL_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/rtds_axis.h b/include/villas/fpga/ips/rtds_axis.h
similarity index 88%
rename from include/villas/fpga/rtds_axis.h
rename to include/villas/fpga/ips/rtds_axis.h
index ecd6072fc..c4b8a907f 100644
--- a/include/villas/fpga/rtds_axis.h
+++ b/include/villas/fpga/ips/rtds_axis.h
@@ -5,12 +5,15 @@
  * @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.
- **********************************************************************************/
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
 
-#ifndef _FPGA_RTDS_AXIS_H_
-#define _FPGA_RTDS_AXIS_H_
+#pragma once
 
-/* Forward declaration */
+/* Forward declarations */
 struct ip;
 
 #define RTDS_HZ				100000000 // 100 MHz
@@ -38,8 +41,8 @@ struct ip;
 /* Control register bits */
 #define RTDS_AXIS_CR_DISABLE_LINK	0	/**< Disable SFP TX when set */
 
-void rtds_axis_dump(struct ip *c);
+void rtds_axis_dump(struct fpga_ip *c);
 
-double rtds_axis_dt(struct ip *c);
+double rtds_axis_dt(struct fpga_ip *c);
 
-#endif /* _FPGA_RTDS_AXIS_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/switch.h b/include/villas/fpga/ips/switch.h
similarity index 63%
rename from include/villas/fpga/switch.h
rename to include/villas/fpga/ips/switch.h
index fe109ad83..39de68b70 100644
--- a/include/villas/fpga/switch.h
+++ b/include/villas/fpga/ips/switch.h
@@ -7,10 +7,13 @@
  * @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.
- **********************************************************************************/
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
 
-#ifndef _FPGA_SWITCH_H_
-#define _FPGA_SWITCH_H_
+#pragma once
 
 #include <xilinx/xaxis_switch.h>
 
@@ -33,17 +36,17 @@ struct sw {
 
 struct ip;
 
-int switch_init(struct ip *c);
+int switch_init(struct fpga_ip *c);
 
 /** Initialize paths which have been parsed by switch_parse() */
-int switch_init_paths(struct ip *c);
+int switch_init_paths(struct fpga_ip *c);
 
-void switch_destroy(struct ip *c);
+int switch_destroy(struct fpga_ip *c);
 
-int switch_parse(struct ip *c);
+int switch_parse(struct fpga_ip *c);
 
-int switch_connect(struct ip *c, struct ip *mi, struct ip *si);
+int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si);
 
-int switch_disconnect(struct ip *c, struct ip *mi, struct ip *si);
+int switch_disconnect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si);
 
-#endif /* _FPGA_SWITCH_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/timer.h b/include/villas/fpga/ips/timer.h
similarity index 73%
rename from include/villas/fpga/timer.h
rename to include/villas/fpga/ips/timer.h
index 27cc37b98..2a83ce1d2 100644
--- a/include/villas/fpga/timer.h
+++ b/include/villas/fpga/ips/timer.h
@@ -7,13 +7,18 @@
  * @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.
- **********************************************************************************/
+ */
+/**
+ * @addtogroup fpga VILLASfpga
+ * @{
+ */
 
-#ifndef _FPGA_TIMER_H_
-#define _FPGA_TIMER_H_
+#pragma once
+
+#include <xilinx/xtmrctr.h>
 
 struct timer {
 	XTmrCtr inst;
 };
 
-#endif /* _FPGA_TIMER_H_ */
\ No newline at end of file
+/** @} */
\ No newline at end of file
diff --git a/include/villas/fpga/vlnv.h b/include/villas/fpga/vlnv.h
new file mode 100644
index 000000000..2abf2721e
--- /dev/null
+++ b/include/villas/fpga/vlnv.h
@@ -0,0 +1,39 @@
+/** Vendor, Library, Name, Version (VLNV) tag.
+ *
+ * @file
+ * @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
+ * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
+ *   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 VILLASfpga
+ * @{
+ */
+
+#ifndef _FPGA_VLNV_H_
+#define _FPGA_VLNV_H_
+
+/* Forward declarations */
+struct list;
+
+struct fpga_vlnv {
+	char *vendor;
+	char *library;
+	char *name;
+	char *version;
+};
+
+/** Return the first IP block in list \p l which matches the VLNV */
+struct fpga_ip * fpga_vlnv_lookup(struct list *l, struct fpga_vlnv *v);
+
+/** Check if IP block \p c matched VLNV. */
+int fpga_vlnv_cmp(struct fpga_vlnv *a, struct fpga_vlnv *b);
+
+/** Tokenizes VLNV \p vlnv and stores it into \p c */
+int fpga_vlnv_parse(struct fpga_vlnv *c, const char *vlnv);
+
+/** Release memory allocated by fpga_vlnv_parse(). */
+int fpga_vlnv_destroy(struct fpga_vlnv *v);
+
+#endif /** _FPGA_VLNV_H_ @} */
\ No newline at end of file
diff --git a/lib/fpga/Makefile.inc b/lib/fpga/Makefile.inc
index 3881fd813..01a3188c8 100644
--- a/lib/fpga/Makefile.inc
+++ b/lib/fpga/Makefile.inc
@@ -1,6 +1,8 @@
 # Enable VILLASfpga support when libxil is available
 ifndef WITHOUT_FPGA
 ifeq ($(shell pkg-config libxil; echo $$?),0)
-	LIB_SRCS += $(wildcard  lib/fpga/*.c)
+	LIB_SRCS += $(wildcard lib/fpga/*.c)
 endif
-endif
\ No newline at end of file
+endif
+
+-include lib/fpga/ip/Makefile.inc
\ No newline at end of file
diff --git a/lib/fpga/card.c b/lib/fpga/card.c
new file mode 100644
index 000000000..02c5d5de6
--- /dev/null
+++ b/lib/fpga/card.c
@@ -0,0 +1,184 @@
+#include <unistd.h>
+
+#include "config.h"
+
+#include "kernel/pci.h"
+#include "kernel/vfio.h"
+
+#include "fpga/ip.h"
+#include "fpga/card.h"
+
+int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc)
+{
+	int ret;
+
+	struct pci_dev *pdev;
+
+	fpga_card_check(c);
+	
+	if (c->state == FPGA_CARD_STATE_INITIALIZED)
+		return 0;
+
+	/* Search for FPGA card */
+	pdev = pci_lookup_device(pci, &c->filter);
+	if (!pdev)
+		error("Failed to find PCI device");
+
+	/* Attach PCIe card to VFIO container */
+	ret = vfio_pci_attach(&c->vd, vc, pdev);
+	if (ret)
+		error("Failed to attach VFIO device");
+
+	/* Map PCIe BAR */
+	c->map = vfio_map_region(&c->vd, VFIO_PCI_BAR0_REGION_INDEX);
+	if (c->map == MAP_FAILED)
+		serror("Failed to mmap() BAR0");
+
+	/* Enable memory access and PCI bus mastering for DMA */
+	ret = vfio_pci_enable(&c->vd);
+	if (ret)
+		serror("Failed to enable PCI device");
+	
+	/* Reset system? */
+	if (c->do_reset) {
+		/* Reset / detect PCI device */
+		ret = vfio_pci_reset(&c->vd);
+		if (ret)
+			serror("Failed to reset PCI device");
+
+		ret = fpga_card_reset(c);
+		if (ret)
+			error("Failed to reset FGPA card");
+	}
+
+	/* Initialize IP cores */
+	list_foreach(struct fpga_ip *i, &c->ips) {
+		ret = fpga_ip_init(i);
+		if (ret)
+			error("Failed to initalize IP core: %s (%u)", i->name, ret);
+	}
+	
+	return 0;
+}
+
+int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg)
+{
+	int ret;
+	const char *slot, *id, *err;
+	config_setting_t *cfg_ips, *cfg_slot, *cfg_id;
+
+	/* Default values */
+	c->filter.id.vendor = FPGA_PCI_VID_XILINX;
+	c->filter.id.device = FPGA_PCI_PID_VFPGA;
+	
+	c->name = config_setting_name(cfg);
+	c->state = FPGA_CARD_STATE_UNKOWN;
+	
+	if (!config_setting_lookup_int(cfg, "affinity", &c->affinity))
+		c->affinity = 0;
+
+	if (!config_setting_lookup_bool(cfg, "do_reset", &c->do_reset))
+		c->do_reset = 0;
+
+	cfg_slot = config_setting_get_member(cfg, "slot");
+	if (cfg_slot) {
+		slot = config_setting_get_string(cfg_slot);
+		if (slot) {
+			ret = pci_dev_parse_slot(&c->filter, slot, &err);
+			if (ret)
+				cerror(cfg_slot, "Failed to parse PCI slot: %s", err);
+		}
+		else
+			cerror(cfg_slot, "PCI slot must be a string");
+	}
+
+	cfg_id = config_setting_get_member(cfg, "id");
+	if (cfg_id) {
+		id = config_setting_get_string(cfg_id);
+		if (id) {
+			ret = pci_dev_parse_id(&c->filter, (char*) id, &err);
+			if (ret)
+				cerror(cfg_id, "Failed to parse PCI id: %s", err);
+		}
+		else
+			cerror(cfg_slot, "PCI ID must be a string");
+	}
+	
+	cfg_ips = config_setting_get_member(cfg, "ips");
+	if (!cfg_ips)
+		cerror(cfg, "FPGA configuration is missing ips section");
+
+	for (int i = 0; i < config_setting_length(cfg_ips); i++) {
+		config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
+
+		struct fpga_ip ip = {
+			.card = c
+		};
+	
+		ret = fpga_ip_parse(&ip, cfg_ip);
+		if (ret)
+			cerror(cfg_ip, "Failed to parse VILLASfpga IP core");
+
+		list_push(&c->ips, memdup(&ip, sizeof(ip)));
+	}
+	
+	c->cfg = cfg;
+	
+	return 0;
+}
+
+int fpga_card_check(struct fpga_card *c)
+{
+	/* Check FPGA configuration */
+	c->reset = fpga_vlnv_lookup(&c->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_gpio", NULL });
+	if (!c->reset)
+		error("FPGA is missing a reset controller");
+
+	c->intc = fpga_vlnv_lookup(&c->ips, &(struct fpga_vlnv) { "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL });
+	if (!c->intc)
+		error("FPGA is missing a interrupt controller");
+
+	c->sw = fpga_vlnv_lookup(&c->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axis_interconnect", NULL });
+	if (!c->sw)
+		warn("FPGA is missing an AXI4-Stream switch");
+	
+	return 0;
+}
+
+int fpga_card_destroy(struct fpga_card *c)
+{
+	list_destroy(&c->ips, (dtor_cb_t) fpga_ip_destroy, true);
+	
+	return 0;
+}
+
+int fpga_card_reset(struct fpga_card *c)
+{
+	int ret;
+	char state[4096];
+
+	/* Save current state of PCI configuration space */
+	ret = pread(c->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
+	if (ret != sizeof(state))
+		return -1;
+
+	uint32_t *rst_reg = (uint32_t *) (c->map + c->reset->baseaddr);
+
+	debug(3, "FPGA: reset");
+	rst_reg[0] = 1;
+
+	usleep(100000);
+
+	/* Restore previous state of PCI configuration space */
+	ret = pwrite(c->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
+	if (ret != sizeof(state))
+		return -1;
+
+	/* After reset the value should be zero again */
+	if (rst_reg[0])
+		return -2;
+	
+	c->state = FPGA_CARD_STATE_RESETTED;
+
+	return 0;
+}
\ No newline at end of file
diff --git a/lib/fpga/ip.c b/lib/fpga/ip.c
index 4bb87f07c..9fcf16ae0 100644
--- a/lib/fpga/ip.c
+++ b/lib/fpga/ip.c
@@ -1,48 +1,9 @@
-#include <string.h>
-#include <unistd.h>
-
 #include <libconfig.h>
 
 #include "log.h"
+#include "plugin.h"
 
-#include "fpga/ip.h"
-#include "fpga/intc.h"
-#include "fpga/fifo.h"
-#include "nodes/fpga.h"
-
-#include "config.h"
-
-int ip_vlnv_cmp(struct ip_vlnv *a, struct ip_vlnv *b)
-{
-	return ((!a->vendor  || !b->vendor  || !strcmp(a->vendor,  b->vendor ))	&&
-		(!a->library || !b->library || !strcmp(a->library, b->library))	&&
-		(!a->name    || !b->name    || !strcmp(a->name,    b->name   ))	&&
-		(!a->version || !b->version || !strcmp(a->version, b->version))) ? 0 : 1;
-}
-
-int ip_vlnv_parse(struct ip_vlnv *c, const char *vlnv)
-{
-	char *tmp = strdup(vlnv);
-
-	c->vendor  = strdup(strtok(tmp, ":"));
-	c->library = strdup(strtok(NULL, ":"));
-	c->name    = strdup(strtok(NULL, ":"));
-	c->version = strdup(strtok(NULL, ":"));
-	
-	free(tmp);
-
-	return 0;
-}
-
-void ip_vlnv_destroy(struct ip_vlnv *v)
-{
-	free(c->vendor);
-	free(c->library);
-	free(c->name);
-	free(c->version);
-}
-
-int ip_init(struct ip *c)
+int fpga_ip_init(struct fpga_ip *c)
 {
 	int ret;
 
@@ -58,22 +19,24 @@ int ip_init(struct ip *c)
 	return ret;
 }
 
-int ip_reset(struct ip *c)
+int fpga_ip_reset(struct fpga_ip *c)
 {
 	debug(3, "Reset IP core: %s", c->name);
 
 	return c->_vt && c->_vt->reset ? c->_vt->reset(c) : 0;
 }
 
-void ip_destroy(struct ip *c)
+int fpga_ip_destroy(struct fpga_ip *c)
 {
 	if (c->_vt && c->_vt->destroy)
 		c->_vt->destroy(c);
 
-	ip_vlnv_destroy(c->vlnv);
+	fpga_vlnv_destroy(&c->vlnv);
+	
+	return 0;
 }
 
-void ip_dump(struct ip *c)
+void fpga_ip_dump(struct fpga_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, 
@@ -83,7 +46,7 @@ void ip_dump(struct ip *c)
 		c->_vt->dump(c);
 }
 
-int ip_parse(struct ip *c, config_setting_t *cfg)
+int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg)
 {
 	int ret;
 	const char *vlnv;
@@ -98,15 +61,15 @@ 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);
 
-	ret = ip_vlnv_parse(&c->vlnv, vlnv);
+	ret = fpga_vlnv_parse(&c->vlnv, vlnv);
 	if (ret)
 		cerror(cfg, "Failed to parse VLNV identifier");
 
 	/* Try to find matching IP type */
 	list_foreach(struct plugin *l, &plugins) {
 		if (l->type == PLUGIN_TYPE_FPGA_IP &&
-		    !ip_vlnv_match(&c->ip.vlnv, &l->ip.vlnv)) {
-			c->_vt = t;
+		    !fpga_vlnv_cmp(&c->vlnv, &l->ip.vlnv)) {
+			c->_vt = &l->ip;
 			break;
 		}
 	}
diff --git a/lib/fpga/ips/Makefile.inc b/lib/fpga/ips/Makefile.inc
new file mode 100644
index 000000000..54f1d72eb
--- /dev/null
+++ b/lib/fpga/ips/Makefile.inc
@@ -0,0 +1,6 @@
+# Enable VILLASfpga support when libxil is available
+ifndef WITHOUT_FPGA
+ifeq ($(shell pkg-config libxil; echo $$?),0)
+	LIB_SRCS += $(wildcard  lib/fpga/ips/*.c)
+endif
+endif
\ No newline at end of file
diff --git a/lib/fpga/dft.c b/lib/fpga/ips/dft.c
similarity index 87%
rename from lib/fpga/dft.c
rename to lib/fpga/ips/dft.c
index db5b4be16..652621f6b 100644
--- a/lib/fpga/dft.c
+++ b/lib/fpga/ips/dft.c
@@ -11,9 +11,10 @@
 #include "plugin.h"
 
 #include "fpga/ip.h"
-#include "fpga/dft.h"
+#include "fpga/card.h"
+#include "fpga/ips/dft.h"
 
-int dft_parse(struct ip *c)
+int dft_parse(struct fpga_ip *c)
 {
 	struct dft *dft = &c->dft;
 
@@ -44,13 +45,16 @@ int dft_parse(struct ip *c)
 	return 0;
 }
 
-int dft_init(struct ip *c)
+int dft_init(struct fpga_ip *c)
 {
 	int ret;
+	
+	struct fpga_card *f = c->card;
 	struct dft *dft = &c->dft;
+
 	XHls_dft *xdft = &dft->inst;
 	XHls_dft_Config xdft_cfg = {
-		.Ctrl_BaseAddress = (uintptr_t) c->card->map + c->baseaddr
+		.Ctrl_BaseAddress = (uintptr_t) f->map + c->baseaddr
 	};
 
 	ret = XHls_dft_CfgInitialize(xdft, &xdft_cfg);
@@ -74,7 +78,7 @@ int dft_init(struct ip *c)
 	return 0;
 }
 
-void dft_destroy(struct ip *c)
+int dft_destroy(struct fpga_ip *c)
 {
 	struct dft *dft = &c->dft;
 	XHls_dft *xdft = &dft->inst;
@@ -85,6 +89,8 @@ void dft_destroy(struct ip *c)
 		free(dft->fharmonics);
 		dft->fharmonics = NULL;
 	}
+	
+	return 0;
 }
 
 static struct plugin p = {
@@ -92,10 +98,11 @@ static struct plugin p = {
 	.description	= "Perfom Discrete Fourier Transforms with variable number of harmonics on the FPGA",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "acs.eonerc.rwth-aachen.de", "hls", "hls_dft", NULL },
-		.init = dft_init,
+		.vlnv	= { "acs.eonerc.rwth-aachen.de", "hls", "hls_dft", NULL },
+		.type	= FPGA_IP_TYPE_MATH,
+		.init	= dft_init,
 		.destroy = dft_destroy,
-		.parse = dft_parse
+		.parse	= dft_parse
 	}
 };
 
diff --git a/lib/fpga/dma.c b/lib/fpga/ips/dma.c
similarity index 89%
rename from lib/fpga/dma.c
rename to lib/fpga/ips/dma.c
index ebfdbadc7..3ca509dab 100644
--- a/lib/fpga/dma.c
+++ b/lib/fpga/ips/dma.c
@@ -17,8 +17,9 @@
 #include "plugin.h"
 #include "utils.h"
 
-#include "fpga/dma.h"
 #include "fpga/ip.h"
+#include "fpga/card.h"
+#include "fpga/ips/dma.h"
 
 int dma_mem_split(struct dma_mem *o, struct dma_mem *a, struct dma_mem *b)
 {
@@ -36,9 +37,11 @@ int dma_mem_split(struct dma_mem *o, struct dma_mem *a, struct dma_mem *b)
 	return 0;
 }
 
-int dma_alloc(struct ip *c, struct dma_mem *mem, size_t len, int flags)
+int dma_alloc(struct fpga_ip *c, struct dma_mem *mem, size_t len, int flags)
 {
 	int ret;
+	
+	struct fpga_card *f = c->card;
 
 	/* Align to next bigger page size chunk */
 	if (len & 0xFFF) {
@@ -52,18 +55,18 @@ int dma_alloc(struct ip *c, struct dma_mem *mem, size_t len, int flags)
 	if (mem->base_virt == MAP_FAILED)
 		return -1;
 
-	ret = vfio_map_dma(c->card->vd.group->container, mem);
+	ret = vfio_map_dma(f->vd.group->container, (uint64_t) mem->base_virt, (uint64_t) mem->base_phys, mem->len);
 	if (ret)
 		return -2;
 
 	return 0;
 }
 
-int dma_free(struct ip *c, struct dma_mem *mem)
+int dma_free(struct fpga_ip *c, struct dma_mem *mem)
 {
 	int ret;
 	
-	ret = vfio_unmap_dma(c->card->vd.group->container, mem);
+	ret = vfio_unmap_dma(c->card->vd.group->container, (uint64_t) mem->base_virt, (uint64_t) mem->base_phys, mem->len);
 	if (ret)
 		return ret;
 	
@@ -74,7 +77,7 @@ int dma_free(struct ip *c, struct dma_mem *mem)
 	return 0;
 }
 
-int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len)
+int dma_ping_pong(struct fpga_ip *c, char *src, char *dst, size_t len)
 {
 	int ret;
 
@@ -97,7 +100,7 @@ int dma_ping_pong(struct ip *c, char *src, char *dst, size_t len)
 	return 0;
 }
 
-int dma_write(struct ip *c, char *buf, size_t len)
+int dma_write(struct fpga_ip *c, char *buf, size_t len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 
@@ -108,7 +111,7 @@ int dma_write(struct ip *c, char *buf, size_t len)
 		: dma_simple_write(c, buf, len);
 }
 
-int dma_read(struct ip *c, char *buf, size_t len)
+int dma_read(struct fpga_ip *c, char *buf, size_t len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	
@@ -119,7 +122,7 @@ int dma_read(struct ip *c, char *buf, size_t len)
 		: dma_simple_read(c, buf, len);
 }
 
-int dma_read_complete(struct ip *c, char **buf, size_t *len)
+int dma_read_complete(struct fpga_ip *c, char **buf, size_t *len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	
@@ -130,7 +133,7 @@ int dma_read_complete(struct ip *c, char **buf, size_t *len)
 		: dma_simple_read_complete(c, buf, len);
 }
 
-int dma_write_complete(struct ip *c, char **buf, size_t *len)
+int dma_write_complete(struct fpga_ip *c, char **buf, size_t *len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	
@@ -141,7 +144,7 @@ int dma_write_complete(struct ip *c, char **buf, size_t *len)
 		: dma_simple_write_complete(c, buf, len);
 }
 
-int dma_sg_write(struct ip *c, char *buf, size_t len)
+int dma_sg_write(struct fpga_ip *c, char *buf, size_t len)
 {
 	int ret, bdcnt;
 
@@ -216,7 +219,7 @@ out:
 	return -5;
 }
 
-int dma_sg_read(struct ip *c, char *buf, size_t len)
+int dma_sg_read(struct fpga_ip *c, char *buf, size_t len)
 {
 	int ret, bdcnt;
 
@@ -284,7 +287,7 @@ out:
 	return -5;
 }
 
-int dma_sg_write_complete(struct ip *c, char **buf, size_t *len)
+int dma_sg_write_complete(struct fpga_ip *c, char **buf, size_t *len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
@@ -313,7 +316,7 @@ int dma_sg_write_complete(struct ip *c, char **buf, size_t *len)
 	return 0;
 }
 
-int dma_sg_read_complete(struct ip *c, char **buf, size_t *len)
+int dma_sg_read_complete(struct fpga_ip *c, char **buf, size_t *len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
@@ -365,7 +368,7 @@ int dma_sg_read_complete(struct ip *c, char **buf, size_t *len)
 	return 0;
 }
 
-int dma_simple_read(struct ip *c, char *buf, size_t len)
+int dma_simple_read(struct fpga_ip *c, char *buf, size_t len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
@@ -401,7 +404,7 @@ int dma_simple_read(struct ip *c, char *buf, size_t len)
 	return XST_SUCCESS;
 }
 
-int dma_simple_write(struct ip *c, char *buf, size_t len)
+int dma_simple_write(struct fpga_ip *c, char *buf, size_t len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
@@ -438,7 +441,7 @@ int dma_simple_write(struct ip *c, char *buf, size_t len)
 	return XST_SUCCESS;
 }
 
-int dma_simple_read_complete(struct ip *c, char **buf, size_t *len)
+int dma_simple_read_complete(struct fpga_ip *c, char **buf, size_t *len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	XAxiDma_BdRing *ring = XAxiDma_GetRxRing(xdma);
@@ -459,7 +462,7 @@ int dma_simple_read_complete(struct ip *c, char **buf, size_t *len)
 	return 0;
 }
 
-int dma_simple_write_complete(struct ip *c, char **buf, size_t *len)
+int dma_simple_write_complete(struct fpga_ip *c, char **buf, size_t *len)
 {
 	XAxiDma *xdma = &c->dma.inst;
 	XAxiDma_BdRing *ring = XAxiDma_GetTxRing(xdma);
@@ -535,7 +538,7 @@ static int dma_init_rings(XAxiDma *xdma, struct dma_mem *bd)
 	return 0;
 }
 
-int dma_init(struct ip *c)
+int dma_init(struct fpga_ip *c)
 {
 	int ret, sg;
 	struct dma *dma = &c->dma;
@@ -590,7 +593,7 @@ int dma_init(struct ip *c)
 	return 0;
 }
 
-int dma_reset(struct ip *c)
+int dma_reset(struct fpga_ip *c)
 {
 	XAxiDma_Reset(&c->dma.inst);
 
@@ -602,9 +605,10 @@ static struct plugin p = {
 	.description	= "Transfer data streams between VILLASnode and VILLASfpga",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "xilinx.com", "ip", "axi_dma", NULL },
-		.init = dma_init,
-		.reset = dma_reset
+		.vlnv	= { "xilinx.com", "ip", "axi_dma", NULL },
+		.type	= FPGA_IP_TYPE_DATAMOVER,
+		.init	= dma_init,
+		.reset	= dma_reset
 	}
 };
 
diff --git a/lib/fpga/fifo.c b/lib/fpga/ips/fifo.c
similarity index 78%
rename from lib/fpga/fifo.c
rename to lib/fpga/ips/fifo.c
index fab633588..d912b60e6 100644
--- a/lib/fpga/fifo.c
+++ b/lib/fpga/ips/fifo.c
@@ -14,18 +14,20 @@
 #include "plugin.h"
 
 #include "fpga/ip.h"
-#include "fpga/fifo.h"
-#include "fpga/intc.h"
+#include "fpga/card.h"
+#include "fpga/ips/fifo.h"
+#include "fpga/ips/intc.h"
 
-int fifo_init(struct ip *c)
+int fifo_init(struct fpga_ip *c)
 {
-	struct fifo *fifo = &c->fifo;
-	XLlFifo *xfifo = &fifo->inst;
-
 	int ret;
 
+	struct fpga_card *f = c->card;
+	struct fifo *fifo = &c->fifo;
+	
+	XLlFifo *xfifo = &fifo->inst;
 	XLlFifo_Config fifo_cfg = {
-		.BaseAddress = (uintptr_t) c->card->map + c->baseaddr,
+		.BaseAddress = (uintptr_t) f->map + c->baseaddr,
 		.Axi4BaseAddress = (uintptr_t) c->card->map + fifo->baseaddr_axi4,
 		.Datainterface = (fifo->baseaddr_axi4 != -1) ? 1 : 0 /* use AXI4 for Data, AXI4-Lite for control */
 	};
@@ -39,7 +41,7 @@ int fifo_init(struct ip *c)
 	return 0;
 }
 
-ssize_t fifo_write(struct ip *c, char *buf, size_t len)
+ssize_t fifo_write(struct fpga_ip *c, char *buf, size_t len)
 {
 	XLlFifo *fifo = &c->fifo.inst;
 	uint32_t tdfv;
@@ -54,7 +56,7 @@ ssize_t fifo_write(struct ip *c, char *buf, size_t len)
 	return len;
 }
 
-ssize_t fifo_read(struct ip *c, char *buf, size_t len)
+ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len)
 {
 	XLlFifo *fifo = &c->fifo.inst;
 
@@ -75,7 +77,7 @@ ssize_t fifo_read(struct ip *c, char *buf, size_t len)
 	return nextlen;
 }
 
-int fifo_parse(struct ip *c)
+int fifo_parse(struct fpga_ip *c)
 {
 	struct fifo *fifo = &c->fifo;
 
@@ -89,7 +91,7 @@ int fifo_parse(struct ip *c)
 	return 0;
 }
 
-int fifo_reset(struct ip *c)
+int fifo_reset(struct fpga_ip *c)
 {
 	XLlFifo_Reset(&c->fifo.inst);
 
@@ -101,10 +103,11 @@ static struct plugin p = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "xilinx.com", "ip", "axi_fifo_mm_s", NULL },
-		.init = fifo_init,
-		.parse = fifo_parse,
-		.reset = fifo_reset
+		.vlnv	= { "xilinx.com", "ip", "axi_fifo_mm_s", NULL },
+		.type	= FPGA_IP_TYPE_DATAMOVER,
+		.init	= fifo_init,
+		.parse	= fifo_parse,
+		.reset	= fifo_reset
 	}
 };
 
diff --git a/lib/fpga/intc.c b/lib/fpga/ips/intc.c
similarity index 86%
rename from lib/fpga/intc.c
rename to lib/fpga/ips/intc.c
index 0e0e32b7d..6c9abf012 100644
--- a/lib/fpga/intc.c
+++ b/lib/fpga/ips/intc.c
@@ -18,13 +18,14 @@
 #include "kernel/kernel.h" 
 
 #include "fpga/ip.h"
-#include "fpga/intc.h"
+#include "fpga/card.h"
+#include "fpga/ips/intc.h"
 
-int intc_init(struct ip *c)
+int intc_init(struct fpga_ip *c)
 {
 	int ret;
 
-	struct fpga *f = c->card;
+	struct fpga_card *f = c->card;
 	struct intc *intc = &c->intc;
 
 	uintptr_t base = (uintptr_t) f->map + c->baseaddr;
@@ -62,18 +63,20 @@ int intc_init(struct ip *c)
 	return 0;
 }
 
-void intc_destroy(struct ip *c)
+int intc_destroy(struct fpga_ip *c)
 {
-	struct fpga *f = c->card;
+	struct fpga_card *f = c->card;
 	struct intc *intc = &c->intc;
 
 	vfio_pci_msi_deinit(&f->vd, intc->efds);
+	
+	return 0;
 }
 
-int intc_enable(struct ip *c, uint32_t mask, int flags)
+int intc_enable(struct fpga_ip *c, uint32_t mask, int flags)
 {
+	struct fpga_card *f = c->card;
 	struct intc *intc = &c->intc;
-	struct fpga *f = c->card;
 
 	uint32_t ier, imr;
 	uintptr_t base = (uintptr_t) f->map + c->baseaddr;
@@ -108,9 +111,9 @@ int intc_enable(struct ip *c, uint32_t mask, int flags)
 	return 0;
 }
 
-int intc_disable(struct ip *c, uint32_t mask)
+int intc_disable(struct fpga_ip *c, uint32_t mask)
 {
-	struct fpga *f = c->card;
+	struct fpga_card *f = c->card;
 
 	uintptr_t base = (uintptr_t) f->map + c->baseaddr;
 	uint32_t ier = XIntc_In32(base + XIN_IER_OFFSET);
@@ -120,10 +123,10 @@ int intc_disable(struct ip *c, uint32_t mask)
 	return 0;
 }
 
-uint64_t intc_wait(struct ip *c, int irq)
+uint64_t intc_wait(struct fpga_ip *c, int irq)
 {
+	struct fpga_card *f = c->card;
 	struct intc *intc = &c->intc;
-	struct fpga *f = c->card;
 
 	uintptr_t base = (uintptr_t) f->map + c->baseaddr;
 
@@ -154,8 +157,9 @@ static struct plugin p = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL },
-		.init = intc_init,
+		.vlnv	= { "acs.eonerc.rwth-aachen.de", "user", "axi_pcie_intc", NULL },
+		.type	= FPGA_IP_TYPE_MISC,
+		.init	= intc_init,
 		.destroy = intc_destroy
 	}
 };
diff --git a/lib/fpga/model.c b/lib/fpga/ips/model.c
similarity index 89%
rename from lib/fpga/model.c
rename to lib/fpga/ips/model.c
index 6c7f8366f..9806cdeb9 100644
--- a/lib/fpga/model.c
+++ b/lib/fpga/ips/model.c
@@ -16,17 +16,22 @@
 #include "plugin.h"
 
 #include "fpga/ip.h"
-#include "fpga/model.h"
+#include "fpga/card.h"
+#include "fpga/ips/model.h"
 
-static void model_param_destroy(struct model_param *p)
+static int model_param_destroy(struct model_param *p)
 {
 	free(p->name);
+
+	return 0;
 }
 
-static void model_info_destroy(struct model_info *i)
+static int model_info_destroy(struct model_info *i)
 {
 	free(i->field);
 	free(i->value);
+	
+	return 0;
 }
 
 static uint32_t model_xsg_map_checksum(uint32_t *map, size_t len)
@@ -130,7 +135,7 @@ static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr)
 	return i;
 }
 
-int model_parse(struct ip *c)
+int model_parse(struct fpga_ip *c)
 {
 	struct model *m = &c->model;
 	struct model_param p;
@@ -188,7 +193,7 @@ static int model_init_from_xsg_map(struct model *m, void *baseaddr)
 	return 0;
 }
 
-int model_init(struct ip *c)
+int model_init(struct fpga_ip *c)
 {
 	int ret;
 	struct model *m = &c->model;
@@ -196,7 +201,7 @@ int model_init(struct ip *c)
 	list_init(&m->parameters);
 	list_init(&m->infos);
 
-	if (ip_vlnv_match(c, NULL, "sysgen", NULL, NULL))
+	if (!fpga_vlnv_cmp(&c->vlnv, &(struct fpga_vlnv) { NULL, "sysgen", NULL, NULL }))
 		ret = model_init_from_xsg_map(m, c->card->map + c->baseaddr);
 	else
 		ret = 0;
@@ -217,7 +222,7 @@ int model_init(struct ip *c)
 	return 0;
 }
 
-void model_destroy(struct ip *c)
+int model_destroy(struct fpga_ip *c)
 {
 	struct model *m = &c->model;
 
@@ -226,9 +231,11 @@ void model_destroy(struct ip *c)
 
 	if (m->xsg.map != NULL)
 		free(m->xsg.map);
+	
+	return 0;
 }
 
-void model_dump(struct ip *c)
+void model_dump(struct fpga_ip *c)
 {
 	struct model *m = &c->model;
 
@@ -264,7 +271,7 @@ void model_dump(struct ip *c)
 
 int model_param_read(struct model_param *p, double *v)
 {
-	struct ip *c = p->ip;
+	struct fpga_ip *c = p->ip;
 
 	union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
 
@@ -290,7 +297,7 @@ int model_param_read(struct model_param *p, double *v)
 
 int model_param_write(struct model_param *p, double v)
 {
-	struct ip *c = p->ip;
+	struct fpga_ip *c = p->ip;
 
 	union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
 
@@ -315,7 +322,7 @@ int model_param_write(struct model_param *p, double v)
 	return 0;
 }
 
-void model_param_add(struct ip *c, const char *name, enum model_param_direction dir, enum model_param_type type)
+void model_param_add(struct fpga_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));
@@ -327,7 +334,7 @@ void model_param_add(struct ip *c, const char *name, enum model_param_direction
 	list_push(&m->parameters, p);
 }
 
-int model_param_remove(struct ip *c, const char *name)
+int model_param_remove(struct fpga_ip *c, const char *name)
 {
 	struct model *m = &c->model;
 	struct model_param *p;
@@ -359,11 +366,12 @@ static struct plugin p_hls = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { NULL, "hls", NULL, NULL },
-		.init = model_init,
+		.vlnv	= { NULL, "hls", NULL, NULL },
+		.type	= FPGA_IP_TYPE_MODEL,
+		.init	= model_init,
 		.destroy = model_destroy,
-		.dump = model_dump,
-		.parse = model_parse
+		.dump	= model_dump,
+		.parse	= model_parse
 	}
 };
 
@@ -374,11 +382,12 @@ static struct plugin p_sysgen = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { NULL, "sysgen", NULL, NULL },
-		.init = model_init,
+		.vlnv	= { NULL, "sysgen", NULL, NULL },
+		.type	= FPGA_IP_TYPE_MODEL,
+		.init	= model_init,
 		.destroy = model_destroy,
-		.dump = model_dump,
-		.parse = model_parse
+		.dump	= model_dump,
+		.parse= model_parse
 	}
 };
 
diff --git a/lib/fpga/rtds_axis.c b/lib/fpga/ips/rtds_axis.c
similarity index 88%
rename from lib/fpga/rtds_axis.c
rename to lib/fpga/ips/rtds_axis.c
index ebb2e1ef6..3bc9372ae 100644
--- a/lib/fpga/rtds_axis.c
+++ b/lib/fpga/ips/rtds_axis.c
@@ -13,9 +13,10 @@
 #include "plugin.h"
 
 #include "fpga/ip.h"
-#include "fpga/rtds_axis.h"
+#include "fpga/card.h"
+#include "fpga/ips/rtds_axis.h"
 
-void rtds_axis_dump(struct ip *c)
+void rtds_axis_dump(struct fpga_ip *c)
 {
 	/* Check RTDS_Axis registers */
 	uint32_t *regs = (uint32_t *) (c->card->map + c->baseaddr);
@@ -42,7 +43,7 @@ void rtds_axis_dump(struct ip *c)
 	}
 }
 
-double rtds_axis_dt(struct ip *c)
+double rtds_axis_dt(struct fpga_ip *c)
 {
 	uint32_t *regs = (uint32_t *) (c->card->map + c->baseaddr);
 	uint16_t dt = regs[RTDS_AXIS_TS_PERIOD_OFFSET/4];
@@ -55,8 +56,9 @@ static struct plugin p = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL },
-		.dump = rtds_axis_dump
+		.vlnv	= { "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL },
+		.type	= FPGA_IP_TYPE_INTERFACE,
+		.dump	= rtds_axis_dump
 	}
 };
 
diff --git a/lib/fpga/switch.c b/lib/fpga/ips/switch.c
similarity index 85%
rename from lib/fpga/switch.c
rename to lib/fpga/ips/switch.c
index 6ba664ccb..a5b1d79ce 100644
--- a/lib/fpga/switch.c
+++ b/lib/fpga/ips/switch.c
@@ -12,14 +12,16 @@
 #include "log.h"
 #include "plugin.h"
 
-#include "fpga/switch.h"
 #include "fpga/ip.h"
+#include "fpga/card.h"
+#include "fpga/ips/switch.h"
 
-int switch_init(struct ip *c)
+int switch_init(struct fpga_ip *c)
 {
 	int ret;
+	
+	struct fpga_card *f = c->card;
 	struct sw *sw = &c->sw;
-	struct fpga *f = c->card;
 
 	XAxis_Switch *xsw = &sw->inst;
 
@@ -29,7 +31,7 @@ int switch_init(struct ip *c)
 
 	/* Setup AXI-stream switch */
 	XAxis_Switch_Config sw_cfg = {
-		.BaseAddress = (uintptr_t) c->card->map + c->baseaddr,
+		.BaseAddress = (uintptr_t) f->map + c->baseaddr,
 		.MaxNumMI = sw->num_ports,
 		.MaxNumSI = sw->num_ports
 	};
@@ -42,11 +44,13 @@ int switch_init(struct ip *c)
 	XAxisScr_RegUpdateDisable(xsw);
 	XAxisScr_MiPortDisableAll(xsw);
 	XAxisScr_RegUpdateEnable(xsw);
+	
+	switch_init_paths(c);
 
 	return 0;
 }
 
-int switch_init_paths(struct ip *c)
+int switch_init_paths(struct fpga_ip *c)
 {
 	int ret;
 	struct sw *sw = &c->sw;
@@ -57,7 +61,7 @@ int switch_init_paths(struct ip *c)
 	XAxisScr_MiPortDisableAll(xsw);
 	
 	list_foreach(struct sw_path *p, &sw->paths) {
-		struct ip *mi, *si;
+		struct fpga_ip *mi, *si;
 		
 		mi = list_lookup(&c->card->ips, p->out);
 		si = list_lookup(&c->card->ips, p->in);
@@ -75,15 +79,18 @@ int switch_init_paths(struct ip *c)
 	return 0;
 }
 
-void switch_destroy(struct ip *c)
+int switch_destroy(struct fpga_ip *c)
 {
 	struct sw *sw = &c->sw;
 
 	list_destroy(&sw->paths, NULL, true);
+	
+	return 0;
 }
 
-int switch_parse(struct ip *c)
+int switch_parse(struct fpga_ip *c)
 {
+	struct fpga_card *f = c->card;
 	struct sw *sw = &c->sw;
 
 	list_init(&sw->paths);
@@ -93,7 +100,7 @@ int switch_parse(struct ip *c)
 	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");
+	cfg_sw = config_setting_get_member(f->cfg, "paths");
 	if (!cfg_sw)
 		return 0; /* no switch config available */
 	
@@ -133,7 +140,7 @@ int switch_parse(struct ip *c)
 	return 0;
 }
 
-int switch_connect(struct ip *c, struct ip *mi, struct ip *si)
+int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
 {
 	struct sw *sw = &c->sw;
 	XAxis_Switch *xsw = &sw->inst;
@@ -169,7 +176,7 @@ int switch_connect(struct ip *c, struct ip *mi, struct ip *si)
 	return 0;
 }
 
-int switch_disconnect(struct ip *c, struct ip *mi, struct ip *si)
+int switch_disconnect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
 {
 	struct sw *sw = &c->sw;
 	XAxis_Switch *xsw = &sw->inst;
@@ -187,10 +194,11 @@ static struct plugin p = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "xilinx.com", "ip", "axis_interconnect", NULL },
-		.init = switch_init,
+		.vlnv	= { "xilinx.com", "ip", "axis_interconnect", NULL },
+		.type	= FPGA_IP_TYPE_MISC,
+		.init	= switch_init,
 		.destroy = switch_destroy,
-		.parse = switch_parse
+		.parse	= switch_parse
 	}
 };
 
diff --git a/lib/fpga/timer.c b/lib/fpga/ips/timer.c
similarity index 82%
rename from lib/fpga/timer.c
rename to lib/fpga/ips/timer.c
index 051eeb6b7..15de04544 100644
--- a/lib/fpga/timer.c
+++ b/lib/fpga/ips/timer.c
@@ -13,12 +13,13 @@
 #include "plugin.h"
 
 #include "fpga/ip.h"
-#include "fpga/timer.h"
+#include "fpga/card.h"
+#include "fpga/ips/timer.h"
 
-int timer_init(struct ip *c)
+int timer_init(struct fpga_ip *c)
 {
+	struct fpga_card *f = c->card;
 	struct timer *tmr = &c->timer;
-	struct fpga *f = c->card;
 
 	XTmrCtr *xtmr = &tmr->inst;
 	XTmrCtr_Config xtmr_cfg = {
@@ -37,8 +38,9 @@ static struct plugin p = {
 	.description	= "",
 	.type		= PLUGIN_TYPE_FPGA_IP,
 	.ip		= {
-		.vlnv = { "xilinx.com", "ip", "axi_timer", NULL },
-		.init = timer_init
+		.vlnv	= { "xilinx.com", "ip", "axi_timer", NULL },
+		.type	= FPGA_IP_TYPE_MISC,
+		.init	= timer_init
 	}
 };
 
diff --git a/lib/fpga/vlnv.c b/lib/fpga/vlnv.c
new file mode 100644
index 000000000..e656fea43
--- /dev/null
+++ b/lib/fpga/vlnv.c
@@ -0,0 +1,45 @@
+/** Vendor, Library, Name, Version (VLNV) tag
+ *
+ * @file
+ * @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
+ * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
+ *   This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
+ *   Unauthorized copying of this file, via any medium is strictly prohibited.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "fpga/vlnv.h"
+
+int fpga_vlnv_cmp(struct fpga_vlnv *a, struct fpga_vlnv *b)
+{
+	return ((!a->vendor  || !b->vendor  || !strcmp(a->vendor,  b->vendor ))	&&
+		(!a->library || !b->library || !strcmp(a->library, b->library))	&&
+		(!a->name    || !b->name    || !strcmp(a->name,    b->name   ))	&&
+		(!a->version || !b->version || !strcmp(a->version, b->version))) ? 0 : 1;
+}
+
+int fpga_vlnv_parse(struct fpga_vlnv *c, const char *vlnv)
+{
+	char *tmp = strdup(vlnv);
+
+	c->vendor  = strdup(strtok(tmp, ":"));
+	c->library = strdup(strtok(NULL, ":"));
+	c->name    = strdup(strtok(NULL, ":"));
+	c->version = strdup(strtok(NULL, ":"));
+	
+	free(tmp);
+
+	return 0;
+}
+
+int fpga_vlnv_destroy(struct fpga_vlnv *v)
+{
+	free(v->vendor);
+	free(v->library);
+	free(v->name);
+	free(v->version);
+	
+	return 0;
+}
diff --git a/lib/nodes/fpga.c b/lib/nodes/fpga.c
index 0c71f3070..7e5487e3e 100644
--- a/lib/nodes/fpga.c
+++ b/lib/nodes/fpga.c
@@ -19,73 +19,38 @@
 #include "timing.h"
 #include "plugin.h"
 
-struct fpga fpga;
-struct pci pci;
-struct vfio_container vc;
+#include "fpga/card.h"
 
-int fpga_reset(struct fpga *f)
-{
-	int ret;
-	char state[4096];
-
-	/* Save current state of PCI configuration space */
-	ret = pread(f->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
-	if (ret != sizeof(state))
-		return -1;
-
-	uint32_t *rst_reg = (uint32_t *) (f->map + f->reset->baseaddr);
-
-	debug(3, "FPGA: reset");
-	rst_reg[0] = 1;
-
-	usleep(100000);
-
-	/* Restore previous state of PCI configuration space */
-	ret = pwrite(f->vd.fd, state, sizeof(state), (off_t) VFIO_PCI_CONFIG_REGION_INDEX << 40);
-	if (ret != sizeof(state))
-		return -1;
-
-	/* After reset the value should be zero again */
-	if (rst_reg[0])
-		return -2;
-
-	return 0;
-}
+static struct list cards;
+static struct pci pci;
+static struct vfio_container vc;
 
 void fpga_dump(struct fpga *f)
 {
+	struct fpga_card *c = f->ip->card;
+	
 	info("VILLASfpga card:");
 	{ INDENT
-		info("Slot: %04x:%02x:%02x.%d", fpga.vd.pdev->slot.domain, fpga.vd.pdev->slot.bus, fpga.vd.pdev->slot.device, fpga.vd.pdev->slot.function);
-		info("Vendor ID: %04x", fpga.vd.pdev->id.vendor);
-		info("Device ID: %04x", fpga.vd.pdev->id.device);
-		info("Class  ID: %04x", fpga.vd.pdev->id.class);
+		info("Slot: %04x:%02x:%02x.%d", c->vd.pdev->slot.domain, c->vd.pdev->slot.bus, c->vd.pdev->slot.device, c->vd.pdev->slot.function);
+		info("Vendor ID: %04x", c->vd.pdev->id.vendor);
+		info("Device ID: %04x", c->vd.pdev->id.device);
+		info("Class  ID: %04x", c->vd.pdev->id.class);
 
-		info("BAR0 mapped at %p", fpga.map);
+		info("BAR0 mapped at %p", c->map);
 
 		info("IP blocks:");
-		list_foreach(struct ip *i, &f->ips) { INDENT
-			ip_dump(i);
+		list_foreach(struct fpga_ip *i, &c->ips) { INDENT
+			fpga_ip_dump(i);
 		}
 	}
 
-	vfio_dump(fpga.vd.group->container);
+	vfio_dump(c->vd.group->container);
 }
 
-struct fpga * fpga_get()
-{
-	return &fpga;
-}
-
-int fpga_parse_card(struct fpga *f, int argc, char * argv[], config_setting_t *cfg)
+int fpga_parse_cards(config_setting_t *cfg)
 {
 	int ret;
-	const char *slot, *id, *err;
-	config_setting_t *cfg_ips, *cfg_slot, *cfg_id, *cfg_fpgas;
-
-	/* Default values */
-	f->filter.id.vendor = FPGA_PCI_VID_XILINX;
-	f->filter.id.device = FPGA_PCI_PID_VFPGA;
+	config_setting_t *cfg_fpgas;
 
 	cfg_fpgas = config_setting_get_member(cfg, "fpgas");
 	if (!cfg_fpgas)
@@ -94,56 +59,16 @@ int fpga_parse_card(struct fpga *f, int argc, char * argv[], config_setting_t *c
 	if (!config_setting_is_group(cfg_fpgas))
 		cerror(cfg_fpgas, "FPGA configuration section must be a group");
 	
-	if (config_setting_length(cfg_fpgas) != 1)
-		cerror(cfg_fpgas, "Currently, only a single FPGA is currently supported.");
-	
-	f->cfg = config_setting_get_elem(cfg_fpgas, 0);
-
-	if (!config_setting_lookup_int(cfg, "affinity", &f->affinity))
-		f->affinity = 0;
-
-	config_setting_lookup_bool(f->cfg, "do_reset", &f->do_reset);
-
-	cfg_slot = config_setting_get_member(f->cfg, "slot");
-	if (cfg_slot) {
-		slot = config_setting_get_string(cfg_slot);
-		if (slot) {
-			ret = pci_dev_parse_slot(&f->filter, slot, &err);
-			if (ret)
-				cerror(cfg_slot, "Failed to parse PCI slot: %s", err);
-		}
-		else
-			cerror(cfg_slot, "PCI slot must be a string");
-	}
-
-	cfg_id = config_setting_get_member(f->cfg, "id");
-	if (cfg_id) {
-		id = config_setting_get_string(cfg_id);
-		if (id) {
-			ret = pci_dev_parse_id(&f->filter, (char*) id, &err);
-			if (ret)
-				cerror(cfg_id, "Failed to parse PCI id: %s", err);
-		}
-		else
-			cerror(cfg_slot, "PCI ID must be a string");
-	}
-	
-	cfg_ips = config_setting_get_member(f->cfg, "ips");
-	if (!cfg_ips)
-		cerror(f->cfg, "FPGA configuration is missing ips section");
-
-	for (int i = 0; i < config_setting_length(cfg_ips); i++) {
-		config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
-
-		struct ip ip = {
-			.card = f
-		};
-	
-		ret = ip_parse(&ip, cfg_ip);
+	for (int i = 0; i < config_setting_length(cfg_fpgas); i++) {
+		config_setting_t *cfg_fpga = config_setting_get_elem(cfg_fpgas, i);
+		
+		struct fpga_card *c = alloc(sizeof(struct fpga_card));
+		
+		ret = fpga_card_parse(c, cfg_fpga);
 		if (ret)
-			cerror(cfg_ip, "Failed to parse VILLASfpga IP core");
-
-		list_push(&f->ips, memdup(&ip, sizeof(ip)));
+			cerror(cfg_fpga, "Failed to parse FPGA card configuration");
+		
+		list_push(&cards, c);
 	}
 
 	return 0;
@@ -152,77 +77,19 @@ int fpga_parse_card(struct fpga *f, int argc, char * argv[], config_setting_t *c
 int fpga_init(int argc, char * argv[], config_setting_t *cfg)
 {
 	int ret;
-	struct fpga *f;
-	struct pci_dev *pdev;
-
-	/* For now we only support a single VILALSfpga card */
-	f = fpga_get();
-	list_init(&f->ips);
-
-	pci_init(&pci);
-	pci_dev_init(&f->filter);
-
-	/* Parse FPGA configuration */
-	ret = fpga_parse_card(f, argc, argv, cfg);
+	
+	ret = pci_init(&pci);
 	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 (!f->reset)
-		error("FPGA is missing a reset controller");
-
-	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");
-
-	f->sw = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axis_interconnect", NULL);
-	if (!f->sw)
-		warn("FPGA is missing an AXI4-Stream switch");
-
-	/* Search for FPGA card */
-	pdev = pci_lookup_device(&pci, &f->filter);
-	if (!pdev)
-		error("Failed to find PCI device");
-
-	/* Get VFIO handles and details */
+		cerror(cfg, "Failed to initialize PCI sub-system");
+	
 	ret = vfio_init(&vc);
 	if (ret)
-		serror("Failed to initialize VFIO");
+		cerror(cfg, "Failed to initiliaze VFIO sub-system");
 
-	/* Attach PCIe card to VFIO container */
-	ret = vfio_pci_attach(&f->vd, &vc, pdev);
+	/* Parse FPGA configuration */
+	ret = fpga_parse_cards(cfg);
 	if (ret)
-		error("Failed to attach VFIO device");
-
-	/* Map PCIe BAR */
-	f->map = vfio_map_region(&f->vd, VFIO_PCI_BAR0_REGION_INDEX);
-	if (f->map == MAP_FAILED)
-		serror("Failed to mmap() BAR0");
-
-	/* Enable memory access and PCI bus mastering for DMA */
-	ret = vfio_pci_enable(&f->vd);
-	if (ret)
-		serror("Failed to enable PCI device");
-	
-	/* Reset system? */
-	if (f->do_reset) {
-		/* Reset / detect PCI device */
-		ret = vfio_pci_reset(&f->vd);
-		if (ret)
-			serror("Failed to reset PCI device");
-
-		ret = fpga_reset(f);
-		if (ret)
-			error("Failed to reset FGPA card");
-	}
-
-	/* Initialize IP cores */
-	list_foreach(struct ip *c, &f->ips) {
-		ret = ip_init(c);
-		if (ret)
-			error("Failed to initalize IP core: %s (%u)", c->name, ret);
-	}
+		cerror(cfg, "Failed to parse VILLASfpga config");
 
 	return 0;
 }
@@ -231,53 +98,78 @@ int fpga_deinit()
 {
 	int ret;
 
-	list_destroy(&fpga.ips, (dtor_cb_t) ip_destroy, true);
+	list_destroy(&cards, (dtor_cb_t) fpga_card_destroy, true);
 	
 	pci_destroy(&pci);
 
 	ret = vfio_destroy(&vc);
 	if (ret)
-		error("Failed to deinitialize VFIO module");
+		error("Failed to deinitialize VFIO sub-system");
+	
+	ret = pci_destroy(&pci);
+	if (ret)
+		error("Failed to deinitialize PCI sub-system");
 
 	return 0;
 }
 
 int fpga_parse(struct node *n, config_setting_t *cfg)
 {
-	struct fpga_dm *d = n->_vd;
+	struct fpga *f = n->_vd;
+	struct fpga_card *card;
+	struct fpga_ip *ip;
 
-	/* There is currently only support for a single FPGA card */
-	d->card = fpga_get();
+	char *cpy, *card_name, *ip_name;
+	const char *dm;
 
-	if (!config_setting_lookup_string(cfg, "datamover", &d->ip_name))
+	if (!config_setting_lookup_string(cfg, "datamover", &dm))
 		cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n));
 
-	if (!config_setting_lookup_bool(cfg, "use_irqs", &d->use_irqs))
-		d->use_irqs = false;
+	if (!config_setting_lookup_bool(cfg, "use_irqs", &f->use_irqs))
+		f->use_irqs = false;
+
+	cpy = strdup(dm); /* strtok can not operate on type const char * */
+	
+	card_name = strtok(cpy, ":");
+	ip_name = strtok(NULL, ":");
+
+	card = list_lookup(&cards, card_name);
+	if (!card)
+		cerror(cfg, "There is no FPGA card named '%s", card_name);
+	
+	ip = list_lookup(&card->ips, ip_name);
+	if (!ip)
+		cerror(cfg, "There is no datamover named '%s' on the FPGA card '%s'", ip_name, card_name);
+	if (!ip->_vt->type != FPGA_IP_TYPE_DATAMOVER)
+		cerror(cfg, "The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name);
+
+	free(cpy);
+	
+	f->ip = ip;
 
 	return 0;
 }
 
 char * fpga_print(struct node *n)
 {
-	struct fpga_dm *d = n->_vd;
-	struct fpga *f = d->card;
+	struct fpga *f = n->_vd;
+	struct fpga_card *c = f->ip->card;
 	
-	if (d->ip)
+	if (f->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.slot.bus, f->filter.slot.device, f->filter.slot.function,
-			f->filter.id.vendor, f->filter.id.device);
+			f->ip->name, f->ip->vlnv.vendor, f->ip->vlnv.library, f->ip->vlnv.name, f->ip->vlnv.version,
+			f->ip->baseaddr, f->ip->port,
+			c->filter.slot.bus, c->filter.slot.device, c->filter.slot.function,
+			c->filter.id.vendor, c->filter.id.device);
 	else
-		return strf("dm=%s", d->ip_name);
+		return strf("dm=%s", f->ip->name);
 }
 
-int fpga_get_type(struct ip *c)
+int fpga_get_type(struct fpga_ip *c)
 {
-	if      (ip_vlnv_match(c, "xilinx.com", "ip", "axi_dma", NULL))
+	if      (!fpga_vlnv_cmp(&c->vlnv, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_dma", NULL }))
 		return FPGA_DM_DMA;
-	else if (ip_vlnv_match(c, "xilinx.com", "ip", "axi_fifo_mm_s", NULL))
+	else if (!fpga_vlnv_cmp(&c->vlnv, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_fifo_mm_s", NULL }))
 		return FPGA_DM_FIFO;
 	else
 		return -1;
@@ -287,36 +179,28 @@ int fpga_open(struct node *n)
 {
 	int ret;
 
-	struct fpga_dm *d = n->_vd;
-	struct fpga *f = d->card;
+	struct fpga *f = n->_vd;
+	struct fpga_card *c = f->ip->card;
 
-	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_init_paths(f->sw);
+	fpga_card_init(c, &pci, &vc);
 
 	int flags = 0;
-	if (!d->use_irqs)
+	if (!f->use_irqs)
 		flags |= INTC_POLLING;
 
-	switch (d->type) {
+	switch (f->type) {
 		case FPGA_DM_DMA:
 			/* Map DMA accessible memory */
-			ret = dma_alloc(d->ip, &d->dma, 0x1000, 0);
+			ret = dma_alloc(f->ip, &f->dma, 0x1000, 0);
 			if (ret)
 				return ret;
 
-			intc_enable(f->intc, (1 << (d->ip->irq    )), flags); /* MM2S */
-			intc_enable(f->intc, (1 << (d->ip->irq + 1)), flags); /* S2MM */
+			intc_enable(c->intc, (1 << (f->ip->irq    )), flags); /* MM2S */
+			intc_enable(c->intc, (1 << (f->ip->irq + 1)), flags); /* S2MM */
 			break;
 
 		case FPGA_DM_FIFO:
-			intc_enable(f->intc, (1 << d->ip->irq),      flags);	/* MM2S & S2MM */
+			intc_enable(c->intc, (1 << f->ip->irq),      flags);	/* MM2S & S2MM */
 			break;
 	}
 	
@@ -328,21 +212,21 @@ int fpga_close(struct node *n)
 {
 	int ret;
 
-	struct fpga_dm *d = n->_vd;
-	struct fpga *f = d->card;
+	struct fpga *f = n->_vd;
+	struct fpga_card *c = f->ip->card;
 
-	switch (d->type) {
+	switch (f->type) {
 		case FPGA_DM_DMA:
-			intc_disable(f->intc, d->ip->irq);	/* MM2S */
-			intc_disable(f->intc, d->ip->irq + 1);	/* S2MM */
+			intc_disable(c->intc, f->ip->irq);	/* MM2S */
+			intc_disable(c->intc, f->ip->irq + 1);	/* S2MM */
 
-			ret = dma_free(d->ip, &d->dma);
+			ret = dma_free(f->ip, &f->dma);
 			if (ret)
 				return ret;
 
 		case FPGA_DM_FIFO:
-			if (d->use_irqs)
-				intc_disable(f->intc, d->ip->irq);	/* MM2S & S2MM */
+			if (f->use_irqs)
+				intc_disable(c->intc, f->ip->irq);	/* MM2S & S2MM */
 	}
 
 	return 0;
@@ -352,7 +236,7 @@ int fpga_read(struct node *n, struct sample *smps[], unsigned cnt)
 {
 	int ret;
 
-	struct fpga_dm *d = n->_vd;
+	struct fpga *f = n->_vd;
 	struct sample *smp = smps[0];
 
 	size_t recvlen;
@@ -364,22 +248,22 @@ int fpga_read(struct node *n, struct sample *smps[], unsigned cnt)
 	smp->ts.origin = time_now();
 
 	/* Read data from RTDS */
-	switch (d->type) {
+	switch (f->type) {
 		case FPGA_DM_DMA:
-			ret = dma_read(d->ip, d->dma.base_phys + 0x800, len);
+			ret = dma_read(f->ip, f->dma.base_phys + 0x800, len);
 			if (ret)
 				return ret;
 			
-			ret = dma_read_complete(d->ip, NULL, &recvlen);
+			ret = dma_read_complete(f->ip, NULL, &recvlen);
 			if (ret)
 				return ret;
 
-			memcpy(smp->data, d->dma.base_virt + 0x800, recvlen);
+			memcpy(smp->data, f->dma.base_virt + 0x800, recvlen);
 
 			smp->length = recvlen / 4;
 			return 1;
 		case FPGA_DM_FIFO:
-			recvlen = fifo_read(d->ip, (char *) smp->data, len);
+			recvlen = fifo_read(f->ip, (char *) smp->data, len);
 			
 			smp->length = recvlen / 4;
 			return 1;
@@ -391,29 +275,22 @@ 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 = n->_vd;
 	struct sample *smp = smps[0];
 
 	size_t sentlen;
 	size_t len = smp->length * sizeof(smp->data[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) {
+	switch (f->type) {
 		case FPGA_DM_DMA:
-			memcpy(d->dma.base_virt, smp->data, len);
+			memcpy(f->dma.base_virt, smp->data, len);
 
-			ret = dma_write(d->ip, d->dma.base_phys, len);
+			ret = dma_write(f->ip, f->dma.base_phys, len);
 			if (ret)
 				return ret;
 			
-			ret = dma_write_complete(d->ip, NULL, &sentlen);
+			ret = dma_write_complete(f->ip, NULL, &sentlen);
 			if (ret)
 				return ret;
 
@@ -421,7 +298,7 @@ int fpga_write(struct node *n, struct sample *smps[], unsigned cnt)
 
 			return 1;
 		case FPGA_DM_FIFO:
-			sentlen = fifo_write(d->ip, (char *) smp->data, len);
+			sentlen = fifo_write(f->ip, (char *) smp->data, len);
 			return sentlen / sizeof(smp->data[0]);
 			break;
 	}
@@ -434,7 +311,7 @@ static struct plugin p = {
 	.description	= "VILLASfpga PCIe card (libxil)",
 	.type		= PLUGIN_TYPE_NODE,
 	.node		= {
-		.size		= sizeof(struct fpga_dm),
+		.size		= sizeof(struct fpga),
 		.vectorize	= 1,
 		.parse		= fpga_parse,
 		.print		= fpga_print,
diff --git a/src/fpga-bench-overruns.c b/src/fpga-bench-overruns.c
index 73346b5e9..fd2f8a418 100644
--- a/src/fpga-bench-overruns.c
+++ b/src/fpga-bench-overruns.c
@@ -65,7 +65,7 @@ static int lapack_workload(int N, double *A)
 
 int fpga_benchmark_overruns(struct fpga *f)
 {
-	struct ip *rtds, *dm;
+	struct fpga_ip *rtds, *dm;
 
 	dm = list_lookup(&f->ips, "dma_1");
 	rtds = list_lookup(&f->ips, "rtds_axis_0");
diff --git a/src/fpga-bench.c b/src/fpga-bench.c
index 1de87f1f3..7dcb2a45f 100644
--- a/src/fpga-bench.c
+++ b/src/fpga-bench.c
@@ -7,9 +7,7 @@
  **********************************************************************************/
 
 #include <stdio.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 #include <sys/utsname.h>
 
 #include <villas/utils.h>
@@ -87,7 +85,7 @@ int fpga_benchmark_jitter(struct fpga *f)
 {
 	int ret;
 
-	struct ip *tmr;
+	struct fpga_ip *tmr;
 
 	tmr = list_lookup(&f->ips, "timer_0");
 	if (!tmr || !f->intc)
@@ -184,7 +182,7 @@ int fpga_benchmark_datamover(struct fpga *f)
 {
 	int ret;
 
-	struct ip *dm;
+	struct fpga_ip *dm;
 	struct dma_mem mem, src, dst;
 
 #if BENCH_DM == 1
diff --git a/src/fpga-tests.c b/src/fpga-tests.c
index 0a44b569d..cade78278 100644
--- a/src/fpga-tests.c
+++ b/src/fpga-tests.c
@@ -7,11 +7,7 @@
  *********************************************************************************/
 
 #include <stdlib.h>
-#include <stdint.h>
 #include <stdbool.h>
-#include <fcntl.h>
-#include <time.h>
-#include <unistd.h>
 
 #include <xilinx/xtmrctr.h>
 
@@ -96,12 +92,12 @@ int fpga_test_xsg(struct fpga *f)
 	int ret;
 	double factor, err = 0;
 
-	struct ip *xsg, *dma;
+	struct fpga_ip *xsg, *dma;
 	struct model_param *p;
 	struct dma_mem mem;
 
-	xsg = ip_vlnv_lookup(&f->ips, NULL, "sysgen", "xsg_multiply", NULL);
-	dma = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_dma", NULL);
+	xsg = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { NULL, "sysgen", "xsg_multiply", NULL });
+	dma = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_dma", NULL });
 
 	/* Check if required IP is available on FPGA */
 	if (!dma || !xsg || !dma)
@@ -160,10 +156,10 @@ int fpga_test_xsg(struct fpga *f)
 int fpga_test_hls_dft(struct fpga *f)
 {
 	int ret;
-	struct ip *hls, *rtds;
+	struct fpga_ip *hls, *rtds;
 	
-	rtds = ip_vlnv_lookup(&f->ips, "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL);
-	hls = ip_vlnv_lookup(&f->ips, NULL, "hls", "hls_dft", NULL);
+	rtds = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL });
+	hls = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { NULL, "hls", "hls_dft", NULL });
 
 	/* Check if required IP is available on FPGA */
 	if (!hls || !rtds)
@@ -216,9 +212,9 @@ int fpga_test_fifo(struct fpga *f)
 	int ret;
 	ssize_t len;
 	char src[255], dst[255];
-	struct ip *fifo;
+	struct fpga_ip *fifo;
 
-	fifo = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_fifo_mm_s", NULL);
+	fifo = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_fifo_mm_s", NULL });
 	if (!fifo)
 		return -1;
 
@@ -261,8 +257,8 @@ int fpga_test_dma(struct fpga *f)
 	int ret = -1;
 	struct dma_mem mem, src, dst;
 
-	list_foreach(struct ip *dma, &f->ips) { INDENT
-		if (!ip_vlnv_match(dma, "xilinx.com", "ip", "axi_dma", NULL))
+	list_foreach(struct fpga_ip *dma, &f->ips) { INDENT
+		if (!fpga_vlnv_match(dma, "xilinx.com", "ip", "axi_dma", NULL))
 			continue; /* skip non DMA IP cores */
 		
 		/* Simple DMA can only transfer up to 4 kb due to
@@ -321,9 +317,9 @@ int fpga_test_dma(struct fpga *f)
 int fpga_test_timer(struct fpga *f)
 {
 	int ret;
-	struct ip *tmr;
+	struct fpga_ip *tmr;
 
-	tmr = ip_vlnv_lookup(&f->ips, "xilinx.com", "ip", "axi_timer", NULL);
+	tmr = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { "xilinx.com", "ip", "axi_timer", NULL });
 	if (!tmr)
 		return -1;
 	
@@ -355,12 +351,12 @@ int fpga_test_timer(struct fpga *f)
 int fpga_test_rtds_rtt(struct fpga *f)
 {
 	int ret;
-	struct ip *dma, *rtds;
+	struct fpga_ip *dma, *rtds;
 	struct dma_mem buf;
 	size_t recvlen;
 
 	/* Get IP cores */
-	rtds = ip_vlnv_lookup(&f->ips, "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL);
+	rtds = fpga_vlnv_lookup(&f->ips, &(struct fpga_vlnv) { "acs.eonerc.rwth-aachen.de", "user", "rtds_axis", NULL });
 	dma = list_lookup(&f->ips, "dma_1");
 
 	/* Check if required IP is available on FPGA */