Verilog, Piccolo esempio

« Older   Newer »
  Share  
Elemento 38
view post Posted on 5/6/2018, 22:36




Eccomi di nuovo, finalmente ho avuto tempo per rimettermi a scrivere qualcosa in Verilog :D
Il progetto della volta scorsa era abbastanza semplice, andiamo su qualcosa di piu' complesso come idea, ma non come soluzione.

Quello che vogliamo progettare e' un arbitro "round-robin".
- N input vogliono passare dati su un unico canale in output
- ogni canale in input ha un segnale (request) che comunica il fatto che ha dei dati da trasmettere
- l'arbitro ritorna un segnale (grant) che dice che il dato e' stato accettato e trasmesso
- se un canale ha piu' di un dato da trasmettere, deve aspettare che i canali successivi abbiano avuto possibilita' di trasmettere, se vogliono (da qui il nome round-robin)

E' abbastanza semplice da capire con delle waveform:
Screen_Shot_2018-06-05_at_10
Come si puo' vedere, il primo canale fa una richiesta (r1) e gli viene permesso di trasmettere immediatamente. Un po' di tempo dopo, i canali 1 e 2 vogliono trasmettere allo stesso momento, ma l'arbitro da' la possibilita' di trasmettere prima al canale 2 (grant[1]) e poi al canale 1 (grant[0]).

