====== 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\\..''