Kurs Assemblera cz. 6

 

ROZKAZ CMP ET CONSORTES

Czy pamiętacie jeszcze, jak w upalne lipcowe dni wypisywaliśmy na ekranie jakieś dziwne stowa o maniakach i pętlach? Tak? To dobrze. Nie? To nieszczególnie dobrze – powtórne przejrzenie tego odcinka nie zaszkodzi. Co my tu mamy… CPX – instrukcja, która wtedy wtaśnie pierwszy raz się pojawiła. A służyła… do porównania zawartości rejestru X z podaną liczbą.

Tu wypada postawić pytanie: na jakiej zasadzie rozkaz ten działa? Komputer odejmuje liczbę podaną jako argument (albo też zawartość komórki podanej jako argument, ale to i tak na jedno wychodzi) od zawartości rejestru X. Tu trzeba jeszcze zauważyć, że odejmowanie to odbywa się bez przeniesienia, czyli stan flagi C przed wykonaniem tego rozkazu nie ma wpływu na wynik (czyli inaczej niż w SBC!). Sam wynik nie jest nigdzie przechowywany, ale – żeby całe nasze działanie nie poszło na marne – komputer odpowiednio do wyniku wygasza lub zapala znaczniki: Zera, Przeniesienia i Liczby ujemnej.

Ale jak w praktyce wygląda ta „odpowiedniość”? Najpierw zbadajmy zachowanie znacznika Zero. Wiemy, że jeśli znacznik ten jest zapalony, to oznacza to, że wynikiem ostatniej operacji matematycznej było zero. Jeżeli zaś wynik był różny od zera, to flaga C będzie zgaszona. Wpiszmy więc, tak dla próby, ten oto program:

Uruchamiamy nasz program i… co widzimy? W lewym górnym rogu ekranu pojawiło się zero. Dlaczego tak się stato? Zanalizujmy program. Najpierw do akumulatora wstawiamy liczbę $30, co odpowiada kodowi ekranowemu zera. Potem do rejestru X wstawiamy liczbę $17, zaraz zaś potem porównujemy zawartość X z liczbą $17 (przy czym sama liczba nie jest tu aż taka istotna; ważne, by była w obu rozkazach taka sama). Po operacji porównania następuje nowy rozkaz: BEQ. BEO $adres to rozkaz, po wydaniu którego komputer sprawdza stan flagi Zero. Jeśli flaga ta jest zgaszona, to ze spokojem przechodzi do następnego rozkazu. Jeżeli zaś znacznik jest zapalony, to program skacze do komórki o podanym adresie. BEO to skrót angielskich stów „Branch if EQual to zero”, czyli (ttumaczenie wolne) „skocz, jeśli wynik równy był zeru”. Oznacza to, że jeśli wynikiem operacji CPX #$17 było 0, to skoczyć trzeba do $271a (oznaczonego etykietą PISZ). Tam znajduje się, znany nam już, rozkaz STA powodujący wydrukowanie zera w lewym górnym rogu ekranu.

Dobrze. Wszystko działa więc zgodnie z przewidywaniami. Zróbmy teraz mały eksperyment: zmień liczbę przy rozkazie CPX na – dajmy na to – $47 albo $00 – byle nie było to $17. Uruchom teraz program. I co? Znowu jest zero? Nie! Tym razem w rogu ekranu pojawiła się jedynka. O czym to świadczy? Przejrzyjmy jeszcze raz program… Najwyraźniej rozkaz BEQ nie zostat wykonany, przez co do akumulatora wzięta została liczba $31 (oznaczająca jedynkę). Mamy więc pierwsze konstruktywne wnioski: jeżeli argument przy rozkazie CPX równy jest zawartości rejestru X, to zapala się wskaźnik Zero. Jeśli liczby te będą różne, wskaźnik ten gaśnie.

Sprawdźmy teraz, jak – w zależności od argumentów – zachowa się wskaźnik Przeniesienia, czyli C. Zmodyfikujmy nasz program tak, by wyglądał jak ten listing:

Przed próbą uruchomienia winien jestem jeszcze wyjaśnienia na temat nieznanego dotąd rozkazu: BCC. BCC to kolejny skok warunkowy. Jego wykonanie zależne jest od stanu znacznika C, czyli Przeniesienia. Jeśli C jest zgaszone, to komputer skacze do miejsca pamięci podanego jako argument rozkazu. Jeśli C jest zapalone, to rozkaz jest ignorowany. Skrót BCC (bo wszystkie mnemoniki asemblera procesora 6502 to TLS-y*, po prostu) oznacza „Branch if Carry Clear”, czyli „skocz, jeśli znacznik przeniesienia jest zgaszony”. Wszystko jasne?

To jadziem. Wynikiem działania programu jest tym razem jedynka. Oznacza to, że flaga C jest zapalona. Proponuję teraz kilka prób ze zmianą liczby przy rozkazie CPX. (Teraz Ty działasz!) No i co? Masz już gotowe wnioski? Jeśli tak, to porównajmy je z moimi.

