====== 6. Pipeline a hazardy ====== * pro vyučující [[..:..:internal:tutorials:06:start|cvičení 6]] ===== 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 3. cvičení byl zadaný příklad na výpočet N-tého [[https://en.wikipedia.org/wiki/Fibonacci_number|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ů [[https://en.wikipedia.org/wiki/Fibonacci_number|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 .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 .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\\..''