Personal computer: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Pizeta (discussione | contributi)
Pizeta (discussione | contributi)
Riga 1 159:
 
=== Conflitti tra dati ===
 
I conflitti tra dati si verificano quando vi è una dipendenza tra le istruzioni inserite nella pipeline.
 
Il seguente spezzone di codice presenta una dipendenza:
ADD R1, R2, R3
SUB R4, R1, R5
Eseguendo le operazioni in pipeline
Cicli di clock 1 2 3 4 5 6
Istruzione ADD IF ID EX MEM WB
Istruzione SUB IF ID EX MEM WB
Il risultato della prima istruzione è disponibile sul banco dei registri dopo lo stadio WB e quindi al clock 5, mentre la seconda operazione legge il valore in R1 nello stadio ID, al clock 3, in anticipo.
 
Tuttavia l'istruzione ADD calcola il valore di R1 già alla fine dello stadio di EX, una soluzione per questo tipo di conflitti è una ''unità di anticipazione'' o '''forwarding unit''' ('''FU''').
La FU consiste nel retroazionare il risultato dell'ALU agli elementi di memoria posti in ingresso all'ALU.
Se la FU rileva che l'operazione ALU in corso richiede come ingresso l'uscita dell'operazione immediatamente precedente, la logica di controllo seleziona come ingresso il valore retroazionato invece del valore letto nel banco dei registri.
 
Occorre, inoltre, passare i risultati non solo all'istruzione che segue immediatamente, ma anche alle successive, ad esempio
ADD R1, R2, R3 IF ID EX MEM WB
SUB R4, R1, R5 IF '''ID''' EX MEM WB
AND R6, R1, R7 IF '''ID''' EX MEM WB
OR R8, R1, R9 IF '''ID''' EX MEM WB
XOR R10,R1, R11 IF ID EX MEM WB
In grassetto sono indicati tutti gli stadi per i quali è richiesta una forwarding unit, l'XOR non ne ha bisogno dato che al momento dell'ID il valore di R1 è già stato scritto dalla prima istruzione.
Si può ridurre il numero di istruzioni da anticipare considerando che il canco dei registri può essere usato due volte in un solo ciclo di clock. Eseguendo le letture nella seconda metà di ID e le scritture nella prima metà di WB l'istruzione OR non necessita di FU.
 
Ridurre il livello di cortocircuitazione richiede un elemento di memoria e una rete logica che decide se l'istruzione condivide il registro sorgente o destinazione con una adiacente.
 
Per le operazioni ALU, usando le forwarding unit, si riescono ad eliminare tutti i conflitti tra dati.
 
Il concetto di anticipazione può essere anche esteso a unità funzionali diverse, ad esempio
ADD R1, R2, R3
SW 25(R1), R1
richiede che l'uscita dell'ALU sia anticipata di nuovo sull'ALU per poter essere calcolato l'indirizzo effettivo, ma anche sull'MDR per poter essere memorizzato senza stalli.
 
I possibili conflitti di dati tra un'istruzione ''i'' e la successiva ''j'' sono:
* '''RAW''' (''Read After Write, lettura dopo scrittura'') l'istruzione ''j'' tenta di leggere una sorgente prima ancora che ''i'' l'abbia scritta.
* '''WAR''' (''Write After Read, scrittura dopo lettura'') ''j'' tenta di scrivere una destinazione prima che sia stata letta da ''i''. Questo tipo di conflitto non è possibile nel DLX dato che per qualsiasi operazione la lettura precede (in ID) la scrittura (in WB). Questo conflitto si verificherebbe con istruzioni che scrivono risultati nei primi stadi della pipeline.
* '''WAW''' (''Write After Write, scrittura dopo scrittura'') ''j'' tenta di scrivere un operando prima che sia stato scritto da ''i'', il risultato scritto corrisponderebbe erroneamente a quello di ''i''. Anche questo conflitto non è possibile nel DLX.
 
Il caso RAR non è un conflitto.
Il primo esempio considerato in questo paragrafo è un conflitto RAW.
 
 
Non tutti i conflitti sui dati si possono risolvere senza conseguenze sulle prestazioni, ad esempio
LW R1, 20(R2) IF ID EX '''MEM''' WB
ADD R3, R1, R4 IF ID '''EX''' MEM WB
Il valore della prima istruzione sarà disponibile soltanto dopo lo stadio di MEM, mentre l'istruzione ALU successiva ha bisogno di quel valore nello stadio EX, ovvero all'inizio dello stesso ciclo di clock.
In questo caso non è possibile realizzare un'unità anticipatrice, ma il conflitto tra i dati può essere risolto soltanto con uno stallo
LW R1, 20(R2) IF ID EX '''MEM''' WB
ADD R3, R1, R4 IF ID '''stallo''' '''EX''' MEM WB
 
In questo caso si è rappresentato lo stallo dopo la fase EX, in realtà, per quanto riguarda la pipeline del DLX, tutti i conflitti possono essere rilevati già durante la fase di ID, un'istruzione si dice ''avviata'' quando passa dallo stadio di decodifica (ID) a quello di esecuzione (EX); se esiste un conflitto tra dati l'istruzione viene sospesa prima di essere avviata.
 
Esiste anche una tecnica, detta di '''scheduling''' della pipeline, che permette di ridurre il numero di stalli riordinando il codice per eliminare i conflitti. Questo compito è affidato al compilatore.
 
Se ad esempio se si vogliono eseguire le operazioni
a = b + c
d = e - f
con a,b,c,d,e,f word in memoria, il codice è
LW R1, b
LW R2, c
ADD R3, R1, R2
SW a, R3
LW R4, e
LW R5, f
SUB R6, R4, R5
SW d, R6
questo codice presenta due situazioni di stallo per conflitto tra dati ( ADD e SUB dopo un LW ), riorganizzando il codice in questo modo
LW R1, b
LW R2, c
LW R4, e ;scambio ADD con la LW successiva in modo da evitare lo stallo
ADD R3, R1, R2 ;questa ADD non dipende dall'istruzione immediatamente precedente
LW R5, f
SW a, R3 ;ritardo la SW per risolvere il secondo conflitto tra dati
SUB R6, R4, R5
SW d, R6
 
Il codice riscritto non presenta stalli.
 
La tecnica della schedulazione può essere impossibile da realizzare, in questo caso viene inserita una operazione nulla ('''NOP''', ''No-OPeration'') tra le due in conflitto. Questa modifica, per quanto riguarda il CPI, è del tutto equivalente ad uno stallo, ma permette di gestire soltanto tramite la schedulazione i conflitti tra dati, semplificando la realizzazione della CPU
 
=== Conflitti di controllo ===