L'algoritmo dietro a questo circuito e' abbastanza semplice (anche se non l'ho testato molto, proviamo a fidarci della prima stesura per questo esempio :P)

- creiamo un vettore che concatena due volte le richieste in ingresso. Per esempio, se il canale 1 e 3 stanno facendo una richiesta, questo vettore sara' {0101 , 0101}
- creiamo una maschera basandoci sulla scorsa richiesta accettata; immaginando che fosse il canale 4, la maschera ha un 1 per ogni bit in una posizione maggiore della 4 {1111 , 0000}
- eseguiamo un AND tra maschera e vettore richieste: 01010101&11110000 = 01010000
- troviamo il primo bit a 1 da destra: 00100000
- dividiamo il risultato a meta' ed eseguiamo un OR tra i due vettori 0001 | 0000 = 0001 -> il canale 1 e' quello a cui verra' permesso di trasmettere!
- aggiorniamo la richiesta accettata con 1 invece di 4

Codice Verilog (di nuovo, funziona per l'esempio sopra, ma non l'ho testato con tutte le combinazioni):
CODE
module arbiter (
 input wire clk,
 input wire resetn,
 input wire [3:0] request,
 output wire [3:0] grant,
 input wire [4*8-1:0] value,
 output wire request_out,
 output wire [7:0] value_out
);

reg [3:0] current_granted;
wire [3:0] next_granted;
wire [1:0] current_granted_noh;
wire [7:0] request_concat, mask, lowest_set, masked_request;
wire [3:0] mask_low;
wire [3:0] lowest_set_merged;
genvar i;

// salviamo l'ultima richiesta accettata (one-hot)
always @(posedge clk or negedge resetn) begin
 if (~resetn) begin
   current_granted <= 4'b0000;
 end else begin
   if (|(next_granted & request)) begin
     current_granted <= next_granted;
   end
 end
end

// ultima richiesta accettata (binario)
assign current_granted_noh = {|current_granted[3:2],
                              current_granted[1]|current_granted[3]};



assign request_concat = {request, request};

// generazione maschera
generate
  for (i=0; i<4; i=i+1) begin : g_mask
     assign mask_low[i] = (i > current_granted_noh);
  end
endgenerate

assign mask = {4'b1111, mask_low};

// mascheriamo le richieste
assign masked_request = mask & request_concat;

// troviamo il primo bit a 1 da destra
assign lowest_set[0] = masked_request[0];
generate
  for (i=1; i<8; i=i+1) begin : g_lowest
     assign lowest_set[i] = masked_request[i] & ~(|(masked_request[i-1:0]));
  end
endgenerate

assign lowest_set_merged = lowest_set[7:4] | lowest_set[3:0];

assign next_granted = lowest_set_merged;
assign grant = lowest_set_merged;

//assegniamo gli output a seconda della richiesta che ha il permesso di passare
assign request_out = |request;
assign value_out = ({8{next_granted[0]}} & value[7:0]) |
                  ({8{next_granted[1]}} & value[15:8]) |
                  ({8{next_granted[2]}} & value[23:16]) |
                  ({8{next_granted[3]}} & value[31:24]);

endmodule

Notare come il codice Verilog rispecchi l'algoritmo in un modo "hardware friendly" :) Inoltre, sarebbe molto semplice avere un numero arbitrario di input senza molti cambiamenti (piu' che altro lunghezze di segnali)

Edited by Elemento 38 - 6/5/2018, 11:57 PM
 
Top
view post Posted on 6/6/2018, 21:08
Avatar

GWFstory

Group:
Administrator
Posts:
359
Location:
da qui...., quo, qua. Siete curiosi di saperlo, vero? No? Beh, tanto non ve l'avrei detto.

Status:


Proprio perchè è una cosa interessante sto cercando di capire l'algoritmo che hai usato (analizzerò in un secondo tempo il discorso del verilog, dato che mi sono fermato molto prima..... :cry:).

Ho riletto 2 volte quello che hai scritto e alla 2° penso di averci capito qualcosa. Vediamo se è vero:

CITAZIONE
- creiamo un vettore che concatena due volte le richieste in ingresso. Per esempio, se il canale 1 e 3 stanno facendo una richiesta, questo vettore sara' {0101 , 0101} Non ho capito perchè crei un vettore di 2 elementi identici in cui (immagino) il 2°bit da sinistra è quello corrispondente al canale 3 e il 4° (quello più a destra) corrisponde al canale 1. Praticamente il mio dubbio è il motivo della ripetizione dello stesso valore per 2 volte (perchè 2 e non una o 3?)
- creiamo una maschera basandoci sulla scorsa richiesta accettata; immaginando che fosse il canale 4, la maschera ha un 1 per ogni bit in una posizione maggiore della 4 {1111 , 0000}
- eseguiamo un AND tra maschera e vettore richieste: 01010101&11110000 = 01010000
- troviamo il primo bit a 1 da destra: 00100000 Non ho capito perchè hai segnato 00100000 invece di 00010000, dato che il numero 01010000 avrebbe il bit 4 a 1 non il bit 5.
- dividiamo il risultato a meta' ed eseguiamo un OR tra i due vettori 0001 | 0000 = 0001 -> il canale 1 e' quello a cui verra' permesso di trasmettere! Immagino che dividere il risultato a metà, equivalente al fatto di shiftare di 1 bit verso destra, venga fatto per fare coincidere l'ingresso 1 col bit 0 corrispondente, giusto?
- aggiorniamo la richiesta accettata con 1 invece di 4 Se ho ben capito la nuova maschera della richiesta effettuata, che nel caso del 4 era 11110000, sarà ora 11111110.
 
Top
view post Posted on 7/6/2018, 11:39
Avatar

Immane Rompiball

Group:
Administrator
Posts:
18,287
Location:
Orlo esterno della cintura di Orione stella 1957

Status:


Lasciatemi dire che il sistema a logica combinatoria tipo PLC (magari evoluti) è molto, molto, molto più assai semplice di quanto non sia fare certe cose con linguaggi informatici più o meno evoluti.
Non pensatee al solito "immane rompiball" ma di solito si fanno programmi decisamente molto complessi, che ovviamente si possono anche fare in verilog o anche in assembler Z80 in C++ o in semplice C, in modo più che altro intellegibile per tutti (coloro che si sono imparati come funziona).
Più che altro se si è elettronici si riesce a leggere il diagramma in modo veloce e determinare con i pochi neuroni rimasti cosa significa.
Il punto, è che non ci sono jump if (cond), call if (cond)... test... ecc... Ma il risultato del test di un bit sia di input che di output che un bit di ram proveniente da qualche parte si riflette su di un bit virtuale che è il risultato dell'operazione logica effettuata. Alla fine quel risultato va ad influire sui dati di output di i/o o di memoria che siano.
Lo stesso si può fare con i byte, le word le longword i float ecc... Per esempio:

CPT: Log (FILIPPO) + Sin(GIOVANNI)- SQR(ANTONIO) DEST: (RESULT)

CPT: È l'operazione di "COMPUTE"
Log: è il logaritmo naturale di:
FILIPPO: è il nome di una variabile che può essere anche una word a 16 bit integer
+: indica la somma del:
Sin: Seno del valore contenuto nella variabile "GIOVANNI" e può essere anche un float in formato ISO.
-" indica la differenza di:
SQR: indica la radice quadrata di:
ANTONIO: che potrebbe essere una variabile a 32 bit di un intero.
DEST: È dove va a finire il risultato che è la variabile "RESULT" che a sua volta può essere un floating point in formati ISO.

La CPU in questo caso riesce a gestire l'apparente incongruenza tra il formato dei numeri impigati senza produrre errori.
Le variabili vengono gestite a seconda dei processori in FILES, o proprio come variabili definite in un elenco. Nei nuovi processori tutte
le variabili sono a 32 bit sia che siano dichiaratamente BIT, INT, CHAR, FLOAT. Questo perchè ormai non ha molto senso cercare di risparmiare
memoria o velocizzare l'esecuzione del programma quando il minimo gestibile è un numero a 32Bit con un tempo di accesso ad ogni livello di
ram di 1 stato. Il nome della variabile può essere quello che ti pare ed includere anche un indirizzo di rete o di ciò che vi pare dal BIT fino al FLOAT.

Ci vuole un attimo a imparare come funziona, ma se sapete programmare, sapete come funziona il vostro siste e cosa vi serve, in un paio di giorni,
una settimana per i più tardi, e imparate. Una volta imparato i vantaggi sono tanti, ma veramente tanti, tra i quali capire velocemente cosa si è programmato
come si è strutturato il programma e perchè. Cosa che invece con i sistemi di programmazione tipo C prettamente informatici ci perdete la testa solo a
capire perchè si fa lo shift di qualcosa perchè gli si somma un numero poi si sottrae ecc... E se dovete usare un PID ve lo dovete saper gestire.
Senza considerare che in tempo reale, mentre il software gira potete vedere le variabili che "variano" il valore ed il risultato delle operazioni. Ma
anche poter variare p.es. il tempo di integrazione o di derivazione, o la costante di amplificazione e vedere che accade al processo. Per non parlare del
fatto che è disponibile (in alcune CPU) l'oscilloscopio integrato dove nella sua finestra potete vedere l'andamento di quelle variabili che avete scelto di monitorare.
Non c'è paragone, tra un Contrllogix e l'ultimo PC di commercio, anche tra quelli in esecuzione industriale. È come paragonare un bel Lamborghini con un F22A Raptor
senza considerare l'armamento... ;)
 
Web  Top
Elemento 38
view post Posted on 7/6/2018, 22:11




QUOTE
Praticamente il mio dubbio è il motivo della ripetizione dello stesso valore per 2 volte (perchè 2 e non una o 3?)

E' perche' vuoi permettere a richieste che vengono prima di quella appena accettata di trasmettere, se non ce ne sono altre a priorita' piu' alta. Considera che i canali 1 e 3 stiano richiedendo nello stesso momento, e lo scorso canale che ha trasmesso e' il 2
CODE
..v----- ultimo trasmesso
0101

La prossima richiesta accettata sara' il canale 3
CODE
.v----- ultimo trasmesso
0001

A questo punto, dovremmo trasmettere il canale 1, ma 1<3, quindi secondo l'algoritmo base non ha possibilita' di trasmettere. Duplicando i canali
CODE
.....v----- ultimo trasmesso
00010001

Il canale 1 diventa un finto canale 5, 5>4 quindi sara' il prossimo a venire accettato.
Questa parte e' importante perche' vogliamo sempre calcolare la maschera in una direzione, senza dover tornare indietro complicando il tutto e aumentando la logica necessaria per il circuito.
QUOTE
Immagino che dividere il risultato a metà, equivalente al fatto di shiftare di 1 bit verso destra, venga fatto per fare coincidere l'ingresso 1 col bit 0 corrispondente, giusto?

Con "dividere il risultato a meta' intendo spezzarlo in due segnali con lo stesso numero di bit. Uno dei due sara' composto da tutti zeri, e facendo l' or con l'altro torniamo ad un segnale lungo quando il vettore iniziale di N richieste, con i canali nelle posizioni giuste (cioe' senza i canali finti che avevamo aggiunto)
QUOTE
Non ho capito perchè hai segnato 00100000 invece di 00010000, dato che il numero 01010000 avrebbe il bit 4 a 1 non il bit 5.

Errore di battitura, modifico nel post precedente! :D
QUOTE
Se ho ben capito la nuova maschera della richiesta effettuata, che nel caso del 4 era 11110000, sarà ora 11111110

Corretto!

Mi sto accorgendo che mi viene molto piu' semplice spiegare in inglese tutte queste cose :lol: :lol:
 
Top
Elemento 38
view post Posted on 7/6/2018, 22:36




QUOTE
Non c'è paragone, tra un Contrllogix e l'ultimo PC di commercio, anche tra quelli in esecuzione industriale. È come paragonare un bel Lamborghini con un F22A Raptor

Non credo che un paragone sia fattibile in ogni caso.
Ho provato a cercare un po' di informazioni sui Controllogix, ma non credo di avere le conoscenze per capire a pieno tutti i datasheet. Quello che mi e' saltato agli occhi, e' che ci sono tabelle che dicono quanto ci mette un'operazione a completare, cosa introvabile in processori da computer moderni. Il linguaggio per programmarli sembra riflettere questo, visto che le istruzioni inserite si riflettono direttamente su operazioni sul PLC, senza la necessita' di dover essere ricompilate ..?

Processori moderni (e performanti) hanno 20+ stadi di pipeline, processano istruzioni non in ordine e hanno almeno 3 livelli di caches che comunicano tra di loro per provare ad avere i dati di cui il processore avra' bisogno N istruzioni piu' avanti.

La grande differenza, a mio parere, e' che in automazione industriale si vuole avere un'esecuzione deterministica, soprattutto temporalmente (considerando che lasciare acceso un motore per qualche millisecondo in piu' puo' provocare disastri).
Un processore da computer e' ottimizzato per avere performance elevate sulla media del programma, che dipende solo in parte sulle singole istruzioni (che in molti casi vengono spezzate in micro-operazioni per avere piu' parallelismo e avere un software piu' veloce, anche se non deterministico sul tempo impiegato per finire
 
Top
view post Posted on 8/6/2018, 10:51
Avatar

Immane Rompiball

Group:
Administrator
Posts:
18,287
Location:
Orlo esterno della cintura di Orione stella 1957

Status:


CITAZIONE
La grande differenza, a mio parere, e' che in automazione industriale si vuole avere un'esecuzione deterministica,

Si, è sempre quello che si vuole da un "COSO" hardware che contro l'hardware. Un generatore di segnali casuale a che serve? Un controllo di "premimentazione" di pulsante per
accendere la luce di casa a cosa serve se a volte ci mette 1uSec e a volte si accende il giorno dopo. Il punto è proprio questo. Per questo motivo se si deve accedere ad un disco,
scrivere o leggere un DVD, accedere ad una scheda viedeo o eseguire dei calcoli complessi un processore può essere utile. Ma diciamocelo chiaro e tondo, in quanti hanno sul proprio
PC un sistema di sviluppo per programmi sotto Wondows 12 ? Eh? Come non è ancora uscito... uscirà domani non vi preoccupate.
L'ultima volta che mi hanno interpellato per sviluppare qualcosa in C dentro un PC perchè non ci riuscivano, avevano tre PC megagalattici connessi in rete perchè uno era il target, uno era
il developer l'altro il gestore di rete. La complessità non era lo sviluppo del programma di per se, non molto semplice ma neppure esasperatamente complesso, ma, era il riuscire a
mettere insieme tutto quello che serviva per scrivere, complilare, linkare, debuggare ecc...
Tutto questo va bene, se hai a disposizione 200 milioni di euro e devi fare un software da vendere tipo Office o giù di li. Per sviluppare un giochino stupido servono almeno 50 milioni di US$ e
una squadra ben affiatata di almeno 10 softwaristi che ci lavorano per un anno.
Oggi, un micro PLC risolve moltissimi problemi, la programmazione è diretta non occorre compilare, assemblare, linkare e fare un debug di qualcosa che non si sa neppure dov'è andato
a finire in memoria e come funziona. Non parliamo di grandi impianti con controlli di posizione, velocità, temperature ecc...
Conosco aziende che si fanno il proprio "marchingegno" per il controllo di processo e non sto a raccontare i problemi che trovano coloro che intendono usarlo sul campo perchè Divina Commedia e Libro delle Origini non bastano per raccontarla tutta.
I processori più grandi, sono moduli multi-processor con più chip superperformanti con firmware sviluppato da decine di softwaristi e testatori con milioni di $ di costo perchè il prodotto va in giro in tutto il
mondo. Processori di comunicazione, processori di interfaccia con i moduli di I/O, processori matematici, ecc... Il tutto criptato automaticamente, e chi più ne ha più ne metta, senza il peso di dover sviluppare
tutto ciò che serve perchè chi ha da controllare un processo ha da fare quello e non perdersi in altre cose. Il software si scarica direttamente sulla CPU (multi processore) e viene esguito in real time mentre si fa il debug (perchè c'è un processore apposito) tramite un'interfaccia di qualche tipo (Ethernet, USB, RS232 o altro).
Per quanto riguarda il multiprocessing, semplicemente si possono generare un numero di processi che girano contemporaneamente dipendentemente da quanto sborsi per la CPU mi sembra, tra un minimo di 16 fino a 64. Anche ,se, come avrai visto il tempo di esecuzione di 1000 istruzioni è di qualche millisecondo e quindi il ritardo tra acquisizione-processo-output è sempre veramente breve.
In altre parole, per divertirsi tutto va bene, anche farsi un processore bit-slice per proprio conto, usare uno Z80, (orrore) un 6502 o farsi una CPU a valvole, ci sono i processori RABBIT, i PIC che sono di tutti i tipi, o chissà che altro, per fare le cose serie ci vogliono sistemi seri. Ma anche per automatizzare la casa o qualche invenzione, ci sono oggi una miriade di "controllorini" con software di programmazione gratuito. Questo era il senso della mia pseudo critica. :)
 
Web  Top
view post Posted on 13/6/2018, 21:51
Avatar

GWFstory

Group:
Administrator
Posts:
359
Location:
da qui...., quo, qua. Siete curiosi di saperlo, vero? No? Beh, tanto non ve l'avrei detto.

Status:


Ele, ho guardato il tuo listato e devo ammettere che la mia conoscenza del VHDL è talmente scarsa da avere capito solo alcune cose sparse qua e là, ma non il listato al completo, ma vorrei cercare di capirci di più, per questo vorrei chiederti chiarimenti su queste linee di programma:

reg [3:0] current_granted;
wire [3:0] next_granted;
wire [1:0] current_granted_noh;
wire [7:0] request_concat, mask, lowest_set, masked_request;
wire [3:0] mask_low;
wire [3:0] lowest_set_merged;

Le ultime 5 dichiarazioni sono state inserite come wire, ma nel listato, se ho ben compreso, vengono trattati come registri. Sto sbagliando qualcosa o ci sono altri motivi per non averli dichiarati "reg"?

CITAZIONE
Mi sto accorgendo che mi viene molto piu' semplice spiegare in inglese tutte queste cose

Se mai ci dovessimo incontrare di persona ti chiederò, magari nel mio inglese non proprio ineccepibile (per usare un eufemismo), di parlare in italiano, anche perchè forse capirei di più se parlassi nel dialetto della tua città che nell'inglese che avrai imparato in questi anni. ;)
 
Top
Elemento 38
view post Posted on 30/6/2018, 08:07




Robo, scusa per il ritardo nella risposta, ma il forum ha deciso di non far comparire il thread nelle notifiche :wb:
QUOTE
Le ultime 5 dichiarazioni sono state inserite come wire, ma nel listato, se ho ben compreso, vengono trattati come registri. Sto sbagliando qualcosa o ci sono altri motivi per non averli dichiarati "reg"?

Solo current granted è un registro. Come puoi vedere dal listato, è l’unica assegnazione che viene fatta in un costrutto always che è sensibile al clock. Tutti gli altri segnali sono assegnati continuamente, indipendentemente dal clock.
Il listato è in Verilog, non VHDL :)
QUOTE
anche perchè forse capirei di più se parlassi nel dialetto della tua città

Il mitico dialètt mudnés :wub:
 
Top
22 replies since 15/5/2018, 18:35   244 views
  Share