Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cn1:laboratoare:09 [2023/05/12 21:50]
maria_teona.olteanu [Resurse]
— (current)
Line 1: Line 1:
-===== Laboratorul 09 - Pipelining ===== 
- 
-==== Obiective ==== 
- 
-În acest laborator vom învăța cum funcționează un pipeline pentru instrucțiuni și vom implementa un pipeline simplu. 
- 
-==== 1. Fazele execuției unei instrucțiuni ==== 
- 
-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: 
-  * **Instruction fetch** (IF): Instrucțiunea este adusă din memorie într-un registru de procesor. 
-  * **Instruction decode** (ID): Instrucțiunea adusă anterior este decodificată și sunt determinate unitățile și datele necesare execuției. 
-  * **Execute** (EX): Acțiunea determinată anterior este executată. 
-  * **Memory access** (MEM): Dacă este necesar, se accesează memoria de date. 
-  * **Register write back** (WB): Dacă este necesar, se scriu date în registrele de procesor. 
- 
-O instrucțiune nu trebuie să folosească toate stagiile disponibile. Spre exemplu, pe o arhitectura [[https://​en.wikipedia.org/​wiki/​Load/​store_architecture|load/​store]],​ doar instrucțiunile //load// și //store// accesează memoria, deci folosesc etapa MEM, restul folosesc doar registrele de procesor, deci folosesc etapa WB. 
- 
-==== 2. Pipelining ==== 
- 
-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). 
- 
-{{ :​cn1:​laboratoare:​09:​ex_no_pipeline.png?​700 |Execuția fără pipeline}} 
- 
-A executa instrucțiuni în pipeline înseamnă că există 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. ​ 
- 
-{{ :​cn1:​laboratoare:​09:​ex_pipeline.png?​700 |Execuția în pipeline}} 
- 
-<​note>​ 
-Execuția fiecărei instrucțiuni în parte durează la fel de mult ca în varianta fără pipeline, însă execuția programului durează mai puțin. 
-</​note>​ 
- 
-Trebuie totuși să aplicăm o constrângere asupra stagiilor: fiecare stagiu trebuie să dureze la fel de mult timp. 
- 
-==== 3. Hazarde ==== 
- 
-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. 
- 
-=== 3.1. Hazarde de date === 
- 
-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)  |  <​code>​ 
-R2 <- R1 + R3 
-R4 <- R2 + R2 
-</​code> ​ |  R2  | 
-|  Write After Read (WAR)  |  <​code>​ 
-R4 <- R1 + R5 
-R5 <- R1 + R2 
-</​code> ​ |  R5  | 
-|  Write After Write (WAW)  |  <​code>​ 
-R2 <- R4 + R7 
-R2 <- R1 + R3 
-</​code> ​ |  R2  | 
- 
-Aceste hazarde sunt rezolvate prin [[https://​en.wikipedia.org/​wiki/​Bubble_(computing)|bubbling]],​ execuția out-of-order sau pasarea operanzilor înainte (forwarding). 
- 
-<​note>​ 
-Hazardele WAR si WAW pot apărea numai în medii de execuție concurente (e.g. procesoare multi-core). 
-</​note>​ 
- 
-=== 3.2. Hazarde structurale === 
- 
-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 (e.g. separarea memoriei de instrucțiuni față de memoria de date) sau prin bubbling. 
- 
-=== 3.3. Hazarde de control === 
- 
-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ă. În cazul unei predicții eronate, instrucțiunea încărcată trebuie eliminată din pipeline. 
- 
-Aceste hazarde pot fi rezolvate prin bubbling, dar de obicei sunt tratate de unități specializate de [[https://​en.wikipedia.org/​wiki/​Branch_predictor|branch prediction]]. 
- 
-==== 4. Exerciții ==== 
- 
-Vom implementa un procesor extrem de simplu, ce execută instrucțiuni în 5 stagii: IF, ID, EX, MEM și WB. 
- 
-**Task 0** și **Task 1** presupun realizarea unui procesor ce va fi capabil să execute următoarele instrucțiuni din memoria de program: 
-<​code>​ 
-xor r0, r1 
-and r2, r3 
-or r4, r5 
-neg r6            
-add r7, r8 
-sub r7, r2 
-mod r7, r2 
-div r20, r2 
-mul r4, r2 
-div r6, r4 
-add r0, r7  
-add r4, r6 
-add r2, r20 
-add r0, r4 
-add r0, r2</​code>​ 
- 
-**Task 0 (3p)** ​ - Implementați logica procesorului făra pipeline în **task01.v**. ​ 
-  * Urmariți TODO-urile. ​ 
-  * Notați numărul de cicluri de ceas până la terminarea ultimei instrucțiuni din **task02.v** (memoria pentru instrucțiuni). 
-<note tip> 
-Structura unei instrucțiuni este următoarea:​ ''​Cod instrucțiune (16 biți) | operand 1 (8 biți) | operand 2 (8 biți)'',​ unde fiecare operand reprezintă indexul unui registru. 
- 
- e.g. instrucțiunea ''​ADD R1, R1''​ este codificată astfel: ''​0000000000000001 00000001 00000001''​. 
- 
-Instrucțiunea ''​NEG''​ are un singur operand (''​operand 1''​). 
-</​note>​ 
- 
-**Task 1 (6p)** ​ - Implementați logica procesorului cu pipeline în **task11.v**. 
-  * Urmariți TODO-urile. 
-  * Observați rezolvarea hazardelor din **task12.v**. 
-  * Notați numărul de cicluri de ceas până la terminarea ultimei instrucțiuni din **task12.v**. 
- 
-<note tip> 
-Din moment ce unele componente ale pipeline-ului folosesc aceleași elemente, avem nevoie să reținem într-o altă variabilă elementele scrise de o componentă în ciclul anterior de ceas, de care are nevoie acum componenta următoare. 
- 
-Variabilele care sunt folosite de componente consecutive ale pipeline-ului trebuie reținute și într-un registru special buffered. Spre exemplu, între //memory// și //decoder// avem variabila **instruction** folosită de ambele. Într-un ciclu de ceas, //memory// scrie în **instruction**,​ dar //decoder// are nevoie de valoarea de la ciclul de ceas anterior. Pentru aceasta, //decoder// va primi variabila **instruction_buffer**,​ care are valoarea lui **instruction** din ciclul anterior de ceas. 
-</​note>​ 
- 
-**Task 2 (2.5p)** ​ - Completați memoria de program din **task21.v** astfel încât la final să se afle în registrul 0 valorea în zecimal 1234. (**HINT**: Ce valori se află inițial în registrele procesorului?​) 
- 
-**Task 3 (0.5p)** ​ - Completați memoria de program din **task31.v** astfel încât la final să se afle în registrul 0 valorea în zecimal 1234. Fiți atenți la posibile hazarde! 
- 
-<note tip> 
-Când simulați orice task se va deschide fișierul ''​Default.wcfg''​. Acesta are toate semnalele incluse pentru debugging. Aveți grijă să nu suprascrieți ''​Default.wcfg''​ când ieșiți din simulator. 
-</​note>​ 
- 
-==== Resurse ==== 
- 
-   * [[https://​gitlab.cs.pub.ro/​calculatoare-numerice/​soc-public/​-/​tree/​main/​lab09|Scheletul de laborator]] 
- 
  
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0