6. Pipeline a hazardy

Co bych si měl na cvičení zopakovat/připravit
  1. Struktura single cycle procesoru
  2. Struktura pipelined processoru
  3. Datových hazardy

Osnova cvičení

  1. Struktura procesoru
  2. Pipeline
  3. Fibonacciho posloupost na pipeline
  4. Bubble sort na pipeline

Zkuste si program

.globl _start

.option norelax

.text
_start:

main:

    addi  x2,  x0, 10
    add   x11, x0, x2   // A : x11<-x2
    add   x12, x0, x2   // B : x12<-x2
    add   x13, x0, x2   // C : x13<-x2

la_auipc_inst_addr:
    la x5, varx  // $5 = (byte*) &varx; 
    // The macro-instruction la is compiled as two following instructions:
    //auipc x5, %pcrel_hi(varx) // load the upper part of address
    //addi  x5, x5, %pcrel_lo(la_auipc_inst_addr) // append the lower part of address
    // they compute and load address as relative to the PC, absolute load address alternative
    //lui   x5, %hi(varx) // load the upper part of address
    //addi  x5, x5, %lo(varx) // append the lower part of address
    // It can be replaced by simple single addi if varx is located lower than 0x800
    //addi  x5,  x0, varx

    lw    x1, 0(x5)     // x1 = *((int*)$5);
    add   x15, x0, x1   // D : x15<-x1
    add   x16, x0, x1   // E : x16<-x1
    add   x17, x0, x1   // F : x17<-x1
loop:
    ebreak
    beq    x0, x0, loop
    nop

.data
.org 0x400
varx:
	.word  0x1234

Odkrokujte si ho:

  1. napřed s vypnutým pipeline,
  2. poté si aktivujte pipeline, ale bez hazard unit.
  3. nakonec navolte pipeline s hazard unit.

Pozn. Datová a instrukční cache jsou zde nepodstatné, můžete je obě deaktivovat.

Sledujte nejen výsledné hodnoty v registrech, ale i případné stall stavy, je-li aktivní hazard unit.

  • Kdy instrukce označené A, B, C, D, E a F dají správné výsledky?
  • Kolik cyklů bude potřebovat celý program?

Počet cyklů Vašeho programu se v QtRVSim zobrazuje vpravo v okně procesoru.

Otázka k zamyšlení: Pokud QtRVSim potřeboval více cyklů hodin se zapnutým pipeline než bez něho, znamená to tedy, že pipeline procesor běží pomaleji, nebo ne?

Navrhněte vylepšení: Popřemýšlejte, jak program upravit, aby více vyhovoval pipeline zpracování. Lze v něm snížit počet stall, či ho modifikovat dokonce tak, aby běžel i bez hazard unit?

Úloha - Kopírování pole

.globl _start
.option norelax

.text
_start:
    addi t0, x0, 5
    lui   s1, 4
    addi s1, s1, 0x400
    lui   s0, 4
loop:
    lw t1, 0(s0)
    sw t1, 0(s1)
    addi s1, s1, 4
    addi s0, s0, 4
    addi t0, t0, -1   
    bne t0, x0, loop
    ebreak
  

.data
.org 0x4000
arr1:
	.word  10,11,12,13,14,15,16
.org 0x4400
arr2:
	.word  1,1,1,1,1,1,1,1,1,1,1

Zjistěte, co přesně program dělá.

Změnou pořadí instrukcí zajistěte, aby program fungoval správně i pro CPU s pipeliningem bez hazard unit. Kolik musíte vložit instrukcí nop? Najděte řešení, aby těchto nop bylo v těle cyklu co nejméně a aby program fungoval stejně (můžete změnit agrumenty některých instrukcí). Upravený program musí fungovat i na procesorech s hazard unit.

Úloha - Fibonacciho čísla

Na 3. cvičení byl zadaný příklad na výpočet N-tého Fibonacciho čísla s ukládáním posloupnosti do paměti. Pro zopakování, předpis funkce

 F(n) = F(n-1) + F(n-2), for n > 2, and F(0) = 0, F(1) = 1.
a několik počátečních členů Fibonacciho řady: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,…

Modifikujte svůj program tak, aby správně běžel i na pipeline procesoru. Zapište jím 20 prvních členů posloupnosti, tj. hodnoty 0, 1, 1, 2, …, 4181 (0x1055), 6765 (0x1A6D) do paměti.

