Registri a scorrimento Verilog
Domanda
Sono molto nuovo al linguaggio HDL. Ho una domanda su come programmare un registro a scorrimento. (So ??spostamento i per l'altra direzione). Perché l'uso wire[N-1:0] r_next
libro? ciò che è inconveniente della mia implementazione?
grazie
il mio primo tentativo è la seguente
module lesson04#(parameter N=8)(
input wire clk, reset,
input wire data,
output wire out
);
reg [N-1: 0] r_reg;
always @(posedge clk or negedge reset)
begin
if(!reset)
r_reg =0;
else
r_reg[0]=data;
r_reg = r_reg<<1;
end
assign out =r_reg[N-1];
endmodule
ma il libro dà:
module lesson04#(parameter N=8)(
input wire clk, reset,
input wire data,
output wire out
);
reg [N-1: 0] r_reg;
wire[N-1:0] r_next;
always @(posedge clk or negedge reset)
begin
if(!reset)
r_reg =0;
else
r_reg <= r_next;
end
assign r_next= {data, r_reg[N-1:1]};
assign out =r_reg[N-1];
endmodule
Soluzione
Prima di tutto, non dimenticate il vostro begin
-end
s intorno sezioni di codice:
else begin
r_reg[0]=data;
r_reg = r_reg<<1;
end
Senza questo, solo r_reg[0]=data
sarà nella clausola else
della dichiarazione if
. Questo funzionerà, ma è considerato un cattivo stile a causa delle dichiarazioni di blocco in una descrizione logica sequenziale ...
In secondo luogo, per la modellazione blocchi sequenziali, uso non bloccante assegnazioni (<=
) o calcoli può 'cadere attraverso' (google non bloccante contro il blocco per maggiori informazioni). Il vostro esempio può benissimo lavoro (avete provato in un simulatore?), Ma se le cose si fanno più complicate e più variabili sono aggiunte le cose possono rompersi.
always @(posedge clk or negedge reset)
begin
if(!reset)
r_reg <= 0;
else begin // This is horrible! Don't write code like this!
r_reg[0] = data; // blocking
r_reg <= r_reg<<1; // non-blocking
end
end
Per la ragione sopra, a volte è consigliabile che la logica combo è separato dalla logica sequenziale in modo che si può scrivere non bloccante assegnazioni ai registri in blocchi sequenziali, e il blocco in blocchi combo e non hanno mai preoccuparsi di programmazione.
Per il codice in questo modo, è necessario calcolare quanto l'uscita successiva deve essere utilizzato allo stato attuale, da qui il bus r_next
nella risposta. Credo che tende ad aiutare la sintesi strumento troppo se tutti i flip-flop sono separati dai circostante logica combinata in questo modo.
Inoltre, se il reset è attivo basso (cioè LOW
azzera) dovrebbe essere chiamato come tale, ad esempio resetb
o reset_n
.
Altri suggerimenti
L'implementazione produce un'uscita molto diverso dal libro di. Si dovrebbe provare questo a te stesso con la costruzione di un semplice banco di prova per guidare i vostri input ed eseguire una simulazione. Vedrete che i turni di uscita del libro i dati di input da un singolo ciclo di clock, mentre i tuoi spostamenti in uscita i dati di input da otto cicli di clock.
Tra l'altro si è rientrato tuo blocco always
, sono portato a credere che non è quello che volevi. Questo è come il tuo blocco si comporta davvero:
always @(posedge clk or negedge reset)
begin
if(!reset) begin
r_reg =0;
end else begin
r_reg[0]=data;
end
r_reg = r_reg<<1;
end
Io uso sempre esplicitamente le parole chiave begin/end
a dichiarazioni if/else
per evitare questa confusione.
Il modo in cui simula, r_reg
è sempre 0 perché si clobber l'assegnazione 1 ° (r_reg[0]=data;
) con il 2 ° (r_reg = r_reg<<1;
). Un'altra differenza è che le assegna libro data
al MSB del registro a scorrimento, ma si assegna alla LSB.
Se si utilizza decenti strumenti linting e di sintesi, si sarebbe probabilmente ottenere un sacco di avvertimenti per il codice. Ciò avvisare l'utente di apportare alcune modifiche.