Kurs Assemblera cz. 5

Rolowanie bajtów i nie tylko

Zawartość komórek możemy nie tylko dodawać lub odejmować (co już od dobrego miesiąca umiemy). 6502 daje nam także bogate możliwości PRZESUWANIA bitów w obrębie jednego bajtu. Wiemy, że bajt składa się z ośmiu bitów, z których każdy może mieć wartość 0 lub 1. Jeżeli ułożymy je wszystkie w jednej linii, możemy je potraktować jako osiem dwójkowych rzędów wielkości. Weźmy jakąkolwiek liczbę. Niech to będzie dla przykładu 105. Po przełożeniu tego na układ dwójkowy dostaniemy liczbę 01101001. Jeśli przesuniemy to co mamy o jeden bit w lewo (po prawej stronie wstawiając 0), dostaniemy liczbę 11010010. Krótkie obliczenia (128+64+16+2)… wynik: 210! Czyli dokładnie dwa razy więcej! Oznacza to, że przesunięcie bitów w lewo jest równoznaczne z pomnożeniem danej liczby przez dwa. Czy można wyciągnąć z tego wniosek, że przesunięcie bitów w prawo to nic innego jak podzielenie liczby przez dwa? Właściwie tak. Każdy bit przekaże swoją zawartość sąsiadowi po prawej. A wiemy, że sąsiad po prawej ma dwa razy mniejszą wartość liczbową. Dlatego też możemy podejrzewać, że zaiste tak będzie. Weźmy więc znowu 105 (czyli %01101001, procentem programiści zwykli poprzedzać liczby zapisane dwójkowo, podobnie jak dolarem – szesnastkoso) i przesuńmy w prawo (po lewej wstawiając 0). Mamy więc %00110100, czyli (32+16+4) 52. A przecież 105 na 2 to 52,5! Co stało się z brakującymi 0,5? Przyjrzyjmy się naszym liczbom dwójkowym. W pierwszej mamy cztery jedynki, w drugiej zaś już tylko 3. Wniosek z tego taki, że nie możemy ot tak, po prostu wyrzucać na śmietnik niepamięci bitów, które wypadły nam poza bajt podczas przesuwania. Trzeba je gdzieś wstawiać. Potrzebny jest nam choć jeden bit, do którego łatwo będzie się dostać. Jak znalazł jest tutaj flaga przeniesienia (bit C, czyli Carry). Przeniesienie przecież po to właśnie istnieje, by wstawiać doń bity, które „wyskoczyły” nam podczas jakichś operacji arytmetycznych poza przewidziane osiem bitów. Tak właśnie działają rozkazy ASL i LSR. ASL to przesunięcie zawartości bajtu w lewo (Arithmetic Shift Left). Jeżeli wykonamy je na jakiejś komórce, bity 0 – 6 przesuną się o jedno oczko w lewo. Jako nowy bit 0 wstawione będzie 0. Jeśli stary bit 7 był jedynką, flaga C zostanie zapalona, jeśli zaś był zerem-zgaszona. Mam nadzieję, że klarownie objaśnia to rys. 1. Sprawdźmy, jak rozkaz ASL dziata w praktyce. vlusimy napisać program, który wstawi do pamięci akąś wartość, następnie przesunie ją w lewo i da tam jakoś znać, jeśli znacznik C został zapalony.


*=$2710
LDA #$40
STA $2800
ASL $2800
LDA #$00
BCC ZERO
LDA #$01
ZERO STA $2801
BRK