Můžete využít následující šablonu asembleru:

.globl _start
.option norelax

_start:
// Zde je misto pro Vas vlastni kod...
   addi t0, x0, 0x400   //  la t0, fibonacci bez hazardu

    ebreak 

.data
.org 0x400
fibonacci:
	.word  0x1234

Program odlaďte:

  1. Nejdříve na simulátoru QtRVSim nakonfigurovaným na jednoduchý procesor bez vyrovnávací paměti a zřetězeného zpracování instrukcí (pipeline).
  2. Poté přepněte na zřetězené zpracování s jednotkou hazardů. Algoritmus by měl stále vydávat předpokládané výsledky.
  3. Následně vypněně jednotku detekce hazardů. Procesor se tím zjednoduší, ale algoritmus přestane vracet očekávané hodnoty.
  4. Zamyslete se, jak by asi měl kompilátor upravit kód pro zřetězený procesor s vypnutou detekcí hazardů, aby nadále vykonával stejnou funkci jako standardní RISC V. Upravte kód v assembleru tak, aby nedocházelo k nechtěnému vlivu datových hazardů, tj. musíte buď změnit pořadí instrukcí nebo vložit NOP instrukce.

Vaším úkolem bude dosáhnout minima použití NOP.

Zápis řady do paměti

Modifikujte předchozí program pro výpočet členů Fibonacciho posloupnosti, aby jednotlivé členy řady zapsal do datové paměti od návěští fibonacci (instrukce sw). Pro výpočet dalšího členu tentokrát využívejte předchozí členy načtené z paměti (instrukce lw). Vykonávání programu sledujte v simulátoru QtRVSim.

Kontrolní otázky:

  • Jak se realizuje instrukce add?
  • Jak se realizuje instrukce addi?
  • Jak se realizuje instrukce lw?
  • Jak se realizuje instrukce sw?
  • Kolik taktů trvá než je známa adresa větvení a jak se zjišťuje? (instrukce beq a bne)
  • Sledujte vykonání programu v simulátoru QtRVSim pro variantu bez pipeline, s pipeline bez a s zapnutou jednotkou řešení hazardů. Sledujte jak se liší doba vykonávání programu pro případ, kdy jsou hazardy řešené pozastavením, a případ, kdy je použitý forward. Pokuste se pro každou variantu navrhnout algoritmus, který je vykonán v nejkratším čase. Především se zaměřte na variantu bez a s řešením hazardů v hardware. Počet potřebných cyklů do dosažení instrukce break můžete odečíst například z počtu čtení z paměti programu spočítanému v okně programové vyrovnávací paměti.

Lineární kód pro sledování postupu instrukcí pipeline

V laboratoři dispozici na /opt/apo/pipe-test

.globl _start
.text
.set noat
.set noreorder

_start:
  nop
  nop
  nop
  nop
  nop
  addi t0,x0,0
  addi t1,x0,0
  addi t2,x0,0
  addi t3,x0,0
  addi t4,x0,0
  addi t5,x0,0
  addi t6,x0,0
  addi s1,x0,0x11
  addi s2,x0,0x22
  addi s3,x0,0x33
  addi s4,x0,0x44
  addi s5,x0,0x55
  addi s6,x0,0x66
  addi s7,x0,0x77
  addi s8,x0,0x88
  addi s9,x0,0x99
  nop
  nop
  nop
_test:
  addi t0,s1,0     // registr t0 bude za čtyři takty nastaven na 0x1111
  // registr s1 změní hodnotu na 0x1133, ale v MipsPipeS tato
  // změna trvá ještě tři hodinové takty, následující dvě instrukce
  // vidí předchozí hodnotu registru
  addi s1,s1,0x22
  add  t1,x0,s1    // t1 se nastaví na starou hodnotu 0x1111
  add  t2,x0,s1    // t2 bude bez přeposílání také ještě nastaveno na 0x1111
  add  t3,x0,s1    // zápis s1 do registru proběhl, t3 bude nastaveno na 0x1133
  beq  x0,x0,skip
  // řídicí hazard
  // načtení dalších instrukcí a pak jejich zahození
  add  t5,x0,s1    
  add  t6,x0,s1    
  add  s2,x0,s1    
  add  s3,x0,s1    
skip:
  nop
  nop
  ebreak

courses/b35apo/tutorials/06/start.txt · Last modified: 2024/02/02 18:41 (external edit)