57 / 63 · Concetto
Puntatori e politiche di confine della FIFO a clock singolo
Implementare puntatori e occupazione di quattro posti e definire accettazione simultanea a vuoto/pieno.
Le lezioni sono gratuite. Iscriviti per salvare i progressi.
Conservare l'ordine senza spostare tutti i dati
Una FIFOFIFO Coda che estrae prima i dati inseriti prima. Pieno, vuoto e regole di lettura/scrittura simultanee fanno parte del contratto. estrae prima ciò che è entrato prima. Qui lettura e scrittura si decidono allo stesso clock: DEPTH=4, dati a otto bit. rptr indica la prossima lettura, wptr la prossima scrittura. I due bit di ciascun puntatore consentono il ritorno naturale da 3 a 0. occupancy deve contare 0–4 e richiede tre bit.
rptr=wptr è possibile sia a vuoto sia a pieno. Usare solo l’uguaglianza per empty farebbe perdere i dati di una FIFO piena. Manteniamo , con e . Per :
Ai confini distinguere richiesta e accettazione
push e pop sono richieste; p e q sono le accettazioni effettive. Senza reset si calcolano dallo stato prima del fronte:
A vuoto con entrambe, si accetta solo push: non esiste un vecchio elemento da estrarre. Il nuovo dato non esce subito. A pieno si accettano entrambe perché estrarre la vecchia testa libera spazio. full significa «quattro elementi memorizzati», non un divieto incondizionato di push.
| Stato prima del fronte | Solo push | Solo pop | Entrambe |
|---|---|---|---|
| C=0 | Memorizza uno | Rifiuta | Solo push, C=1 |
| 0<C<4 | C+1 | C−1 | Entrambe, C invariato |
| C=4 | Rifiuta | C=3 | Entrambe, C=4 |
Verificare i confini avanzando il clock
All'inizio richiedete push e pop insieme: deve passare solo push. Poi riempite quattro posti senza pop e riattivate entrambe con nuovi dati. occupancy resta 4, esce la vecchia testa e resta una nuova coda.
FIFO a quattro elementi. Inizialmente vuota, con puntatori di lettura e scrittura a 0. Accetta pop se non è vuota. Accetta push se c’è spazio o se viene accettato un pop sullo stesso fronte.
Il modello mostra lo stato dopo ogni fronte di salitaFronte di salita Passaggio del clock da 0 a 1, distinto dall’intero intervallo di livello CLK=1. Approfondisci. Un pop accettato pone output valid=1; senza pop al fronte seguente, il registroRegistro Memorizza uno stato di più bit. I registri sincroni del corso acquisiscono gli ingressi specificati al fronte di clock. Approfondisci mantiene il valore ma valid diventa 0. I vecchi bit dei posti vuoti sono nascosti. «Dall'inizio» reinizializza l'intero laboratorio, non simula il resetReset Controllo che riporta allo stato iniziale specificato. Occorre definirne sincronicità e priorità rispetto agli altri controlli. Approfondisci della RAM RTL.
RTL con uscita registrata
module fifo4 (
input logic clk, rst, push, pop,
input logic [7:0] din,
output logic [7:0] dout,
output logic dout_valid, full, empty,
output logic [2:0] occupancy
);
timeunit 1ns;
timeprecision 1ps;
logic [7:0] mem [0:3];
logic [1:0] rptr, wptr;
logic take_push, take_pop;
assign empty = (occupancy == 3'd0);
assign full = (occupancy == 3'd4);
assign take_pop = !rst && pop && !empty;
assign take_push = !rst && push && (!full || take_pop);
always_ff @(posedge clk) begin
if (rst) begin
rptr <= 2'd0;
wptr <= 2'd0;
occupancy <= 3'd0;
dout_valid <= 1'b0;
end else begin
dout_valid <= take_pop;
if (take_push) begin
mem[wptr] <= din;
wptr <= wptr + 2'd1;
end
if (take_pop) begin
dout <= mem[rptr];
rptr <= rptr + 2'd1;
end
case ({take_push, take_pop})
2'b10: occupancy <= occupancy + 3'd1;
2'b01: occupancy <= occupancy - 3'd1;
default: occupancy <= occupancy;
endcase
end
end
endmoduleoccupancy non usa due if indipendenti per incremento e decremento. Due assegnazioni nonblockingNonblocking Assegnazione RTL sequenziale con <=. Valuta il membro destro e pianifica l’aggiornamento, permettendo ai registri dello stesso fronte di usare lo stato precedente. Approfondisci allo stesso registro farebbero prevalere l'ultima nella simultaneità. I puntatori avanzano ciascuno all'accettazione; count si decide una volta fra quattro casi. Le condizioni impediscono decremento da 0 e incremento da 4.
Leggere e scrivere lo stesso posto a pieno
Dopo A, B, C, D: rptr=wptr=0, occupancy=4. Con pop=push=1, din=E, dopo il fronte dout=A, dout_valid=1 e contenuto [B, C, D, E]. Entrambi i puntatori diventano 1 e count resta 4. mem[0] diventa E, ma il membro destro nonblocking legge il vecchio A. Questo read-first è essenziale alla sostituzione a pieno.
Un successivo solo pop restituisce B e count=3. A vuoto, din=Z con entrambe dà invece count=1, dout_valid=0: occorre un altro pop per vedere Z. Passaggio immediato a vuoto e sostituzione a pieno sono scelte distinte.
Reset sincrono active-high inizializza puntatori, count, dout_valid, non memoria o dout. Dopo reset empty blocca i vecchi dati; si leggeranno solo posti riscritti da nuovi push. Non serve azzerare tutto l'array per il funzionamento normale. Con dout_valid=0 i dati si ignorano. Un'uscita valida risponde a un pop accettato; senza ready d'uscita il consumatore deve riceverla.
Con profondità non potenza di due non basta l'overflow naturale: a profondità tre si torna esplicitamente da indirizzo 2 a 0. Se la sintesi usa RAM, verificatene l'old-data in collisione. Questo RTL è a clock singolo e non realizza sincronizzazione dei puntatori di una FIFO asincrona.
Prova tu
Dopo reset, un fronte ciascuno: (1) push A+pop, (2) push B, (3) push C, (4) push D, (5) push E+pop, (6) pop. Indicate coda, occupancy, valid e dato valido. Perché (5) richiede read-first?
Leggi la spiegazione
(1) [A],1, valid=0. (2) [A, B],2,0. (3) [A, B, C],3,0. (4) [A, B, C, D],4,0. (5) [B, C, D, E],4, valid=1, dout=A. (6) [C, D, E],3, valid=1, dout=B. In (1) non c’è vecchia testa, quindi niente pop. In (5) rptr=wptr=0: lettura e scrittura coincidono e devono restituire il vecchio A. Write-first con E viola ordine e contenuto FIFO. Le uscite con valid=0 non vengono valutate.