Introduction
Dans cet article, nous aborderons une introduction au co-design CPU/FPGA en créant une plateforme matérielle sur un FPGA et en développant un système d'exploitation avec PetaLinux, un kit de développement logiciel basé sur Yocto.
Présentation du projet
D'abord, pour saisir l'essence du projet, parlons un peu FPGA. Un FPGA (Field Programmable Gate Array) est un composant électronique composé de plusieurs blocks d'unités logiques (contenant LUT, flip-flop et multiplexer), d'interconnexions programmables, de blocs mémoire et d'interfaces d'entrée-sortie. En personnalisant ces éléments à l'aide d'un bitstream (le fichier binaire du FPGA), il devient possible d'exécuter diverses fonctions logiques de complexité variable. En résumant grossièrement, les FPGA sont similaires à des ASIC, mais ils sacrifient un peu de leurs performances (vitesse de traitement/consommation energetique) pour gagner en flexibilité et reconfigurabilité.
Aujourd'hui, notre mise en œuvre s'appuiera sur des puces SoC/FPGA de la famille zynq, ce sont des composants intégrant à la fois une logique programmable (FPGA) et un système de traitement (CPU) sur la même structure. Ces SoC permettent d'améliorer les performances grâce à une communication rapide (courte distance de transmission), tout en économisant de l'énergie et en diminuant la taille du système. De plus, ils contribuent à réduire les coûts en regroupant diverses fonctionnalités et en simplifiant le développement. Ces SoC sont particulièrement adaptés aux applications comme les systèmes de contrôle en temps réel, qui requièrent des temps de traitement réguliers et prévisibles, l'implémentation de protocoles spécifiques et les systèmes nécessitant du parallélisme.
L'objectif de cet article est de réaliser un exemple simple d'une fonctionnalité matérielle contrôlée par le CPU. J'ai décidé de présenter un chenillard répondant aux critères suivants :
- Fonctionnement sur quatre LED ;
- Une fréquence de clignotement modifiable et contrôlable ;
- Une fonction de réinitialisation (reset) ;
- Des registres accessibles par le système Linux du CPU, permettant de contrôler la fréquence et la réinitialisation.
Passons donc à la réalisation en abordant d'abord la partie matérielle.
Création de la platforme matériel.
Afin de créer la plateforme matérielle, nous utiliserons Vivado, un environnement de développement intégré (IDE) conçu pour les cartes Xilinx (AMD). Cet IDE permet la programmation en langages matériels (principalement Verilog/VHDL), la synthèse, la simulation, l'implémentation (le routage) et la génération du bitstream. Je me sert ici de la version 2022.1.
Après avoir ouvert Vivado, la première étape consiste à créer un projet. Dans mon cas, voici les paramètres du projet :
- Nom : Chenilinux
- Emplacement : /home/leomo/worspace_vivado/
- Type de projet : RTL project
- Sources :
div_horloge.vhd: Ce premier bloc permet de passer d'une horloge système (généralement en MHz) à une échelle perceptible par l'homme, ici, j'ai choisi 100 Hz. Pour passer de 125 MHz (dans mon cas, sur la Zybo Z7-20) à 100 Hz, on a Ff = Fi / D => D = Fi / Ff = 125 x 10^6 / 100 = 125 x 10^4. Cependant, le fait de changer l'état d'une horloge en comptant seulement ses fronts montants revient à diviser par deux. Ainsi, il faudra 125 x 10^4 / 2 fronts montants pour obtenir une horloge de 100 Hz.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Div_horloge is
generic (clk_board : integer := 125_000_000); --fréquence de la clk sys de votre carte
Port (
clk_in : in std_logic;
reset : in std_logic;
clk_out_100hz : out std_logic
);
end Div_horloge;
architecture Behavioral of Div_horloge is
constant N_to_100hz : integer := ((clk_board)/100) /2;
signal count : integer := 0;
signal clk_tmp : std_logic := '0';
begin
process(clk_in, reset)
begin
if reset = '1' then
count <= 0;
clk_tmp <= '0';
elsif rising_edge(clk_in) then
if count = N_to_100hz - 1 then
count <= 0;
clk_tmp <= NOT clk_tmp;
else
count <= count + 1;
end if;
end if;
end process;
clk_out_100hz <= clk_tmp;
end Behavioral;
counter_clock.vhd:Ce deuxième bloc est celui qui va compter les impulsions de notre nouvelle horloge et comparer la valeur de ce compteur à la valeur du registre sur lequel nous écrirons plus tard depuis notre Linux. Lorsque la valeur du compteur est égale à celle du registre, nous enverrons une impulsion au bloc suivant et remettrons le compteur à zéro.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity counter_clock is
port(
clk_in_100hz : in std_logic; -- entrée horloge 100hz
reset : in std_logic; -- entrée reset
count_value : in std_logic_vector(9 downto 0); -- entrée valeur de comptage (donné par le registre du GPIO)
pulse_out : out std_logic -- sortie impulsion
);
end entity;
architecture behavioral of counter_clock is
signal counter : std_logic_vector (9 downto 0) := (others => '0'); -- signal de compteur initialisé à zéro
signal toggle : std_logic := '0'; -- signal de basculement initialisé à zéro
begin
process(clk_in_100hz,reset,count_value) -- liste de sensitivité du process (signaux dont la modification éxécute le process)
begin
if reset = '1' then -- si reset = '1'
counter <= (others => '0'); -- compteur remis à zéro
toggle <= '0'; -- signal de basculement remis à zéro
elsif count_value <= "0000000000" then
toggle <= clk_in_100hz; -- cas particulier ou si count_value=0 alors pulse=clk_in car difficile de faire une impulsion plus brève que notre clk d entrée.
elsif rising_edge(clk_in_100hz) then
counter <= counter + 1; -- à chaque coup d horloge le compteur est incrémenté
if counter = count_value then -- si la valeur de comptage est atteinte
toggle <= '1'; -- début impulsion
counter <= (others => '0'); -- compteur remis à zéro
elsif toggle = '1' then
toggle <='0'; -- fin impulsion (un coup de clock a 100hz)
end if;
end if;
end process;
pulse_out <= toggle; -- on passe par le signal toggle pour modifier la sortie
end architecture;
modulo_4_counter.vhd: Ce code correspond à un compteur simple sur deux bits qui s'incrémente à chaque impulsion. Lorsqu'il y a overflow, le compteur revient à zéro. La valeur du compteur est en permanence transmise au bloc suivant.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity modulo_4_counter is
Port (
pulse_in : in std_logic;
reset : in std_logic;
count_out : out std_logic_vector (1 downto 0)
);
end modulo_4_counter;
architecture Behavioral of modulo_4_counter is
signal count : std_logic_vector(1 downto 0) := "00";
begin
process(pulse_in, reset)
begin
if reset = '1' then
count <= "00";
elsif rising_edge(pulse_in) then
count <= count + 1;
end if;
end process;
count_out <= count;
end Behavioral;
demux_2to4.vhd :Ce dernier bloc est un démultiplexeur qui active l'une des quatre LED en fonction de la valeur reçue du bloc précédent. Il attribue une valeur haute à la LED correspondante, permettant de créer un effet de chenillard en fonction de l'entrée reçue.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity demux_2to4 is
Port (
reset : in std_logic;
sel : in std_logic_vector(1 downto 0);
led : out std_logic_vector(3 downto 0)
);
end demux_2to4;
architecture Behavioral of demux_2to4 is
begin
process(sel,reset)
begin
if reset = '1' then
led <= (others => '0');
else
case sel is
when "00" =>
led(0) <= '1';
led(1) <= '0';
led(2) <= '0';
led(3) <= '0';
when "01" =>
led(0) <= '0';
led(1) <= '1';
led(2) <= '0';
led(3) <= '0';
when "10" =>
led(0) <= '0';
led(1) <= '0';
led(2) <= '1';
led(3) <= '0';
when "11" =>
led(0) <= '0';
led(1) <= '0';
led(2) <= '0';
led(3) <= '1';
when others =>
null; -- Ne devrait jamais arriver
end case;
end if;
end process;
end Behavioral;
- Contraintes :
Port.xdc: Ce fichier correspond au routage des entrées-sorties externes du SoC. En général, les fournisseurs de cartes fournissent des fichiers templates préparés où il ne reste plus qu'à renseigner les noms donnés à nos ports lors du développement. Voici un exemple de configuration des entrées et sorties pour la carte Zybo Z7020, avec l'entrée 'sys_clk' et les sorties 'led' :
##ports.xdc
##Clock signal
set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { sys_clk }]; #IO_L12P_T1_MRCC_35 Sch=sysclk
##LEDs
set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L23P_T3_35 Sch=led[0]
set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L23N_T3_35 Sch=led[1]
set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_0_35 Sch=led[2]
set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L3N_T0_DQS_AD1N_35 Sch=led[3]
- Carte : Zybo Z7-20
Votre projet est maintenant créé. Nous allons utiliser l'outil de diagramme pour générer les interfaces CPU/FPGA et réaliser le routage des source précédent et des IP.
Ouvrez le mode diagramme de Vivado en créant un nouveau schéma bloc et attribuez-lui un nom. Ensuite, cliquez sur le symbole + bleu pour ajouter l'IP "ZYNQ7 Processing System" à votre schéma.
Vivado vous offre la possibilité de router automatiquement les entrées/sorties (I/O) essentielles pour assurer le bon fonctionnement de la carte, ainsi que la mémoire DDR. Pour ce faire, lancez l'option "Run Block Automation".
Après cela, ajoutez l'IP "AXI GPIO" de la même façon que le processing system et double-cliquez dessus afin de configurer son premier canal en sortie avec 4 bits et le second canal en sortie avec 1 bit.
Le choix de 10 bits est effectué pour permettre une variation de temps de 0,01s (100hz) à 10s (0,1hz), avec un pas de 0,01s. Ainsi, il est nécessaire d'avoir au moins 1000 valeurs pour couvrir cette gamme de fréquences. Avec 10 bits, on peut représenter 2^10 = 1024 valeurs, ce qui est suffisant pour couvrir les 1000 valeurs requises. Cela permet d'avoir une résolution suffisante pour régler précisément la fréquence du système.
Complétez maintenant le diagramme en faisant glisser les sources VHDL précédemment importées dans l'espace de travail, en créant les ports 'led' et 'sys_clk', puis en connectant l'ensemble de la manière suivante.
Lancez ensuite l'option "Run Connection Automation" pour créer et router les IP de gestion des bus entre le Processing System et les GPIO, ainsi que les signaux de réinitialisation (ces derniers servent notamment à réinitialiser la partie logique lors du redémarrage du CPU).
Votre GPIO sera connecté au port General Purpose 0 (GP0). Si vous souhaitez ajouter d'autres ports en mode maître ou esclave, vous pouvez le faire en double-cliquant sur l'IP Processing System, puis en accédant à la section PS/PL Configuration. Cependant, puisque nous n'avons besoin que d'un port maître pour ce projet, nous conserverons la configuration par défaut.
Vous pouvez visualiser et modifier l'adresse de votre GPIO dans les fenêtres "Address Editor" et "Address Map" de Vivado. Ces fenêtres vous permettent d'ajuster les adresses de vos composants IP et de mieux comprendre la configuration de votre système.
Ensuite, nous pouvons générer le portmap (routage des IP en langage matériel) correspondant au diagramme en cliquant sur l'icône du diagramme et en sélectionnant "Générer l'HDL Wrapper". Cela permet de créer automatiquement un portmap basé sur les connexions établies dans le diagramme.
N'oubliez pas de modifier votre fichier de contraintes (.xdc) si vous avez changé le nom de vos ports.
Votre plateforme matérielle est maintenant presque terminée. La dernière étape consiste à générer le bitstream. Toutes les étapes du développement (synthèse, implémentation, génération de bitstream) vont se succéder les unes après les autres.
Il n'y a plus qu'a exporter la plateforme ainsi que le bitstream sous forme de fichier .xsa. Pour ce faire, suivez les étapes suivantes : allez dans le menu File sélectionnez Export, puis Export hardware. Assurez-vous de cocher l'option "Inclure le bitstream", puis cliquez sur OK pour valider et terminer l'exportation.
Création de l'os.
PetaLinux est un SDK basé sur Yocto destiné à créer des distributions Linux personnalisées spécifiquement pour les puces Xilinx. Son fonctionnement est similaire à Yocto, mais il inclut des outils et automatisations supplémentaires, offrant un niveau d'abstraction légèrement supérieur pour les utilisateurs de SoC Xilinx. Nous nous servons ici de la version 2022.1.
La première étape pour utiliser Petalinux est de créer un nouveau projet. Pour ce faire, ouvrez un terminal et tapez la commande suivante :
petalinux-create --type project --template zynq --name <project-name>
cd <project-name>
Il faut maintenant configurer Petalinux en utilisant la description matérielle de votre système que vous avez exportez avec vivado. Pour ce faire, utilisez la commande suivante:
petalinux-config --get-hw-description=<path-to-xsa-file>
Après avoir exécuté cette commande, un menu de configuration apparaîtra. Il n'y a rien à changer ici, assurez-vous de sauvegarder avant de quitter.
Un des principaux avantages de PetaLinux est qu'en important le fichier .xsa, il génère automatiquement une configuration de base de la plateforme dans le device tree, que vous pouvez retrouver dans <project_path>/components/plnx_workspace/device-tree/device-tree/pl.dtsi.
/ {
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_gpio_0: gpio@41200000 {
#gpio-cells = <2>;
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a";
gpio-controller ;
reg = <0x41200000 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,all-outputs = <0x1>;
xlnx,all-outputs-2 = <0x1>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0xa>;
xlnx,gpio2-width = <0x1>;
xlnx,interrupt-present = <0x0>;
xlnx,is-dual = <0x1>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
};
};
On voit ici l'interface AMBA-PL (Advanced Microcontroller Bus Architecture - Programmable Logic), utilisée pour les SoC intégrant des processeurs ARM. On y trouve notre GPIO, avec l'adresse de ses registres, leur tailles et leur configurations.
Pour ce projet cette configuration est suffisante car nous allons nous servir de dev/mem et mmap pour écrire dans nos registres, cependant si pour un autre projet vous avez besoin d'un driver spécifique à configurez avec votre platforme matériel, vous pouvez modifiez le fichiez situez dans <project_path>/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi, voici un exemple pour configurer notre GPIO avec le driver uio qui à lui l'avantage par rapport à notre méthode de pouvoir gérez les interrupts.
/include/ "system-conf.dtsi"
&axi_gpio_0 {
compatible = "generic-uio";
interrupt-parent = <&intc>;
interrupts = <0 29 4>;
};
Ajoutons maintenant une application qui sera pré-compilée et intégrée aux commandes de notre système d'exploitation pour contrôler la fréquence de notre système.
dans la racine du projet lancez la commande:
petalinux-create -t apps --template c --name freqled
Cette commande crééra un dossier dans <project_path>/project-spec/meta-user/recipes-apps/ avec un .c et un makefile pour faire une cross-compilation du code, modifiez ce .c par ce code ci:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#define ADDR_REG 0x41200000 // Adresse du registre de fréquence
#define ADDR_RESET 0x41200008 // Adresse du registre de reset
#define REG_RANGE 1000 // Valeur maximale du registre de fréquence
#define s_MAX 10 // période maximale en secondes
#define s_MIN 0.01 // période minimale en secondes
int main(int argc, char *argv[])
{
int fd;
void *map;
volatile unsigned int *reg;
volatile unsigned int *reset;
unsigned int temps_s_100;
float temps_s;
// Ouverture du fichier de device driver
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
perror("open");
return EXIT_FAILURE;
}
// Mappage de l'adresse physique dans l'espace virtuel du processus
map = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, ADDR_REG & ~(getpagesize() - 1));
if (map == MAP_FAILED) {
perror("mmap");
close(fd);
return EXIT_FAILURE;
}
// Accès au registre de fréquence et au registre de reset
reg = (volatile unsigned int *) (map + (ADDR_REG & (getpagesize() - 1)));
reset = (volatile unsigned int *) (map + (ADDR_RESET & (getpagesize() - 1)));
// Vérification du nombre d'arguments
if (argc != 2) {
printf("Usage: %s freq\n", argv[0]);
return EXIT_FAILURE;
}
// Conversion de la fréquence en argument en entier non signé
temps_s = atof(argv[1]);
if (freq_f > s_MAX || freq_f < s_MIN) {
printf("value must be between %f s and %d s\n", s_MIN, s_MAX);
return EXIT_FAILURE;
}
temps_s_100 = temps_s*100;
*reset = 1;
*reg = temps_s_100;
*reset = 0;
// Fermeture du fichier de device driver et libération de la mémoire mappée
close(fd);
munmap(map, getpagesize());
return EXIT_SUCCESS;
}
Ce code permet de modifier la fréquence de clignotement de 0,1 à 100hz via la période avec un pas de 0,01s en rentrant la valeur souhaité (en seconde) en argument. On se sert de /dev/mem
et mmap
() pour accéder et manipuler directement les adresses mémoire des registre de notre FPGA.
Au cours de la réalisation de ce projet, j'ai utilisé deux paquets pour développer et déboguer mon système. Bien que l'ajout de l'application rende leur utilisation directe moins nécessaire, il est toujours intéressant de les avoir à portée de main. BusyBox est une collection d'outils légers, incluant la commande devmem qui permet d'écrire directement sur la mémoire en ligne de commande et build-essential est nécessaire pour développer et compiler du code C et utiliser Make. Pour les inclure, procédez comme suit :
petalinux-config -c rootfs
Cela ouvrira un menu de configuration pour votre système de fichiers racine. Vous pouvez ajouter des packages en naviguant dans les différentes catégories. Pour ajouter les packages build-essential et busybox, vous pouvez naviguer comme suit :
Filesystem Packages>misc>packagegroupe-core-buildessential
Filesystem Packages>base>busybox
On en profite pour ajouter notre application freqled à la liste des packets en naviguant vers :
apps>freqled
Assurez-vous de sauvegarder et de quitter après avoir terminé.
Maintenant que vous avez terminé de configurer votre projet, vous pouvez le construire en utilisant la commande suivante :
Petalinux-build
Les fichiers d'images généré ce trouve dans <project_path>/images/linux
Nous allons générer un BOOT.bin qui comprendra:
- Le FSBL qui est responsable de la configuration initiale du système et de l'amorçage du processeur.
- Le bitstream du FPGA pour programmer notre platfome matériel.
- U-Boot qui est le bootloader du système qui charge le système d'exploitation.
petalinux-package --boot --fsbl zynq_fsbl.elf --fpga system.bit --u-boot u-boot.elf
Notre image est maintenant prête. Prenez une carte SD formatée en FAT32, copiez-y les fichiers BOOT.bin, boot.src et image.ub, puis insérez-la dans votre carte.Le fichier boot.scr est un script de démarrage contenant les commandes nécessaires pour lancer le système d'exploitation sur la carte cible. Quant au fichier image.ub, il s'agit d'un fichier contenant le noyau Linux et les fichiers root.
Test sur la cible
Assurez-vous que le cavalier est correctement positionné sur la configuration carte SD. Connectez votre ordinateur à la carte via USB et ouvrez une connexion série avec le terminal de votre choix, tel que gtkterm, en utilisant les paramètres suivants :
- Baud Rate : 115200
- Parity : none
- Bits : 8
- Stopbits : 1
- Flow control : none
Mettez sous tension votre carte, et vous devriez voir l’os démarrer sur le terminal.
Une fois le boot fini connectez vous à la sessions “petalinux” et rentrez le mot de passe de votre choix.
Vous pouvez aussi brancher un cable ethernet et vous connectez en SSH sur votre carte.
Passez en mode sudo, puis lancer la commande ledfreq en choisissant la période souhaitée entre 10 et 0,01 secondes.
ledfreq 1.84
Vous pouvez choisir d'importer freqled.c en SSH ou sur la carte SD ou créer vous même votre code,et faire vos test et compilation sur la carte.
Vous pouvez aussi écrire et lire directement sur vos registre avec la commande devmem:
devmem 0x41200008 w 0x1
devmem 0x41200008
devmem 0x41200000 w 0x1F4
devmem 0x41200000
devmem 0x41200008 w 0x0
Suite.
Dans cet article, nous avons exploré le potentiel du co-design CPU/FPGA en utilisant un exemple simple de chenillard. Cela ouvre la voie à la réalisation de projets plus complexes, on peut par exemple imaginer de :
-
Concevoir un système capable de prétraiter des images en temps réel sur le FPGA et de les traiter avec des algorithmes de reconnaissance sur le CPU.
-
Mettre en œuvre des systèmes de communication basés sur un protocole spécifique, dont les couches matérielles et logicielles sont gérées par le FPGA et un traitement des données et ressources par le CPU.
-
Concevoir des systèmes de contrôle pour piloter des moteurs, des robots ou d'autres dispositifs mécaniques. Le CPU pourrait être utilisé pour exécuter des algorithmes de contrôle, tandis que le FPGA pourrait être utilisé pour générer les signaux de commande et communiquer avec les actionneurs/capteurs.
-
Mettre en œuvre un système de traitement du signal audio ou vidéo. Développer des algorithmes de traitement du signal pour filtrer, compresser ou encoder des signaux audio/vidéo sur le CPU, en tirant parti des capacités parallèles du FPGA pour accélérer les performances.
-
Implémenter des algorithmes de chiffrement et de signature numérique sur le FPGA, tout en utilisant le CPU pour gérer les protocoles de communication sécurisés et les opérations d'authentification.
-
Et bien d'autres...
Place de l'open source dans les FPGA.
Comme vous avez pu le constater, bien que PetaLinux soit basé sur Yocto, cet article n'a pas abordé l'utilisation de logiciels open-source. Il existe pourtant de nombreux logiciels open-source qui peuvent être utilisés à différentes étapes du développement des FPGA. Par exemple, GHDL et Icarus Verilog pour la synthèse et la simulation de code HDL, ou encore cocotb pour réaliser des bancs d'essai en Python, et bien d'autres.
Cependant, l'une des principales limites de l'open-source pour disposer d'un framework complet est l'accès à l'architecture des puces elle-même pour pouvoir compiler un bitstream, ce qui rebute de nombreux ingénieurs car un IDE propriétaire (tel que Vivado, Quartus, etc.) est dans ce cas toujours nécessaire pour compiler le bitstream. Toutefois, depuis quelques années, cette contrainte n'est plus une réalité car F4PGA, à travers la CHIPS Alliance, a réussi à documenter et créer un compilateur pour différentes puces provenant de différents fabricants (Xilinx 7-Series, Lattice iCE40, Lattice ECP5 FPGAs, QuickLogic EOS S3) et continue de développer les cibles et les fonctionnalités de leurs outils open-source.
La présence des FPGA dans l'open-source se manifeste également au niveau des IP. Par exemple, des sites tels que https://opencores.org/ qui répertorient des listes d'IP open-source. On peut aussi parler de l'émergence de technologies matérielles open-source, comme RISC-V, qui met en avant l'importance des FPGA en tant qu'outils de développement et d'implémentation. En effet, RISC-V offre la possibilité d'avoir un CPU personnalisé pour des applications spécifiques qui n'est possible avec aucun autre processeurs dont l'archictecture est propriétaire.
Les FPGA contribuent et profitent ainsi de l'émergence de l'open-source dans l'hardware, et cette émergence n'a jamais atteint un niveau aussi élevé qu'à l'heure actuelle.