Uruchom program przez SYS 10000 albo G2710. W komórce $2800 (dziesiętnie 10240) znajdzie się wynik przesunięcia, w $2801 (10241) zaś to, co znalazło się w znaczniku przeniesienia. Jeśli wpiszemy program tak, jak jest podany-w $2800 dostaniemy $80, a w $2801 – $00, czyli tak, jak to było do przewidzenia. Wpiszmy jednak w pierwszej linii LDA #$ff, a potem uruchomimy program. $ff to % 11111111. Po przesunięciu w lewo dostaniemy wynik $fe, czyli %11111110. W komórce $2801 (czyli 10241) będzie jedynka, która bierze się z ostatniej jedynki bajtu poprzedniego. Powinna być więc traktowana jako dodatkowy bit przesuwanego przez nas bajtu. Proponuję trochę się pobawić tym programikiem-pomoże to dokładnie pojąć działanie rozkazu ASL. Instrukcją odwrotną jest LSR. LSR to przesunięcie w prawo (Logical Shift Right). Ten rozkaz przesuwa bity w bajcie w prawo, przy czym skrajny prawy bit jest wstawiany do C, zaś za skrajny lewy komputer bierze 0. Działanie tego rozkazu objaśnia rys. 2 oraz ten oto niewielki programik:


*=2710
LDA #$40
STA $2800
LSR $2800
LDA #$00
BCC ZERO
LDA #$01
ZERO STA $2801
BRK

Po uruchomieniu programu -zgodnie z przewidywaniami – w komórce $2800 znajdzie się $20 (32), czyli dwa razy mniej niż $40 (64). Wszystko się więc zgadza. Para opisywanych rozkazów okazała się jednak niewystarczającą. Nie dla wszystkich bowiem zastosowań za nowy, skrajny bit można było przyjąć 0. Nie byłoby też szczególnie wygodne, gdyby zaprojektować dwa rozkazy, które wstawiałyby 1 zamiast 0. Dla większej elastyczności i wygody powstała więc dwójka ROL i ROR. ROL to ROtate Left, czyli obrócenie w lewo. Od rozkazu ASL różni się tym, że jako skrajny prawy bit wstawiane jest nie – 0, lecz to, co było w C PRZED wykonaniem rozkazu. Zaś to, co było na lewym skraju, wchodzi do C (tak jak w ASL). Ilustruje to rysunek 3 oraz ten oto program:


*=$2710
SEC
LDA #$40
STA $2800
ROL $2800
LDA #$00
BCC ZERO
LDA #$01
ZERO STA $2801
BRK

W komórce $2800 znajdzie się $81, czyli %10000001. $40 to 101000000. Jedynka, która została przeniesiona z szóstego do siódmego bitu a to, co było w przeniesieniu, pojawiło się po prawej. Jeżeli napiszemy CLC zamiast SEC, wynik będziemy mieli identyczny, jak w przypadku ASL -jako bit zerowy będzie 0. Rozkazem, który działa w stronę przeciwną jest ROR. ROR to skrót od angielskich słów ROtate Right, czyli obróć w prawo. Jak wskazuje nazwa, przesuwa on zawartość bajtu w prawo. Poza tym w miejsce bitu siódmego wstawia zawartość Carry, a to, co było w bicie zerowym, do przeniesienia odsyła. I bardzo dobrze (rys. 4).


*=$2710
SEC
LDA #$40
STA $2800
ROR $2800
LDA #$00
BCC ZERO
LDA #$01
ZERO STA $2801
BRK

Po wykonaniu w $2800 dostaniemy z $40 (czyli %00010000) liczbę $a0 (%10001000). W $2801, zgodnie z przewidywaniami będzie 0 – bit zerowy był zgaszony.

Oczywiście, rozkazy te służą nam nie tylko do przesuwania jakichś abstrakcyjnych bajtów w prawo czy w lewo. Mogą się nam przydać, jeśli np. będziemy chcieli sprawdzić po kolei bity danego bajtu, jeżeli będziemy chcieli zrobić procedurę płynnego przesuwania napisów na ekranie graficzny albo mnożyć/dzielić coś przez wielokrotności 2.

 


Rys. 1
ASL
C <- 7 6 5 4 3 2 1 0 <- 0

Rys. 2
LSR
0 -> 7 6 5 4 3 2 1 0 -> C

Rys. 3
ROL
->---------->---------->-
- 7 6 5 4 3 2 1 0 <- C <-

Rys. 4
ROR
-<----------<----------<-
-> C -> 7 6 5 4 3 2 1 0 -

Dodaj komentarz

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