Kurs Assemblera cz. 4
- TeBe / MadTeam
Po długiej przerwie spowodowanej zmasowanym atakiem wirusów kurs powraca .
Jak dotąd nie omawialiśmy struktury programu dla Antica (układ generujący obraz), zapoznamy się z nim na podstawie przykładów.
Teraz jednak fragment z książki Wojtka Zientary 'Mapa pamięci Atari XL/XE' na temat ANTIC-a.
TWORZENIE OBRAZU
Tworzeniem obrazu na monitorze zajmuje się w komputerach Atari specjalizowany układ scalony - ANTIC (Alphanumeric Television Interface Controller). Jest to specjalnie zaprojektowany dla Atari mikroprocesor, który posiada własny zestaw rozkazów i własny program. Według tego programu ANTIC pobiera z pamięci komputera dane umieszczone tam przez jednostkę centralną (procesor 6502) i po odpowiedniej interpretacji przesyła je do monitora.
Obraz telewizyjny generowany przez ANTIC jest jednak monochromatyczny. Kolory są dodawane przez inny układ specjalny - GTIA (Graphics Television Interface Adaptor), który także został zaprojektowany specjalnie dla Atari. Poza kolorem GTIA tworzy jeszcze ruchome obiekty ekranowe zwane popularnie duszkami, a według nomenklatury Atari - grafiką graczy i pocisków (PM6 - Player/Missile Graphics).
Spośród układów graficznych stosownych w komputerach domowych ANTIC wyróżnia się dwoma cechami. Przede wszystkim może bezpośrednio korzystać z pamięci komputera poprzez tzw. DMA (Direct Memory Access). Odciąża więc w ten sposób procesor centralny, co pozwala znacznie przyspieszyć jego pracę. Ponadto ANTIC posiada kompletną 16-bitową szynę adresową, dzięki czemu ma dostęp do całych 64KB pamięci. Umożliwia to umieszczenie danych dla obrazu oraz programu ANTIC-a w dowolnym miejscu pamięci.
Przed przejściem do dalszego opisu trzeba wiedzieć, jak wygląda obraz telewizyjny tworzony przez ANTIC. 0braz ten jest wyświetlany na ekranie przez wiązkę elektronów poruszającą się poziomo od lewej do prawej krawędzi ekranu (patrząc od strony użytkownika) i tworzącą jedną linię ekranu. Wiązka jest wygaszana na czas przejścia do początku nowej linii - ten okres nazywamy synchronizacją poziomą. Po utworzeniu całego obrazu wiązka jest wygaszana na czas przejścia z prawego, dolnego rogu ekranu do lewego, górnego. Nazywa się to synchronizacją pionową. Cała operacja powtarza się co 1/50 sekundy, a więc 50 razy na sekundę.
Pozioma wielkość linii ekranu jest mierzona w specjalnych jednostkach zwanych cyklami koloru. Jest to czas wykonywania przez procesor 6302 połowy cyklu maszynowego. Pełna linia ekranu ma 228 cykli koloru, co pozwala na przedstawienie 456 pojedynczych punktów, a pełny obraz zawiera 310 linii (w systemie PAL). Jednak tak utworzony obraz nie mieściłby się w całości na ekranie telewizora. Aby uniknąć utraty części informacji, obraz tworzony przez ANTIC ma nieco ograniczone wymiary.
Maksymalna wielkość obrazu generowanego przez ANTIC może wynosić 216 linii, ponieważ na więcej nie wystarcza czasu. Utworzenie większej liczby linii spowoduje "zerwanie" synchronizacji czyli pionowe przesuwanie się obrazu. Aby górna krawędź obrazu nie wychodziła poza ekran, w górnej części ANTIC tworzy 24 linie puste. Pozostają więc 192 linie i taka właśnie jest maksymalna rozdzielczość pionowa obrazu. Można ją nieco zwiększyć przez zmniejszenie liczby pustych liny i zwiększenie liczby linii obrazu, lecz suma wszystkich linii nigdy nie może przekraczać 216.
Także w poziomie nie jest wykorzystywana cała długość linii. W tym przypadku możliwe są jedynie trzy rozwiązania. Wyświetlana linia obrazu może posiadać 128, l60, 192 cykle koloru. Normalnie używany jest obraz o szerokości 160 cykli koloru, co daje 320 punktów ekranu. Zmiana szerokości linii jest dokonywana przez zmianę zawartości odpowiedniego rejestru ANTIC-a i programista nie może jej ustalić dowolnie.
Pozostaje jeszcze wyjaśnienie różnicy między linią ekranu i linią obrazu oraz między punktem ekranu i pixelem (punktem obrazu). Wszystko to, co zostało napisane wyżej dotyczy linii i punktów ekranu, ponieważ stanowią one podstawowe elementy ekranu (niezależne od komputera). Natomiast najmniejszy element obrazu (PICture Element = pixel), na którego wygląd może wpływać programista zależy od wybranego trybu graficznego. Ogólnie można powiedzieć, że linia obrazu składa się z jednej lub kilku linii ekranu, zaś pixel z jednego lub kilku punktów ekranu.
ANTIC posiada kilkanaście rejestrów, które sterują jego pracą. Poprzez zmianę ich zawartości można wpływać na wygląd obrazu. Najważniejszym rejestrem jest DMACTL (DMA ControL - $D400) kontrolujący dostęp ANTIC-a do pamięci komputera. Bity 6 i 7 tego rejestru są niewykorzystane, a znaczenie pozostałych jest następujące:
Bit 5 włącza (gdy jest ustawiony) bezpośredni dostęp ANTIC-a do pamięci w celu czytania programu. Skasowanie tego bitu uniemożliwia więc wyświetlanie obrazu pomimo tego, że znajduje się on w pamięci.
Bity 2-4 są wykorzystywane do sterowania grafiką graczy i pocisków.
Bity 0 i 1 regulują dostęp ANTiC-a do pamięci w celu odczytu danych obrazu. Gdy oba są równe zero, to ANTIC nie może odczytywać danych i nie wyświetla obrazu. Inny kombinacje ustalają szerokość wyświetlanego obrazu: 01 - obraz wąski (128 cykli koloru), 10 - obraz normalny (160 cykli koloru) i 11 - obraz szeroki (192 cykle koloru).
Podczas wykonywania programu często zachodzi konieczność przeprowadzenia jakiejś operacji (np. zmiany koloru) między liniami ekranu, a nie w trakcie tworzenia linii. Pomocny jest w tym rejestr WSYNC (Wait for SYNChronisataon - $D40A). Wpisanie dowolnej wartości do tego rejestru powoduje zatrzymanie pracy CPU (6502) do zakończenia tworzenia na ekranie aktualnej linii.
Także licznik linii ekranu VCOUNT (Vertical COUNT - $D40B) jest zwykle wykorzystywany podczas przerwań DLI. Zawiera on numer aktualnie tworzonej linii ekranu podzielony przez dwa. Podczas tworzenia obrazu VCOUNT zlicza więc od O do 155.
Stosunkowo najrzadziej wykorzystywane są dwa następne rejestry - LPENH (Light PEN Horizontal - $D40C) i LPENV (LPEN Vertical). Wskazują one aktualną pozycję pióra świetlnego na ekranie. Rejestr LPENH zawiera numer cyklu koloru (od 0 do 227), a LPENV numer linii podzielony przez dwa (jak VCOUNT).
PROGRAM ANTIC-A
ANTIC tworzy obraz według programu zawartego w pamięci RAM komputera, oznaczanego skrótem DL (Display List). Adres tego programu jest wpisywany do wektora DLPTRS (Display List PoinTeR Shadow register), a następnie podczas przerwania synchronizacji pionowej VBLK (w tym czasie obraz nie jest generowany) przepisywany do DLPTR.
Program ANTIC-a jest układany przez system operacyjny i zapisywany w pamięci podczas procedury otwarcia ekranu (SCOPN) dla każdego trybu program ANTTC-a jest inny, ale jest tylko jeden. Użytkownik może ingerować w jego treść, aby mieszać między sobą różne tryby oraz dla uzyskania innych specjalnych efektów.
ROZKAZY ANTIC-A
Aby zmieniać program ANTIC-a trzeba przede wszystkim znać kody jego rozkazów i ich znaczenie. Wszystkie rozkazy, którymi dysponuje ANTIC, można podzielić na trzy zasadnicze grupy: rozkazy tworzenia pustych linii, rozkazy skoków i rozkazy tworzenia linii trybu. Rodzaj rozkazu jest rozpoznawany według czterech młodszych bitów. Cztery starsze bity służą do modyfikacji podstawowego rozkazu.
We wszystkich rozkazach ustawienie najstarszego bitu powoduje wywołanie przez ANTIC (po wykonaniu rozkazu) przerwania niemaskowalnego. Przerwanie to nazywane jest przerwaniem programu ANTIC-a (DLI - Display List Interrupt). Nie należy przez to rozumieć, że przerywany jest program ANTIC-a, lecz, że wywołuje on przerwanie. Po otrzymaniu żądania przerwania DLI procesor wykonuje procedurę przerwania, której adres znajduje się w rejestrze DLIV (DLI Vector - $0200).
Rozkazy tworzenia pustych linii mają cztery młodsze bity skasowane, są więc postaci $x0. Pozostałe bity (4-6, bo bit 7 sygnalizuje przerwanie DLI) zawierają liczbę tworzonych pustych linii zmniejszoną o jeden. Pełna lista rozkazów tworzących puste linie jest następująca:
bez DLI z DLI 1 pusta linia $00 $80 2 puste linie $10 $90 3 pusta linie $20 $A0 4 puste linie $30 $80 5 pustych linii $40 $C0 6 pustych linii $50 $D0 7 pustych linii $60 $E0 8 pustych linii $70 $F0
Rozkazy skoków mają najmłodszy bit równy jeden, są więc postaci $x1. Bity 4 i 5 są niewykorzystane, zaś bit 6 określa rodzaj skoku. Gdy bit 6 jest skasowany, to tworzona jest jedna pusta linia, a dwa następne bajty programu przepisywane są do licznika programu w kolejności LSB/MSB. Powoduje to wykonywanie dalszej części programu od wskazanego adresu, czyli po prostu skok bezwzględny (JMP). Rozkaz ten jest podobny do rozkazu JMP procesora 6502.
Gdy bit 6 jest ustawiony, to ANTIC wykonuje te same czynności, lecz dalsza realizacja programu jest zatrzymywana, aż do synchronizacji pionowej. Jest to więc skok z oczekiwaniem na synchronizacje VBLK (JVB) i musi on występować na końcu programu ANTIC-a (i tylko tam).
Kody rozkazów skoku przedstawia poniższa tabela:
bez DLI z DLI JMP $01 $81 JVB $41 $C1
Rozkazy tworzenia linii trybu zawierają w czterech młodszych bitach numer trybu (od $02 do $0F), który określa sposób interpretacji danych z pamięci obrazu. Chodzi tu oczywiście o numery trybów ANTIC-a, które są inne niż numery stosowane przez OS. Wszystkie numery trybów w tym rozdziale oznaczają tryby ANTIC-a, o ile nie zostało specjalnie zaznaczone, że chodzi o tryb OS. Pozostałe cztery bity oznaczają modyfikacje rozkazu. Znaczenie bitu 7 (DLI) zostało już opisane, teraz kolej na pozostałe modyfikacje.
- Bit 4 (HSC - Horizontal SCrolling) oznacza, gdy jest ustawiony, włączenie poziomego przesuwu tworzonej linii obrazu.
- Bit 5 (VSC - Vertical SCrolling) oznacza gdy jest ustawiony, włączenie pionowego przesuwu tworzonej linii obrazu.
- Bit 6 (LMS - Load Memory Scan) powoduje, qdy jest ustawiony przepisania dwóch następnych bajtów programu do licznika pamięci obrazu. Licznik obrazu wskazuje ANTIC-owi miejsce w pamięci, z którego ma on pobrać dane obrazu. Ta modyfikacja rozkazu jest bardzo ważna i wymaga szerszego omówienia. ANTIC po rozpoznaniu rozkazu tworzenia linii pobiera z pamięci obrazu odpowiednią liczbę bajtów (zależną od trybu) i po zinterpretowaniu wyświetla na ekranie. Pobieranie danych dla następnej linii rozpoczyna się od następnego bajtu po ostatnio odczytanym. Trzeba więc na początku programu odpowiednio ustawić adres tych danych i to z dwóch powodów. Po pierwsze dlatego, aby ANTIC wiedział skąd ma pobierać dane. Po drugie dlatego, że program ANTIC-a jest wykonywany w całości 50 razy na sekundę i po pobraniu danych dla jednego obrazu, dane dla następnego byłyby pobierane z innego miejsca pamięci.
Licznik obrazu ma specyficzną konstrukcję, która wpływa na sposób jego działania. Posiada on szesnaście bitów ustalanych przez wpisanie adresu odczytanego z programu ANTIC-a. Podczas pobierania danych z pamięci zmieniane jest jednak tylko 12 młodszych bitów. Ogranicza to zakres działania licznika do bloku 4 KB. Jeżeli dane obrazu zajmują więcej niż 4KB, to licznik musi być ponownie ustawiony. W przeciwnym razie po osiągnięciu końca bloku 4KB następne dane będą pobierane z początku tego samego bloku. Trzeba przy tym uważać, aby dane żadnej linii obrazu nie przekraczały granicy bloku, gdyż nie można zmienić stanu licznika w środku tworzonej linii. Sytuacja taka występuje w trybach E i F. Normalnie rozkaz LMS występuje w programie ANTIC-a razem z rozkazem tworzenia pierwszej linii obrazu i razem z rozkazem tworzenia pierwszej linii okna tekstowego (jeśli ono jest).
Poniższe tabele zawierają kody wszystkich rozkazów ANTIC-a tworzących linie trybu.
Bez przerwania DLI - HSC - HSC - HSC - HSC modyfikacje - - V5C VSC - - VSC VSC - - - - LMS LMS LMS LMS tryb 2 $02 $12 $22 $32 $42 $52 $62 $72 3 $03 $13 $23 $33 $43 $53 $63 $73 4 $04 $14 $24 $34 $44 $54 $64 $74 5 $05 $15 $25 $35 $45 $55 $65 $75 6 $06 $16 $26 $36 $46 $56 $66 $76 7 $07 $17 $27 $37 $47 $57 $67 $77 8 $08 $18 $28 $38 $48 $58 $68 $78 9 $09 $19 $29 $39 $49 $59 $69 $79 A $0A $1A $2A $3A $4A $5A $6A $7A B $0B $1B $2B $3B $4B $5B $6B $7B C $0C $1C $2C $3C $4C $5C $6C $7C D $0D $1D $2D $3D $4D $5D $6D $7D E $0E $1E $2E $3E $4E $5E $6E $7E F $0F $iF $2F $3F $4F $5F $6F $7F
Z przerwaniem DLI - HSC - HSC - HSC - HSC modyfikacje - - VSC VSC - - VSC VSL - - - - LMS LMS LMS LMS tryb 2 $82 $92 $A2 $B2 $C2 $D2 $E2 $F2 3 $83 $93 $A3 $B3 $C3 $D3 $E3 $F3 4 $84 $94 $A4 $B4 $C4 $D4 $E4 $F4 5 $85 $95 $A5 $B5 $C5 $D5 $E5 $F5 6 $86 $96 $A6 $B6 $C6 $D6 $E6 $F6 7 $87 $97 $A7 $B7 $C7 $D7 $E7 $F7 8 $88 $98 $A8 $B8 $C8 $D8 $E8 $F8 9 $89 $99 $A9 $B9 $C9 $D9 $E9 $F9 A $8A $9A $AA $BA $CA $DA $EA $FA B $8B $9B $AB $BB $CB $DB $EB $FB C $8C $9C $AC $BC $CC $DC $EC $FC D $8D $9D $AD $BD $CD $DD $ED $FD E $8E $9E $AE $BE $CE $DE $EE $FE F $8F $9F $AF $BF $CF $DF $EF $FF
STRUKTURA PROGRAMU ANTIC-A
Program ANTIC-a musi spełniać kilka warunków, aby jego wykonanie dało na ekranie pożądany efekt. Przede wszystkim musi koniecznie zawierać rozkaz LMS na początku oraz rozkaz JVB na końcu. Aby górna krawędź obrazu nie wychodziła poza ekran, przed rozkazami tworzenia linii trybu powinny znaleźć się rozkazy tworzenia pustych linii (może być ich mniej niż 24). Przykładowy program ANTIC-a tworzony przez system operacyjny jest przedstawiony poniżej.
START $70 \ $70 > 3*8=24 puste linie $70 / $4x linia trybu + LMS <SCRM \adres pamięci obrazu >SCRM /w kolejności LSB/MSB $0x \ $0x | ... : linie trybu $0x | $0x / $42 linia trybu 2 + LMS <TXTM \ adres pamięci okna >TXTM / tekstowego (LSB/MSB) $02 $02 $02 $41 JVB <START \ adres początku >START /programu ANTIC-a
Oczywiście fragment programu dotyczący okna tekstowego występuje tylko wtedy, gdy to okno istnieje. Najkrótsze programy ANTIC-a są ustalane dla trybów 5 (tryb 13 OS) i 7 (2) bez okna tekstowego, mają one po 20 bajtów. Tryby E (15) i F (8) bez okna mają najdłuższe programy - po 202 bajty. Jak widać, czym większa rozdzielczość, tym dłuższy program ANTIC-a.
KOLORY
Informacja o obrazie utworzona przez ANTIC przed wysłaniem do monitora jest jeszcze uzupełniana informacją o kolorze. Ta czynność jest wykonywana przez GTIA. Do realizacji tego zadania GTIA wykorzystuje dziewięć rejestrów, w których przechowywane są wartości kolorów. Znajdują się one w obszarze od $D012 do $DO1A, a ich rejestry-cienie od $02C0 do $02C8.
Wszystkie rejestry koloru maja jednakową strukturę. Cztery starsze bity zawierają numer barwy, a cztery młodsze stopień jasności. Ponieważ bit O nie jest odczytywany, to mamy do dyspozycji l6 barw w 8 jasnościach. Daje to razem 128 kolorów, a we wszystkich informacjach o Atari jest napisane, że można wybierać z palety 256 kolorów. Skąd ta różnica? Obie podane wyżej informacje są prawdziwe. Rzeczywiście do wyboru jest l28 kolorów. Natomiast szczególna interpretacja danych obrazu w trybie 9 (tryb systemu operacyjnego) pozwala na uzyskanie szesnastu zamiast ośmiu stopni jasności i teraz można wybierać z 256 kolorów. Tak więc we wszystkich trybach mamy dostępne 128 kolorów, a tylko w trybie 9 (OS) - 256.
Teraz wypada przedstawić kolory, które odpowiadają różnym wartościom umieszczanym w rejestrach koloru. Ze stopniami jasności sprawa jest prosta wartość najmniejsza ($00) oznacza kolor najciemniejszy, a największa ($0F) - najjaśniejszy. Znacznie trudniejsze jest przedstawienie barw. Przede wszystkim dlatego, że barwa zależy także od jasności, np. barwa $00 z jasnością $00 to kolor czarny, zaś z jasnością $0E - biały. Poza tym kolory w dużym stopniu zależą od konkretnego egzemplarza monitora, nie mówiąc już o systemie telewizyjnym (wszystkie źródła podają barwy w systemie NTSC, a nie PAL). Po przedstawieniu tych zastrzeżeń, czas na wykaz barw (x oznacza jasność).
kod kolor $0x szary $lx złoty $2x pomarańczowy $3x czerwony $4x różowy $5x purpurowy $6x fioletowy $7x niebieski zimny $8x niebieski $9x błękitny $Ax turkusowy $Bx niebiesko-zielony $Cx zielony $Dx żółto-zielony $Ex pomarańczowp-zielony $Fx żółty
Na zakończenie jeszcze jedna ważna informacja. Podczas tworzenia obrazu kolor jest określany zawsze według rejestru sprzętowego. Ten kolei jest zapisywany wartością z rejestru-cienia podczas każdego przerwania VBLK, czyli 50 razy na sekundę. Po zmianie koloru w rejestrze-cieniu kolor na ekranie zmieni się więc najpóźniej po 1/50 sekundy. Jeśli zmiana zostanie dokonana w rejestrze sprzętowym, to kolor zmieni się natychmiast lecz nie da się tego zobaczyć. Najpóźniej bowiem po 1/50 sekundy kolor zostanie odtworzony według starej wartości z rejestru-cienia. Gdy jednak kolor w rejestrze sprzętowym będzie zmieniany podczas każdego tworzenia obrazu (np. przez procedurę przerwania DLI), to zmiana będzie trwała, ale tylko w tej części obrazu, która jest tworzona po przerwaniu. Podczas przerwania VBLK stara wartość zostanie odtworzona i część obrazu do ponownego wywołania procedury DLI będzie miała stary, kolor. Jest to najczęstsze zastosowanie przerwań DLI.
To tyle na temat ANTIC-a, dowiemy się teraz jak możemy modyfikować nasz program w czasie rzeczywistym, porównamy liczby 2bajtowe(word), wyświetlimy 8KB grafikę, poscrolujemy i pofalujemy text.
Pamiętacie że kompilacja zamienia nasz assemblerowy program na ciąg liczb, które są odpowiednikami zastosowanych mnemoników, np.:
lda #$70 ;oznacza bezwzględny rozkaz załadowania do akumulatora wartości $70 ;po kompilacji mamy $a9 $70
Teraz dorzucimy etykiete 'test':
Test lda #$70 ;czyli pod adresem 'test' mamy wartość $a9 ;pod adresem 'test+1' wartość $70
Jak sprawić aby zamiast $70 było $10:
lda #$10 sta test+1
Prawda, że zrozumiałe .
Po tym przydługim wstępie zabieramy się za przykłady.
Prg1:
opt h+ ;generuj plik z naglówkiem, naglówek jest 6-bajtowy, ma postac: ; dta b($FF),b($FF),l(start),h(start),l(start+end-1),h(start+end-1) ;opt h- wygeneruje plik bez naglowka
org $8000 ;adres pod którym znajdzie sie nasz program ldx <antic ;mlodszy bajt adresu ANTIC do rejestru X ldy >antic ;starszy bajt adresu ANTIC do rejestru Y stx 560 ;bajt z rejestru X wpisz pod adres 560 sty 561 ;bajt z rejestru Y wpisz pod adres 561 ; w bajtach 560, 561 znajduje sie cien adresu pod którym uklad Antic znajdzie dla ; siebie programik, który opisuje wyglad wyswietlanego obrazu ; podczas przerwania VBL (co 1 ramke, czyli 1/50 sekundy) wartosci spod 560, 561 ; zostana przepisane do $d402, $d403 petla jmp petla ;petla, tak zeby nie wrócil do DOS'a antic dta b($70),b($70) ;$70 - oznacza 7 pustych linii dta b($42),a(obraz) dta d'"""""""""""""""' ;kod " to tryb 2 - znakowy dta b($41),a(antic) ;$41 czyli czekaj na koniec ramki i wtedy zacznij od adresu... obraz dta d'To jest text przykladowy' end
W/w programik wyświetli nam obraz w trybie 2, oraz nasz tekst, chyba proste .
Niektórzy pewnie chcieliby trochę poanimować. Ten programik sprawi ze nasz txt będzie falował.
Prg2:
opt h+ ;generuj plik z naglówkiem, naglówek jest 6-bajtowy, ma postac: ;dta b($FF),b($FF),l(start),h(start),l(start+end-1),h(start+end-1) org $8000 ;adres pod którym znajdzie sie nasz program ldx <antic ;mlodszy bajt adresu ANTIC do rejestru X ldy >antic ;starszy bajt adresu ANTIC do rejestru Y stx 560 ;bajt z rejestru X wpisz pod adres 560 sty 561 ;bajt z rejestru Y wpisz pod adres 561 lop ldy #0 ;tzn lda #0 = po kompliacji $a9 $00 lda tablica,y sta f0 ;pierwsza linia z textem sec lda #$70 ;odejmujemy od $70, nastepne linie sbc f0 ;beda nieruchome sta f1 lda tablica+8,y ;animacja drugiej linii z textem sta f2 lda 20 ;czekaj 1 ramke cmp 20 beq *-2 inc lop+1 ;zwiekszamy o 1 lda lop+1 cmp #28 ;sprawdzamy czy jest = 28 bne lop ;jesli nie to petl sie dalej lda #0 ;w przeciwnym razie wyzeruj i od poczatku sta lop+1 jmp lop antic dta b($70),b($70) ;$70 - oznacza 7 pustych linii dta b($42),a(title),d'""' f0 dta b($70) dta b($42),a(txt1) f1 dta b($70) f2 dta b($70) dta b($42),a(txt2) dta b($41),a(antic) ;$41 czyli czekaj na koniec ramki i wtedy zacznij od adresu... title dta d' ' dta d' TeBe presents ' dta d' ' txt1 dta d' Text 1 ' txt2 dta d' Text 2 ' tablica dta b($10,$10,$10,$20,$30,$30,$40,$40,$50,$50,$50,$60,$60,$60,$70) dta b($70,$70,$60,$60,$60,$50,$50,$50,$40,$40,$30,$30,$20) dta b($10,$10,$10,$20,$30,$30,$40,$40) end
Ten programik modyfikuje w czasie rzeczywistym program Antica na podstawie predefiniowanych danych 'tablica'. Analiza należy do Was.
Prg3 Przykład falującego scrolla w high-res
org $8000 obraz equ $a150 obr1 equ 203 obr2 equ 205 znaki equ $e000 hscrol equ $d404 ldx <antic ldy >antic stx 560 sty 561 lda #%00100010 sta 559 jsr a_obr1 ;obr1,obr1+1 = obraz maz ldx #3 ;czyscimy obszar 'obraz' - 768bajtow (3*256) ldy #0 tya m_1 sta (obr1),y dey bne m_1 inc obr1+1 dex bne m_1 jsr ad_tex ;tex+1,tex+2 = text (sprawdz procedurke 'ad_tex') lda #3 sta scrol ;scrol = 3 start ldy #80 lda adr_ek,y ;mlodszy bajt adresu obrazu sta obr1 lda adr_ek+1,y ;starszy bajt adresu obrazu sta obr1+1 ;adr_ek to tablica adresow okreslajaca ksztalt scrolla ldy #0 tex lda $ffff,y ;tutaj jest 'lda text,y', adres naszego scrolowanego tekstu pha and #$7f ;tutaj obliczymy adres naszej literki w pamieci Atari lsr @ lsr @ lsr @ lsr @ lsr @ clc adc >znaki ;starszy bajt adresu zestawu znakow sta znak+2 ;znak opisany jest przez 8 nastepujacych po sobie bajtow pla and #$1f asl @ asl @ asl @ sta znak+1 ;ok, w znak+1, znak+2 mamy adres 8 bajtowej paczuszki ;opisujacej ksztalt znaku znak lda $ffff,y ;to tutaj znak+1, znak+2 zmodyfikowalo adres sta (obr1),y ;przepisujemy 8 bajtow na ekran (adres ekranu w obr1, obr1+1) lda #47 ;nasz ekran ma wlaczony poziomy scrol wiec ma szerokosc 48 bajtow jsr d_obr1 iny cpy #8 bne znak lda #3 sta scrol ;zmienna scrol znowu ustawiona na 3 przesuw lda scrol sta hscrol ;przepisujemy wartosc ze scrol do sprzetowego rejestru HSCROL jsr wait ;dzieki temu sprzetowo przesuwamy obraz w lewo o cykl koloru (4x) dec scrol bpl przesuw lda #1 ;ok, teraz musimy przepisac caly widoczny ekran w lewo sta licz p_0 asl @ tay lda adr_ek,y sta obr1 lda adr_ek+1,y sta obr1+1 lda adr_ek-2,y sta obr2 lda adr_ek-1,y sta obr2+1 p_1 ldy #0 lda (obr1),y sta (obr2),y ldy #48 lda (obr1),y sta (obr2),y ldy #96 lda (obr1),y sta (obr2),y ldy #144 lda (obr1),y sta (obr2),y ldy #192 lda (obr1),y sta (obr2),y ldy #240 lda (obr1),y sta (obr2),y inc obr1+1 inc obr2+1 ldy #32 lda (obr1),y sta (obr2),y ldy #80 lda (obr1),y sta (obr2),y inc licz lda licz cmp #41 bne p_0 inc tex+1 ;zwiekszamy adres naszego scrola, bedzie wskazywal nastepna literke bne t_1 inc tex+2 t_1 lda tex+1 cmp <over ;sprawdzamy czy koniec scrola, zwroccie uwage jak sie porownuje lda tex+2 ;liczby 2bajtowe (word) sbc >over bcc run jsr ad_tex ;ustawiamy adres na poczatek tekstu run jmp start wait lda 20 ;czekamy 1 ramke q_1 cmp 20 beq q_1 rts ad_tex lda <text sta tex+1 lda >text sta tex+2 rts d_obr1 sta hlp ;dodawanko liczba 2bajtowa + 1bajt lda obr1 clc adc hlp sta obr1 bcc do_1 inc obr1+1 do_1 rts d_obr2 sta hlp lda obr2 clc adc hlp sta obr2 bcc do_1 inc obr2+1 do_2 rts a_obr1 lda <obraz sta obr1 lda >obraz sta obr1+1 rts text dta d'To jest tekst ' dta d'probny moi mili ! No ' dta d'i co mam tu pisac !' dta d' Moze to ze mecze sie z falujacym scrolem ' dta d'i jeszcze go nie skonczylem.' over equ * antic dta b($70),b($70),b($70) dta b($70),b($70),b($70) dta b($5f),a(obraz) dta b($1f),b($1f),b($1f) dta b($1f),b($1f),b($1f) dta b($1f),b($1f),b($1f) dta b($1f),b($1f),b($1f) dta b($1f),b($1f) dta b($41),a(antic) adr_ek dta a($a150+147) dta a($a150+196),a($a150+245) dta a($a150+294),a($a150+295) dta a($a150+248),a($a150+201) dta a($a150+154),a($a150+107) dta a($a150+60),a($a150+13) dta a($a150+14),a($a150+63) dta a($a150+112),a($a150+161) dta a($a150+210),a($a150+259) dta a($a150+308),a($a150+309) dta a($a150+262),a($a150+215) dta a($a150+168),a($a150+121) dta a($a150+74),a($a150+27) dta a($a150+28),a($a150+77) dta a($a150+126),a($a150+175) dta a($a150+224),a($a150+273) dta a($a150+322),a($a150+323) dta a($a150+276),a($a150+229) dta a($a150+182),a($a150+135) dta a($a150+88),a($a150+41) dta a($a150+42),a($a150+91) dta a($a150+140),a($a150+189) hlp dta b(0) licz dta b(0) scrol dta b(0) adres1 dta b(0),b(0) adres2 dta b(0),b(0)
Prg4 Wyświetlenie grafiki wiekszęj niż 4KB
W przypadku Antica należy zwrócić uwagę że może on zaadresować tylko 4KB danych. Aby wyświetlić 8KB obrazek musimy niejako kazać mu pokazać dwa 4KB obszary. 4KB=4096 / 40 = 102,4
Wiersz ma 40 bajtów w klasycznej szerokości obrazu, czyli w 4KB zmieścimy 102 linie. Obrazek wczytamy od adresu $X010, np. $a010, $2010, $8010, dzięki temu nie będziemy musieli dzielić grafiki na części, zostanie zachowana ciągłość.
Antic musi wyświetlić naszą grafikę od $X010 4KB i od $X010+$1000 4KB. W przypadku większych obrazków jak np. RIP, trzeba niestety dzielić grafikę na 4KB bloki.
Obr equ $a010 ;adres z danymi obrazka ; tutaj procedurka ; która spowoduje ze antic wyswietli obraz, ; analogicznie jak w poprzednich przykladach Ant equ * dta d'ppp' ;24 puste linie dta b($4e),a(obr) ;1 linia dta d'................' ;17 dta d'................' ;33 dta d'................' ;49 dta d'................' ;65 dta d'................' ;81 dta d'................' ;97 dta d'.....' ;102 linie = 1 obszar 4KB dta b($4e),l(0),h(obr+$1000) ;103 dta d'................' ;119 dta d'................' ;135 dta d'................' ;151 dta d'................' ;167 dta d'................' ;183 dta d'.........' ;192 linie - cały obraz dta b($41),a(ant)
Prg5 Animacja z buforowaniem
W naszych przyszłych graficznych efektach, które będą zajmowały więcej niż jedną ramkę zajdzie potrzeba buforowania wyświetlanych obrazów. Pierwszy obraz będzie pokazywał pierwszą fazę animacji, w tym samym czasie nasz program będzie wyliczał drugą fazę, gdy skończy pokażemy ją na drugim obrazie. Znowu wyliczamy, obraz2 ciągle jest wyświetlany, a my już liczymy trzecią fazę, którą pokażemy na obrazie1 i tak dalej.
Potrzebujemy dwa obszary pamięci o zadanej wielkości, np. $a000-$afff obraz1, $b000-$bfff obraz2. Czyli w sumie 2 obszary po 4KB.
ob1 equ $a000 ob2 equ $b000 frame equ $80 org $8000 main lda >ob1 ;obliczymy sobie wartosc, przy pomocy ktorej bedziemy eor >ob2 ;eor-owac ob1 i ob2, czyli przelanczac sta switch+1 ldx <ant ldy >ant stx 560 sty 561 petla lda >ob1 ;nasz parametr, starszy bajt adresu obrazu jsr czysc ;czysci zadany obszar 4KB jsr oblicz ;procedurka OBLICZ, cos tam liczy jsr pokaz ;procedurka pokazujaca kolejne klatki ;teraz pokaze obraz1 lda >ob2 ;mieszamy w obszarze obrazu drugiego jsr czysc jsr oblicz jsr pokaz ;pokazemy obraz2 jmp petla ;---------- czysc sta hlp sta czy+2 ;zmodyfikuj bajt pod adresem czy+2 ldx #16 ;czyli starszy bajt adresu obrazu ldy #0 sty 20 ;zerujemy bajt, ktory VBL zwieksza o 1 tya czy sta $ff00,y iny bne czy inc czy+2 dex bne czy rts ;--- ; wypelniamy ekrany po kolei wartosciami 0..255 ;- oblicz lda #0 inc oblicz+1 ldx #16 ldy #0 lda hlp sta czy+2 lda oblicz+1 jmp czy ;skorzystamy z fragmentu procedurki 'czysc' ;-- pokaz lda 20 sta frame ;tutaj ile ramek trwalo rysowanie tak na prawde wait lda 20 cmp #32 ;max czekamy 32 ramki bne wait lda adr+1 switch eor #0 sta adr+1 rts org $0600 ;tutaj nasz programik dla Antica ;adres powinien byc parzysty, inaczej moga wyjsc krzaczki, dziwaczki ant dta d'ppp',b($4e) adr dta a(ob2) ;na poczatek pokazemy obraz2, bo liczymy na poczatku obraz1 dta d'................' dta d'................' dta d'................' dta d'................' dta d'................' dta d'................' dta d'.....' dta b($41),a(ant) hlp brk org $2e0 ;adres startu programu po wczytaniu dta a(main) ;do pamieci end
Następnym razem zajmiemy się przerwaniami. Jeśli macie jakieś pytania, propozycje tematu napiszcie.