Dagens tema Mer MIPS maskinkode (P&H: 4.4 + 3.6 + 3.3 + A.6 + A.10) Maske-operasjoner Skift-operasjoner Lesing og skriving Pseudo-instruksjoner Mer om funksjonskall Registeroversikt Ark 1 av 16 Forelesning 3.2.1998
Maskeoperasjoner Maskeoperasjonene brukes til å sette eller nulle ut bit i henhold til et gitt mønster (en maske). Maske-AND Denne operasjonen nuller ut de bit som ikke er markert i masken. 0 1 0 1 0 1 0 1 AND 0 0 0 0 1 1 1 1 = 0 0 0 0 0 1 0 1 Denne operasjonen er tilgjengelig i C og heter der &. NB! Det er forskjell på & (maske-and eller bit-and) og && (logisk AND): 1 & 4 == 0 1 && 4 == 1 Siden operasjonen er symmetrisk, er det vilkårlig hvilken operand som betraktes som maske og hvilken som er data. Forelesning 3.2.1998 Ark 2 av 16
Maske-OR Denne operasjonen setter de bit som er markert i masken. 0 1 0 1 0 1 0 1 OR 0 0 0 0 1 1 1 1 = 0 1 0 1 1 1 1 1 Denne operasjonen er tilgjengelig i C og heter der. Maske-XOR Denne operasjonen snur de bit som er markert i masken. 0 1 0 1 0 1 0 1 XOR 0 0 0 0 1 1 1 1 = 0 1 0 1 1 0 1 0 Denne operasjonen også ofte «logisk addisjon». Den er tilgjengelig i C og heter der ^. Forelesning 3.2.1998 Ark 3 av 16
Skift-operasjoner Dette er operasjoner som flytter alle bit-ene i et ord mot høyre eller venstre. Logisk skift Her settes det inn 0-er fra enden: 0 1 0 1 0 1 1 1 sll $x,$x,1 1 0 1 0 1 1 1 0 sll $x,$y,2 1 0 1 1 1 0 0 0 srl $x,$x,1 0 1 0 1 1 1 0 0 srl $x,$x,4 0 0 0 0 0 1 0 1 Forelesning 3.2.1998 Ark 4 av 16
Aritmetisk skift I vårt desimale tallsystem kan man gange med 10 ved å sette inn en 0, og dele med 10 ved å fjerne siste siffer: 42 10 = 420 217/10 = 21 Det samme gjelder i det binære tallsystemet, men her er effekten å gange med 2 eller dele på 2: 0 0 1 0 1 0 1 0 (=42 ti ) 0 1 0 1 0 1 0 0 (=84 ti ) 1 1 0 1 1 0 0 1 (=217 ti ) 0 1 1 0 1 1 0 0 (=108 ti ) Forelesning 3.2.1998 Ark 5 av 16
Hva gjør vi så hvis det er fortegnsbit? Løsningen er å kopiere inn fortegnsbittet ved aritmetisk skift mot høyre. 0 1 0 1 0 1 1 1 sra $x,$x,1 0 0 1 0 1 0 1 1 sra $x,$y,2 0 0 0 0 1 0 1 0 1 1 0 1 0 1 1 1 sra $x,$x,1 1 1 1 0 1 0 1 1 sra $x,$y,2 1 1 1 1 1 0 1 0 Skifting i C C har to operatorer for skifting: << skifter mot venstre. >> skifter mot høyre. Hvis data er unsigned, foretas logisk skifting; ellers er det implementasjonsavhengig om det skjer logisk eller aritmetisk skifting. Forelesning 3.2.1998 Ark 6 av 16
Lesing og skriving Hittil har vi kun benyttet registre og konstanter. Nå er det på tide å ta for oss instruksjonene som gir kontakt med hurtiglageret («RAM»). 0x00FFFFFF RAM. CPU 0x0000000C 0x00000008 0x00000004 0x00000000 RAM består av byte gruppert 4 og 4 i ord. Instruksjonen lw («load word») flytter ett ord fra RAM til CPU-en. lw $8,100($4) Hvis $4 inneholder 1000, vil bytene i adresser 1100 1103 bli kopiert over i $8. Instruksjonen sw («store word») flytter motsatt vei. Forelesning 3.2.1998 Ark 7 av 16
Tilpasning («alignment») De fleste prosessorer krever at operasjoner på ord ikke må krysse ordgrenser; dette gjelder også MIPS. Følgelig må adresser som benyttes av lw og sw være et muliplum av 4, siden disse instruksjonene flytter 4 byte. Assembleren tilbyr et eget direktiv for dette:.align 2 (Senere skal vi ta for oss instruksjoner som leser eller skriver én og én byte. Da trenger vi ikke bekymre oss for tilpasningen.) Forelesning 3.2.1998 Ark 8 av 16
Byte-rekkefølge Hvis $8 inneholder 01020304 hex, vil instruksjonen sw $8,1000($0) lagre de fire byte-ene i lokasjonene 1000 1003 i RAM. Vil så byte-en 01 hex havne i 1000 eller 1003? Her er det forskjell på prosessorene. «Big-endian» vil lagre 01 hex i 1000, 02 hex i 1001, 03 hex i 1002 og 04 hex i 1003. Eksempler på «big-endian»-maskiner er 680x0. «Little-endian» vil lagre 01 hex i 1003, 02 hex i 1002, 03 hex i 1001 og 04 hex i 1000. Eksempler på «little-endian»-maskiner er Intels prosessorer. MIPS kan være begge deler: «little-endian» på en DECstation og «big-endian» på en Silicon Graphics. spim følger vertsmaskinen. Forelesning 3.2.1998 Ark 9 av 16
Pseudo-instruksjoner Det er uheldig å måtte skrive «gale» instruksjoner som add $4,$2,$0 når vi egentlig bare ønsker å flytte en verdi. Dessuten er det dumt å måtte skrive sekvenser som mult $4,$5 mflo $2 bare fordi prosessoren velger å legge svaret fra en mulitplikasjon i et spesielt register. Forelesning 3.2.1998 Ark 10 av 16
Løsningen på begge disse problemene er pseudo-instruksjoner. Dette er instruksjoner som ikke finnes i prosessoren, men som assembleren godtar og «oversetter» til én eller flere ekte instruksjoner. Vi får således lov å skrive move $4,$2 mul $2,$4,$5 la $8,adresse Den siste instruksjonen («load address») er en pseudo-instruksjon for lui ori $8, adresse/0x10000 $8, adresse%0x10000 Alle standard pseudo-instruksjoner står listet opp sammen med de ekte instruksjonene i avsnitt A-10 i læreboken. Forelesning 3.2.1998 Ark 11 av 16
Funksjonskall Vi har tidligere sett på funksjonskall, men noen problemer ble ikke dekket: Hva skjer hvis funksjonen har mer enn 4 parametre? Hva skal man gjøre med returadressen i register $31 hvis funksjonen selv kaller andre funksjoner? Hvor skal man lagre funksjonens lokale variable? Hvilke registre har funksjonen lov å endre, og hva gjør den hvis den trenger noen registre den ikke har lov å endre? Hva skjer hvis funksjonen brukes rekursivt (kaller seg selv)? Løsningen på alle disse punktene er: Bruk stakken! Forelesning 3.2.1998 Ark 12 av 16
Stakken Stakken er et sammenhengende område i lageret som kan brukes til mellomlagring. Register $29 peker alltid på første ledige posisjon på stakken. Høye adresser.. Lave adresser $29 Man kan legge en verdi på stakken ved å utføre sw $x,0($29) addi $29,$29,-4 og verdien kan hentes tilbake med addi $29,$29,4 lw $y,0($29) Forelesning 3.2.1998 Ark 13 av 16
Funksjonskall Når en funksjon («caller») skal kalle en annen funksjon («callee»), bør følgende skje: 1. Kalleren legger de temporære registre $8 $15 samt $24 og $25 på stakken hvis de inneholder noe viktig. Dette er de usikre («caller-save») temporærregistrene. 2. Kalleren legger de fire første parametrene i registre $4 $7; hvis det er flere parametre, legges de på stakken (i omvendt rekkefølge). 3. Det hoppes til funksjonen med en jal. Den kalte funksjonen bør så gjøre følgende: 1. Gjem unna register $31, om nødvendig. 2. Gjem også registrene $16 $23 hvis de skal endres. Dette er de sikre («callee-save») temporærregistrene. Forelesning 3.2.1998 Ark 14 av 16
Retur fra funksjon Det er litt mindre arbeid å returnere fra en funksjon. Den kalte funksjonen bør gjøre følgende: 1. Plassér funksjonsverdien i $2. 2. Hent tilbake registrene $16 $23 og $31 hvis disse er lagret på stakken. 3. Returner ved å hoppe til $31. Funksjonen som kalte, må også rydde opp litt: 1. Fjern parametrene fra stakken (hvis det var mer enn 4 parametre). 2. Hent tilbake de usikre registrene som ble lagret unna før kallet. Forelesning 3.2.1998 Ark 15 av 16
Registre Siden registrene har spesielle oppgaver, har de også et alternativt navn som illustrerer denne oppgaven: $zero $0 Alltid 0 MIPS $at $1 For assembleren $v0 $v1 $2 $3 Returverdi fra funksjon $a0 $a3 $4 $7 Parametre til funksjon $t0 $t9 $8 $15, $24 $25 Temporære (usikre) $s0 $s7 $16 $23 Temporære (sikre) $k0 $k1 $26 $27 For OS-kjernen $gp $28 Globale data $sp $29 Stakkpeker $fp $30 Rammepeker $ra $31 Returadresse MIPS Denne tabellen finnes også på side A-23 i læreboken. Forelesning 3.2.1998 Ark 16 av 16