Aggiornato il 30/07/2007

 

 

HDL blocking e nonblocking

 

Dovendo assegnare qualcosa ad una variabile si usa di regola il segno di uguale, il più naturale per tutti. Negli HDL, non solo in Verilog, le assegnazioni hanno invece due simboli diversi, per forma e significato.

Le assegnazioni blocking, fatte appunto con il segno = oppure l’operatore di assegnazione nonblocking  che è indicato come <=.

I nomi, non proprio auto esplicativi, derivano dal fatto che con queste assegnazione il sintetizzatore può seguire due strade assai diverse.

 

  

Il blocking prende il nome, per inverso dall’altro caso, poiché blocca il flusso del sintetizzatore ad ogni dichiarazione; in pratica il software di sintesi  si ferma fino a che tutta l’espressione non è stata messa a posto. Il lato sinistro, chiamato LHS left hand side, della dichiarazione è cioè assegnato al momento stesso della lettura.

Tutte le assegnazioni continue del tipo assign out = !sel ? in1 : in2; sono sempre e solo eseguite con questo operatore.

 

Il nonblocking  prende il nome dal fatto che l’espressione che la usa viene esaminata in due passi dal sintetizzatore.

Questi valuta la parte destra della frase, quella a destra del simbolo detta RHS e la pone nello stack.

In seguito, alla fine del blocco(*) di dichiarazioni in genere segnato da un always @(…edge), tutti i destination, la parte sinistra dell’espressione vengono assegnati.

In pratica il flusso di sintesi non è “bloccato” dalla dichiarazione ma il software va avanti in attesa della fine del blocco dichiarativo.

Si noti che una dichiarazione nonblocking non può ovviamente essere usata in una assegnazione continua pena un errore del software né, di regola, al di fuori di un always su clock.

 

(*) In realtà nessuno ha mai saputo se il termine usato si riferisse realmente al verbo bloccare o al trattamento del blocco dei dati. Block in Inglese, ha lo stesso nome, come in Italiano per indicare la stessa cosa: o un verbo o un sostantivo. Può però essere utile per ricordarsi che il simbolo del nonblocking, <=, prende campo proprio solo alla fine del blocco.

 

 

Iniziamo con un esempio semplice ma chiaro. Supponiamo di aver bisogno di eseguire lo swap di un bus a 16 bit che cattura i dati sul fronte di un clock che pilota un flipflop e lo inverte sul fronte successivo del ff stesso. Si tratta di esempi volutamente essenziali per far capire. Nulla di più semplice quindi e basta scrivere:

 

Descrizione: Descrizione: wrong_swap_code

Figura 1

 

Peccato che il circuito non funzionerà come è possibile vedere dalla simulazione:

 

Descrizione: Descrizione: wrong_swap_tim

Figura 2

 

 

Osservando l’RTL generato si capisce bene il perché:

 

Descrizione: Descrizione: wrong_swap_rtl

Figura 3

 

 

Il motivo è semplice, essendo la dichiarazione = di tipo blocking il sintetizzatore attua come prima cosa la prima dichiarazione, perdendo parte del contenuto del registro. La seconda frase è quindi inutile, nel senso che non ha più il contenuto precedente. Il sintetizzatore se ne accorge e ottimizza il circuito, errato, togliendo la parte inutile.

Ripetiamo la stessa cosa ora con del codice nonblocking.

 

 

 

Figura 4

 

Il risultato questa volta è corretto e i byte vengono scambiati regolarmente tra LSB e MSB della word.

 

 

Figura 5

 

 

Corretto quindi anche il circuito RTL derivato ( Figura 6 ) con un mux che scambia, quando occorre i dati. La differenza è evidente ed è dovuta al fatto che il sintetizzatore si è accorto che una parte dei dati era modificata nel corso del blocco di dichiarazioni ed ha provveduto con un circuito corretto che ne salva il contenuto.

 

 

Figura 6

 

 

Occorre però stare molto attenti nell’uso di queste dichiarazioni tanto che molti testi riportano l’avvertenza di usare le dichiarazioni blocking solo nelle assegnazioni continue lasciando invece sempre e solo le nonblocking nei circuiti sequenziali.

 

Un esempio di stranezze.

 

Qui vi è un circuito che possiamo assimilare ad uno shift register a 2 bit oppure ad uno stadio risincronizzatore, come preferite. Scritto come visibile in Figura 7 tutto è corretto e funziona come si vede dalla simulazione e dal relativo circuito sintetizzato.

 

 

 

Figura 7

 

 

 

Descrizione: Descrizione: flip_flop2_nc

Figura 8

 

 Questa è la simulazione, corretta, del circuito.

 

 

 

Figura 9

 

 

Anche con una notazione blocking potremmo ottenere lo stesso risultato come visibile qui.

 

 

Descrizione: Descrizione: non_bnb_code

Figura 11

 

Attenzione però! In questo caso basta invertire l’ordine delle righe di codice e il circuito si trasforma in quello visibile a fianco del codice di Figura 12: errato. L’unica modifica, come si vede sono le due assegnazioni invertite cosa che invece potevamo fare con l’assegnazione non blocking senza problema.

 

 

 

Figura 12

 

 

 Ecco cosa si ottiene simulandolo, nulla che vedere con il voluto shift o sincronizzatore…

 

 

Figura 13

 

 

 

 

 

 

 

NOTA BENE

Se osserviamo solo l’uscita RTL del sintetizzatore troveremo che nel caso del codice di Figura 12 i flipflop saranno lo stesso due, ma non è vero. L’ottimizzatore nella passata successiva toglierà l’evidentemente inutile latch lasciano al suo posto quanto visto nella figura stessa.

 

 

Figura 14

 

 

 

Ciò è dovuto come avrete già capito al fatto che il sintetizzatore nel primo caso analizza correttamente il sorgente ed assegna in via definitiva le variabili senza perdere informazione. Nel secondo caso trovandosi già b assegnato non farà altro che duplicare l’uscita b, già valutata non scordiamolo, con il segnale di nome c.

 

 

 

 

Torna all’indice


Paolo Lavacchini 

 

Descrizione: Descrizione: http://www.lsoft.it/maily.gif