56 / 63 · Concept
Banc de registres à deux lectures, une écriture et bypass
Réaliser deux lectures indépendantes et une écriture synchrone, puis vérifier bypass, initialisation et validité.
Les leçons sont gratuites. Inscrivez-vous pour enregistrer vos progrès.
Sortir deux opérandes simultanément
Calculer A+B demande les deux opérandes dans le même cycle. Un banc de registresRegistre Circuit stockant plusieurs bits d'état. Les registres synchrones du cours capturent leur entrée définie sur un front d'horloge. En savoir plus à deux lectures et une écriture possède deux adresses de lecture et une d'écriture. Ici, huit mots de seize bits ont deux lectures enregistrées au front montant : adresse trois bits, capacité 8×16=128 bits. L'adresse 0 est ordinaire, sans règle de registre constant.
Chaque lecture a ses propres enable et valid. L'une peut être inactive pendant que l'autre lit ; les deux peuvent lire la même adresse. Deux lectures simultanées à des adresses distinctes ont un coût différent d'une simple capacité accrue. Un petit circuit peut employer des basculesBascule Élément capturant l'entrée au front d'horloge spécifié et la conservant jusqu'au suivant. L'entrée doit respecter setup et hold. En savoir plus et deux réseaux de sélection ; une réalisation RAM peut dupliquer le stockage et partager les écritures pour offrir deux ports. La déclaration RTL seule ne détermine pas la ressource.
Quand la valeur écrite est aussi lue
Le contrat retourne la nouvelle donnée en cas de lecture et écriture de la même adresse au même front. Un bypass envoie wr_data directement vers l'entrée du registre de lecture, sans attendre la mise à jour du tableau. Pour le port :
Si , la réponse est :
désigne le stockage avant le front. Chaque compare indépendamment son adresse. Une collision sur un port ne doit pas remplacer les deux opérandes ; omettre wr_en activerait aussi le bypass à tort lors d'une simple coïncidence d'adresse sans écriture.
module regfile8x16_2r1w (
input logic clk, rst, wr_en,
input logic [2:0] wr_addr,
input logic [15:0] wr_data,
input logic rd_en0, rd_en1,
input logic [2:0] rd_addr0, rd_addr1,
output logic [15:0] rd_data0, rd_data1,
output logic rd_valid0, rd_valid1
);
timeunit 1ns;
timeprecision 1ps;
logic [15:0] mem [0:7];
always_ff @(posedge clk) begin
if (rst) begin
rd_valid0 <= 1'b0;
rd_valid1 <= 1'b0;
end else begin
rd_valid0 <= rd_en0;
rd_valid1 <= rd_en1;
if (wr_en)
mem[wr_addr] <= wr_data;
if (rd_en0)
rd_data0 <= (wr_en && wr_addr == rd_addr0)
? wr_data : mem[rd_addr0];
if (rd_en1)
rd_data1 <= (wr_en && wr_addr == rd_addr1)
? wr_data : mem[rd_addr1];
end
end
endmoduleLe bypass change la sélection d'entrée, pas l'étage enregistré. Adresse et requête précèdent le front ; la réponse suit et un registre aval la capture au front suivant. Passer à une lecture combinatoire change chemin adresse-sortie et latence : ce n'est pas une simple simplification du code.
Exemple : collision d'un seul port
Avec M[2]=12 et M[5]=7 préalablement écrits, activez les deux lectures avant E0, adresses 2 et 5, et écrivez 20 à 2. Après E0, le port 0 répond 20 par bypass, le port 1 répond 7. Leur somme valide vaut 27, contre 19 avec read-first sans bypass.
À E1, lisez 2 sur les deux ports et écrivez 30 à 2 : les sorties valent 30. À E2, gardez wr_addr=2,wr_data=99 mais wr_en=0 et lisez 2 : les deux sorties doivent rester 30. Ce cycle révèle un bypass conditionné uniquement par l'adresse. À E3, rd_en0=0,rd_en1=1 donne valid0=0,valid1=1.
Chaque colonne observe un front montantFront montant Instant où l'horloge passe de 0 à 1, distinct du niveau désignant tout l'intervalle CLK=1. En savoir plus, entrées avant et états after après ; ce n'est pas un retard physiqueRetard de propagation Temps nécessaire après un changement d'entrée pour que la sortie se stabilise à sa valeur correcte. Équivalence logique et caractéristiques temporelles sont distinctes. En savoir plus. M[2]=12,M[5]=7 sont préchargés, les lectures toujours actives et l'écriture adressée à 2. La dernière colonne wr_en=0 ne doit pas transmettre 99.
Voir les données du chronogramme
| Signal | Forme d'onde | Valeurs du bus |
|---|---|---|
| edge | 234 | E0 → E1 → E2 |
| wr_en | 1.0 | |
| wr_data | 234 | 20 → 30 → 99 |
| rd_addr0 | 2.. | 2 |
| rd_addr1 | 23. | 5 → 2 |
| out0 après | 23. | 20 → 30 |
| out1 après | 23. | 7 → 30 |
Que faut-il initialiser ?
Le reset synchrone actif haut empêche l'écriture et annule les deux valid ; il n'efface ni tableau ni données de sortie. Conserver une ancienne donnée avec valid=0 est donc normal. Le contenu stocké reste ; un système qui n'accepte que de nouvelles opérations après reset doit définir séparément son ordre d'initialisation.
Lire une adresse lors de sa première écriture donne ici une valeur définie grâce au bypass. Sans écriture, une adresse jamais initialisée reste indéfinie. rd_valid marque une réponse, pas un bit initialized par adresse. Le vérificateur doit contrôler la connaissance de l'adresse avant de calculer l'attendu, avec traitement distinct du bypass.
Testez les quatre combinaisons d'enable, adresses égales/différentes, collisions aucune/port0/port1/deux, écritures consécutives et priorité reset. Plusieurs ports d'écriture sont hors du périmètre ; en les ajoutant, définissez d'abord la priorité de deux écritures à la même adresse. Nombre de ports, contrat et coût évoluent ensemble.
Essayez vous-même
M[1]=4,M[4]=9. Les lectures actives portent sur 1 et 4 et l'on écrit 13 à 4 : quelles sorties ? Ensuite wr_en=0,wr_addr=1,wr_data=99 et les deux lectures portent sur 1 : quelles sorties ? Enfin, expliquez valid et consommation si seul enable0 devient 0.
Lire l’explication
Première réponse : (4,13), car seul le port 1 contourne vers 13. Ensuite : (4,4), car wr_en=0 interdit 99. Enfin rd_valid0=0,rd_valid1=1 : le registre de données du port 0 conserve l'ancien résultat, mais il ne doit pas être consommé. L'adresse 0 se lit et s'écrit comme les autres.