Comment les instructions Verilog sont-elles «toujours» implémentées dans le matériel?

8

La alwaysdéclaration Verilog , à savoir

always @(/* condition */)
    /* block of code */

exécute le block of codechaque fois qu'il conditionest satisfait. Comment un tel alwaysbloc est-il implémenté dans le matériel?

Randomblue
la source
Je pense que cela dépend fortement de ce que block of codec'est ..
m.Alin
1
Et si la condition est posedge xou simplementx
Justin
@Justin: Supposons qu'il n'y en ait pas posedge.
Randomblue

Réponses:

16

Tout d'abord, notez que tous les modèles Verilog ne sont pas synthétisables. Habituellement, seul un sous-ensemble très spécifique de constructions peut être utilisé dans une conception qui doit être réalisée dans le matériel.

Une restriction importante qui apparaît est que chaque regvariable ne peut être affectée qu'à au plus une alwaysinstruction. En d'autres termes, les regs ont une affinité avec les alwaysblocs.

Les types de alwaysblocs suivants peuvent généralement être utilisés.

always @(*) begin
    // combinational
end

always @(posedge clk) begin
    // sequential
end

Dans le premier cas, le *indique que le bloc doit être exécuté chaque fois qu'un signal utilisé dans le bloc change ou, de manière équivalente, que le bloc doit être exécuté en continu. Par conséquent, les regs qui ont une affinité pour les alwaysblocs combinatoires sont implémentés en tant que signaux calculés à partir d'autres signaux en utilisant une logique combinatoire, c'est-à-dire des portes.

Les registres qui ont une affinité avec des alwaysblocs de ce dernier type, en revanche, sont des sorties de bascules D qui sont cadencées sur le front montant de clk(front descendant si negedgeutilisé). Les entrées des bascules sont, encore une fois, calculées avec une logique combinatoire à partir d'autres signaux.

Prenons l'exemple suivant, quelque peu artificiel.

reg out, out_n;
always @(*) begin
    out_n = !out;
end
always @(posedge clk) begin
    out <= !out;
end

