Lösningar till tentamen i EIT070 Datorteknik Institutionen för Elektro- och informationsteknik, LTH Torsdagen den 13 mars 2014, klockan 14:00 19:00 i MA:10. Tillåtna hjälpmedel: på tentan utdelad formelsamling, ej programmerbar miniräknare. Skriv lösningar till varje uppgift på separata ark och använd endast ena sidan på varje ark. Ange namn, program och startår på varje ark. Motivera dina svar tydligt, kommentera all kod du skriver, samt redogör för alla antaganden du gör. Skriv tydligt och läsbart. Betygsgränserna är normalt 20 p för betyg 3, 30 p för betyg 4, och 40 p för betyg 5, av totalt 50 möjliga poäng. Uppgift 1 Betrakta följande C-funktion: int fakultet(int n) { if (n==0) return 1; return (n*fakultet(n-1)); Funktionen beräknar n! genom en serie rekursiva anrop. Skriv din egen version av fakultet i MIPSassembler. Subrutinen skall vara rekursiv och anropa sig själv. Du kan förutsätta att argumentet som skickas in är större än eller lika med noll. Du ska skriva komplett assemblerkod, inklusive direktiv och kommentarer, och du ska följa samtliga MIPS programmeringskonventioner, (10 p)..globl fakultet.ent fakultet fakultet: subu sp, sp, 16 # reservera plats på stacken sw ra, 0(sp) # Spara värdet av ra på stacken sw a0, 4(sp) # Spara värdet av a0 på stacken sw s0, 8(sp) # Spara värdet av s0 på stacken bne a0, zero, continue # testa om n==0 ori v0, zero, 1 # spara returvärdet 1 i v0 b exit # hoppa till exit continue: or s0, a0, a0 # spara argumentet i s0 addi a0, a0, -1 # minska argumentet med 1 jal fakultet # rekursivt anrop mult s0, v0 # beräkna n * fakultet(n-1) mflo v0 # flytta resultet från LO till v0 exit: lw s0, 8(sp) # återställ gamla värdet i s0 lw a0, 4(sp) # återställ gamla värdet i a0 lw ra, 0(sp) # återställ gamla värdet i ra addu sp, sp, 16 # lämna tillbaks platsen på stacken jr ra # resultatet ligger i v0.end fakultet Sida 1 av 5
Uppgift 2 Studera följande satser i språket C: int matrix[100][100], i; for (i=0; i<10000; i++) { matrix[0][i]=0; Förklara vad programmeraren har tänkt att for-loopen ska göra, (2 p). For-loopen ska nollställa hela matrisen matrix. Kommer det att fungera i C? Motivera noggrant, (3 p). Ja, det kommer att fungera. Matrisen matrix ligger konsekutivt utlagd i minnet som 100 * 100 fyra bitars ord. Om man är noggrann som programmerare bör man skriva två for-loopar inuti varandra, men resultatet blir att samma index nollställs, som om man bara har en loop från noll till 9999. Det är viktigt att man använder det index som ligger mest till höger. Satsen matrix[i][0]=0 hade inte fungerat. Studera följande subrutin. Förklara kortfattat men tydligt vad subrutinen gör, (5 p)..globl reset.ent reset reset: ori t0, a0, 0 ori t1, zero, 512 loop: sw zero, 0(t0) addi t0, t0, 4 addi t1, t1, -1 bne t1, zero, loop jr ra.end reset Subrutinen nollställer 512 ints i minnet, med början på den adress som anges som argument. Sida 2 av 5
Uppgift 3 Förklara vad registerbanken är i en MIPS-processor. Vad består den av? Hur fungerar den? Vilka är dess insignaler och vilka är dess utsignaler? (5 p). Registerbanken är de interna minnena där samtliga beräkningar utförs, (1 p). Registerbanken består av 32 * 32 D-vippor, (1 p). Registerbanken kan parallellt ta emot nummer för två register vars värden den skickar ut, samt ta emot nummer och innehåll för ett register där värdet skrivs in, (1 p). Insignaler är tre registernummer om vardera fem bitar, ett registervärde om 32 bitar, och en binär signal som talar om ifall registervärdet skall skrivas in, (1 p). Utsignaler är två registervärden om vardera 32 bitar, (1 p). Förklara steg för steg vad som händer vid ett trådbyte i en realtidkärna, (5 p). Ett avbrott kommer till processorn, och avbrottsrutinen startas, (1 p). Samtliga register sparas på stacken, (1 p). Schedulern anropas och väljer vilken ny tråd som ska köras, (1 p). Den nya trådens registervärden laddas i registren, (1 p). Avbrottsrutinen avslutas och exekveringen fortsätter i den nya tråden, (1 p). Sida 3 av 5
Uppgift 4 Översätt följande avsnitt C-kod till assembler så noggrant som möjligt. Du behöver inte skriva ett fullständigt program. Det räcker om du skriver de instruktioner som exakt motsvarar den givna koden, (5p): k=0; for (n=0; n<8; n++) { k=k+n*n; andi t0, t0, 0 # k=0 andi t1, t1, 0 # n=0 andi t2, t2, 8 # spara slutvärdet 8 i t2 loop: mult t1, t1 # n*n add t0, t0, LO # k=k+n*n addi t1, t1, 1 # n++ blt t1, t2, loop # hoppa tillbaks om n<8 Översätt följande avsnitt assemblerkod till C så noggrant som möjligt. Du behöver inte skriva ett fullständigt program. Det räcker om du skriver de instruktioner som exakt motsvarar den givna koden, (5p): while: bge t0, t1, ready # a<b? add t2, t0, t2 # summera addi t0, t0, 2 # öka b while # hoppa ready: # klart! while (a<b) { sum=sum+a; a=a+2; Sida 4 av 5
Uppgift 5 Man har upptäckt ett programmeringsfel i styrprogrammet till en satellit, som dock redan befinner sig i bana runt Jupiter. Det är en instruktion som är fel. Den ser ut så här: sw t1, 12(t2) Egentligen borde konstanten 12 i adressberäkningen vara 8. Man vill dock inte riskera att rätta koden, kompilera om den och skicka upp en ny version av hela programmet via radiolänk till satelliten. I stället beslutar man sig för att göra en så kallad runtime patch, alltså att skriva ett annat program som går in och ändrar i den befintliga maskinkoden, på plats i satellitens instruktionsminne. På så vis riskerar man inte att införa andra förändringar i den körande koden. Skriv den del av det nya programmet som utför denna ändring och rättar instruktion ovan. Subrutinen unsigned int getinstaddr () returnerar adressen till den felaktiga instruktionen i register v0. Du behöver inte skriva hela programmet med initialiseringar och avslutning, utan det räcker om du skriver den kod som är nödvändig just för att utföra rättningen av sw-instruktionen. Programmet ska vara skrivet i MIPSassembler, (10 p). När man gör en patch, behandlar man maskinkoden som data. I det här fallet ska man hämta bitmönstret som utgör den felaktiga instruktionen, ändra på den del av bitmönstret som utgör konstanten 12, samt spara tillbaks instruktionen på samma ställe i minnet. Det görs till exempel med följande kodsnutt, som utnyttjar att konstanten ligger i de minst signifikanta bitarna. Då räcker det med att subtrahera 4 från det befintliga mönstret. jal getinstaddr # anrop för att få adressen till instruktionen lw t0, 0(v0) # ladda instruktionens bitmönster i t0 addi t0, t0, -4 # minska talet i t0 med 4 sw t0, 0(v0) # lagra det nya bitmönstret i minnet Ett mer korrekt sätt att lösa uppgiften är kanske som följer, där man lägger en korrekt instruktion i minnet och sedan kopierar den till rätt adress. new: sw t1, 8(t2)... jal getinstaddr la t1, new lw t0, 0(t1) sw t0, 0(v0) # så här ser den korrekta instruktionen ut # anrop för att få adressen till instruktionen # ladda adressen till den korrekat instruktionen # ladda instruktionens bitmönster i t0 # lagra det nya bitmönstret i minnet Lycka till! Sida 5 av 5