William Sandqvist william@kth.se Datorteknik övning 2 Subrutinanrop William Sandqvist william@kth.se
Datorteknik & komponenter DC F1 DC Ö1 DC F2 DC Ö2 lab dicom Digitala komponenter CE F1 CE F2 CE Ö1 CE F3 CE Ö2 CE F4 CE Ö3 lab nios2time Assemblerprogram CE F5 CE Ö4 hemlab C C CE F6 CE Ö5 CE Ö6 lab nios2io In- och utmatning CE F7 CE Ö7 lab nios2int Avbrott och "trap" CE F8 CE Ö8 hemlab cache Cacheminnen CE F9 CE Ö9 hemlab trådar Trådar, synkronisering CE F10 CE Ö10 tentamen William Sandqvist william@kth.se
2.1 Binära lagringsformat Det finns tre olika binära lagringsformat för Nios- II-instruktioner. Studera figurer över dessa tre i Nios-II-manualen. Förklara hur de olika fälten i instruktionerna används. William Sandqvist william@kth.se
Register operations, R-type instructions William Sandqvist william@kth.se
Program constants, I-type instructions William Sandqvist william@kth.se
William Sandqvist william@kth.se I-type, Branch William Sandqvist william@kth.se
William Sandqvist william@kth.se J-type Call 32 - 28 = 4 bit obestämda. Man kan nå subrutiner inom ”egen” sida (av 16 sidor) The IMM26 adress is effectively a 28 bit ”Byte-adress” because instructions must be word-aligned. William Sandqvist william@kth.se
2.2 Subrutinanrop med call eller callr Studera de två Nios-II-instruktioner som finns för subrutinanrop. Var lagras retur-adressen, och vilka konsekvenser ger denna lagringsmetod? Visa hur en CALL kan bytas mot en CALLR, om destinationsadressen ligger för långt bort. William Sandqvist william@kth.se
William Sandqvist william@kth.se Subrutinanrop William Sandqvist william@kth.se
William Sandqvist william@kth.se Returnaddress Returadressen lagras i register R31 William Sandqvist william@kth.se
callr – adress i register movia r11, 0x471100 # destinationsadress till R11 callr r11 # anropa subrutinen 2) hämta hoppadressen 1) spara undan återhoppsadressen William Sandqvist william@kth.se
William Sandqvist william@kth.se call och ret Om subrutinen finns inom 256 Mbyte kan call användas. Subrutinen avslutas med instruktionen ret call subrut ... ... subrut: ... ret ret återinsätter det ”tidigare” program-räknarvärdet William Sandqvist william@kth.se
Nästlat subrutinanrop Problem: hur hanterar man flera returadresser? ( fler lektioner följer … ) William Sandqvist william@kth.se
2.4 Multiplikation som upprepad addition Studera de varianter av Add- och Sub-instruktioner som finns för Nios II. Skriv en subrutin muladd() i Nios-II-kod som utför multiplikation genom heltalsadditioner. Vid anrop av muladd() skall Du förutsätta att faktorerna är två positiva binärkodade heltal som finns i R4 och R5, och att produkten blir högst 32 bitar och returneras i R2. Du får använda register R2 … R15 som arbetsregister. Övriga register måste vara oförändrade vid retur. Hur många klockcykler (ungefär) tar en multiplikation med 10? William Sandqvist william@kth.se
William Sandqvist william@kth.se flödesschema Multiplikation av tal1 tal2 genom att addera tal2, tal1 stycken gånger … William Sandqvist william@kth.se
William Sandqvist william@kth.se C-funktion int muladd(int a, int b) { int i; int total = 0; for(i=0; i < a; i++) total += b; /* b adderas a ggr */ return total; } William Sandqvist william@kth.se
William Sandqvist william@kth.se for while int muladd(int a, int b) { int i; int total = 0; for(i=0; i < a; i++) total += b; return total; } int muladd(int a, int b) { int total = 0; int i = 0; while(i < a) { total += b; i++; } return total; } William Sandqvist william@kth.se
William Sandqvist william@kth.se while if - goto int muladd(int a, int b) { int total = 0; int i = 0; while(i < a) { total += b; i++; } return total; } int muladd(int a, int b) { int total = 0; int i = 0; L1: if(i >= a) goto L2; total += b; i++; goto L1; L2: return total; } Omvänt vilkor! William Sandqvist william@kth.se
William Sandqvist william@kth.se Registeranvändning William Sandqvist william@kth.se
William Sandqvist william@kth.se Val av register R2 R4 R5 int muladd(int a, int b) { int total = 0; int i = 0; L1: if(i >= a) goto L2; total += b; i++; goto L1; L2: return total; } R2 (smart, det register vi ska returnera) R8 (första lediga allmänna register) William Sandqvist william@kth.se
William Sandqvist william@kth.se Assemblerkod int muladd(int a, int b){ int total = 0; int i = 0; L1: if(i >= a) goto L2; total += b; i++; goto L1; L2: return total; } muladd: mov r2,r0 # total = 0 mov r8,r0 # i = 0 L1: bge r8, r4, L2 # i>=a add r2, r2, r5 # total += b addi r8, r8, 1 # i++ br L1 L2: ret # return total William Sandqvist william@kth.se
William Sandqvist william@kth.se Hur lång tid tar det? Om ena faktorn är 0 behöver inte så mycket göras! Snabbretur! muladd: mov r2,r0 # total = 0 beq r4,r0,L2 # fakt a är 0 beq r5,r0,L2 # fakt b är 0 mov r8,r0 # i = 0 L1: bge r8, r4, L2 # i>=a add r2, r2, r5 # total += b addi r8, r8, 1 # i++ br L1 L2: ret # return total muladd( 10, 232 ) eller muladd(232, 10) ? William Sandqvist william@kth.se
William Sandqvist william@kth.se worst case muladd(232, 10); Processorn körs med klockfrekvensen 50 MHz muladd: mov r2,r0 # total = 0 mov r8,r0 # i = 0 L1: bge r8, r4, L2 # i>=a add r2, r2, r5 # total += b addi r8, r8, 1 # i++ br L1 L2: ret # return total 232 Antag att hopp br tar två klockcykler, andra instruktioner en klockcykel. bge tar en klockcykel eftersom hoppet bara tas en enda gång, på slutet då loopen kört klart! 232 ·(1+1+1+2)·(1/50·106) 3 minuter ! William Sandqvist william@kth.se
2.5 Skifta eller rotera bitarna i ett ord Förklara instruktionerna skifta (shift) och rotera (rotate). Undersök vilka instruktioner Nios II har för att skifta och rotera. Förklara dessa instruktioner. William Sandqvist william@kth.se
William Sandqvist william@kth.se vänsterskift Skifta R9 vänster två steg ( multiplicera med 22 ): slli r9,r9,2 # R9 << 2 0x05050505 ( = 84215045 ) 0x14141414 ( = 336860180 = 484215045 ) William Sandqvist william@kth.se
William Sandqvist william@kth.se högerskift Skifta R9 höger två steg ( dividera med 22 ): srli r9,r9,2 # R9 >> 2 0x14141414 ( = 336860180 ) 0x05050505 ( = 84215045 = 336860180/4 ) William Sandqvist william@kth.se
William Sandqvist william@kth.se aritmetiskt skift OBSERVERA! srli r9,r9,2 ger inte division med fyra om R9 innehåller ett negativt tal! De nollor som skiftas in från vänster gör talet positivt! Det finns därför en aritmetisk högerskiftinstruktion som skiftar in bitar av samma typ som registrets teckenbit. R9 = 0xfffffff4 (-12) srai r9,r9,2 R9 = 0xfffffffd (-3 = -12/4) William Sandqvist william@kth.se
rotationsinstruktioner Rotera R9 vänster tre steg: roli r9,r9,3 Rotation har ingen direkt aritmetisk betydelse, men kommer till användning vid olika krypterings- dekrypterings-algoritmer. ( Det finns ingen rotationsoperation i C så därför kan det finnas anledning av effektivitetsskäl att skriva assemblerkod i ett krypteringsprogram). William Sandqvist william@kth.se
2.6 Multiplikation med konstant Skriv en subrutin mul10() som utför multiplikation med det konstanta värdet 10. Använd addition och skift. Vid anropet ligger det tal som skall multipliceras med tio i R4, returvärdet lämnas i R2. Använd R2 … R15, lämna övriga register oförändrade. Helst skall subrutinen klara negativa tal. Hur många instruktioner exekveras för att multiplicera ett tal med tio? Finns det risk för overflow/spill? William Sandqvist william@kth.se
Multiplikation med två Multiplikation med två är enkelt, skifta vänster ett steg. William Sandqvist william@kth.se
Multiplikation med åtta Multiplikation med åtta är enkelt, skifta vänster tre steg. William Sandqvist william@kth.se
Multiplikation med tio 10x = ( 8 + 2 )x = 8x + 2x Antag att x ligger i R4 och att retur skall ske i R2 … slli r10,r4,3 # 8x i R10 slli r11,r4,1 # 2x i R11 add r2,r10,r11 # 8x+2x i R2 William Sandqvist william@kth.se
William Sandqvist william@kth.se Subrutin mul10() int mul10(int tal); R4 R2 mul10: slli r10,r4,3 # R10 = 8R4 slli r11,r4,1 # R11 = 2R4 add r2,r10,r11 # R2 = (10+2)R4 ret Beräkningen tar nu 1+1+1+2 klockcykler, blixtsnabbt i jämförelse med 3 minuter! William Sandqvist william@kth.se
William Sandqvist william@kth.se 2.7 Logiska operatorer Repetera (eller lär dig) innebörden av de logiska operationerna ”bitvis AND”, ”bitvis OR” och ”bitvis XOR”. Undersök vad Nios II har för instruktioner för logiska operationer, och hur de används med immediate operand. William Sandqvist william@kth.se
Bitoperationer saknas De flesta procerssorer (utom vissa små-processorer) saknar instruktioner som opererar direkt på enskilda bitar i register. Med hjälp av de bitvisa logiska operationerna kringår man detta. • Man kan 1-ställa enskilda bitar • Man kan 0-ställa enskilda bitar • Man kan testa enskilda bitar William Sandqvist william@kth.se
William Sandqvist william@kth.se Logiska operationer and andi or ori xor xori nor nori Exempel med bitvis and: resultat = operand & bitmask; /* C */ andi resultat,operand,bitmask # assembler operand bitmask AND. Dom bitpositioner som är 0 i bitmasken, blir 0-ställda i resultatet, övriga bitar tas oförändrade från operanden. William Sandqvist william@kth.se
William Sandqvist william@kth.se Logiska operationer and andi or ori xor xori nor nori Exempel med bitvis OR: resultat = operand | bitmask; /* C */ ori resultat,operand,bitmask # assembler OR. Dom bitpositioner som är 1 i bitmasken, blir 1-ställda i resultatet, övriga bitar tas oförändrade från operanden. William Sandqvist william@kth.se
William Sandqvist william@kth.se Logiska operationer and andi or ori xor xori nor nori Exempel med bitvis XOR: resultat = operand ^ bitmask; /* C */ xori resultat,operand,bitmask # assembler XOR. Dom bitpositioner som är 1 i bitmasken, blir ”togglade” i resultatet, övriga bitar tas oförändrade från operanden. William Sandqvist william@kth.se
William Sandqvist william@kth.se nor and andi or ori xor xori nor nori Exempel med bitvis NOR: resultat = ~(operand | bitmask); /* C */ nori resultat,operand,bitmask # assembler Det finns ingen instruktion för bitvis invertering (~). Det kan man lösa med nori – instruktionen: nori resultat,r0,operand Oftast skriver man bitmasken som en hexadecimal konstant, men om det är många inledande nollor kan det i assembler även vara praktiskt att använda binära konstanter. Ex. 0b0111 William Sandqvist william@kth.se
2.8 Ladda en konstant till ett register Instruktionen movi r2,value Sign extension görs på 16-bitarstalet value -32768 < value < +32767 Använd: movi r2, -1 # för att returnera –1 movia finns för 32-bitarskonstanter (oftast adresser) movia r2, -1 # går ej tyvärr, en bug! William Sandqvist william@kth.se
William Sandqvist william@kth.se (2.9 Makron) Saknar Du någon instruktion så kan Du skriva ett makro. Tex kanske man vill ha en instruktion för att 0-ställa ett register? .makro CLR reg # 0-ställ register add \reg,r0,r0 .endm William Sandqvist william@kth.se
( Makro invertera, makro negera ) .makro INV reg # invertera register nor \reg,r0,\reg .endm .makro NEG reg # negera register sub \reg,r0,\reg # reg = 0-reg .endm William Sandqvist william@kth.se
2.10 Multiplikation av godtyckliga tal Skriv en subrutin mul() som multiplicerar två positiva 32-bitarstal. Förutsätt att produkten rymms i 32 bitar, detta behöver inte kontrolleras. Som vanligt för Nios II finns inparametrarna i R4 och R5, och det beräknade resultatet skall levereras i R2. Du får använda register R2 … R15 som arbetsregister. Övriga register skall ha oförändrat innehåll vid returen. William Sandqvist william@kth.se
William Sandqvist william@kth.se Ex. godtyckliga tal 1043 (= 430) a=10 och b=43 är här godtyckliga tal för detta exempel. William Sandqvist william@kth.se
William Sandqvist william@kth.se En algoritm Så här skulle Du göra för hand … skifta höger multiplicera med bit skifta vänster ackumulerad summa Klart! (fast datorn vet inte om att alla avslutande positionerna är noll och måste slutföra alla 32 stegen …) 1101011102 = 1AE16 = 43010 William Sandqvist william@kth.se
från algoritm till program Algoritmen undersöker en enda bit i tal A per loop-varv Om den bitpositionen är ett adderas B till summan Skifta tal A till höger varje loop-varv, undersök alltid biten längst till höger Talet B flyttar ett steg till vänster per loop-varv Spara skiftat B i varje loop-varv William Sandqvist william@kth.se
William Sandqvist william@kth.se Flödesschema int mul(int a, int b) R4 R2 R5 Det blir enklare assembler-program med nedräkning från 32 till 0 i stället för uppräkning från 0 till 32. William Sandqvist william@kth.se
William Sandqvist william@kth.se programförslag ( C ) ... for(i = 32; i > 0; i--) { if(a&1 != 0) total += b; a = a >> 1; b = b << 1; } ... testa biten längst till höger ny bit längst till höger, skifta a skifta b inför nästa varv så att det blir rätt position inför additionen total placeras i R2 (skall returneras) i placeras i tex. R11 (som är ett av många lediga register) William Sandqvist william@kth.se
William Sandqvist william@kth.se assemblerprogram mul: mov r2,r0 # total=0 movi r11, 32 # i=32 L1: andi r12,r4,1 # a&1 testa bit beq r12,r0,L2 # hoppa förbi additionen add r2,r2,r5 # total += b L2: srli r4,r4,1 # a>>1 slli r5,r5,1 # b<<1 subi r11,r11,1 # i-- bgt r11,r0,L1 # loopa tills i=0 ret För C är det ok att funktionen ”förstör” värdena i R4 och R5 (om det anropande programmet inte är C kan annat gälla, då måste kanske dessa kopieras till andra register). William Sandqvist william@kth.se