2.1. W architekturze MIPS, na liście instrukcji widzimy dwie instrukcje dotyczące funkcji: .text main: la $a0, string1 # drukuj pierwszy łańcuch



Podobne dokumenty
4 Literatura. c Dr inż. Ignacy Pardyka (Inf.UJK) ASK MP.01 Rok akad. 2011/ / 24

Procedury. int mult (int mcand, int mlier){ int product = 0; while (mlier > 0) { product = product + mcand; mlier = mlier -1; } return product; }

Programowanie Niskopoziomowe

Zadanie Zaobserwuj zachowanie procesora i stosu podczas wykonywania następujących programów

Architektura systemów komputerowych Laboratorium 7 Symulator SMS32 Stos, Tablice, Procedury

Język programowania: Lista instrukcji (IL Instruction List)

Wstęp do informatyki. Architektura co to jest? Architektura Model komputera. Od układów logicznych do CPU. Automat skończony. Maszyny Turinga (1936)

Architektura komputerów

Procesor ma architekturę rejestrową L/S. Wskaż rozkazy spoza listy tego procesora. bgt Rx, Ry, offset nand Rx, Ry, A add Rx, #1, Rz store Rx, [Rz]

Programowanie Niskopoziomowe

Architektura systemów komputerowych Laboratorium 14 Symulator SMS32 Implementacja algorytmów

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

ZASADY PROGRAMOWANIA KOMPUTERÓW

Architektura komputerów

Rozszerzalne kody operacji (przykład)

Obliczenia na stosie. Wykład 9. Obliczenia na stosie. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 266 / 303

PROGRAMOWANIE NISKOPOZIOMOWE. Adresowanie pośrednie rejestrowe. Stos PN.04. c Dr inż. Ignacy Pardyka. Rok akad. 2011/2012

Podstawy programowania w języku C++

Podstawy programowania 2. Przygotował: mgr inż. Tomasz Michno

JAK DZIAŁAJĄ FUNKCJE PODZIAŁ PAMIĘCI

Wieczorowe Studia Licencjackie Wrocław, Wykład nr 6 (w oparciu o notatki K. Lorysia, z modyfikacjami) Sito Eratostenesa

Struktura i działanie jednostki centralnej

Dodatek B. Zasady komunikacji z otoczeniem w typowych systemach komputerowych

Rejestry procesora. Nazwa ilość bitów. AX 16 (accumulator) rejestr akumulatora. BX 16 (base) rejestr bazowy. CX 16 (count) rejestr licznika

Podstawy programowania 2. Temat: Funkcje i procedury rekurencyjne. Przygotował: mgr inż. Tomasz Michno

Dynamiczny przydział pamięci w języku C. Dynamiczne struktury danych. dr inż. Jarosław Forenc. Metoda 1 (wektor N M-elementowy)

Wstęp do programowania. Procedury i funkcje. Piotr Chrząstowski-Wachtel

Wstęp do programowania

Język programowania: Lista instrukcji (IL Instruction List) Wykład w ramach przedmiotu: Sterowniki programowalne Opracował dr inż. Jarosław Tarnawski

Lab 9 Podstawy Programowania

Rekurencja (rekursja)

Podstawy programowania. Wykład: 4. Instrukcje sterujące, operatory. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Programowanie komputerowe. Zajęcia 3

Układ sterowania, magistrale i organizacja pamięci. Dariusz Chaberski

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

Lista Rozkazów: Język komputera

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Układ wykonawczy, instrukcje i adresowanie. Dariusz Chaberski

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

PARADYGMATY PROGRAMOWANIA Wykład 4

DYNAMICZNE PRZYDZIELANIE PAMIECI

2 Literatura. c Dr inż. Ignacy Pardyka (Inf.UJK) ASK MP.02 Rok akad. 2011/ / 24

lekcja 8a Gry komputerowe MasterMind

INFORMATYKA W SZKOLE. Podyplomowe Studia Pedagogiczne. Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Przykładowe pytania DSP 1

IX. Wskaźniki.(3 godz.)

Podstawy Programowania C++

Przydział pamięci. Teoria kompilacji. Dr inż. Janusz Majewski Katedra Informatyki

MOŻLIWOŚCI PROGRAMOWE MIKROPROCESORÓW

Wstęp do wskaźników w języku ANSI C

