Czyszczenie pamięci
Potrzeba wyzerowania jakiegoś konkretnego obszaru pamięci pojawia się nader często. Przykładem niech będzie przygotowanie pamięci dla grafiki PMG (player misille graphics). Najczęściej w programach pisanych w dialektach Basic na Atari będzie to konstrukcja z pętlą zerującą obszar danych.
Na przykład taka postać, gdzie POCZ i KON to odpowiednio początek i koniec obszaru do wyzerowania:
21 FOR I=POCZ TO KON: POKE I,0: NEXT I
Program będzie okrutnie powolny, tym dłuższy im większa odległość POCZ od KON. Będzie się nadawał do wyzerowania niewielkiego obszaru danych lub w sytuacji, w której obszar danych może i jest spory ale nie zależy nam na prędkości. Pytanie jak sobie poradzić w sytuacji w której potrzeba wyzerować większy kawałek RAM oraz zrobić to w miarę szybko. Turbo Basic XL nie posiada stosownego polecenia ale kombinacja istniejących może dać satysfakcjonujące rezultaty. Dla porównania biblioteka języka Action! dostarcza polecenie ZERO(POCZ,KON) realizującą dokładnie to zadanie lecz w języku maszynowym.
Turbo Basic XL większość operacji podstawowych wykonuje zdecydowanie szybciej niż Atari Basic, na dodatek dysponuje poleceniem DPOKE, które można zastosować od razu dla obszaru o wielkości KON-POCZ o parzystej wartości:
21 FOR I=POCZ TO KON STEP 2: DPOKE I,0: NEXT I
Teraz dorzucimy kilka linii dla zbadania ile trwa wyzerowanie obszaru pamięci o wielkości równej pamięci ekranu trybu graficznego 8 (7680 bajtów). Pobrany z komórek pamięci 88-89 adres to początek pamięci ekranu:
12 GRAPHICS(24): POCZ=DPEEK(88): KON=POCZ+7679: TIME$=”000000″
30 ? TIME$
Czas wykonania takiego programu dla POKE to około 13 sekund, DPOKE tę samą operację wykona już w 6 sekund.
Jeżeli potrzebna będzie operacja wyzerowania pamięci ekranu właśnie, to w języku Turbo Basic XL operacją taką można wykonać tak:
21 CLS #6
lub równoważne:
21 PUT #6,125
Oczywiście w tym wypadku skutek jest natychmiastowy i pomiar czasu nie ma sensu. Należy też zauważyć, że już samo polecenie GRAPHICS 8 powoduje przygotowanie „pustego” ekranu czyli de facto operację wyzerowania obszaru 7680 bajtów mamy już wykonaną. To przywodzi na myśl, że skoro już taki pusty obszar mamy to można go wykorzystać jako wzorzec obszaru z bajtami o wartości zero. Teraz można już wykorzystać polecenie MOVE lub -MOVE kopiujące blok pamięci z jednego miejsca w drugie.
W naszym przykładzie będzie to prawie dosłowne „przelewanie z pustego w próżne”:
21 MOVE(POCZ, GDZIE, ILE)
Wartości dla GDZIE (docelowe miejsce pamięci) oraz ILE (wielkość danych do kopiowania) należy wskazać.
Co jeśli nie chcemy lub nie możemy w trakcie programu wyzerować obszaru pamięci ekranu ? Inna sztuczka stara jak świat Atari daje możliwość przygotowania obszaru pamięci, który potraktujemy dokładnie tak samo jak wcześniej pamięć ekranu. Do tego celu wykorzystamy zmienną tekstową, ponieważ cechą zmiennej jest jej dynamiczna alokacja w pamięci to trzeba ustalić też jej położenie w pamięci:
10 DIM A$(7680): POCZ=ADR(A$)
Teraz sztuczka wypełniająca ciąg tekstowy dowolną wartością – w tym wypadku będzie to 0 (zero):
11 A$=CHR$(0): A$(7680)=A$: A$(2)=A$
Jeśli będziemy chcieli poprzestać jedynie na ciągu z wartościami 0 (zero) to linię tę można uprościć:
11 A$(7680)=CHR$(0)
Od teraz cały obszar A$ wypełniony jest zerami, pozostaje skopiowanie w dowolne miejsce pamięci np. wspomniany we wstępie obszar PMG. Należy zauważyć, że wielkość naszego „bufora” to 7680 bajtów, więc ILE będzie mieścić się w przedziale od 1 do 7680.
21 MOVE(POCZ, GDZIE, ILE)
Otrzymaliśmy zatem substytut polecenia ZERO. A teraz w drugą stronę – bo warto zauważyć, że wypełnienie zmiennej A$ każdą inną wartością zbuduje nam odpowiednik innego polecenia Action! – SETBLOCK, które wypełnia obszar pamięci określoną wartością. Na marginesie polecenie ZERO to właśnie SETBLOCK ale z ustawioną wartością 0 (zero).
No to powypełniajmy:
10 DIM A$(7680): POCZ=ADR(A$): GRAPHICS(24): EKR=DPEEK(88)
11 FOR I=0 to 255
12 A$=CHR$(I): A$(7680)=CHR$(I): A$(2)=A$: MOVE POCZ,EKR,7680
13 NEXT I: GET I
Przy szczupłych zasobach pamięciowych często wystarczy tylko krótki wzorzec, który zwykle wystarczy powielić. W przykładzie powyżej wystarczyłaby zmienna np. 40 bajtowa, tak aby wypełnić jedną poziomą linię obrazu, a potem ten wzór powielić na pozostałej części ekranu. Będzie wolniej, lecz oszczędniej.
No i można wykonywać wariacje:
10 DIM A$(40): POCZA=ADR(A$): A$=CHR$(170): A$(40)=A$: A$(2)=A$
11 DIM B$(40): POCZB=ADR(B$): B$=CHR$(85): B$(40)=B$: B$(40)=B$
12 GRAPHICS (24): EKR=DPEEK(88): MOVE POCZA,EKR,40: MOVE POCZB,EKR+40,40
13 FOR I=EKR+80 TO EKR+7600 STEP 80
14 MOVE EKR,I,80
15 NEXT I: GET I
W zasadzie pozostaje przypomnieć o rzeczy którą każdy Atarowiec wie lub wiedzieć będzie. Nasz maluch posiada dwa procesory. Procesor graficzny Antic tak samo jak procesor 6502 potrzebuje dostać się do pamięci RAM, w tym celu zatrzymuje pracę procesora głównego. Skutkiem tego działania jest obniżenie faktycznej „mocy” obliczeniowej o około 30 procent. Wyłączanie obrazu w Atari na czas wykonania jakichś karkołomnych operacji jest powszechnie stosowanym zabiegiem, oczywiście o ile nie dzieje się nic ciekawego na ekranie. W przykładach powyżej ekran można wyłączyć tuż po poleceniu GRAPHICS a przywrócić na końcu programu, kiedy obraz jest już namalowany.
10 DIM A$(40): POCZ=ADR(A$)
11 GRAPHICS (24): POKE 559,0: EKR=DPEEK(88)
12 A$=CHR$(170): A$(40)=A$: A$(2)=A$: MOVE POCZ,EKR,40
13 A$=CHR$(85): A$(40)=A$: A$(2)=A$: MOVE POCZ,EKR+40,40
14 FOR I=EKR+80 TO EKR+7600 STEP 80
15 MOVE EKR,I,80
16 NEXT I
17 COLOR 1: TEXT 1,1,” File Edit Option Help „: POKE 559,34: GET I ’napis File w inwersji’
Teraz można już do woli mazać po ekranie lub kasować dowolne obszary, w większości programów użytkowych napisanych w Turbo Basic XL właśnie tak się to wykonuje.