Chapter 6 Digital Design and Computer Architecture, 2nd Edition David Money Harris and Sarah L. Harris
Rozdział 6 :: Tematyka Wstęp Język Asembler Język maszynowy Programowanie Tryby adresowania Światła, Kamera, Akcja: Kompilacja, Asemblacja, & Ładowanie Przerwania
Wstęp Przeskoczenie o kilka poziomów abstrakcji Architektura: jak programista widzi komputer Zdefiniowane instrukcje & lokalizacja operandu(operand locations) Mikroarchitektura: jak zaimplementować architektur w sprzęcie(kolejne wykłady)
Język Asembler Instrukcje: komendy w języku komputera Język asembler: instrukcje w formacie czytelnym Język maszynowy: format czytelny dla komputera (1 i 0) Architektura MIPS: Stworzona przez John Hennessy i jego kolegów w Stanford w latach 80. Wykorzystywana w wielu komercyjnych systemach np. Silicon Graphics, Nintendo i Cisco Kiedy pozna się jedną architekturę, wtedy łatwo nauczyć się innych.
John Hennessy Rektor Stanford Uniwersytetu Profesor Wydziału Inżynierii Elektrycznej i Informatyki w Stanford od 1977 Wynalazł komputer o zmniejszonej liczbie instrukcji (RISC) z Davidem Pattersonem Stworzył architekturę MIPS w Stanford w 1984 i założył MIPS Computer Systems W 2004, sprzedano ponad 300 millionów MIPS mikroprocesorów
Zasady projektowania architektury Zasadnicze reguły projektowe stworzone przez Hennessy i Pattersona: Prostota sprzyja regularności Wykonuj szybko powszechne przypadki Mniejsze jest szybsze Dobre projektowanie wymaga dobrych kompromisów
Instrukcje: Dodawanie add: mnemonik wskazujący operację do wykonania b, c: źródłowe operandy ( na których operacja jest wykonywana) a: operand docelowy ( do którego jest zapisywany wynik) Kod C a = b + c; Kod asemblera MIPS add a, b, c
Instrukcje: Odejmowanie Podobny do dodawania – zmiana tylko mnemonika sub: mnemonik b, c: źródłowe operandy a: docelowy operand Kod C a = b - c; Kod asemblera MIPS sub a, b, c
Pierwsza zasada projektowa Prostota sprzyja regularności Zwięzły format instrukcji Takie same operandy (dwa źródłowe i jeden docelowy) Łatwiej zakodować i zaimplementować w sprzęcie
Wielokrotność instrukcji Bardziej złożony kod jest realizowany przez kilka instrukcji MIPS. Kod C a = b + c - d; Kod asemblera MIPS add t, b, c # t = b + c sub a, t, d # a = t - d
Druga zasada projektowa Wykonuj szybko powszechne przypadki MIPS zawiera tylko proste powszechnie wykorzystywane instrukcje Sprzęt do dekodowania i wykonywania instrukcji może być prosty, mały i szybki Bardziej skomplikowane instrukcje (które nie są powszechnie wykorzystywane) są wykonywane z wykorzystaniem kilku prostych instrukcji MIPS jest reduced instruction set computer (RISC), z małą liczbą prostych instrukcji Inne architektury, takie jak Intel x86, są complex instruction set computers (CISC)
Operandy Położenie operanda: fizyczne umiejscowienie w komputerze Rejestry Pamięć Stałe (zwane bezpośrednimi)
Operandy: Rejestry MIPS ma 32 32-bitowe rejestry Rejestry są szybsze niż pamięć MIPS zwana “32-bitową architekturą” ponieważ operuje na 32-bitowych danych
Trzecia zasada projektowa Mniejsze jest szybsze MIPS zawiera tylko niewielką liczbę rejestrów
MIPS zbiór rejestrów Nazwa Numer rejestru Wykorzystanie $0 Stała wartość 0 $at 1 asembler tymczasowy $v0-$v1 2-3 Zwraca wartość funkcji $a0-$a3 4-7 Argumenty funkcji $t0-$t7 8-15 tymczasowe $s0-$s7 16-23 Zapisane zmienne $t8-$t9 24-25 Więcej tymczasowych $k0-$k1 26-27 OS tymczasowe $gp 28 Wskaźnik globalny $sp 29 Wskaźnik stosu $fp 30 Wskaźnik ramkiframe $ra 31 Adres powrotu funkcji
Operandy: Rejestry Registery: Registery specjalnego przeznaczenia: $ przed nazwą Np: $0, “rejestr zero”, “dollar zero” Registery specjalnego przeznaczenia: $0 zawsze przechowuje wartość 0. Rejestry zapisujące, $s0-$s7, wykorzystywane do przechowywania zmiennych tymczasowe rejestry, $t0 - $t9, wykorzystywane do przechowywania pośrednich wartości podczas wiekszych obliczeń Pozostałe rejestry w dalszej części
Instrukcje z rejestrami Powrót do instrukcji add Kod C a = b + c Kod asemblera MIPS # $s0 = a, $s1 = b, $s2 = c add $s0, $s1, $s2
Operandy: Pamięć Za dużo danych do przechowania tylko w 32 rejestrach Przechowywanie danych w pamięci Pamięć jest duża ale wolna Często wykorzystywane zmienne trzymamy w rejestrach
Word-Adresowalna Pamięć Każda 32-bitowe słowo danych ma unikalny adres Uwaga: MIPS wykorzystuje bajtowo-adresowalną pamięć, o tym w dalszej części.
Odczytanie z Word-Adresowalnej pamięci Odczyt z pamięci load Mnemonik: load word (lw) Format: lw $s0, 5($t1) Obliczenie adresu: dodać bazowy adres ($t1) do ofsetu (5) adres = ($t1 + 5) Wynik: $s0 przechowuje wartość spod adresu ($t1 + 5) Dowolny rejestr może być użyty jako bazowy adres
Odczyt Word-Adresowalnej pamięci Np: odczytaj słowo danych z pamięci o adresie 1 do $s3 adres = ($0 + 1) = 1 $s3 = 0xF2F1AC07 po załadowaniu Asembler Kod lw $s3, 1($0) # read memory word 1 into $s3
Zapis Word-adresowalnej pamięci Zapis do pamięci: store Mnemonic: store word (sw)
Zapis Word-Adresowalnej pamięci Np: Zapisz (store) wartość z $t4 do adresu pamięci 7 dodaj adres bazowe ($0) do ofsetu (0x7) adres: ($0 + 0x7) = 7 Ofset może być zapisany dziesiętnie (domyślnie) albo hexadecymalnie Asembler kod sw $t4, 0x7($0) # write the value in $t4 # to memory word 7
Byte-adresowalna pamięć Każda bajtowa dana ma unikalny adres Odczyt/zapis słów albo pojedynczych bajtów: load byte (lb) and store byte (sb) 32-bit word = 4 bajty, więc słowo adresowe jest zwiększane co 4
Odczytanie Byte-Adresowej Pamięci Adres słowa pamięci musi być mnożona przez 4. Np. Adres słowa pamięci 2 jest 2 × 4 = 8 Adres słowa pamięci 10 jest 10 × 4 = 40 (0x28) MIPS jest adresowana bajtowo, a nie słowami
Odczytanie Byte-Adresowej Pamięci Przykład: Odczytanie słowa danych z pamięci o adresie 4 do $s3. $s3 przechowuje wartość0xF2F1AC07 po załadowaniu Kod asemblera MIPS lw $s3, 4($0) # read word at address 4 into $s3
Zapis Byte-adresowej pamięci Przykład: przechowuje wartość z rejestru$t7 do pamięci pod adresem 0x2C (44) Kod asemblera MIPS sw $t7, 44($0) # write $t7 into address 44
Big-Endian & Little-Endian Pamięć Jak są ponumerowane bajty w słowie? Little-endian (Liliputy): bajty numerowane są od najmniej znaczącego bajtu Big-endian (Blefuski): bajty numerowane od najbardziej znaczącego Słowo adresowe jest takie samo dla big- i little-endian
Big-Endian & Little-Endian Pamięć Jonathan Swift’s Podróże Guliwera: Little-Endians rozłupywali jajka mniejszym końcem a Big-Endians rozłupywali jajka na większym końcu Nie ma znaczenia który typ adresacji jest używany – z wyjątkiem kiedy dwa systemy muszą wymienić dane!
Przykład Big-Endian & Little-Endian Example Załóżmy że $t0 przechowuje wartość 0x23456789 Po wykonaniu poniższego kodu na systemie big-endian, jaka wartość jest w $s0? W systemie little-endian? sw $t0, 0($0) lb $s0, 1($0)
Przykład Big-Endian & Little-Endian Załóżmy że $t0 przechowuje wartość 0x23456789 Po wykonaniu poniższego kodu na systemie big-endian, jaka wartość jest w $s0? W systemie little-endian? sw $t0, 0($0) lb $s0, 1($0) Big-endian: 0x00000045 Little-endian: 0x00000067
Czwarta zasada projektowa Dobre projektowanie wymaga dobrych kompromisów Podobny format instrukcji zapewnia uniwersalność add, sub: wykorzystuje 3 operandy rejestrów lw, sw: wykorzystuje 2 operandy rejestrów i stałą Mała liczba formatów instrukcji po dodaniu 1-3 zasad projektowania (prostota sprzyja regularności i mały jest szybszy).
Operandy: Stałe/Bezpośrednie lw i sw wykorzystują stałą albo bezpośrednią bezpośrednia dostępna z instrukcji liczba 16-bitowa z uzupełnieniem do dwóch addi: dodaje bezpośrednio Odejmowanie bezpośrednie (subi) czy jest potrzebne? Kod C a = a + 4; b = a – 12; Kod asemblera MIPS # $s0 = a, $s1 = b addi $s0, $s0, 4 addi $s1, $s0, -12
Kod maszynowy Binarna reprezentacja instrukcji Komputery rozumieją tylko 0 i 1 32-bitowe instrukcje Uoraszczanie wymusza regularność : 32-bitowe dane & instrukcje 3 formaty instrukcji: R-Typ: operandy rejestrowe I-Typ: operandy bezpośrednie J-Typ: skok (wyjaśnione w dalszej części)
R-Typ Register-typ 3 operandy rejestrowe: Inne pola: rs, rt: rejestry źródłowe rd: rejestr docelowy Inne pola: op: kod operacji albo opcode (0 dla R-typu instrukcji) funct: funkcja z opcode, mówi komputerowi jaka operacja ma zostać wykonana shamt: liczba przesunięcia dla instrukcji przesunięcia, w przeciwnym przypadku ustawiane na 0
Przykład R-Typu Note kolejność rejestrów w kodzie asemblera: add rd, rs, rt
I-Typ Bezpośrednie-typ 3 operandy: Pozostałe pola: rs, rt: rejestry operandów imm: bezpośrednia 16-bitowa w kodzie uzupełnienia do dwóch Pozostałe pola: op: opcode Upraszczanie wymusza regularność: wszystkie instrukcje mają opcode Rodzaj operacji jest są zdefiniowany przez opcode
Przykład I-Typ Note różna kolejność rejestrów w asemblerze i kodzie maszynowym: addi rt, rs, imm lw rt, imm(rs) sw rt, imm(rs)
Język maszynowy : J-Typ Jump-typ 26-bit adres operand (addr) Wykorzystywana do skosku (j)
Podsumowanie: Formaty instrukcji
Siła zapisanego programu 32-bitowe instrukcje & dane przechowane w pamięci Sekwencyjność instrukcji: brak różnicy pomiędzy dwoma aplikacjami W celu uruchomienia programu: Nie ma potrzeby pisania go ponownie Po prostu nowy program jest przechowywany w pamięci Wykonanie programu: Procesor „chwyta” (czyta) sekwencyjnie instrukcje z pamięci Procesor wykonuje określone operacje
Zapisany program Program Licznik programu (PC): przechowuje numer aktualnie wykonywanej instrukcji
Interpretacja kodu maszynowego Zaczynamy od opcode: wtedy wiadomo jak przetworzyć pozostałą część Jeśli opcode jest 0 Instrukcja R-typu Bity funkcji określają jaka operacja W przeciwnym przypadku opcode określa typ operacji
Programowanie Języki wysokiego poziomu: e.g., C, Java, Python Napisane na wyższym poziomie abstrakcji Oprogramowanie wysokiego-poziomu posiada: instrukcje if/else pętle for pętle while tablice Wywołanie funkcji
Ada Lovelace, 1815-1852 Napisała pierwszy program komputerowy Jej program obliczał liczby Bernoulliego na analitycznym silniku Charlesa Babbage Była córką poety Lord Byron
Instrukcje logiczne and, or, xor, nor andi, ori, xori and: przydatne do maskowania bitów Maskowanie wartości najmniej znaczącego bajtu 0xF234012F AND 0x000000FF = 0x0000002F or: przydatne do łączenia pól bitowych Połącz 0xF2340000 z 0x000012BC: 0xF2340000 OR 0x000012BC = 0xF23412BC nor: przydatne do inwersji bitów: A NOR $0 = NOT A andi, ori, xori 16-bitowa bezpośrednia uzupełniana zerami (bit znaku nie) nori jest niepotrzebna
Instrukcje logiczne Przykład 1
Instrukcje logiczne przykład 1
Instrukcje logiczne przykład 2
Instrukcje logiczne przykład 2
Instrukcje przesunięcia sll: przesunięcie logiczne w lewo Przykład: sll $t0, $t1, 5 # $t0 <= $t1 << 5 srl: przesunięcie logiczne w prawo Przykład: srl $t0, $t1, 5 # $t0 <= $t1 >> 5 sra: przesunięcie arytmetyczne w prawo Przykład: sra $t0, $t1, 5 # $t0 <= $t1 >>> 5
Instrukcje zmiennego przesunięcia sllv: zmienne przesunięcie logiczne w lewo Przykład: sllv $t0, $t1, $t2 # $t0 <= $t1 << $t2 srlv: zmienne przesunięcie logiczne w prawo Przykład: srlv $t0, $t1, $t2 # $t0 <= $t1 >> $t2 srav: zmienne przesunięcie arytmetyczne w prawo Przykład: srav $t0, $t1, $t2 # $t0 <= $t1 >>> $t2
Instrukcja przesunięcia
Generowanie stałych 16-bitowe stałe wykorzystując addi: 32-bitowe stałe wykorzystując ładowanie stałej na 32 górnych bitach (lui) i ori: C Code // int jest 32-bitowym słowem //ze znakiem int a = 0x4f3c; MIPS assembly code # $s0 = a addi $s0, $0, 0x4f3c C Code int a = 0xFEDC8765; MIPS assembly code # $s0 = a lui $s0, 0xFEDC ori $s0, $s0, 0x8765
Mnożenie, Dzielenie Specialne rejestry: lo, hi 32 × 32 mnożenie, 64 bitowy wynik mult $s0, $s1 Wynik w {hi, lo} 32-bitowe dzielenie, 32-bitowy iloraz, reszta div $s0, $s1 Mnożnik w lo Reszta w hi Przesuwa z lo/hi do specjalnych rejestrów mflo $s2 mfhi $s3
Rozgałęziania Wykonywanie instrukcji nie w sposób sekwencyjny Rodzaje rozgałęzień: Warunkowy Rozgałęzij jeśli jest równe (beq) Rozgałęzij jeśli nie jest równe (bne) Bezwarunkowy skok (j) skok rejestrowy (jr) skok i link (jal)
Podsumowanie: Zapisany program
Warunkowe rozgałęzienie (beq) # MIPS assembly addi $s0, $0, 4 # $s0 = 0 + 4 = 4 addi $s1, $0, 1 # $s1 = 0 + 1 = 1 sll $s1, $s1, 2 # $s1 = 1 << 2 = 4 beq $s0, $s1, target # rozgałęzienie jest wykonane addi $s1, $s1, 1 # nie wykonana sub $s1, $s1, $s0 # nie wykonana target: # Etykieta add $s1, $s1, $s0 # $s1 = 4 + 4 = 8 Etykieta wskazuje lokalizacje instrukcji. Nie mogą być użyte słowa zastrzeżone i musi zakończyć się dwukropkiem (:) .
Rozgałęzienie nie wykonane (bne) # MIPS assembly addi $s0, $0, 4 # $s0 = 0 + 4 = 4 addi $s1, $0, 1 # $s1 = 0 + 1 = 1 sll $s1, $s1, 2 # $s1 = 1 << 2 = 4 bne $s0, $s1, target # brak wykonania rozgałęzienia addi $s1, $s1, 1 # $s1 = 4 + 1 = 5 sub $s1, $s1, $s0 # $s1 = 5 – 4 = 1 target: add $s1, $s1, $s0 # $s1 = 1 + 4 = 5
Bezwarunkowy skok (j) # MIPS assembly addi $s0, $0, 4 # $s0 = 4 j target # skok do target sra $s1, $s1, 2 # nie wykona się addi $s1, $s1, 1 # nie wykona się sub $s1, $s1, $s0 # nie wykona się target: add $s1, $s1, $s0 # $s1 = 1 + 4 = 5
Bezwarunkowy skok (jr) # MIPS assembly 0x00002000 addi $s0, $0, 0x2010 0x00002004 jr $s0 0x00002008 addi $s1, $0, 1 0x0000200C sra $s1, $s1, 2 0x00002010 lw $s3, 44($s1) jr jest instrukcją typu R.
Konstrukcje kodu wysokiego poziomu Instrukcje if Instrukcje if/else Pętle while Pętle for
Instrukcja If C Code MIPS assembly code # $s0 = f, $s1 = g, $s2 = h if (i == j) f = g + h; f = f – i; MIPS assembly code # $s0 = f, $s1 = g, $s2 = h # $s3 = i, $s4 = j
Instrukcja If C Code MIPS assembly code if (i == j) f = g + h; f = f – i; MIPS assembly code # $s0 = f, $s1 = g, $s2 = h # $s3 = i, $s4 = j bne $s3, $s4, L1 add $s0, $s1, $s2 L1: sub $s0, $s0, $s3 W asemblerze mamy przeciwny przypadek (i != j) niż w kodzie wysokiego poziomu (i == j)
Instrukcja If/Else C Code MIPS assembly code if (i == j) f = g + h; f = f – i; MIPS assembly code
Instrukcja If/Else C Code MIPS assembly code if (i == j) f = g + h; f = f – i; MIPS assembly code # $s0 = f, $s1 = g, $s2 = h # $s3 = i, $s4 = j bne $s3, $s4, L1 add $s0, $s1, $s2 j done L1: sub $s0, $s0, $s3 done:
Pętle While C Code MIPS assembly code // oblicza potęgę // x takiego wyrażenia 2x = 128 int pow = 1; int x = 0; while (pow != 128) { pow = pow * 2; x = x + 1; } MIPS assembly code W asemblerze mamy przeciwny przypadek (pow == 128) niż w kodzie wysokiego poziomu (pow != 128).
Pętle While C Code MIPS assembly code // oblicza potęgę // x takiego wyrażenia 2x = 128 int pow = 1; int x = 0; while (pow != 128) { pow = pow * 2; x = x + 1; } MIPS assembly code # $s0 = pow, $s1 = x addi $s0, $0, 1 add $s1, $0, $0 addi $t0, $0, 128 while: beq $s0, $t0, done sll $s0, $s0, 1 addi $s1, $s1, 1 j while done: W asemblerze mamy przeciwny przypadek (pow == 128) niż w kodzie wysokiego poziomu (pow != 128).
Pętle For for (inicjalizacja; warunek; operacja pętli) instrukcja initialization: wykonuje się przed rozpoczęciem pętli condition: jest sprawdzany na początku każdej iteracji operacja pętli: wykonuje się na końcu każdej iteracji instrukcja: wykonuje się każdorazowo jeśli warunek jest spełniony
Pętle For Kod wysokiego poziomu MIPS assembly code // dodawanie liczb od 0 do 9 int sum = 0; int i; for (i=0; i!=10; i = i+1) { sum = sum + i; } MIPS assembly code # $s0 = i, $s1 = sum
Pętle For C Code MIPS assembly code // dodawanie liczb od 0 do 9 int sum = 0; int i; for (i=0; i!=10; i = i+1) { sum = sum + i; } MIPS assembly code # $s0 = i, $s1 = sum addi $s1, $0, 0 add $s0, $0, $0 addi $t0, $0, 10 for: beq $s0, $t0, done add $s1, $s1, $s0 addi $s0, $s0, 1 j for done:
Porównanie mniejsze niż C Code // dodawanie potegi 2 od 1 do 100 int sum = 0; int i; for (i=1; i < 101; i = i*2) { sum = sum + i; } MIPS assembly code
Porównanie mniejsze niż MIPS assembly code # $s0 = i, $s1 = sum addi $s1, $0, 0 addi $s0, $0, 1 addi $t0, $0, 101 loop: slt $t1, $s0, $t0 beq $t1, $0, done add $s1, $s1, $s0 sll $s0, $s0, 1 j loop done: C Code // dodawanie potegi 2 od 1 do 100 int sum = 0; int i; for (i=1; i < 101; i = i*2) { sum = sum + i; } $t1 = 1 if i < 101
Tablice Dostęp do dużej liczby podobnych danych Index: dostęp do każdego elementu Size: liczba elementów
Tablice 5-elementowa tablica Adres bazowy = 0x12348000 (adres pierwszego elementu, array[0]) Pierwszy krok dostępu do tablicy: załadować adres bazowy do rejestru
Dostęp do tablic // C Code int array[5]; array[0] = array[0] * 2; array[1] = array[1] * 2;
Dostęp do tablicy // C Code int array[5]; array[0] = array[0] * 2; array[1] = array[1] * 2; # MIPS assembly code # $s0 = adres bazowy tablicy lui $s0, 0x1234 # 0x1234 w wyższej połowie $s0 ori $s0, $s0, 0x8000 # 0x8000 w niższej połowie $s0 lw $t1, 0($s0) # $t1 = array[0] sll $t1, $t1, 1 # $t1 = $t1 * 2 sw $t1, 0($s0) # array[0] = $t1 lw $t1, 4($s0) # $t1 = array[1] sw $t1, 4($s0) # array[1] = $t1
Tablice wykorzystujące pętle // C Code int array[1000]; int i; for (i=0; i < 1000; i = i + 1) array[i] = array[i] * 8; # MIPS assembly code # $s0 = adres bazowy tablicy, $s1 = i
Tablice wykorzystujące tablice # MIPS assembly code # $s0 = array base address, $s1 = i # initialization code lui $s0, 0x23B8 # $s0 = 0x23B80000 ori $s0, $s0, 0xF000 # $s0 = 0x23B8F000 addi $s1, $0, 0 # i = 0 addi $t2, $0, 1000 # $t2 = 1000 loop: slt $t0, $s1, $t2 # i < 1000? beq $t0, $0, done jeśli nie to wtedy sll $t0, $s1, 2 # $t0 = i * 4 (byte offset) add $t0, $t0, $s0 # adres array[i] lw $t1, 0($t0) # $t1 = array[i] sll $t1, $t1, 3 # $t1 = array[i] * 8 sw $t1, 0($t0) # array[i] = array[i] * 8 addi $s1, $s1, 1 # i = i + 1 j loop # repeat done:
Kody ASCII Każdy znak ma unikalną wartość American Standard Code for Information Interchange Każdy znak ma unikalną wartość Np., S = 0x53, a = 0x61, A = 0x41 Małe litery i duże różnią się o 0x20 (32)
Lista znaków ASCII
Wywołanie funkcji Caller: wywołująca funkcja(w tym przypadku, main) Callee: wywoływana funkcja (w tym przypadku , sum) C Code void main() { int y; y = sum(42, 7); ... } int sum(int a, int b) return (a + b);
Konwencja Funkcji Caller: Callee: przekazuje argumenty do callee wykonuje skok do callee Callee: wykonuje funkcje zwraca wynik do caller Wraca do punktu wywołania nie może nadpisywać rejestrów albo pamięci wykorzystywanych przez caller
MIPS konwencje funkcji Conventions Wywołanie funkcji: skok i link (jal) Powrót z funkcji: skok pod adres rejestru (jr) Argumenty: $a0 - $a3 Zwracana wartość: $v0
Wywołanie funkcji C Code MIPS assembly code int main() { simple(); a = b + c; } void simple() { return; MIPS assembly code 0x00400200 main: jal simple 0x00400204 add $s0, $s1, $s2 ... 0x00401020 simple: jr $ra void znaczy że nie jest zwracana wartość
Wywołanie funkcji C Code MIPS assembly code jal: skok do simple int main() { simple(); a = b + c; } void simple() { return; MIPS assembly code 0x00400200 main: jal simple 0x00400204 add $s0, $s1, $s2 ... 0x00401020 simple: jr $ra jal: skok do simple $ra = PC + 4 = 0x00400204 jr $ra: skok pod adres $ra (0x00400204)
Argumenty wejściowe & Zwracanie wartości MIPS konwencja: Wartości argumentów: $a0 - $a3 Zwracana wartość: $v0
Argumenty wejściowe & Zwracanie wartości C Code int main() { int y; ... y = diffofsums(2, 3, 4, 5); // 4 argumenty } int diffofsums(int f, int g, int h, int i) int result; result = (f + g) - (h + i); return result; // zwracana wartość
Argumenty wejściowe & Zwracanie wartości MIPS assembly code # $s0 = y main: ... addi $a0, $0, 2 # argument 0 = 2 addi $a1, $0, 3 # argument 1 = 3 addi $a2, $0, 4 # argument 2 = 4 addi $a3, $0, 5 # argument 3 = 5 jal diffofsums # call Function add $s0, $v0, $0 # y = returned value # $s0 = result diffofsums: add $t0, $a0, $a1 # $t0 = f + g add $t1, $a2, $a3 # $t1 = h + i sub $s0, $t0, $t1 # result = (f + g) - (h + i) add $v0, $s0, $0 # put return value in $v0 jr $ra # return to caller
Argumenty wejściowe & Zwracanie wartości MIPS assembly code # $s0 = result diffofsums: add $t0, $a0, $a1 # $t0 = f + g add $t1, $a2, $a3 # $t1 = h + i sub $s0, $t0, $t1 # result = (f + g) - (h + i) add $v0, $s0, $0 # put return value in $v0 jr $ra # return to caller diffofsums nadpisuje 3 registery: $t0, $t1, $s0 diffofsums może używać stosu do tymczasowego przechowywania stanu rejestru
Stos Pamięć wykorzystywana do tymczasowego przechowywania zmiennych Jak stos talerzy, kolejka last-in-first-out (LIFO) Rozwija się: wykorzystuje więcej pamięci, kiedy potrzeba zajmuje więcej miejsca Zakontraktowanie: wykorzystuje mniej pamięci kiedy nie jest potrzebna
Stos Rośnie w dół (od większych do mniejszych adresów pamięci) Wskaźnik stosu: $sp wskazuje na szczyt stosu
W jaki sposób funkcje wykorzystują stos Wywoływane funkcje nie mogą powodować zamazywania rejestrów Ale diffofsums nadpisuje 3 rejestry: $t0, $t1, $s0 # MIPS assembly # $s0 = result diffofsums: add $t0, $a0, $a1 # $t0 = f + g add $t1, $a2, $a3 # $t1 = h + i sub $s0, $t0, $t1 # result = (f + g) - (h + i) add $v0, $s0, $0 # put return value in $v0 jr $ra # return to caller
Przechowywanie stanu rejestru na stosie # $s0 = result diffofsums: addi $sp, $sp, -12 # make space on stack # to store 3 registers sw $s0, 8($sp) # save $s0 on stack sw $t0, 4($sp) # save $t0 on stack sw $t1, 0($sp) # save $t1 on stack add $t0, $a0, $a1 # $t0 = f + g add $t1, $a2, $a3 # $t1 = h + i sub $s0, $t0, $t1 # result = (f + g) - (h + i) add $v0, $s0, $0 # put return value in $v0 lw $t1, 0($sp) # restore $t1 from stack lw $t0, 4($sp) # restore $t0 from stack lw $s0, 8($sp) # restore $s0 from stack addi $sp, $sp, 12 # deallocate stack space jr $ra # return to caller
Stos podczas wywołania funkcji diffofsums
Rejestry Preserved Nonpreserved Callee-zabezpieczone Caller-zabezpieczone $s0-$s7 $t0-$t9 $ra $a0-$a3 $sp $v0-$v1 stos powyżej $sp stos poniżej $sp
Zagnieżdżone wywołania funkcji proc1: addi $sp, $sp, -4 # make space on stack sw $ra, 0($sp) # save $ra on stack jal proc2 ... lw $ra, 0($sp) # restore $ra from stack addi $sp, $sp, 4 # deallocate stack space jr $ra # return to caller
Przechowywanie zapisanych rejestrów na stosie # $s0 = result diffofsums: addi $sp, $sp, -4 # make space on stack to # store one register sw $s0, 0($sp) # save $s0 on stack # no need to save $t0 or $t1 add $t0, $a0, $a1 # $t0 = f + g add $t1, $a2, $a3 # $t1 = h + i sub $s0, $t0, $t1 # result = (f + g) - (h + i) add $v0, $s0, $0 # put return value in $v0 lw $s0, 0($sp) # restore $s0 from stack addi $sp, $sp, 4 # deallocate stack space jr $ra # return to caller
Wywołanie rekursywne funkcji High-level code int factorial(int n) { if (n <= 1) return 1; else return (n * factorial(n-1)); }
Wywołanie rekursywne funkcji MIPS assembly code
Wywołanie rekursywne funkcji MIPS assembly code 0x90 factorial: addi $sp, $sp, -8 # make room 0x94 sw $a0, 4($sp) # store $a0 0x98 sw $ra, 0($sp) # store $ra 0x9C addi $t0, $0, 2 0xA0 slt $t0, $a0, $t0 # a <= 1 ? 0xA4 beq $t0, $0, else # no: go to else 0xA8 addi $v0, $0, 1 # yes: return 1 0xAC addi $sp, $sp, 8 # restore $sp 0xB0 jr $ra # return 0xB4 else: addi $a0, $a0, -1 # n = n - 1 0xB8 jal factorial # recursive call 0xBC lw $ra, 0($sp) # restore $ra 0xC0 lw $a0, 4($sp) # restore $a0 0xC4 addi $sp, $sp, 8 # restore $sp 0xC8 mul $v0, $a0, $v0 # n * factorial(n-1) 0xCC jr $ra # return
Stos podczas rekursywnego wywołania funkcji
Wywołanie funkcji-podsumowanie Caller wstawia argumenty do $a0-$a3 zapisuje stan potrzebnych rejestrów ($ra, może $t0-t9) jal callee Przywraca stan rejestrów Wynik zapisany w rejestrze $v0 Callee Zapisuje rejestry które mogą być nadpisane ($s0-$s7) Wykonuje działanie funkcji Wstawia wynik do$v0 jr $ra
Tryby adresowania W jaki sposób przekazujemy operandy adresów? Tylko przez rejestry Bezpośrednio Adresowanie bazowe PC-relatywne Pseudo bezpośrednie
Tryby adresowania Tylko przez rejestry Bezpośrednie Operandy znajdują się w rejestrach Przykład: add $s0, $t2, $t3 Przykład: sub $t8, $s1, $0 Bezpośrednie 16-bitowa wartość użyta jako operand Przykład: addi $s4, $t5, -73 Przykład: ori $t3, $t7, 0xFF
Tryby adresowania Bazowe adresowanie Opreand adresu jest tworzony: basowy adres + stała ze znakiem Przykład: lw $s4, 72($0) adres = $0 + 72 Przykład: sw $t2, -25($t1) adres = $t1 - 25
Tryby adresowania PC-relatywne adresowanie 0x10 beq $t0, $0, else 0x14 addi $v0, $0, 1 0x18 addi $sp, $sp, i 0x1C jr $ra 0x20 else: addi $a0, $a0, -1 0x24 jal factorial
Tryby adresowania Pseudo-bezpośrednie adresowanie 0x0040005C jal sum ... 0x004000A0 sum: add $v0, $a0, $a1
Jak kompilować&uruchomić program
Co jest przechowywane w pamięci? Instrukcje (zwane textem) Dane Globalne/statyczne: ulokowane przed programem Dynamczne: ulokowane razem z programem Jak wielka jest pamięć? Maksymalnie 232 = 4 gigabytes (4 GB) Od adresu 0x00000000 do 0xFFFFFFFF
MIPS Mapa Pamięci
Przykład programu: C Code int f, g, y; // global variables int main(void) { f = 2; g = 3; y = sum(f, g); return y; } int sum(int a, int b) { return (a + b);
Przykład programu: MIPS Assembly .data f: g: y: .text main: addi $sp, $sp, -4 # stack frame sw $ra, 0($sp) # store $ra addi $a0, $0, 2 # $a0 = 2 sw $a0, f # f = 2 addi $a1, $0, 3 # $a1 = 3 sw $a1, g # g = 3 jal sum # call sum sw $v0, y # y = sum() lw $ra, 0($sp) # restore $ra addi $sp, $sp, 4 # restore $sp jr $ra # return to OS sum: add $v0, $a0, $a1 # $v0 = a + b jr $ra # return int f, g, y; // global int main(void) { f = 2; g = 3; y = sum(f, g); return y; } int sum(int a, int b) { return (a + b);
Przykład Programu: Tabela Symboli Adres
Przykład Programu: Tabela Symboli Adres f 0x10000000 g 0x10000004 y 0x10000008 main 0x00400000 sum 0x0040002C
Przykład programu: Wykonanie
Przykład programu: W pamięci
Odds & Ends Pseudoinstrukcje Wyjątki Signed and unsigned instrukcje Instrukcje zmienno-przecinkowe
Pseudoinstrukcje Pseudoinstrukcja MIPS Instrukcje li $s0, 0x1234AA77 lui $s0, 0x1234 ori $s0, 0xAA77 clear $t0 add $t0, $0, $0 move $s1, $s2 add $s2, $s1, $0 nop sll $0, $0, 0
Wyjątki Niezaplanowana funkcja wywołuje obsługę wyjątków Spowodowana przez: Sprzęt, zwane przerwaniem np. klawiatura Oprogramowanie, zwane pułapką np. niezdefiniowaną instrukcją Kiedy występuje wyjątek, procesor: Zapamiętuje powód wyjątku Wykonuje skok do obsługi wyjątków (na adres instrukcji 0x80000180) Powrót do programu
Rejestry wyjątków Nie jest częścią rejestru pliku Przyczyna: Zapamiętuje przyczynę wyjątku EPC (wyjątek PC): Zapamiętuje PC gdzie wystąpił wyjątek EPC i Przyczyna: część koprocesora 0 Przenieś z Koprocesora 0 mfc0 $k0, EPC Przeniesienie kontekstu EPC do $k0
Przyczyny wyjątków Wyjątek Przyczyna Przerwanie sprzętowe 0x00000000 Wywołanie systemowe 0x00000020 Punkt przerwania / Dzielenie przez 0 0x00000024 Niezdefiniowana instrukcja 0x00000028 Arytmetyczne przepełnienie 0x00000030
Obsługa wyjątku Procesor zapisuje przyczynę wyjątku i PC wyjątku w przyczynie i EPC Procesor wykonuje skok do obsługi wyjątku (0x80000180) Obsługa wyjątku: Zapisuje stan rejestrów na stosie Odczytuje rejestr przyczyny (cause) mfc0 $k0, Cause Obsługuje wyjątek Przywraca stan rejestrów Powrót do programu mfc0 $k0, EPC jr $k0
Instrukcje ze znakiem&bez znaku Dodawanie i odejmowanie Mnożenie i dzielenie Set less than (ustaw 1 jeśli jest a<b)
Dodawanie & Odejmowanie Ze znakiem: add, addi, sub Niektóre operacje w wersji bez znaku Procesor obsługuje wyjątek dotyczący przepełnienia Bez znaku: addu, addiu, subu Nie obsługuje wyjątku przepełnienia Uwaga: addiu rozszerzenie znaku stałej //sign-extends the immediate
Mnożenie & Dzielenie Ze znakiem: mult, div Bez znaku: multu, divu
Set Less Than Ze znakiem: slt, slti Bez znaku: sltu, sltiu ///////////////////////// Note: sltiu sign-extends the immediate before comparing it to the register
Ładowanie Ze znakiem: Bez znaku: Rozszerzenie znaku do stworzenia 32-bitowej wartości załadowywanej do rejestru Załaduj pół słowa: lh Załaduj bajt: lb Bez znaku: Uzupełnienie zerami dla stworzenia 32-bitowej wartości Załaduj pół słowa bez znaku: lhu Załaduj bajt: lbu
Instrukcje zmienno-przecinkowe Koprocesor zmienno-przecinkowy (Koprocesor 1) 32 32-bitowe zmienno-przecinkowe rejestry ($f0-$f31) Podwójnej-precyzji wartości przechowywane w dwóch zmienno przecinkowych rejestrach np., $f0 i $f1, $f2 i $f3, itd. Rejestry podwójnej precyzji zmienno-przecinkowe: $f0, $f2, $f4, itp.
Instrukcje zmienno-przecinkowe Nazwa Numer rejestru Wykorzystanie $fv0 - $fv1 0, 2 Zwraca wartości $ft0 - $ft3 4, 6, 8, 10 Tymczasowe zmienne $fa0 - $fa1 12, 14 Argumenty funkcji $ft4 - $ft8 16, 18 $fs0 - $fs5 20, 22, 24, 26, 28, 30 Zapisane zmienne
Format instrukcji typu F Instruction Format Opcode = 17 (0100012) Pojedynczej precyzji: cop = 16 (0100002) add.s, sub.s, div.s, neg.s, abs.s, etc. Podwójnej precyzji: cop = 17 (0100012) add.d, sub.d, div.d, neg.d, abs.d, etc. 3 operandy rejestrów: fs, ft: operandy źródłowe fd: operand docelowy
Zmienno-przecinkowe rozgałęzienia Ustaw/wyczyść flaga warunku: fpcond Equality: c.seq.s, c.seq.d Less than: c.lt.s, c.lt.d Less than or equal: c.le.s, c.le.d Warunek rozgałęzienia bclf: rozgałęzienie jeśli fpcond jest FALSE bclt: rozgałęzienie jeśli fpcond jest TRUE Ładowanie i przechowywanie lwc1: lwc1 $ft1, 42($s1) swc1: swc1 $fs2, 17($sp)
Zagadnienia w wykładu 1. Co to jest kod maszynowy? 2. Instrukcje typu R, I, J 3. Kod ASCII. 4. Pojęcie stosu. Zasada pobierania i odczytu. Do czego jest wykorzystywany. 5. Co to są pseudoinstrukcje. Podaj przykłady. 6. Przerwania. Co to jest, rodzaje przerwań. Zasada obsługi przerwań.