kiedy znowu uzyska sterowanie, to podejmuje obliczenie od miejsca, w którym poprzednio przerwała, i z dotychczasowymi wartościami zmiennych,

Elementy języka C. ACprogramislikeafastdanceonanewlywaxeddancefloorbypeople carrying razors.

typ_zwracanej_wartości nazwa_funkcji(lista deklaracji argumentów) { ciało(treść) funkcji return Val; //zwracana wartość }

List s a R ozkazó z w: w Ję J z ę y z k y k k o k mp o u mp t u er e a a ( cd c. d )

Programowanie w asemblerze MIPSa

Organizacja typowego mikroprocesora

Wstęp. do języka C na procesor (kompilator RC51)

ALGORYTMY I STRUKTURY DANYCH

Algorytmy i język C++

Programowanie komputerowe. Zajęcia 2

część 8 wskaźniki - podstawy Jarosław Gramacki Instytut Informatyki i Elektroniki Podstawowe pojęcia


Wprowadzenie. Dariusz Wawrzyniak. Miejsce, rola i zadania systemu operacyjnego w oprogramowaniu komputera

Dynamiczne struktury danych

Ćwiczenie nr 6. Programowanie mieszane

Wstęp do informatyki. Maszyna RAM. Schemat logiczny komputera. Maszyna RAM. RAM: szczegóły. Realizacja algorytmu przez komputer

Wprowadzenie. Dariusz Wawrzyniak. Miejsce, rola i zadania systemu operacyjnego w oprogramowaniu komputera

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 2. Karol Tarnowski A-1 p.

Spis treœci. Co to jest mikrokontroler? Kody i liczby stosowane w systemach komputerowych. Podstawowe elementy logiczne

Programowanie obiektowe

Tablice, funkcje - wprowadzenie

Systemy operacyjne. Wprowadzenie. Wykład prowadzą: Jerzy Brzeziński Dariusz Wawrzyniak

Języki i metodyka programowania. Wskaźniki i tablice.

Opis: Instrukcja warunkowa Składnia: IF [NOT] warunek [AND [NOT] warunek] [OR [NOT] warunek].

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Architektura komputerów. Asembler procesorów rodziny x86

Sprzęt i architektura komputerów

UTK Można stwierdzić, że wszystkie działania i operacje zachodzące w systemie są sterowane bądź inicjowane przez mikroprocesor.

iii. b. Deklaracja zmiennej znakowej poprzez podanie znaku

Struktury. Przykład W8_1

1.1 Definicja procesu

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Ćwiczenie nr 6. Poprawne deklaracje takich zmiennych tekstowych mogą wyglądać tak:

Ćwiczenie nr 3. Wyświetlanie i wczytywanie danych

Zaprojektować i zaimplementować algorytm realizujący następujące zadanie.

Algorytm. a programowanie -

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Wstęp do programowania

Wskaźniki. Programowanie Proceduralne 1

Programowanie obiektowe

Zasady programowania Dokumentacja

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Podstawy programowania w języku C++

ARCHITEKTURA SYSTEMÓW KOMPUTEROWYCH

A Machine Architecture that is Really Intuitive and Easy. Dane: notacja dwójkowa, zapis w kodzie dopełnieniowym

Wykład 2 Składnia języka C# (cz. 1)

Podstawy programowania w języku C++

Transkrypt:

ARCHITEKTURA SYSTEMÓW KOMPUTEROWYCH: Instrukcja do laboratorium 4, (2x2h) Opracowanie i prowadzenie: dr inż. Ignacy Pardyka, Uniwersytet Jana Kochanowskiego w Kielcach Temat: Architektura MIPS: wywołanie funkcji, stos, złożone struktury danych symulator: MARS 1. Wstęp W ramach niniejszego laboratorium, najpierw poznajemy mechanizm wywoływania funkcji, stosowany w architekturze MIPS. Aby zrozumieć ten mechanizm, musimy poznać i zrozumieć pojęcie ramki stosu. Szczególne miejsce, w programowaniu komputerów, zajmują algorytmy rekurencyjne, dlatego ważne jest by rozumieć, w jaki sposób należy prawidłowo organizować program, w którym występują rekurencyjne wywołania funkcji. W języku asemblera stos odgrywa ważną rolę. Poznamy też zasadę przechowywania i przetwarzania złożonych struktur danych. 2. Instrukcje wywołania funkcji i powrotu 2.1. W architekturze MIPS, na liście instrukcji widzimy dwie instrukcje dotyczące funkcji: a) instrukcję jal, która określa operację przekazania sterowania do funkcji (ze śladem); instrukcja ta nakazuje, aby procesor, zanim przekaże sterowanie do wskazanej funkcji (wykonując operację skoku), zapamiętał w rejestrze $ra adres instrukcji, występującej w programie tuż za instrukcją jal (czyli adres powrotu z funkcji do miejsca wywołania). b) instrukcję jr, określającą operację powrotu z funkcji do programu, który ją wywołał; instrukcja ta, faktycznie, nakazuje procesorowi wykonanie operacji skoku bezwarunkowego pod adres, który aktualnie jest w rejestrze $ra (return address). 2.2. Zadanie 1 a) Wprowadzić następujący program string1: string2:.data.asciiz "Hello world!\n".asciiz "Drugi napis\n".text main: la $a0, string1 drukuj pierwszy łańcuch jal function teraz wywołać funkcję function() bez argumentów. stosujemy instrukcję jal, która nakazuje zapamietać w $ra adres instrukcji występującej tuż za jal, a następnie wykonać skok do pierwszej instrukcji w funkcji $a0 zawiera wskaźnik do pierwszego z łańcuchów więc drukować go li $v0, 10 exit Ta funkcja jest wywoływana z main(). Drukuje łańcuch i zwraca sterowanie do wywołującego. function: la $a0, string2 drukuj łańcuch powrót do instrukcji wskazywanej przez $ra str. 1/8

