Løsningsforslag til eksamen i IN 147(A) Dag Langmyhr (oppgave 1, 2 og 6) Sigbjørn Næss (oppgave 3, 4 og 5) 29. mai 2000 1 Oversettelse Assemblerversjonen av split ser slik ut: 1 #include <regdef.h> 2 3.text 4.globl split 5 6 # Navn: split. 7 # Synopsis: Splitter en vektor i stor» og liten» del. 8 # C-signatur: int split(int a[], int n). 9 # Registre: a0: &a[0] 10 # a1: n 11 # t0: i 12 # t1: &a[i] 13 # t2: a[i] 14 # t3: &a[big] 15 # t4: a[0] 16 # t9: bruk og kast» 17 # v0: big 18 19 split: move v0,zero # big = 0; 20 move t3,a0 # 21 22 addi t0,a1,-1 # (n-1) 23 sra t0,t0,1 # i = /2; 24 sll t9,t0,2 # [i] 25 add t1,a0,t9 # $t1 = &a ; 26 lw t9,0(a0) # t = a[0]; 27 lw t4,0(t1) # $t4 = a[i]; 28 sw t9,0(t1) # a[i] = t; 29 sw t4,0(a0) # a[0] = $t4; 30 31 li t0,1 # i = 1; 32 addi t1,a0,4 # 33 spl_1: bge t0,a1,spl_9 # while (t0 < n) 34 # 35 lw t2,0(t1) # if (a[i] 36 bge t2,t4,spl_5 # <a[0]) 37 # 38 addi v0,v0,1 # ++big; 39 addi t3,t3,4 # 40 lw t9,0(t3) # t = a[big]; 41 sw t2,0(t3) # a[big] = a[i]; 42 sw t9,0(t1) # a[i] = t; 43 # } 44 spl_5: addi t0,t0,1 # ++i; 1
45 addi t1,t1,4 # 46 j spl_1 # } 47 48 spl_9: lw t9,0(t3) # t = a[big]; 49 sw t4,0(t3) # a[big] = a[0]; 50 sw t9,0(a0) # a[0] = t; 51 52 jr ra # return big; Følgende er verdt å merke seg: Vektoren er en int-vektor, så adressene øker med 4 for hvert element (se linje 24, 32 og 45). 2 Maskinkode Den lille funksjonen, som altså finner det minste av to heltall, ser slik ut i assemblerspråk: 1 # Navn: min. 2 # Synopsis: Finner det minste av to heltall. 3 # C-signatur: int min(int a, int b). 4 5 min: add v0,zero,a0 6 slt t0,a0,a1 7 bne t0,zero,min_x 8 nop 9 add v0,zero,a1 10 min_x: jr ra 11 nop (Det er lagt inn to nop-er slik at man skal slippe å bekymre seg om pipelineen.) 3 Digitalteknikk Design av T-flipflop med D-flipflop og eksterne porter. Observasjonen man gjør her er at den karakteristiske likningen til en D-flipflop er Q(t + 1) = D, dvs at nestetilstanden er lik nåværende inngang (D-inngangen). For en T- flipflop er nestetilstand lik 1 når Q(t) =0og T = 1, ognårq(t)=1og T = 0, dvsatq(t+1)=q(t)t +Q (t)t. Dette kan implementeres med en XOR-port slik det er vist i figuren under: Figur 1: Løsning på oppgave 3A Eventuelt kan man bruke 2 AND-porter, 1 OR-port og 2 invertere istedenfor XOR-porten, men dette er ikke like elegant siden man bruker 5 porter istedenfor 1... 2
Det letteste for å sjekke om de foreslåtte forenklingene er korrekte er å sette opp sannhetsverditabeller for F 1 og F 2,ogG 1 og G 2, og sjekke at for samme input gir de samme output: a b c F 1 F 2 G 1 G 2 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 Tabell 1: Sannhetsverditabell til løsning av oppgave 3b Av tabell 1 ser man at F 1 = F 2,ogatG 1 =G 2. 4 Instruksjonssett Generell kommentar: Oppgave a c ligner på tilsvarende oppgave som ble gitt i 1998, men bør være tilstrekkelig forskjellig til at man må ha forstått problemstillingen for å kunne svare korrekt. Oppgave 4a Hvis Ainvert=1, Binvert=1, CarryIn=1 og Operation=0, utføres logisk AND mellom den inverterte verdien av a og b, altså, Result=a AND b.selvom Operation=0, vil adderen fremdeles generere Carryout, og for de gitte verdiene a = 0, b = 0 blir CarryOut=1 (fordi a = 1, b = 1 og resultatet av addisjonen 1 + 1 + 1 = 11). Oppgave 4b Gitt kontrollordet i figur 5 utfører ALU-en Result=a + b + 1. (Legg merke til at dette er aritmetisk «+» og ikke logisk OR.) Dette bør observeres som Result=(a + 1)+b=b a, fordi man nå beregner 2-komplementet av a ved først å snu alle bit-ene og så legge til 1 ved å sette CarryIn=1. Forståelsen av hva ALU-en utfører med input gitt i denne oppgaven er nødvendig for å kunne svare på oppgave 4c. Oppgave 4c For å svare på dette punktet, må man granske både figur 3, 4, 5 og 6. Ved å betrakte kontrollordet i figur 5 finner man ut hvilke signalveier som benyttes i datapath-en i figur 3, mens oppgave 4b benyttes som underlag for å bestemme hva ALU-en gjør. Selve instruksjonsformatet sier hva som er source- og target-registre for operasjonen. RegDst=0 angir at resultatet på instruksjonen skal legges tilbake i registerfilen gitt ved RT. ALUSrc=0 betyr at ALU-inngang B skal hentes direkte fra registerfilen og ikke direkte fra instruksjonen. MemReg og MemRead er begge 0 siden det ikke skal leses fra minnet. Branch=1 betyr at det er en hoppinstruksjon som vil endre hvor neste instruksjon skal hentes fra avhengig av AluZero og InvZero. I dette tilfellet vil instruksjonen gjøre et hopp hvis AluZero=1 (det forutsettes 3
at AluZero=1 når resultatet av operasjonen i ALU-en er 0), siden InvZero=0, med andre ord vil instruksjonen gjøre et betinget hopp hvis resultatet av operasjonen i ALU-en er 0. ALU-en utfører operasjonen gitt i oppgave 4, dvs at den beregner den aritmetiske differensen mellom b- og a-inngangene. Da blir operasjonen som utføres lik «RT = RT - RS», med hopp hvis resultatet av operasjonen er 0, m.a.o «General decrement and branch if zero». Ulempen med instruksjonen er at RS kan ha en vilkårlig verdi, slik at man kan risikere å dekrementere seg «forbi» 0, og følgelig ikke foreta hopp, selvom det kanskje var tanken. En mer naturlig variant ville nok være å sjekke på om resultatet var større/mindre enn 0 enn eksakt 0 i et tilfelle med vilkårlig dekrementeringsverdi. Oppgave 4d Denne oppgaven kan løses på flere måter. En mulighet er å sjekke om bit 15 1 er satt, og hvis det er tilfelle, sette inn 1-bit på de øverste 16 bitene og 0 ellers. Det er nødvendig å sette inn 0 hvis tallet er positivt fordi det ikke er gjort forutsetninger om hva som ligger i dette feltet. Funksjonen kan da se ut slik: 1 void SignExtend(int *inpval) /* Forutsetter at int er 32 bit */ 2 3 int temp = *inptval; 4 5 if (temp & 0x00008000) /* Sjekk hva bit 15 er satt til */ 6 temp = temp 0xFFFF0000; /* Tallet er negativt, sett inn 16 1-bit */ 7 else 8 temp = temp & 0x0000FFFF; /* Tallet er positivt, sett inn 16 0-bit */ 9 10 *inpval = temp; 11 return; 12 } Her kan man selvfølgelig programmere mer elegant og kompakt, f.eks 1 Void SignExtend(int *inpvalue) 2 3 *inpval = (*inpval)&00008000? 4 (*inpval) 0xFFFF0000 : 5 (*inpval) & 0x0000FFFF; 6 return; 7 } 5 Flervalgsoppgave 5a) Påstand 1 er korrekt 5b) Påstand 2 er korrekt 5c) Påstand 4 er korrekt 5d) Påstand 1 er korrekt 5e) Påstand 2 er korrekt 5f) Påstand 4 er korrekt 5g) Påstand 4 er korrekt 5h) Påstand 3 er korrekt 1 Bit-ene nummereres fra 0 til 31 fra høyre mot venstre på vanlig måte. 4
6 Parallellstyring Det første problemet er et rent produsent/konsument-problem, men med den globale telleren n i tillegg. Vi trenger derfor de faste tre semaforene pluss én til å kontrollere n. 1 semaphore n_sem = 1, tomme = 10, fulle = 0, mutex = 1; 2 3 void P(int i) 4 5 int nx; 6 7 while (1) 8 down(n_sem); nx = n++; up(n_sem); 9 10 generér fargene i kolonne `nx'» 11 down(tomme); down(mutex); 12 legg fargedata i bufferen» 13 up(mutex); up(fulle); 14 } 15 } 16 17 void K(void) 18 19 while (1) 20 down(fulle); down(mutex); 21 hent en kolonne med fargedata fra bufferen» 22 up(mutex); up(tomme); 23 tegn kolonnen på skjermen» 24 } 25 } Når det gjelder problemet med de spisende filosofer, har jeg valgt å bruke en melding som inneholder tre elementer: mottaker, avsender og avsenders status. Prosessene identifiseres som K = 0, F 1 = 1, F 2 = 2, osv. Aktuell status er sulten og mett. 1 typedef enum sulten, mett } status; 2 typedef struct 3 int til, fra; 4 status stat; 5 } f_meld; Da er det enkelt å skrive filosofenes kode; når de er sultne, ber de kelneren om gafler og venter til de får dem. Når de har spist ferdig, sender de ny melding til kelneren om at andre kan få gaflene. 6 void filosof(int i) 7 8 f_meld m; 9 10 while (1) 11 tenk» 12 m.til = 0; m.fra = i; m.stat = sulten; send(q, 0, &m); 13 receive(q, i, &m); 14 spis» 15 m.til = 0; m.fra = i; m.stat = mett; send(q, 0, &m); 16 } 17 } Kelneren er litt mer komplisert å programmere, for han må holde orden på en kø av ventende sultne filosofer. 5
18 void kelner(void) 19 20 f_meld m; 21 int ant_g = g»; 22 23 while (1) 24 receive(q, 0, &m); 25 if (m.stat == sulten) 26 if (ant_g >= 2) 27 ant_g -= 2; 28 m.til = m.fra; m.fra = 0; send(q, m.til, &m); 29 } else sett m.fra inn i k en av de som venter» 30 } else 31 ant_g += 2; 32 if ( noen som venter på gafler») 33 ant_g -= 2; 34 m.til = neste i k en»; m.fra = 0; send(q, m.til, &m); 35 } 36 } 37 } 38 } 6