Magazyn Enter, grudzień 1993, strona 153

Adam Ryba

Wykonywanie rozkazów

Analizując kody wojowników można się czasem natknąć na instrukcje, których próba interpretacji może przyprawić o ból głowy. Np. taka sekwencja:

        DAT $0    $1
  start MOV <-1   @-1
        …
        END start

Wykonanie rozkazu MOV może dać różne wyniki, zależnie np. od tego, w którym momencie będzie zmniejszona wartość argumentu instrukcji DAT. Aby rozwiać wątpliwości, jakie mogą się pojawić w podobnych przypadkach, przyjrzyjmy się jak są wykonywane rozkazy Redcode. Jest to przydatne do analizy cudzych, jak i tworzenia własnych wojowników.

Sędzia walki, zanim przystąpi do wykonywania rozkazu, zapamiętuje go w specjalnym rejestrze. Oznacza to, że treść rozkazu nie może ulec zmianie w trakcie wykonywania.

Kolejnym krokiem jest opracowanie argumentów rozkazu. Polega ono na wyznaczeniu adresów argumentów A i B oraz na wyciągnięciu spod tych adresów dwóch par wartości tamtejszych argumentów. Bardzo ważną zasadą jest niezmienianie zawartości rdzenia aż do wyznaczenia wszystkich adresów i wszystkich wartości. Konsekwencją tej zasdy jest fakt, iż podczas wyznaczania adresu argumentu typu < sędzia nie od razu zmienia zawartość rdzenia. Najpierw adres jest liczony jak dla typu @, z tym, ze końcowy wynik jest zmniejszany o jeden. Dopiero po całkowitym opracowaniu obu argumentów sędzia odszukuje na rdzeniu odpowiednią komórkę i zmniejsza jej zawartość (a dokłądnie wartość pola argumentu B) o jeden. Gdyby oba argumenty były typu <, zmniejszona byłaby zawartość dwóch komórek, a gdyby wskazywały one na tę samą komórkę, jej zawartość byłaby zmniejszona o dwa.

Po przygotowaniu obu argumentów sędzia wykonuje rozkaz, oraz, jeśli nie był to skok, zwiększa licznik programu (program counter) o jeden, aby wskazywał kolejną instrukcję. Potem sędzia odczytuje licznik następnego procesu (jeśli program jest wieloprocesowy), przepisuje do specjalnego rejestru kolejny rozkaz i wszystko zaczyna się od początku.

Po takiej dawce teorii mozemy się zabrać za analizę powyższej sekwencji. Z łatwością wyznaczymy faktyczne adresy argumentów:

  A-adres = -1
  B-adres = 0

Ponieważ argument A rozkazu MOV nie jest typu #, rozkaz operuje tylko na adresach argumentów i nie interesują nas ich wartości. Sędzie po opracowaniu obu argumentów zmniejszy argument instrukcji DAT o jeden, i w ramach wykonania rozkazu, przeniesie instrukcję DAT $0 $0 w miejsce instrukcji MOV. Możemy się o tym przekonać w debuggerze WOJOWNIKA.

Przeanalizujmy teraz kolejny przykład:

        DAT <0    <2
  start DJN @-1   $-1
        SPL $-2
        JMP $0
        END start

Zaczynamy od wyznaczenia adresów argumentów rozkazu DJN:

  A-adres = 1
  B-adres = -1

Wykonanie rozkazu zmniejszy B-adres-B-wartość z 2 do 1 i ponieważ będzie ona różna od zera, spowoduje skok pod A-adres, czyli do rozkazu SPL. Tutaj widzimy, jak ważna jest konieczność wyznaczania wszystkich adresów i wartości argumentów przed wykonaniem rozkazu. Gdyby sędzie wyznaczył A-adres nie od razu, a dopiero po stwierdzeniu, że należy wykonać skok (a zatem także i po wykonaniu rozkazu DJN), jego wartość byłaby już inna A-adres = 0 (wartość błędna).

Kolejny rozkazem jest SPL. Wykonanie go spowoduje uruchomienie równoległego procesu od adresu A-adres, czyli od rozkazu DAT. Teraz próba wykonania rozkazu DAT spowoduje śmierć procesu potomnego, podczas gdy proces macierzysty zapętli się wykonując bez końca rozkaz JMP. Operacje te są konieczne, aby móc w debuggerze WOJOWNIKA zobaczyć efekt wykonania rozkazu DAT.

Zgodnie z przyjętą zasadą sędzia najpierw wyznacza adresy i wartości argumentów, następnie, jeśli wystąpiły argumenty typu <, zmniejsza B-wartość odpowiednich komórek, a dopiero na końcu wykonuje rozkaz. W konsekwencji wykonanie rozkazu DAT <0 <1 zmniejszy B-wartości komórek o adresach 0 (instrukcja DAT) i 1 (instrukcja DJN). Arena będzie zatem wyglądała tak:

        DAT <0    <0
  start DJN @-1   $-2
        SPL $-2
        JMP $0 ; tu uwięziony jest proces macierzysty

Tekst ten jest niejako uzupełnieniem artykułu A. Stasiewicza „Kowboj, Ferret i inni wojownicy” (ENTER 2/92 i 3/92). Miłośnicy Wojen Rdzeniowych znajdą tam opis języka Redcode wraz z krótkim kursem programowania.

Na stronie 151-152 tego numeru przedstawiamy nowe środowiska do rozgrywania Wojen Rdzeniowych. Następcą WOJOWNIKA został program Arbiter. Ponieważ Mistrzostwa Polski będą rozegrane w nowym środowisku, odbędą się one później niż zapowiadałem. Termin wstępnie przesunęliśmy na marzec, aby wszyscy zainteresowani zdążyli zakupić nowe oprogramowanie i poznać je. O dokładnym terminie poinformujemy, a mnie pozostaje przeprosić Czytelników za błędne informacje.