b) Przeprowadzić asemblację i wykonać program krokowo. Proszę zaobserwować wykonanie operacji wskazywanej w instrukcji jal: jaki adres jest zapamietany w $ra, jaki jest adres początkowy funkcji? Zaobserwować zakończenie funkcji: jaki jest adres w $ra, jaki jest adres instrukcji, która będzie realizowana po instrukcji? 3. Organizacja funkcji 3.1. Pisząc (w języku asemblera) funkcje i programy, w których występują wywołania funkcji, należy przestrzegać pewnych reguł: a) Wywołujący funkcję powinien mieć możliwość przekazania jej listy argumentów (kolejność może być istotna). W ciele funkcji, dostęp do argumentów powinien być taki, jak do zmiennych lokalnych. b) Funkcja powinna mieć możliwość tworzenia własnych zmiennych. c) Wywołujący funkcję (ang. caller) i wywołana funkcja (ang. callee) muszą przestrzegać uzgodnień odnośnie do korzystania z rejestrów procesora, tak aby nie było obaw, że mogą wystąpić kolizje, prowadzące do utraty danych przechowywanych w rejestrach. d) Funkcja musi mieć możliwość zwrócenia (wywołującemu) wartości, będącej rezultatem jej działania. e) Jeśli planujemy korzystać z funkcji do implementacji algorytmów rekurencyjnych, to trzeba tak napisać funkcję, aby funkcja mogła wywołać samą siebie bez ograniczenia głębokości zagnieżdżenia. 3.2. Rejestry używane do przekazania argumentów i wartości zwracanych a) W architekturze MIPS, standardowo, do przekazania argumentów do funkcji, stosuje się rejestry $a0, $a1, $a2, $a3, $a4 jeśli trzeba przekazać więcej argumentów, to należy je przekazać poprzez pamięć (stos). b) Rezultat powinien być, standardowo, zwracany w rejestrach $v0, $v1 (wartość typu doubleword jest zwracana w parze rejestrów). 3.3. Podział odpowiedzialności za stan rejestrów CPU a) odpowiedzialność wywołującego: przed wywołaniem funkcji, należy zachować (w pamięci) stan tych spośród rejestrów $t0 do $t7, których zawartość jest istotna, i chcemy mieć pewność, że nie zostanie zmieniona przez funkcję; analogicznie, należy zadbać o stan rejestrów $a0 do $a3, oraz $v0, $v1. b) odpowiedzialność wywoływanego: funkcja musi, przede wszystkim, zachować stan (w pamięci) tych spośród rejestrów $s0.. $s7, $fp, $ra, które mają być używane przez tę funkcję, w celu przechowywania w nich nowych wartości. 3.4. Stos a) Stos jest strukturą LIFO (ang. last in first out) zorganizowaną w pamięci, wskazywaną przez rejestr $sp (stack pointer). Dane, które trzeba przechować na stosie, odkłada się na wierzchołek (rejestr $sp zawiera adres danych leżących na wierzchołku stosu). W architekturze MIPS, stos rośnie w kierunku adresów malejących, więc przed odłożeniem na stos, należy dekrementować rejestr $sp (aby nie nadpisać danych leżących na wierzchołku). str. 2/8

