"Les systèmes sur une puce ("System on Chip" ou SoC) sont désormais une réalité et leur utilisation se répand, notamment grâce aux technologies reprogrammables (SoPC : System on Programmable Chip) de type FPGA. La réalisation de ces systèmes repose sur une nouvelle approche de conception qui consiste à associer dans un même composant, des coeurs de processeurs exécutant des programmes et des blocs fonctionnels spécifiques appelés IP (Intellectual Property).Avec l'évolution des technologies FPGA, des architectures SoPC reconfigurables (matériel et logiciel) permettent d'améliorer la souplesse d'utilisation et la compacité des systèmes.La conception de ces systèmes mixtes logiciel/matériel (hard/soft) nécessite d'introduire de nouvelles méthodologies, traitant des spécifications soft et des blocs matériels synthétisables, et de la co-vérification. "
Pour ceux qui veulent en savoir plus : Le cours Soc d'Olivier sentieys
Pour réaliser un système sur puce, il faut donc intégrer des IPs . Vous l'avez déjà fait avec l'IP rdm, celui-ci était très simple et très rapide puisqu'il ne prenait q'un seul cycle pour produire une nouveau nombre aléatoire lorsqu'il était sollicité. Pour construire un SoC il est souvent nécessaire d'intégrer des IPs complexes qui réalisent de grosses taches matérielles comme des I/O, crypto, dsp etc... Ces IPs sont soit à développer pour un cas particulier soit à réutiliser depuis des bibliothèques d'IPs open ou "corporate".
Voici un exemple de site d'IP open, on y trouve de tout!
Dans cette philosophie, le processeur HoMade ne fonctionne que si vous lui ajoutez des IPs adaptés à votre algorithme. Ces IPs sont de deux types:
Dans la bibliothèque fournie, il n'existe que 2 IPs long :
Beaucoup de calculs matériels demandent plus d'un cycle pour être réalisés. Dans ce cas avant de passer à l'instruction suivante, il faut à chaque top d'horloge savoir si le calcul est terminé. Seulement alors les résultats produits par l'IP seront positionnés sur les bus de sortie et afin de signaler la fin d'activité à l'unité de contrôle su processeur HoMade; c'est le signal IPdone qui doit être actif pendant ce cycle uniquement.
Le meilleur moyen pour réaliser cette logique séquentielle consiste à utiliser une FSM. Vous avez manipulé ces FSM en VHDL dans les TPs précédents, cette fois ils seront encapsulés dans un composant respectant l'interface HoMade afin de devenir une nouvelle instruction déclenchable par programme.
Les IP long s'exécutent sur plusieurs cycles processeurs, leur comportement doit être spécifié pour chaque phase de calcul.
Le premier test que je vous propose est l'IP long le plus simple que l'on puisse imaginer. L'ip fibo est déjà instancié dans le master HoMade, il faudra comme pour rdm dé-commenter le code correspondant. Vous remarquerez que la sortie IPdone est utilisée dans un OR avec tous les autres IPdone des IP long... Pour ajouter un autre IP long il faudra respecter cette règle!!! ( en contrôle vous pourrez utiliser le signal de cet IPFibo)
Voici le code à insérer dans votre projet:
Le generic permet d'instancier cet IP avec différents numéros qui seront utilisés par l’instruction IP.(sur les 11 bits du champs de l’instruction, ici le bit S est = à '1' car long). Une valeur par défaut est indispensable pour la simulation..
Tin sera connecté au sommet de la pile d'HoMade en lecture
IPcode reçoit le code de l'IP en cours d'exécution, ce signal est valide un seul cycle!!! (si ce n'est pas une instruction IP le code envoyé est "11111111111", idem pour les cycles suivant pendant l’exécution d'un IP long. Ce code d'IP est bien entendu interdit!!!!
clk et reset sont les deux signaux pour la clock et le reset du processeur HoMade
Tout sera connecté en écriture sur le sommet de la pile
IPdone valide la fin d'exécution de cet IP long , il déclenche l'écriture sur la pile et le passage à instruction suivante.
entity IP_fibo is
generic ( mycode : STD_LOGIC_VECTOR (10 downto 0):= "10000000011");
port (
clk : in STD_LOGIC;
reset : in STD_LOGIC:='0';
Tin : in STD_LOGIC_VECTOR (31 downto 0);
Tout : out STD_LOGIC_VECTOR (31 downto 0);
Ipcode : in STD_LOGIC_VECTOR (10 downto 0);
IPdone : out STD_LOGIC);
end IP_fibo;
architecture dummyfibo of IP_fibo is
signal sel : boolean;
begin
sel <= true when mycode = Ipcode else false;
IPdone <= '1' when sel else '0';
Tout <= x"12345678" when sel else ( others=>'Z');
end dummyfibo;
Placez le code suivant dans masterbench et lancez le simulateur, vous devriez observer le comportement suivant:
constant rom : rom_array := (
-- master code
x"0C00_0000_000C_FFFF", -- 0x0000
x"2001_8C03_8003_c820", -- 0x0004
x"8003_1400_FFFF_FFFF", -- 0x0008
x"1000_0000_0004_1C00", -- 0x000c
x"FFFF_FFFF_FFFF_FFFF", -- 0x0010
-- slave code
x"1c00_ffff_ffff_ffff", -- 0x0000
x"ffff_ffff_ffff_ffff" -- 0x0004
);
Que fait ce programme? Quelle est la différence majeur avec un IP short qui ferait la même chose?
Dans ce TP vous allez construire cette fois un IP long. L'IP rdm était réalisé à partir de circuits combinatoires et son fonctionnement permettait d'obtenir le résultat sur la pile dans le même cycle processeur. Pour réaliser un travail plus long qu'un cycle il vous faut intégrer une FSM qui déclenche à chaque top d’horloge le travail correspondant. Cette FSM assurera également le protocole de synchronisation avec HoMade, en particulier pour le déclenchement de l'IP, le cycle de rangement des résultats sur la pile et la fin d’exécution. Vous allez pouvoir comparer un code qui s"exécute de façon assez traditionnelle sur une ALU avec un code spécialisé qui sollicite un IP matériel. Vous verrez également comment utiliser la réflexivité du processeur HoMade afin d'adapter dynamiquement l'exécution d'un programme entre soft et hard en fonction du contexte.
La version HoMade que vous utilisez intègre des IP de ALU (+ - and or ...) qui permettent les opérations de bases sur des nombres de 32 bits en complément à 2.
Vous allez écrire un code en vhdl qui calcul le Nième nombre de fibonacci pour N>2, N étant rangé sur le sommet de la pile. C'est un IP long car le temps d'exécution dépend de cette valeur de N!!!
Construire fibogen
Vous allez réalisez dans un premier temps un composant matériel qui calcule Fibo indépendamment de son utilisation dans HoMade. Pour cela il vous faut définir une nouvelle source de type vhdl, nommez-là fibogen.
Vous pouvez de suite créer les ports afin d'obtenir cette entity. Ajoutez à la main les attributs sur le signal CLK, cela permet à Vivado de mieux synthétiser les signaux qui véhiculent la clock du FPGA.
entity fibogen is
Port ( clk : in STD_LOGIC;
init : in STD_LOGIC;
fiboout : out STD_LOGIC_VECTOR (31 downto 0));
attribute clock_signal : string;
attribute clock_signal of clk : signal is "yes";
end fibogen;
A vous de spécifier l'architecture de ce composant!! voici quelques indications , l'idée et de faire clculer le prochain fibo à l'infini avec un reset sur les deux premières valeurs quand init ='1'. IP_fibo se chargera de lire la sortie de fibogen au bon moment sous contrôle d'une FSM.
Vérifiez le comportement de fibogen par simulation, voici ce que j'ai obtenu:
En plaçant le symbole set as top sur fibogen.vhd, vous pouvez alors observer ce que Vivado va produire comme RTL schematic à partir du code. La commande RTL ANALYSYS> Schematic vous en donne un premier aperçu. voici ce que le mien a donné..
Ce composant fibogen produit donc a chaque top le nombre suivant dans la suite de fibonacci.... ( après un certains temps le codage sur 32 bits entraîne un overflow!!) Ce composant tourne tout le temps dans le processeur, il faut donc le remettre en début de liste lorsque l'on sollicite l'IP_fibo . Il faudra aussi récupérer la valeur produite au bon moment en fonction de la position recherchée dans la liste ( la valeur en sommet de pile). Il faut pour cela un compteur de cycle et une FSM. Cette FSM est assez semblable à celle du digicode.
Vous avez déjà créé l'IP fibo il y a quelques minutes
Vous allez utiliser le template proposé par Vivado pour construire votre FSM. Il se trouve dans le menu Tools/Language Templates puis sectionnez la machine de Moore. Copier/coller le template dans votre architecture de IP_fibo
Construire l'automate de votre FSM. A partir de cet automate vous pouvez déjà compléter le type state_type, inspirez vous de mon chronogramme....
Je vous propose les étapes suivantes.
Une fois le code complet , lancez une simulation. Vous pouvez soit créer un fichier IP_fibo_tb soit le lancer à la main. Il faut
J'ai ici affiché la 5ième valeur de la liste fibo.
fig65 simulation de IP_fibo
Vous pouvez alors tester cet IP dans HoMade, l'IP a déjà été instancier dans l'exercice 1 quand vous avez dé-commenté dans Hmaster et dans IPcode les zones associées à fibo. Voici un programme simple à tester avec master_tb qui empile le fibo(5) sur le sommet de pile.
constant rom : rom_array := (
-- master code
x"2005_AC03_1C00_FFFF", -- 0x0000
x"FFFF_FFFF_FFFF_FFFF", -- 0x0010
-- slave code
x"1c00_ffff_ffff_ffff", -- 0x0000
x"ffff_ffff_ffff_ffff" -- 0x0004
);
Si le RTL schematic est satisfaisant, vous pouvez générer le .bit. Voici le mien !
Sachant que le code associé à IP_fibo et "100_0000_0011" et qu'il consomme une valeur sur la pile pour en produire une, reconstruisez le code hexa de cette instruction et créez un :IP avec ce code. Vous pouvez copier puis modifier votre programme fibo.fsh afin de remplacer le calcul Soft par le calcul Hard!
Combien de cycle sont nécessaires pour calcul en fonction de N?
Une nouvelle instruction apparaît à partir de la version 2.2. La réflexivité comme concept matériel du processeur HoMade: cette nouvelle instruction est dédiée à la modification de la mémoire de programme. Il est sans doute nécessaire de rappeler que le processeur HoMade fonctionne plutôt suivant une architecture Harvard avec séparation de la mémoire d'instructions et de la mémoire de données. Cette mémoire de données n'existe que si un IP mémoire a été instancié dans la configuration du processeur.
L'instruction WIM va permettre d'écrire dans une mémoire de programme (du maître ou des esclaves) une suite de trois instructions alignées sur un mot de 64 bits de la mémoire. L’instruction WIM doit nécessairement être alignée sur un début de mot en mémoire. Seules les adresses 1&00 à 111111111111&00 sont accessibles par cette intercession. Le champ WIM précise explicitement cette adresse (ou du moins les 12 bits de poids forts de cette adresse). La quatrième instruction du mot de 64 bits n'est pas modifié par le WIM, il convient de l'initialiser soit à RETURN soit à HLT suivant l'usage local au processeur ou SPMD. Dans la mémoire; il faut mieux réserver les emplacements nécessaires pour l'intercession du programme en cours.En aucun cas cette zone de mémoire d'instructions ne pourra être swappée en mémoire secondaire si une implémentation de cache d'instruction devient nécessaire.
Cette instruction machine sera exploitée principalement pour introduire la notion de VIRTUAL_COMPONENT et PARALLEL_COMPONENT au niveau assembleur.
Le WIM (Write in Instruction Memory)
Utilisation avec ses trois arguments sur 48 bits:
Cette instruction modifiera le code à l'adresse IIIIIIIIIIII&00 et y rangera le mot de 64 bits "CODE1_CODE2_CODE3_xxxx". (xxxx ne sont pas modifiés)
Un exemple d’utilisation: la reconfiguration dynamique hard/soft:
WIM CALL AAAA BBBB permettra de construire une indirection dynamique vers un appel de fonction en rangeant CALL AAAA BBBB RETURN sur un mot de 64 bits initialisé à xxxx xxxx xxxx RETURN
WIM IPCODE RETURN NULL permet de changer cet appel de fonction en déclenchement d'IP en rangeant IPCODE RETURN NULL RETURN sur ce même mots mémoire.
On peut aussi produire une fonction "online" dynamiquement:
WIM ADD ROT DUP rangera le code ADD ROT DUP dans la mémoire d'instruction.
Ce sont des entités de calcul dynamiques qui sont associées durant l'exécution soit à des composants logiciels soit des composants matériels. L'association lie le code du composant virtuel avec son code effectif et ce pendant l’exécution d'un composant logiciel dans lequel il est utilisé, en fait il s'agit de l'instruction machine WIM. Le code est donc limité à trois mots de 16 bits. On peut y mettre jusque trois IPs codé sur un mot, des litéraux sur 12 bits, les IPs NULL ou les instructions RETURN et HLT sont automatiquement insérées si le VC est associé à moins de trois IPs. On peut aussi placer un appel à un composant logiciel, lui aussi est codé sur 3 mots via l'instruction CALL. Le temps d’exécution d'un virtual composant est celui du composant associé plus 2 cycles pour le call et return appelant ce composant virtuel. Lors de la déclaration d'un composant virtuel une initialisation des trois instructions à la compilation est possible toujours
Au niveau assembleur on retrouve à un plus haut niveau cette fonctionnalité de Virtual Component. Les VC sont déclarés par le mot clef VC avec leur nom et éventuellement leur valeur initiale. La déclaration d'un VC réserve 4 mots mémoire en début de programme. Dans ces 4 mots on pourra venir y écrire dans les trois premiers, soit trois instructions sur 1 mots soit un call codé sur 3 mots . Le quatrième mot est constant et initialisé à la compilation à return . Lorsque le VC est affecté à une valeur à la compilation on parle d'affectation statique, avec la même syntaxe := si il est affecté lors de l''exécution on parle d'affectation dynamique .
Lors de la référence à un VC dans un programme l'assembleur génère un appel vers l’emplacement mémoire réservé lors de la déclaration. Les règles de visibilités sont les mêmes que pour des mots ou des IPs.
exemple:
VC random // déclaration d'un virtual component
VC random := ? // déclaration d'un VC qui "pointe " vers l'IP ?
VC random := { ? $ff led } // déclaration d'un VC qui pointe vers les triplet << ? literal led >>
VC random
random := ? // dans une partie déclarative il s"agit d'un statique dans du code HoMade il s'agit d'un dynamique
if
random := ? // dynamique sur un Ip
else
random := ?_soft // dynamique sur une fonction générée ici à partir de l'IP
endif
...
random // appel du VC random qui peut appeler soit l'IP ? , soit sa version soft ?_soft en fonction du contexte
En utilisant la notion de VC proposez un code qui permette de choisir entre version soft et hard avec les boutons 0 et 1 et qui utilise la version précédemment sélectionnée lorsque un autre bouton 2, 3 ou 4 est pressé. (I>2)