În acest laborator vom învăța cum funcționează un pipeline pentru instrucțiuni și vom implementa un pipeline simplu.
Execuția unei singure instrucțiuni poate fi împărțită în mai multe etape. Acestea pot fi oricât de multe sau puține și pot avea diverse funcții. O împărțire comună, utilizată de primele procesoare RISC, are 5 stagii:
O instrucțiune nu trebuie să folosească toate stagiile disponibile. Spre exemplu, pe o arhitectura load/store, doar instrucțiunile load și store accesează memoria, deci folosesc etapa MEM, restul folosesc doar registrele de procesor, deci folosesc etapa WB.
Execuția normală a instrucțiunilor are loc în mod secvențial. Deci execuția unei instrucțiuni va începe după terminarea ultimului stagiu al instrucțiunii precedente. Astfel, considerând modelul descris mai sus, pentru a executa 3 instrucțiuni avem nevoie de 15 cicli de ceas (considerând că toate instrucțiunile folosesc toate stagiile).
A executa instrucțiuni în pipeline înseamnă că este câte o instrucțiune în fiecare stagiu la orice moment dat. În timp ce o instrucțiune este în stagiul de execuție, alta este decodificată, alta este adusă din memorie, etc. Asta duce la o reducere semnificativă a timpului de execuție al unui program. În același timp în care puteam executa doar 3 instrucțiuni fără pipeline, putem executa 11 instrucțiuni în pipeline.
Trebuie totuși să aplicăm o constrângere asupra stagiilor. Fiecare stagiu trebuie să dureze la fel de mult timp.
O problemă introdusă de execuția în pipeline sunt hazardele. Un hazard este situația în care execuția următoarei instrucțiuni este imposibilă sau va produce rezultate greșite.
Un hazard de date se produce atunci când o instrucțiune are nevoie de un rezultat într-un stagiu al execuției, iar acel rezultat este calculat într-un stagiu al altei instrucțiuni ce va fi executat mai târziu.
Hazard | Exemplu | Registru afectat |
---|---|---|
Read After Write (RAW) | R2 <- R1 + R3 R4 <- R2 + R2 | R2 |
Write After Read (WAR) | R4 <- R1 + R5 R5 <- R1 + R2 | R5 |
Write After Write (WAW) | R2 <- R4 + R7 R2 <- R1 + R3 | R2 |
Aceste hazarde sunt rezolvate prin bubbling, execuția out-of-order sau pasarea operanzilor înainte (forwarding).
Hazardele structurale au loc atunci când două instrucțiuni trebuie să folosească aceeași unitate hardware în același timp. Un astfel de hazard are loc, spre exemplu, într-un sistem cu o singură memorie când se încearcă citirea unei instrucțiuni în același timp cu scrierea rezultatului altei instrucțiuni în aceeași memorie. Aceste hazarde sunt rezolvate prin separarea unităților astfel încât această situație să nu se poată întâmpla (ex: separarea memoriei de instrucțiuni față de memoria de date) sau prin bubbling.
Hazardele de control au loc după instrucțiunile de salt condițional. Problema aici este că procesorul trebuie să încarce următoarea instrucțiune înainte de a ști rezultatul saltului, deci s-ar putea să încarce instrucțiunea greșită. Aceste hazarde pot fi rezolvate prin bubbling, dar de obicei sunt tratate de unități specializate de branch prediction.
Vom lucra pe un procesor extrem de simplu, ce execută instrucțiuni în 5 stagii: IF, ID, EX, MEM și WB.
Task 0 (3p) - Implementati logica procesorului fara pipeline in task01.v.
Cod instructiune (16 biți) | operand 1 (8 biți) | operand 2 (8 biți)
. Spre exemplu, instrucțiunea ADD R1, R1
este codificată astfel: 00000000000000010000000100000001
.NEG
are un singur operand (operand 1
).Task 1 (6p) - Implementati logica procesorului cu pipeline in task11.v.
Task 2 (2.5p) - Implementati un algoritm in ``task21.v`` astfel incat la final registrul 0 sa aiba valorea in zecimal 1234. Incarcati ``task2.v`` pe placa de dezvoltare si observati rezultatul pe display-ul 7LED.
Task 3 (0.5p) - Implementati un algoritm in ``task31.v`` astfel incat la final registrul 0 sa aiba valorea in zecimal 1234. Incarcati ``task3.v`` pe placa de dezvoltare si observati rezultatul pe display-ul 7LED. Fiti atenti la posibile hazarde.
Default.wcfg
. Acesta are toate semnalele incluse pentru debugging. Dupa ce ați incărcat fișierul în simulator, apăsați butonul de Relaunch
. De asemenea, aveți grijă să nu suprascrieți Default.wcfg
când ieșiți din simulator.