b) Stos jest używany przez wywołującego funkcję do zachowania zawartości rejestrów (w ramach swoich odpowiedzialności za stan rejestrów), a także do przekazania argumentów do funkcji (gdy jest ich więcej niż cztery). c) Stos jest używany przez funkcję do przechowania zawartości rejestrów (w ramach swoich odpowiedzialności za stan rejestrów), a także do przechowywania swoich zmiennych lokalnych. d) Operacja odkładania na stos (ang. push), np. subu $sp, $sp, 4 sw $t1, ($sp) dekrementacja $sp zapamiętanie zawartości rejestru $t1 na stosie e) Operacja zdejmowania ze stosu (ang. pop), np. lw $t3, ($sp) addu $sp, $sp, 4 pobranie słowa wskazywanego przez $sp aktualizacja wskaźnika wierzchołka stosu 3.5. Ramka stosu a) Funkcja tworzy na stosie obszar zwany ramką stosu (ang. stack frame), gdzie dla swoich potrzeb przechowuje: argumenty przekazane przez wywołującego adres powrotny (adres ten jest zawarty w rejestrze $ra, i byłby zniszczony, gdyby w ciele funkcji nastąpiło wywołanie innej funkcji) zawartość rejestrów, które ma zachować w ramach swojej odpowiedzialności za stan rejestrów zmienne lokalne (deklarowane w funkcji) zawartość rejestrów, które ma zachować wywołujący jeśli funkcja wywołuje funkcję. b) Przykładowa organizacja podstawowej, 24-bajtowej, ramki stosu (stos rośnie w kierunku adresów malejących; z lewej strony pokazano offset względem wierzchołka wskazywanego przez $sp): c) Przykład fragmentu prologu funkcji (początkowe instrukcje dotyczące ramki): function: subu $sp, $sp, 24 miejsce w ramce stosu dla 24 bajtów sw $ra, 20($sp) zachować $ra gdy funkcja ma wywoływać funkcję d) Przykład fragmentu epilogu funkcji (końcowe instrukcje): lw $ra, 20(sp) addu $sp, $sp, 24 pobranie adresu powrotnego niszczenie ramki stosu powrót z funkcji str. 3/8

3.6. Zadanie 2 a) Wprowadzić następujący program string1: string2:.data.asciiz "Hello world!\n".asciiz "Drugi tekst\n".text main: subu $sp, $sp, 24 program główny, main(), sam jest funkcją sw $ra, 20($sp) więc najpierw trzeba utworzyć ramkę stosu la $a0, string1 drukować pierwszy łańcuch sw $a0, 0($sp) zachować w ramce stan rejestru $a0 jal function wywołać funkcję o nazwie function lw $a0, 0($sp) odtworzyć rejestr $a0 li $v0, 10 powtórnie drukować pierwszy łańcuch exit (tutaj nie ma potrzeby niszczyc ramki) function: subu $sp, $sp, 24 utworzyć ramkę stosu sw $ra, 20($sp) la $a0, string2 lw $ra, 20($sp) addu $sp, $sp, 24 drukować drugi łańcuch zrekonstruować adres powrotny zniszczyć ramkę stosu powrót do wywołującego b) Wykonać program krokowo; prześledzić operacje na stosie, zmieniający się stan stosu, zrozumiec i zapamiętać, jak działa stos, jak utworzyć ramkę stosu, jak należy organizować funkcje. 4. Zmienne lokalne 4.1. Zmienne lokalne funkcji przechowuje się na stosie, w ramce stosu. Zmienne te mają więc charakter dynamiczny, gdyż w odróżnieniu od zmiennych statycznych (które są przechowywane w segmencie.data), zmienne lokalne nie zajmują pamięci przez cały czas wykonywania programu: istnieją (i można w nich przechowywać wartości) od chwili utworzenia ramki do czasu zniszczenia ramki stosu. a) W prologu funkcji, zmienne lokalne tworzy się następująco: należy zwiększyć rozmiar ramki stosu tak, aby utworzyć miejsce do przechowania w niej wszystkich zmiennych lokalnych należy zdecydować, gdzie w ramce stosu mają rezydować poszczególne zmienne (jaki jest ich adres względem początku ramki stosu). b) Do adresowania zmiennych lokalnych można wykorzystać rejestr $fp (wskaźnika ramki stosu), do którego można wpisać adres początkowy ramki (oczywiście, przed tą operacją, należy zachować na stosie zastaną zawartość rejestru $fp, a w epilogu funkcji zrekonstruować $fp). str. 4/8

