Radosław Maciaszczyk Mirosław Łazoryszczak Sprzęt i architektura komputerów Laboratorium Temat: Mikroprocesory i elementy asemblera Katedra Architektury Komputerów i Telekomunikacji
1. MIKROPROCESORY I ELEMENTY ASEMBLERA 1.1. ARCHITEKT UR A M IKROPR O CESORA 8086 Schemat blokowy mikroprocesora 8086 przedstawia rys. 1. Moduł współpracy z magistralą Jednostka wykonawcza 1 2 3 4 5 6 magistrala wewnętrzna magistrala systemowa kolejka instrukcji FR AH BH AL BL CS IP ALU CH DH CL DL bufory DS SP ES BP sterowanie SS sterowanie SI DI Rys. 1 Schemat blokowy mikroprocesora 8086 Procesor 8086 jest procesorem 16-bitowym. Posiada bowiem 16-bitowe rejestry oraz 16-bitową magistralę danych. Magistrala adresowa jest 20- bitowa, co pozwala na uzyskanie 1MB przestrzeni adresowej. Budowa rejestru znaczników (FR flag register) SF znacznik znaku ZF znacznik zera PF znacznik parzystości AF przeniesienie pomocnicze CF przeniesienie OF nadmiar IF interrupt DF znacznik kierunku TF znacznik pułapki Rejestry robocze: AX [AH, AL] akumulator BX [BH, BL] rejestr bazowy CX [CH, CL] rejestr zliczający DX [DH, DL] rejestr danych SP wskaźnik stosu BP wskaźnik bazy DI rejestr adresu przeznaczenia SI rejestr adresu operandu źródłowego Rejestry segmentowe: CS segment programu DS segment danych SS segment stosu ES segment dodatkowy Tryb adresowania sposób wyznaczania adresu argumentu lub wyniku
natychmiastowe (MOV AX, 20 w rejestrze AX zostanie zapisana liczba 20) rejestrowe (MOV AX, BX w rejestrze AX zostanie zapisana zawartość rejestru BX) bezpośrednie (MOV AX, [40] w rejestrze AX zostanie zapisana zawartość komórki pamięci o adresie 40) pośrednie (MOV AX, [CX] w rejestrze AX zostanie zapisana zawartość komórki pamięci o adresie, który znajduje się w rejestrze CX) bazowe (MOV AX, [BP]) indeksowe (MOV AX, [SI]) bazowo indeksowe (MOV AX, [SI+BP]) Możemy wyróżnić następujące instrukcje procesora: arytmetyczno logiczne przesłań skoków, obsługi pętli wywołań i powrotów z podprogramów obsługi rejestrów segmentowych operacje na ciągach słów rozkazy we/wy 1.2. PRZY KŁADY PRO G RAMOWA N IA MIK ROPROCESORA 8 0 86 Przykład 1 Napisać program obliczający wartość następującego wyrażenia: A*C + B*D, gdzie: A = 13 B = 43 C = -4 D = 19 Rozwiązanie Najpierw należy zamienić poszczególne wartości na liczby hexadecymalne. Liczby ujemne powinny być zapisane za pomocą kodu U2. Program nie ma charakteru ogólnego, ponieważ wielkość i ilość rejestrów została dopasowana do danych liczb. A = 0Dh B = 2Bh C = FCh D = 13h 1: MOV AL,0Dh ;Umieszczamy liczbę A w rejestrze AL 2: MOV AH,0FCh ;Do rejestru AH wpisujemy liczbę C 3: IMUL AH ;Mnożymy (ze znakiem) zawartość rejestru AL przez ;liczbę z rejestru AH, wynik umieszczony będzie ;w rejestrze AX 4: MOV BX,AX ;Przechowujemy wynik pierwszego mnożenia ;w rejestrze BX 5: MOV AL,2Bh ;Wpisujemy liczbę B do rejestru AL 6: MOV AH,13h ;W rejestrze AH umieszczamy liczbę D 7: MUL AH ;Mnożymy (bez znaku) zawartość rejestru AL przez ;liczbę z rejestru AH, wynik umieszczony będzie ;w rejestrze AX ADD AX,BX ;Do wyniku pierwszego mnożenia dodajemy wynik ;drugiego mnożenia. Wynik dodawania (i całego ;wyrażenia) znajdzie się w rejestrze AX
Realizacja Uruchomić program c:\emu8086. Wybrać w oknie startowym polecenie new, wybrać com template. Przepisać podany kod (od miejsca ; add your code here. Sprawdzić czy składnia jest poprawna kompilując go. Po kompilacji zapisać przykład na własnym dysku sieciowym. Następnie uruchomić program i wykonać go w trybie krokowym obserwując poszczególne rejestry, oraz rejestr znaczników (view->flags). Podać wynik oraz jakie flagi zmieniły się w ostatnim kroku programu. Dlaczego? Przykład 2 Napisać program obliczający sumę ośmiu kolejnych bajtów zapisanych w pamięci począwszy od adresu DS:SI czyli 0700h:0000h Rozwiązanie W programie należy zastosować instrukcję pętli (LOOP). Ma ona charakter skoku bezwarunkowego, przy czym z rozkazem tym związany jest rejestr CX pełniący funkcję licznika pętli, dekrementowanego automatycznie po każdym wykonaniu instrukcji LOOP. Suma 8 bajtów wykracza poza zakres rejestru połówkowego, wobec tego wynik musi być umieszczony w rejestrze 16-bitowym. 1: MOV CX,08 ;Ustawiamy licznik pętli na 8 2: XOR AX,AX ;Zerujemy rejestry AX, SI, BX (poniżej) 3: XOR SI,SI 4: XOR BX,BX 5: loop1: 6: MOV BL,[SI] ;Wczytujemy do rejestru BL pierwszy bajt z pamięci ;(rejestr SI wskazuje na pierwszy bajt tablicy). ;Ponieważ sumowane składniki są bajtami, musimy ;zatem pobierać pojedyncze bajty z pamięci. Stąd ;użycie rejestru BL. Gdyby użyto rejestru 16- ;bitowego jako miejsca przeznaczenia, wówczas ;procesor odczytałby całe słowo (dwa bajty) zamiast ;bajtu 7: ADD AX,BX ;Wykonanie dodawania. Rejestr BH pozostaje ;wyzerowany, więc do akumulatora zawierającego ;cząstkowe wyniki dodawana jest zawartość rejestru ;BL 8: INC SI ;Zwiększenie zawartości rejestru SI o 1, tak aby w ;kolejnym przebiegu pętli możliwy był odczyt ;kolejnego bajtu pamięci 9: LOOP loop1: ;Wykonanie skoku do linii 5(stała loop1), automatyczna ;dekrementacja rejestru CX i sprawdzenie, czy jego ;zawartość jest większa od 0 Realizacja Przpisać kod. Otworzyć okienko RAM (view-> memory), przejść do adresu wskazywanego przez rejestr DS:SI. Krokowo wykonać program i sprawdzić jak zmieniają się rejestry procesora. Wyliczyć ręcznie sumę i porównać z uzyskanym wynikiem. Przykład 3 Napisać program obliczający sumę dwóch wektorów 8 elementowych, zadeklarowanych w kodzie programu, współrzedne tych wektorów zostaną wyznaczone po asemblacji. Założyć, że wynik będzie 16 bitowy.
Rozwiązanie Najpierw należy zadeklarować dwa wektory wejściowe oraz wektor wynikowy. W pierwszym kroku następuje skok do właściwego kodu programu, omijając deklaracje zmiennych. Korzystająć z rejestrów pośrednich należy wczytać adresy wektorów. Do rejestru CX wczytujemy licznik pętli. Następnie wykonujemy w pętli dodawanie dwóch wektrów zaś wynik zapisujemy do 3 wektora. LITERATURA 1: JMP start ; 2: vec1 db 1, 2, 5, ;definiujemy wektory wejściowe (2 i 3) oraz wektor 6, 9,11, 33, 99 ;wyjściowy (4) 3: vec2 db 11, 10, 7, 26, 99,1, 3, 9 4: vec3 db?,?,?,?,?,?,?,? 5: start: ;etykieta start 6: LEA SI, vec1 ;obliczenie efektywnego adresu wectora vec1 i ;umieszenie wartości w rejestrze SI 7: LEA BX, vec2 ;adres początku wektora vec2 w rejestrze BX 8: LEA DI, vec3 ;adres początku wektora vec3 w rejestrze DI 9: MOV CX,8 ;ustawienie licznika pętli 10: XOR AX,AX ;wyzerowanie rejestru AX 11: loop1: 12: MOV AL,[SI] ;wpisanie do rejestru AL wartośći spod adresu ;DS*16+SI 13: ADD AL,[BX] ;dodanie do rejestru AL wartości spod adresu ;DS*16+BX 14: MOV [DI],AL ;przenieś wynik dodawania pod adres DS*16 + DI 15: INC SI ;inkrementacja rejestru SI,BX,DI 16: INC BX ; 17: INC DI ; 18: LOOP loop1 ; Realizacja Przepisz kod, przetestuj jego działanie. Zadanie 1 Napisać program ustawiający wartość 1 w 6 bicie dowolnego adresu w pamięci np 0700:0100. Zadanie 2 Napisać program negujący 4 bit dowolnego adresu w pamięci np 0700:0100. [1]. Pr. zbiorowa, red. Stępień C.: Mikroprocesory firmy Intel, PWN, Warszawa 1992. [2]. Turbo assembler. Quick Reference Guide. Borland International 1991. [3]. Instrukcje procesorów rodziny 80x86 http://4programmers.net/assembler/