index

l’istruzione ha cinque fasi (con relative unità funzionali):

  1. instruction fetch (IF) - memoria istruzioni e aggiornamento PC
  2. instruction decode - blocco registri e CU
  3. execute - ALU
  4. memory access - memoria dati
  5. write back - banco registri

l’obiettivo è trasformare la CPU in una catena di montaggio, in cui ogni unità funzionale elabora la fase corrispondente e passa l’istruzione alla fase successiva.

center

esempio parallelizzazione

immaginiamo che la durata delle fasi sia la seguente:

  • Instruction Fetch → 200ps
  • Instruction Decode → 100ps
  • Instruction Execute → 200ps
  • Memory Access → 200ps
  • Write Back → 100ps

normalmente, per poter eseguire un’istruzione che richiede il completamento di tutte e 5 le fasi (come la lw), sarebbe necessario utilizzare un periodo di clock di 800ps center

invece, con la pipeline, il periodo può essere ridotto a quello della fase più lenta - 200ps center

banco registri e periodo di clock

poiché le fasi di ID e WB, che lavorano entrambe sul Register File, impiegano una quantità di tempo molto inferiore rispetto alle altre, se svolgo prima il write e poi il read posso, in un’unica fase, scrivere per l’istruzione precedente e leggere per l’istruzione corrente (anche il registro appena scritto) center

criticità nell’esecuzione (hazard)

Con l’anticipazione delle istruzioni, possono nascere alcune criticità all’interno dell’architettura.

le criticità possono essere di diversi tipi:

  • structural hazard - risorse hardware non sufficienti
  • data hazard - il dato necessario non è ancora pronto
  • control hazard - la presenza di un salto cambia il flusso di esecuzione delle istruzioni

esempio: data hazard

immaginiamo di avere le due istruzioni: addi $s0, $s1, 5 $sub $s2, $s0, $t0 si verificherà un data hazard sul registro $s0, il cui valore non sarà ancora stato scritto perché non sarà stato eseguito il Write Back. center per risolvere l’hazard, dobbiamo quindi alineare le fasi di WB e ID, introducendo due “stalli” nella pipeline: center chiarimento: ricordiamo che la scrittura sul Register File viene eseguita nella prima metà del periodo di clock, mentre la lettura nella seconda metà, dunque è sufficiente sovrapporre le due fasi affinché venga letto il dato corretto, senza la necessità di dover inserire un terzo stallo.

forwarding

in alcuni casi, l’informazione necessaria è già presente nella pipeline prima del WB - in questo caso, possiamo aggiungere delle “scorciatoie”, che recapiteranno il dato necessario senza dover aspettare la fase di WB.

continuando con un esempio come il precedente

center in questo caso, visto che la seconda istruzione ha bisogno del registro $s0 per effettuare la sottrazione, questo viene passato dal forwarding in avanti dopo la prima operazione center

Se la fase che ha bisogno del dato si trova prima di quella che lo produce, sarà comunque necessario inserire qualche stallo (o bolla) fino a quando esso non sarà generato.

esempio (exyss)\

Nel seguente esempio, il dato aggiornato viene generato in fase di accesso alla memoria, dunque il dato rimarrà conservato nel banco di registri MEM/WB. Tuttavia, durante la fase di MEM viene svolta in contemporanea la fase di EXE dell’istruzione successiva, la quale necessiterebbe del dato aggiornato. Poiché il dato non può essere contemporaneamente generato e propagato tramite il forwarding, è necessario introdurre almeno uno stallo.

center center

control hazard

nel caso in cui venga effettuato un salto, l’esecuzione di un programma genera problemi per la sua sequenzialità.

possono infatti verificarsi due casi:

  • il salto non viene eseguito - non serve lavorare sulla pipeline perché l’istruzione successiva è già stata caricata
  • il salto viene eseguito - servirà rimpiazzare l’istruzione attualmente caricata nella pipeline con quella a cui si salta

ci sono tre modi per mitigare i control hazard:

  1. branch not taken - si assume che il salto venga sempre considerato come falso e si carica normalmente l’istruzione successiva, che viene poi scartata e rimpiazzata in caso il salto si verifichi
  2. branch taken - si assume che il salto venga sempre considerato come vero e si carica l’istruzione a cui si salta, che viene poi scartata e rimpiazzata in caso il salto non si verifichi
  3. branch prediction - la CPU osserva i salti eseguiti e cerca di caricare l’opzione eseguita più spesso