PROGRAMOWANIE PROCESORA 6502 W KOMPUTERACH ATARI XL/XE
Poczta 6502
Dostaję dużo listów. Serdecznie za nie dziękuję. Szczególnie cenne są rzeczowe uwagi dotyczące cyklu "Programowanie...", konkretne pytania i postulaty. Brane są one pod uwagę przy przygotowywaniu kolejnych odcinków kursu. Zdarzają się też przedziwne listy, na które doprawdy trudno odpowiedzieć. Jeden z czytelników uskarża się, że język wykładu jest zbyt trudny, słownictwo niezrozumiałe, a przykłady nie dają się uruchomić. Ten list roi się od błędów ortograficznych, gramatycznych i stylistycznych. Wszystkim tym, którzy uważają moją rubrykę za zbyt trudną, radzę bez złośliwości: porzućcie ten temat. Może za jakiś czas, gdy poznacie lepiej swój komputer, nabierzecie wprawy w programowaniu w Basicu i Pascalu, język asemblera wyda się Wam przystępniejszy. W żadnym jednak wypadku zabawa z komputerem nie powinna hamować postępów w nauce. Szkoła jest najważniejsza!
Życie programisty asemblerowego obfituje w klęski o niepowodzenia, stresy, załamania nerwowe oraz wszelkie inne plagi. Rozmiar wiedzy niezbędnej do wchłonięcia jest ogromny. Szeregu problemów charakterystycznych dla języka maszynowego i asemblera nie spotyka się w innych językach programowania.
Jeden z czytelników pyta: "Jaka instrukcja lub instrukcje asemblera odpowiadają rozkazowi basicowemu GRAPHICS 0?". Oczywiście nie ma gotowej recepty. Sposób postępowania będzie zależał od kontekstu, czyli tego, co działo się dotąd w komputerze oraz tego, co zamierzamy zrobić dalej. Najprostszą znaną mi metodą byłby skok
JMP GR0
do systemowej procedury, która wykonuje wspomnianą instrukcję Basica. Niestety, należałoby ją poprzedzić deklaracją GR0 EQU .... ale nie znam stosownego adresu. W tej sytuacji stosuję więc trik, który polega na otwarciu kanału dla urządzenia "E:". System sam wykona akcję "GRAPHICS 0".
READ EQU 4
WRITE EQU 8
OPEN EQU 3
EOL EQU $9B
IOCB EQU $340
IO_COM EQU IOCB+2
IO_ADR EQU IOCB+4
IO_MOD EQU IOCB+10
CHN1 EQU $10
CIOV EQU $E456
ORG $480
GR0 LDX #CHN1
LDA #OPEN
STA IO_COM,X
LDA E
STA IO_ADR+1,X
LDA #READ+WRITE
STA IO_MOD,X
JSR CIOV
W tym momencie na ekranie jest już tryb 0. Oczywiście nie można tak po prostu pozostawić aktywnego kanału. Ponieważ nie będzie więcej używany, należy go zamknąć.
CLOSE EQU 12
LDA #CLOSE
STA IO_COM,X
JSR CIOV
GROMożna to zrobić bez obawy, że CLOSE "zabierze" tryb z ekranu. Ta sztuczka została zastosowana między innymi w programie Panther. Powyższy program może służyć do przywrócenia standardowego ekranu z poziomu DOS-u. Wiele DOS-ów nie regeneruje ekranu po zmianie trybu np. na 8 w BASIC-u lub w jakimś programie, o ile program sam tego nie zrobi. Należy dopisać zakończenie
DOSVEC EQU $OA
RUNAD EQU $2EO
JMP (DOSVEC)
E DTA C'E:',B(EOL)
ORG RUNAD
DTA A(GR0)
END
Taki program, wygenerowany po dołączeniu z przodu
DOS EQU %100000
ERR EQU %000101
OPT ERR+DOS
i zasemblowaniu na dysk (kasetę) pod nazwą CLS.COM nadaje się do uruchomienia z poziomu dowolnego systemu DOS.
Czasem jednak zdarza się, że sekretny zamysł zmusi nas do tworzenia trybu 0 na własną rękę. Do tego niezbędna jest wiedza o budowie programu ANTIC-a (Display List). Myślę, że wszyscy (czytelnicy cyklu "Piszemy Demo") Już ją posiadamy. Umieszczenie DL w programie pozwala ulokować obszar ekranu praktycznie w dowolnym miejscu pamięci. Spróbujmy napisać taki "program" bez programu, który objawi się naszym oczom podczas wczytywania:
DOS EQU %100000
ERR EQU %000101
OPT ERR+DOS
Pierwszą czynnością będzie skierowanie ANTIC-u na nasz, nie istniejący jeszcze, program DL. W tym celu wstawiamy adres DL do słowa DLPTR. Zamiast zbędnych LDA i STA definiujemy po prostu dwubajtowy blok danych, a resztę zrobi za nas DOS lub COS:
DLPTR EQU $230
DL_ORG EQU $9C20
ORG DLPTR
DTA A(DL)
Analogicznie należy zdefiniować dane DL:
ORG DL_ORG
DL DTA B($70),DTA B($70),DTA B($70)
DTA B($42),A(SCR)
DTA B($02),DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($02),DTA B($02)
DTA B($41),A(DL)
Zwróć uwagę, że nasza DL ma się znaleźć pod adresem $9C20, czyli tam, gdzie się zwykle mieści podczas pracy z BASIC-em. Jeżeli uruchomimy nasz program przy nieobecnym BASIC-u, to DL (i podążający za nią ekran) znajdzie się w nietypowym w tych warunkach miejscu. Po zakończeniu programu cała ta struktura pozostanie oczywiście widoczna w telewizorze, podczas gdy inne adresy, jak SAVMSC ($58) wskazują całkiem co innego. To powoduje nieco zamieszania, gdyż komunikaty systemu będą się "pokazywać" w niewidocznym dla nas miejscu. Jedynym rozsądnym zakończeniem tarapatów będzie użycie przycisku RESET. Można, rzecz jasna, ustalić DL_ORG na $BC20, tak jak w systemie bez BASIC-u, ale wówczas program uruchomiony przy BASIC-u zachowa się jeszcze gorzej: pokaże "sieczkę", gdyż obszar ten znajdzie się w obrębie ROM-u. Jest to ważna, choć nie jedyna wada prezentowanego programu.
SCR DTA D'****** EKRAN TESTOWY'
DTA D' WIERSZ #01 ********'
DTA D'****** EKRAN TESTOWY'
DTA D' WIERSZ #02 ********'
DTA D'****** EKRAN TESTOWY'
DTA D' WIERSZ #24 ********'
z brakującymi 21 wierszami w miejscu kropek. Oczywiście, zamiast przepisywać bezmyślnie "EKRAN TESTOWY" możesz pofolgować swojej wyobraźni i wypełnić ekran według własnego uznania, na przykład obrazkiem ze znaczków semigraficznych. W przykładzie każdy 40-znakowy wiersz został podzielony na dwie części po 20 znaków z powodu ograniczonej szerokości szpalty w TA. Jednak we własnym programie można. a nawet należy wpisywać każdy wiersz ekranu w jednej linijce. Pseudorozkaz DTA typu D służy do definiowania danych przeznaczonych do wyświetlania na ekranie w formie znaków. Kody tych znaków, generowane przez QA różnią się od kodów ASCII (uzyskiwanych przez DTA typu C), tak jak wymaga tego ANTIC. Trzeba o tym pamiętać, gdy sami umieszczamy dane w pamięci ekranu. Przy korzystaniu z CIO napisy podaje się w ASCII, gdyż system sam dokonuje konwersji.
Tu dostrzegamy drugą poważną wadę tego sposobu wyświetlania. Program musi zawierać dane całego ekranu i DL, czyli bez mała 1K bajtów, choć czasem spora część ekranu świeci pustką lub powtarza ten sam wzór.
Niestety, choć program jest już niemal gotowy, okazuje się, że niektóre DOS-y próbują ZAWSZE wykonać wczytany program, nawet gdy nie podamy adresu uruchomienia. Oto więc adres:
RUNAD EQU $2EO
DUMMY EQU $E450
ORG RUNAD
DTA A(DUMMY)
Jest to systemowa procedura inicjalizacji sterownika dysku, znana z literatury jako DISKIV (co można humorystycznie odczytać jako DISK4 albo DISKI5). Jest bardzo krótka, niewiele robi (czytaj: psuje), nie stwierdziłem jej szkodliwego działania w żadnych warunkach. Wykorzystuję ją zazwyczaj jako równoważnik rozkazu RTS, którym jest zakończona, gdy nie mam pod ręką żadnego innego RTS-a.
Pozostaje problem RESET-u, który trzeba wykonać dla przywrócenia właściwych parametrów ekranu. Pozostawienie tego zapominalskiemu użytkownikowi byłoby nieroztropne. Z drugiej strony trzeba zostawić trochę czasu na zapoznanie się z obrazem. 10 sekund powinno wystarczyć:
CDTMV2 EQU $21A
CDTMA2 EQU $228
T EQU 500 (10 * 50)
ORG CDTMV2
DTA A(T)
Wpisanie wartości do licznika CDTMV2 inicjuje odliczanie czasu. Ponieważ jednostką jest tu 1/50 sekundy, więc na sekundę trzeba ich 50. Po odliczeniu do zera system wykona skok do adresu podanego w CDTMA2. Trzeba tam wpisać (szybko, zanim upłynie te 10 sekund!)
WARMST EQU $E474
ORG CDTMA2
DTA A(WARMST)
END
Proszę zauważyć, że w całym programie nie padł ani jeden rozkaz maszynowy! Pokazana metoda nie nadaje się do krótkich programów uruchamianych DOS-em. Doskonała jest natomiast do czołówek gier, w trybie graficznym.
Janusz B. Wiśniewski
|