Ici, out_nest associé au premier alwaysbloc, outau second. out_nsera implémenté avec une seule porte NOT qui pilotera out_net sera pilotée out(notez qu'il s'agit d'une pure logique combinatoire). D'autre part, outsera entraîné par une bascule cadencée à partir de clk. L'entrée de la bascule sera à nouveau calculée par une porte NON à partir de out(qui est entraînée par la bascule susmentionnée). L'optimisation des synthétiseurs combinera les deux portes NOT et utilisera une porte NOT et une bascule.

Selon le matériel dont vous disposez, d'autres types de constructions peuvent être utilisés. Par exemple, si les bascules ont des réinitialisations asynchrones, la construction suivante est également synthétisable.

always @(posedge clk or posedge rst) begin
    if (rst)
        // reset
    else
        // sequential
end
avakar
la source
Merci. Concernant le *, j'ai pensé qu'il indiquait que le bloc devait être exécuté chaque fois qu'un signal dans le bloc change (par opposition à la conception ).
Randomblue
@Randomblue, vous avez raison, je vais corriger la réponse. Notez, cependant, que les deux ont un comportement équivalent.
avakar
Vrai; C'est suffisant!
Randomblue
2

Un alwaysbloc est couramment utilisé pour décrire une bascule, un verrou ou un multiplexeur. Le code serait implémenté avec une bascule, un verrou ou un multiplexeur.

Dans un FPGA, une bascule et un verrou ne sont généralement que deux configurations différentes d'un dispositif de registre à usage plus général. Un multiplexeur serait construit à partir d'un ou plusieurs éléments logiques à usage général (LUT).

En général, il y a deux façons de concevoir avec Verilog:

  1. Visualisez la logique que vous souhaitez en termes de portes et de registres, puis découvrez comment la décrire dans Verilog. Les guides de synthèse des fournisseurs de FPGA ou des fournisseurs d'outils de synthèse donnent une plaque chauffante pour les structures les plus courantes avec lesquelles vous pourriez vouloir travailler.

  2. Écrivez simplement Verilog et ne vous inquiétez pas de l'apparence du matériel sous-jacent. Cependant, même si vous faites cela, vous devez toujours savoir ce qui est et ce qui n'est pas synthétisable. Encore une fois, vous vous tournerez vers le passe-partout fourni par votre fournisseur d'outils et l'adapterez à votre application.

ÉDITER

La réponse d'Avakar est bien meilleure pour votre question, mais cela a suscité une discussion intéressante sur les différences entre Xilinx et Altera, donc je ne vais pas la supprimer.

Le photon
la source
"La bascule et le verrou ne sont généralement que deux configurations différentes". Je m'attendrais à ce que les verrous soient implémentés avec des LUT (avec soin si les LUT ne sont pas sans problème).
avakar
@avakar, je sais que dans tous les FPGA Xilinx (ou du moins dans tous les modèles récents à distance), les verrous utilisent le même matériel qu'une bascule, ne différant que d'un seul bit dans le flux binaire de configuration. Je ne suis pas sûr des autres marques.
Kevin Cathcart
Hmm. Certaines anciennes conceptions d'Altera avaient des chemins de rétroaction qui permettraient d'utiliser la LUT pour implémenter des verrous. Il semble presque que le routage principal pourrait être nécessaire pour implémenter des verrous dans les nouvelles conceptions. Ce n'est pas surprenant cependant, car dans la conception RTL moderne, les verrous réels (plutôt que les bascules) sont rarement souhaités.
Kevin Cathcart
@avakar, je connais mieux Xilinx, où le dispositif d'enregistrement peut être configuré comme une bascule ou un verrou. Si ce n'est pas possible chez Altera ou chez un autre fournisseur, cela rendrait encore plus général le conseil «ne pas concevoir avec des verrous».
The Photon
@KevinCathcart et Photon: Je vois, je ne connais pas Xilinx, seulement avec la série Altera Cyclone, qui n'a pas de circuit de verrouillage dédié.
avakar
0

Comme cela a été dit, tous les blocs ne sont pas toujours synthétisables. Il y a aussi quelques blocs que les outils de synthèse accepteront mais qui produiront des résultats différents de ce que produira un simulateur.

Tout d'abord, la liste de sensibilité. La règle habituelle est qu'il ne doit contenir que des constructions de détection de bord (et il y a généralement une sélection limitée de combinaisons possibles) ou qu'il doit contenir (peut-être en utilisant * ou toujours_comb de systemverilog) chaque signal utilisé comme entrée pour le bloc. Nous appelons le premier un bloc combinatoire et le second un bloc séquentiel ou. En règle générale, si vous n'incluez qu'un sous-ensemble d'entrées dans un bloc de combinaison, les outils de synthèse vous ignoreront et agiront comme si la liste complète avait été spécifiée (création de disparités de simulation / synthèse)

Deuxièmes affectations de blocage contre noblocage. Dans un bloc combinatoire, la différence n'a pas beaucoup d'importance, mais dans un bloc séquentiel, elle importe beaucoup.

Dans un bloc séquentiel, les affectations non bloquantes modélisent un registre assez directement tout en bloquant les variables du modèle d'affectations (qui peuvent impliquer ou non des registres selon l'ordre de définition et de lecture). En règle générale, un ensemble "reg" utilisant des assignations de blocage dans un bloc séquentiel ne doit être lu que dans le même bloc et les assignations bloquantes et non bloquantes ne doivent pas être mélangées sur le même "reg".

Le mélange des affectations bloquantes et non bloquantes au même élément est susceptible de provoquer des échecs de synthèse. Faire une évaluation de blocage dans un bloc et la lire dans un autre est susceptible d'entraîner des décalages de simulation / synthèse (et peut-être même des décalages entre différents cycles de simulation).

Nous avons maintenant les règles de base de la façon dont nous pouvons considérer comment le compilateur transforme le code en logique.

La première étape consiste à dérouler toutes les boucles. Cela signifie que les boucles doivent avoir un nombre d'itérations maximum qui peut être déterminé au moment de la synthèse, sinon vous obtiendrez un échec de synthèse.

L'outil peut ensuite analyser le flux de contrôle du bloc et le transformer en flux de données. Chaque variable devient un ou plusieurs signaux. Chaque instruction if ou construction similaire devient un ou plusieurs multiplexeurs sélectionnant l'ensemble de résultats qui sera réellement utilisé.

L'outil tentera alors probablement d'appliquer certaines optimisations.

Dans quartus, vous pouvez voir les résultats de ce processus après avoir construit votre projet en allant dans "tools-> netlist viewers-> rtl viewer".

Après avoir généré cette représentation structurelle en termes d'éléments logiques abstraits, l'outil passe ensuite au mappage de ces éléments abstraits sur les ressources que la puce possède réellement.

Peter Green
la source