c) Przykładowa, rozszerzona, ramka stosu z miejscem na zachowanie stanu rejestrów i zmienne lokalne: 4.2. Zadanie 3 a) Wprowadzić następujący program.data prompt:.asciiz "Prosze napisac jakis tekst (jedna linia): " resultstr:.asciiz "Najczesciej wystepujacy znak w tym tekscie, to " resultchar:.asciiz "X".text main: drukuj komunikat (polecenie) la $a0, prompt jal mostfreqchar sb $v0, resultchar la $a0, resultstr la $a0, resultchar li $v0, 10 wyznacz najczęściej występujący znak zapisz ten znak w resultchar drukuj resultstr drukuj znak najczęściej występujący exit Funkcja mostfreqchar nie ma argumentów, wczytuje linię tekstu do tablicy znaków, umieszczonej na stosie, a następnie wyznacza najczęściej występujący znak. char mfc; znak najczęściej występujący (rezultat) char ch; znak, którego wystąpienia są zliczane int cnt; licznik występowania bieżącego znaku int mfccnt = 0; aktualnie największa liczba wystapień for (int iptr = pointer_do line[0]; znak_wskazywany_przez iptr!= NUL; iptr++) { ch = znak_wskazywany_przez iptr; zacząć zliczać przypadki występowania tego znaku cnt = 0; start licznika for (int jptr = pointer_do line[0]; znak_wskazywany_przez jptr!= NUL; jptr++) { if (znak_wskazywany_przez jptr == ch) cnt++; zwiększyć licznik występowania } if (cnt > mfccnt) { ten znak wystąpił, jak dotąd, najczęściej mfccnt = cnt; zaktualizować licznik mfccnt mfc = ch; zapamiętać ten znak, występujący jak dotąd, najczęściej } } return(mfc); str. 5/8

Algorytm jest mało efektywny, ale tutaj nie jest to istotne, bo liczba znaków w linii jest niewielka wykorzystywane rejestry: int iptr => $a0 int jptr => $a1 int cnt => $a2 int ch => $a3 int mfc => $v0, wartość zwracana int mfccnt => $v1 char line[200] => 24($sp), rozmiar 200 bajtów pointer to line[0] => $t1 char at jptr => $t0 mostfreqchar: subu $sp, $sp, 224 miejsce na ramkę stosu sw $ra, 20($sp) li $v1, 0 mfccnt = 0 add $t1, $sp, 24 zapisać w $t1 wskaźnik do tablicy line move $a0, $t1 argument: $a0 <= $t1 li $v0, 8 usługa: read_string li $a1, 200 maksymalna liczba znaków w linii: 200 move $a0, $t1 iptr = adres line[0] iloop: lb $a3, ($a0) ch = znak_wskazywany_przez iptr beqz $a3, endiloop przerwać gdy ch jest NUL li $a2, 0 cnt=0 move $a1, $t1 jptr = adres line[0] jloop: lb $t0, ($a1) jch = znak_wskazywany_przez jptr beqz $t0, endjloop przerwać, gdy jch jest NUL bne $t0, $a3, jincr skok, gdy ch!= jch addi $a2, $a2, 1 kolejne wystąpienie, więc cnt++ jincr: addi $a1, $a1, 1 jptr++ b jloop zapętlić dla nowej wartości jptr endjloop: bgt $v1, $a2, iincr if mfccnt > cnt, pominąć aktualizację mfccnt move $v1, $a2 aktualizacja: mfccnt = cnt move $v0, $a3 aktualizacja: mfc = ch iincr: addi $a0, $a0, 1 iptr++ b iloop zapętlić dla nowej wartości iptr endiloop: endoffunc: lw $ra, 20($sp) odtworzenie adresu powrotnego addu $sp, $sp, 224 zniszczenie ramki stosu powrót z funkcji b) Program ten przechowuje w ramce stosu tablicę znaków, jako zmienną lokalną. W języku C, odpowiadałoby to następującej deklaracji funkcji: char mostfreqchar(void) { char line[200]; lokalna tablica 200 znaków... } c) Przeanalizować wprowadzony program, starając się zrozumieć algorytm i metodę jego implementacji w języku asemblera, a następnie program poddać asemblacji i wykonać. d) Wykonując krokowo, zaobserwować stan stosu tuż przed wywołaniem funkcji, podczas realizacji prologu, a następnie podczas realizacji epilogu funkcji. Odnaleźć, na stosie, tablicę wprowadzanych znaków linii. W sprawozdaniu opisać spostrzeżenia i przedstawić wnioski. str. 6/8

5. Rekurencja 5.1. Funkcje rekurencyjne muszą być tak konstruowane, aby mogły wywoływać same siebie, dlatego należy: a) w ramce stosu zachować stan rejestrów, zgodnie z odpowiedzialnością wywołującego b) w ramce stosu zachować stan rejestrów, zgodnie z odpowiedzialnością wywoływanego c) w ramce stosu przechowywać zmienne lokalne 5.2. Przykładowa funkcja rekurencyjna wyznaczająca silnię a) zapis w pseudokodzie int fact(int X) { int result; if (X == 1) return(1); result = X * fact(x-1); return(x); } b) Zmienna lokalna X jest jednocześnie argumentem funkcji, więc należy ją zachować w ramce stosu dla potrzeb wykonania mnożenia przez zwrócony rezultat. 5.3. Zadanie 4 a) Wprowadzić kod programu.text main: subu $sp, $sp, 24 utworzyć standardową ramkę sw $ra, 20($sp) li $a0, 6 jal factorial move $a0, $v0 li $v0, 1 li $v0, 10 wywołać factorial(6) rezultat jest w $v0, wydrukować go exit factorial: subu $sp, $sp, 24 utworzyć standardową ramkę 24-bajtową sw $ra, 20($sp) zachować adres powrotny bo będzie wywołanie rekurencyjne. sw $a0, 0($sp) zachować argument wywołania, bo będzie potrzebny do mnożenia. bgt $a0, 1, notbasecase if arg > 1, not the base case, skip basecase: li $v0, 1 przypadek bazowy: fact(1) = 1 b factreturn zwrócić rezultat. notbasecase: subi $a0, $a0, 1 przypadek niebazowy: argument funkcji zmniejszyć o 1 jal factorial i wywołać funkcję factorial rezultat jest w $v0 lw $a0, 0,($sp) pobrać oryginalny argument z ramki stosu mulo $v0, $a0, $v0 result = argument * factorial(argument - 1) factreturn: lw $ra, 20($sp) addu $sp, $sp, 24 odtworzyć adres powrotny zniszczyć ramkę wrócić do wywołującego (rezultat w $v0) b) Przeanalizować program, podać asemblacji i wykonać. c) Wykonać program krokowo, analizując stan stosu, ramki dla kolejnych wywołań rekurencyjnych, kolejne operacje mulo. str. 7/8

d) Przyjmując powyższy program za wzorzec, samodzielnie napisać program, służący do rekurencyjnego wyznaczania wartości elementów ciągu Fibonacciego: 1. Fib(1) = 1 2. Fib(2) = 1 3. Fib(X) = Fib(X-1) + Fib(X-2). e) Program poddać asemblacji i przetestować. Rezultaty pracy umieścić i opisać w sprawozdaniu. 5.4. Zadanie 5 a) W programie z zadania 4 wprowadzić zmianę organizacji dostępu do danych zawartych w ramce stosu, polegającą na zastosowaniu rejestru $fp, jako wskaźnika ramki stosu (zawartość rejestru $fp, w ciele funkcji, nie może podlegać zmianom, należy zastosować tryb adresowania pośredniego z przesunięciem, ang. indirect). b) Program przetestować za pomocą pracy krokowej. W sprawozdaniu zamieścić progam i opisać rezultaty przeprowadzonych testów. str. 8/8