====== 6. Pipeline a hazardy ======
* [[..:..:internal:tutorials:05:start|pro vyučující]]
===== Osnova cvičení =====
- Fibonacciho posloupost na pipeline
- Bubble sort na pipeline
===== Co bych si měl na cvičení zopakovat/připravit =====
- Porozumět přednášce o pipeline procesoru a datových hazardech
===== Zkuste si program ====
.globl _start
.set noat
.set noreorder
.text
_start:
main:
addi $2, $0, 10
add $11, $0, $2 // A : $11<-$2
add $12, $0, $2 // B : $12<-$2
add $13, $0, $2 // C : $13<-$2
// la $5, varx // $5 = (byte*) &varx;
// The macro-instruction la is compiled as two following instructions:
lui $5, %hi(varx) // load the upper part of address
ori $5, $5, %lo(varx) // append the lower part of address
lw $1, 0($5) // $1 = *((int*)$5);
add $15, $0, $1 // D : $15<-$1
add $16, $0, $1 // E : $16<-$1
add $17, $0, $1 // F : $17<-$1
loop:
break
beq $0, $0, loop
nop
.data
varx:
.word 1
Odkrokujte si ho:
- napřed s vypnutým pipeline,
- poté si aktivujte pipeline, ale bez hazard unit.
- 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 QtMips zobrazuje dole v okně procesoru.
**Otázka k zamyšlení**: Pokud QtMips 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?
===== Náplň cvičení =====
Na 2. cvičení jste řešili výpočet N-tého Fibonacciho čísla s ukládáním posloupnosti do paměti. 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:
#define t0 $8
#define t1 $9
#define t2 $10
#define s0 $16
#define s1 $17
#define s2 $18
.globl start
.set noat
.set noreorder
.ent start
start:
// Zde je misto pro Vas vlastni kod...
nop
.end start
Program odlaďte:
- Nejdříve na simulátoru QtMips nakonfigurovaným na jednoduchý procesor bez vyrovnávací paměti a zřetězeného zpracování instrukcí (pipeline). Volba delay slot musí ale být zapnutá, pipeline procesor ho vždy používá.
- 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.
- Následně vypněně jednotku detekce hazardů. Procesor se tím zjednoduší, ale algoritmus přestane vracet očekávané hodnoty.
- 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í MIPS. 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.
Pokud je v programu
.set noreorder
pak musíte sami vyplnit delay sloty za instrukcemi.
Když nezadáte "noreorder", pak se assembler postará o standardní vyplňování delay slotů, přičemž zkoumá předchozí instrukci. Pokud ta nezapisuje do registru, na kterém závisí skok, a navíc se před ní nenachází návěští, bude ve výsledném binárním
kódu posunutá až za instrukci skoku. Není-li to splněné, za skok se vloží NOP.
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í fibo_series (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 QtMips.
=== 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 QtMips 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 =====
Adresář s Makefile naleznete na cestě
/opt/apo/pipe-test
Testovací příklad
#define zero $0
#define AT $1
#define v0 $2
#define v1 $3
#define a0 $4
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define t8 $24
#define t9 $25
#define k0 $26
#define k1 $27
#define s0 $16
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define gp $28
#define sp $29
#define fp $30
#define ra $31
.globl start
.globl _start
.set noat
.ent start
.set noreorder
start:
_start:
nop
nop
nop
nop
nop
addi t0,$0,0
addi t1,$0,0
addi t2,$0,0
addi t3,$0,0
addi t4,$0,0
addi t5,$0,0
addi t6,$0,0
addi t7,$0,0
addi t8,$0,0
addi s1,$0,0x1111
addi s2,$0,0x2222
addi s3,$0,0x3333
addi s4,$0,0x4444
addi s5,$0,0x5555
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,$0,s1 // t1 se nastaví na starou hodnotu 0x1111
add t2,$0,s1 // t2 bude bez přeposílání také ještě nastaveno na 0x1111
add t3,$0,s1 // zápis s1 do registru proběhl, t3 bude nastaveno na 0x1133
beq $0,$0,skip
// Jedna instrukce za skokem má být provedena - architekturou definovaný
// delay slot
add t5,$0,s1 // Provede se a měla se provést
add t6,$0,s1 // V MipsPipeS se provede, ale neměla by se provést
add t7,$0,s1 // t7 se také nastaví na 0x1133
add t8,$0,s1 // tato instrukce již provedena nebude, pc bylo nastavené na skip
skip:
nop
.end start
V simulátoru [[..:..:documentation:qtmips:start|QtMips]] není varianta zřetězeného zpracování s porovnáním obsahu registrů pro určení podmínky skoku až ve fázi execute implementovaná. Toto chování je možné demonstrovat na simulátoru [[..:..:documentation:mipsit:start|MipsIt]]. Tento simulátor lze spustit v požadované variantě příkazem
mipsit-mipspipes
Váš kód zkompilovaný do formátu ''srec'' naleznete v simulátoru [[..:..:documentation:mipsit:start|MipsIt]] na cestě ''Z:\home\\..''