Mi wyszło, że:
1) Jeśli zawartość rejestru jest większa niż liczba przy rozkazie porównania, to znacznik C będzie zapalony.
2) Jeśli zawartość rejestru jest równa liczbie przy rozkazie porównania, to znacznik C będzie zapalony.
3) Jeśli zawartość rejestru jest mniejsza niż liczba przy rozkazie porównania, to znacznik C będzie zgaszony. Teraz zmień w linii BCC $271 a (czy też BCC PISZ) mnemonik BCC na BCS. Rozkaz BCS oznacza „Branch if Carry Set”, czyli „skocz, jeśli znacznik przeniesienia jest zapalony”, zaś jego działanie jest dokładnie odwrotne niż BCC. Teraz jeśli uruchomimy program, wyniki będą dokładnie odwrotne niż poprzednio. Wiadomo dlaczego? Kolejnym znacznikiem, na który wpływać ma rozkaz CPX, jest znacznik Liczby ujemnej. Po zmianie rozkazu skoku program wyglądał będzie tak:

Nowy rozkaz BPL oznacza „Branch if PLus”, czyli „skocz, jeśli dodatnia”. Tym razem skok zależeć więc będzie od faktu, czy wynik ostatniej operacji będzie ujemny czy dodatni. W artytmetyce dwójkowej przyjętej przez projektantów układu 6502 (czyli tego procesora, który siedzi w Twoim C-64), liczby ujemne odróżnia się od dodatnich tym, że mają one zapalony siódmy, najstarszy bit. I to wtaśnie jest najśmieszniejsze. Jeżeli masz np. liczbę %10010011, to nigdy nie wiesz, czy dziesiętnie jest to (128+16+2+1) 147, czy też (-16-2-1) -19. Po prostu nie wiadomo. Dlatego też korzystanie z liczb ujemnych w asemblerze jest, delikatnie mówiąc, ograniczane w miarę możliwości. Zwtaszcza, że w bajcie, którego pierwszy bit jest stracony na znak liczby, mieści się dokładnie dwa razy mniej informacji niż w zwykłym. Pomimo tego wszystkiego ze wskaźnika Liczb ujemnych (Negative) przydaje się korzystać w innych sytuacjach. Przy współpracy z rozkazem CPX zastosowanie jego jest jednak dość ograniczone.

Teoretycznie wskaźnik N zostaje zapalony, gdy zawartość rejestru jest mniejsza od liczby, do której chcemy ją porównać. W rzeczywistości napotykamy jednak kilka problemów. Na przykład, gdybyśmy wzięli liczbę $ff (255) i porównali ją z liczbą $04 (4), to flaga N zostałaby zapalona. Czyli 4 ma być większe od 255? Ale numer! A to wynika po prostu z tego, że liczba 255 jest zbyt duża, by można do niej stosować zasady ujemności. Ujemne liczby muszą się zawierać między -127 a 127. Inaczej wychodzą brednie. Podobne brednie wychodzą i w innych przypadkach. Czyli. do wyników rozkazu BPL powinniśmy zachować dość daleko idącą rezerwę i starać się nie nadużywać tego skoku.

Rozkazem przeciwnym BPL jest BMI („Branch if Mlnus”, „skocz, jeśti ujemna”). Stosowanie jego napotyka podobne kłopoty jak BPL.

Cierpliwy i uważny Czytelnik zapewne zauważył już, że jakoś dziwnie tekst nie jest powiązany z tytułem. W nagłówku jest bowiem mowa o jakimś CMP, zaś my – jak do tej pory – zajmujemy się tylko tymi „consortes”. Czas wreszcie przedstawić gtównego bohatera: rozkaz CMP!

CMP oznacza „CoMPare accumulator” czyli „porównaj akumulator”. Działanie jego jest identyczne, dokładnie takie samo – prócz jednego szczególika – jak CPX. Szczególikiem tym jest fakt, że jako „mięso armatnie” do porównywania nie idzie zawartość rejestru X, a samego akumulatora. W świecie rozkazu CMP nie może – skoro jest rozkaz CPX odpowiedzialny za rejetr X – zabraknąć rozkazu porównania dla rejestru Y. Rozkazem tym jest CPY („ComPare Y”, „porównaj Y). Analogicznie, wszystkie flagi ustawiane są dokładnie tak samo, jak po rozkazach CMP i CPX.

 

‚ TLS to skrót od stów TrzyLiterowy Skrót. Zwrotu tego używamy, gdy chcemy zrobić na kimś dobre wrażenie lub zaciemnić nieco sytuację.

Dziś poznaliśmy rozkazy:
CMP – porównanie zawartości akumulatora z podaną liczbą

CPY – porównanie zawartości rejestru Y z podaną liczbą

BEQ – skok do podanego adresu, pod warunkiem, że wynikiem ostatniej operacji matematycznej było 0.

BCC – skok do podanego adresu, pod warunkiem, że w wyniku osstatniej operacji matematycznej znacznik przeniesienia został zgaszony.

BCS – skok do podanego adresu, pod warunkiem, że w wyniku ostatniej operacji matematycznej znacznik przeniesienia został zapalony.

BPL – skok do podanego adresu, pod warunkiem, że wynikiem ostatniej operacji matematycznej była liczba dodatnia.

BMI – skok do podanego adresu, pod warunkiem, że wynikiem ostatniej operacji matematycznej była liczba ujemna.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *