Antic

Generowanie linii

W komputerach z systemem NTSC generowane są 262 linie obrazu, a w komputerach z systemem PAL generowanych jest 312 linii obrazu. Linie obrazu ponumerowane są odpowiednio od 0 do 261 w systemie NTSC oraz od 0 do 311 w systemie PAL. Przy czym w obu systemach na ekranie można zobaczyć maksymalnie 240 linii o numerach od 8 do 247. Poza obszarem od 8 do 247 generowane są sygnały synchronizujące i pomocnicze. Numer aktualnie generowanej linii przechowywany jest w 9-bitowym rejestrze VCOUNT. Programista może odczytać z komórki $D40B tylko 8 bardziej znaczących bitów tego rejestru. Zatem rejestr $D40B ma wartość 0 dla linii z numerem 0 oraz 1, wartość 1 dla linii z numerem 2 oraz 3, itd. Natomiast zmiana wartości rejestru $D40B następuje w liniach z numerem nieparzystym. Poniżej znajduje się tabela z numerami linii oraz odpowiadającymi im wartościami rejestru $D40B dla systemu PAL.

Numer liniiVCOUNT
00
10
21
31
......
310155
311155

Cykle koloru

Cykl koloru (ang. color clock) to miara i jednostka czasu rysowania linii na ekranie. W cyklach koloru możemy określić pozycję punktu w linii - podając czas, od którego nastąpi jego rysowanie. Jak również możemy określić szerokość punktu - podając czas przez jaki będzie on rysowany. Punkt rysowany przez czas jednego cyklu koloru ma szerokość 1 piksela z trybów rozdzielczości 160x192. Narysowanie linii na ekranie zajmuje dokładnie 228 cykli koloru. Cykle koloru ponumerowane są od 0 do 227. Przy czym, pole gry razem z tłem może liczyć maksymalnie 176 cykli koloru od 44 do 219 cyklu koloru. Poza obszarem od 44 do 219 generowane są sygnały synchronizujące i pomocnicze. W komputerach Atari taktowanie procesora jest zsynchronizowane z generowaniem linii. W czasie gdy procesor wykonuje 1 cykl maszynowy (ang. machine clock) generowane są 2 cykle koloru. Zatem wygenerowanie linii na ekranie zajmuje dokładnie 114 cykli maszynowych (228 / 2 = 114). Cykle maszynowe ponumerowane są od 0 do 113.

Cykle koloru:012345......226227
Cykle maszynowe:012...113

Duszki i pociski

Duszki i pociski to obiekty, które można poruszać w kierunku poziomym niezależnie od pola gry. Położenie duszków i pocisków w linii określa się w cyklach koloru. Dla przykładu, pocisk na pozycji 48 rysowany jest od 48 cyklu koloru przez 2 cykle koloru, czyli zajmuje pozycje 48 i 49. Jeśli wyświetla się obraz z Atari przez kartę telewizyjną, to można zaobserwować, że pocisk lub duszek można umieścić na ekranie począwszy od 16 cyklu koloru.

Program dl

Na podstawie programu dl (ang. display list) antic wyświetla na ekranie kolejne linie trybów graficznych, tekstowych lub linie puste. Linia trybu graficznego może się składać z 1, 2, 4 lub 8 linii obrazu. Linia trybu tekstowego może się składać z 8, 10 lub 16 linii obrazu. Natomiast linia pusta może zawierać od 1 do 8 linii obrazu. Instrukcje programu dl można podzielić na trzy grupy:

  1. Instrukcje generujące od 1 do 8 pustych linii obrazu.
  2. Instrukcje generujące linie trybów graficznych i tekstowych.
  3. Instrukcje skoku i skoku po zakończeniu wygaszania pionowego.

Przerwanie dli

Przerwanie dli (ang. display list interrupt) wywoływane jest przez antic. Aby wywołać przerwanie dli należy w instrukcji programu dl ustawić 7 bit. Dla linii trybu lub linii pustych przerwanie dli wywoływane jest w ostatniej linii obrazu.

Testy

Wszystkie testy dostępne są na dysku testy.atr w postaci plików źródłowych. Plik źródłowy należy wczytać, skompilować i uruchomić w programie Quick Assembler. Niektóre testy wymagają dokonywania zmian w źródłach.

Test 1

Test 1 ma na celu określenie, w którym cyklu maszynowym w linii pojawia się nowa wartość w rejestrze VCOUNT ($D40B). Źródła testu 1 dostępne są tu.

Opis testu:

W procedurze przerwania dli odczytujemy kolejno, 256 razy, wartości rejestru $D40B. Otrzymane wartości zapisujemy na 6 stronie pamięci, a następnie wypisujemy na ekranie w postaci liczb szesnastkowych. Przerwanie dli ustawiane jest w 4 albo 5 instrukcji programu dl tak, aby zostało ono wywołane w nieparzystej linii obrazu linii trybu lub linii pustej. Przerwanie dli wywoływane jest w ostatniej linii obrazu linii trybu lub linii pustej. Zatem, jeśli linia trybu lub linia pusta składa się z parzystej liczby linii obrazu, to jest ona umieszczana w 4 instrukcji programu dl od linii z numerem $20. Jeśli natomiast linia trybu lub linia pusta składa się z nieparzystej liczby linii obrazu, to jest ona umieszczana w 5 instrukcji programu dl od linii z numerem $21, a od linii z numerem $20 w 4 instrukcji programu dl umieszczana jest jedna linia pusta. Chodzi o to, aby przerwanie dli zostało wywołane w nieparzystej linii obrazu, bo w takiej linii następuje zmiana rejestru $D40B.

Opis interfejsu:

Aby wykonać test:

Wczytujemy z dysku testy.atr program QA. W programie QA wczytujemy plik TEST1.ASM, kompilujemy i uruchamiamy. Przy pomocy klawiszy J oraz ; wybieramy instrukcję programu dl, w której zostanie ustawione przerwanie dli. Oczekujemy na pojawienie się wyników. Następnie wychodzimy z testu i QA. Za pomocą komendy SAV TEST1 600 6FF zapisujemy 6 stronę pamięci do pliku TEST1. Po raz kolejny test możemy uruchomić instrukcją RUN 9000.

Opis testu 1a dla emulatora Atari800Win PLus 3.1

Określamy, w którym cyklu w linii trybu $00+$80 pojawia się nowa wartość w rejestrze $D40B. Program dl ma postać:

dlist   dta b($70),b($70),b($70)
linia1  dta b($00)
linia2  dta b($00+$80)
linia3  dta b($00)
        ...

W trakcie rysowania linii linia1 i linia2 rejestr $D40B ma wartość $10, a w trakcie rysowania linii linia3 rejestr $D40B ma wartość $11. Ponadto w linia2 ustawione jest przerwanie dli. Na początku procedura przerwania dli ma postać:

dli     pha
        sta $d40a
        cmp 0
        lda $d40b
        ...
Test 1a.1 Wynik testu 1a.1 dla emulatora.

Z dokumentacji Atari Hardware Manual wynika, że po instrukcji STA $D40A procesor jest wstrzymywany do 103 cyklu w linii. W procedurze przerwania dli po instrukcji STA $D40A mamy instrukcje CMP 0 i LDA $D40B, których wykonanie zajmuje odpowiednio 3 i 4 cykle maszynowe. Zatem odczyt wartości z komórki $D40B nastąpi w 110 cyklu w linii (103 + 3 + 4 = 110). Z komórki $D40B zostaje odczytana wartość $10. Zmieniamy teraz w źródłach testu procedurę przerwania dli w następujący sposób:

dli     pha
        sta $d40a
        nop
        nop
        lda $d40b
        ...
Test 1a.2 Wynik testu 1a.2 dla emulatora.

W procedurze przerwania dli po instrukcji STA $D40A mamy teraz instrukcje NOP, NOP i LDA $D40B, których wykonanie zajmuje odpowiednio 2, 2 i 4 cykle maszynowe. Zatem odczyt wartości z komórki $D40B nastąpi teraz w 111 cyklu w linii (103 + 2 + 2 + 4 = 111). Z komórki $D40B zostaje odczytana wartość $11.

Opis testu 1b dla emulatora Atari800Win PLus 3.1

Określamy, w którym cyklu w linii trybu $4C+$80 pojawia się nowa wartość w rejestrze $D40B. Test 1b przebiega analogicznie jak test 1a. Program dl ma teraz postać:

dlist   dta b($70),b($70),b($70)
linia1  dta b($00)
linia2  dta b($4c+$80),a($9185)
linia3  dta b($00)
        ...

Uzyskane wyniki są takie same, jak w przypadku testu 1a.

Interpretacja testu 1a i testu 1b dla emulatora Atari800Win PLus 3.1

W emulatorze Atari800Win PLus 3.1 nowa wartość w rejestrze VCOUNT ($D40B) pojawia się w 111 cyklu maszynowym w linii.

Opis testu 1a i testu 1b dla komputera Atari 800XE

Testy przebiegają analogicznie jak w emulatorze, z tym że rozpatrujemy tylko jedną procedurę przerwania dli:

dli     pha
        sta $d40a
        cmp 0
        lda $d40b
        ...
Test 1a Wyniki testu 1a dla komputera Atari 800XE.
Test 1b Wyniki testu 1b dla komputera Atari 800XE.

Interpretacja testu 1a i testu 1b dla komputera Atari 800XE

Wyniki testów pokazują, że wartości, jakie zostaną odczytane z rejestru $D40B zależą od instrukcji dl, w której jest ustawione przerwanie dli. Należało by również sprawdzić, czy zależą one od numeru linii, od tego czy instrukcja dl zmienia wskaźnik danych dla obrazu i od tego, czy w instrukcji dl ustawione jest przerwanie dli.

Możliwe są następujące interpretacje:

  1. Po instrukcji STA $D40A procesor jest wstrzymywany raz do 102 a raz do 103 cyklu w linii.
  2. Nowa wartość w rejestrze $D40B pojawia się raz w 110 a raz w 111 cyklu w linii.
  3. Inne interpretacje.

Osobiście wydaje mi się, że interpretacja nr 1 jest najbardziej prawdopodobna. Jeśli jest ona prawdziwa, to nowa wartość w rejestrze $D40B pojawia się w 110 cyklu w linii, czyli tuż po zakończeniu rysowania szerokiego pola gry. Szerokie pole gry rysowane jest od 44 do 219 cyklu koloru, co odpowiada cyklom maszynowym od 22 do 109. Jeśli w procedurze przerwania dli z rejestru $D40B zostaje odczytana wartość $10, to po instrukcji STA $D40A procesor został wstrzymany do 102 cyklu w linii, a wartość $10 została odczytana w 109 cyklu w linii (102 + 3 + 4 = 109). Jeśli natomiast z rejestru $D40B zostaje odczytana wartość $11, to po instrukcji STA $D40A procesor został wstrzymany do 103 cyklu w linii, a wartość $11 została odczytana w 110 cyklu w linii (103 + 3 + 4 = 110).

Wyjaśnienie testu 1a i 1b dla komputera Atari 800XE

Nie jest prawdą, że "procesor jest wstrzymywany raz do 102 a raz do 103 cyklu w linii". Niemniej jednak interpretacja 1 będzie potrzebna do zrozumienia testu 3. Zanim podamy wyjaśnienie testu 1a i 1b opiszemy najpierw na czym się ono opiera oraz opiszemy w jaki sposób komputer zachowuje się po wykonaniu przez procesor instrukcji STA $D40A (WSYNC).

Po wykonaniu przez procesor instrukcji STA $D40A Antic utrzymuje stan 0 na nóżce RDY procesora. W książce „Mikroprocesor 6502 i jego rodzina” - Henryk Kruszyński, Krzysztof Kulpa znalazłem takie oto informacje na temat sygnału RDY:

Str. 49
„(...) Jeśli jednak w czasie cyklu odczytu (w 65C02 - w dowolnym cyklu) w jego pierwszej fazie sygnał RDY stanie się równy 0, to praca mikroprocesora zostanie zatrzymana (tzn. ten sam cykl powtarza się aż do zniknięcia stanu RDY = 0). (...)”
Str. 61
„(...) Po podaniu na linię READY stanu 0 procesor powtarza cykl odczytu (dla wersji CMOS każdy cykl) tak długo, dopóki nie stwierdzi w fazie fi2 stanu 1 na tej linii (rys. 6.3). (...)”

Wyjaśnienie testu 1 opiera się na założeniach:

  1. Po STA $D40A stan 0 na nóżce RDY utrzymywany jest do 103 cyklu maszynowego w linii.
    (Na podstawie diagramu z Atari Hardware Manual.)
  2. Jeśli zapis w instrukcji STA $D40A przypada na z-ty cykl w linii, to stan 0 na nóżce RDY pojawi się w z+2 cyklu w linii.
    (Hipoteza zweryfikowana przez test 3.)

Możliwe są dwa przypadki:

...z1w...w23...
Pierwsza instrukcja po STA $D40A rozpocznie się od drugiego taktu w 104 cyklu w linii. Mamy wtedy wrażenie, że procesor został wstrzymany do 102 cyklu w linii.
...zdw...w123...

Pierwsza instrukcja po STA $D40A rozpocznie się od pierwszego taktu w 104 cyklu w linii. Mamy wtedy wrażenie, że procesor został wstrzymany do 103 cyklu w linii.

Objaśnienia:

Interpretacja testu 1 dla komputera Atari 800XE

W komputerze Atari 800XE nowa wartość w rejestrze VCOUNT ($D40B) pojawia się w 110 cyklu maszynowym w linii.

Test 2

Test 2 jest bardzo podobny do testu 1. Różnica polega na tym, że wartości z rejestru $D40B odczytujemy 256*12 razy i zapisujemy w obszarze pamięci od $9500 do $A0FF. Na ekranie jest wypisywana tylko pierwsza strona odczytanych wartości. Źródła testu 2 dostępne są tu.

Test 2a Wyniki testu 2a dla komputera Atari.
Test 2b Wyniki testu 2b dla komputera Atari.

Test 3

Test 3 ma na celu określenie, w których cyklach maszynowych w linii Antic odświeża pamięć. Źródła testu 3 dostępne są tu.

Opis testu:

Fragment programu dl ma postać:

dlist   dta b($70)
        dta b($70)
        dta b($70+$80)

linia1  dta b($10)
        ...

Instrukcja $10 programu dl generuje linię pustą, która składa się z dwóch linii obrazu. W pierwszej i drugiej linii obrazu linii pustej LINIA1 rejestr $D40B ma wartość $10, a jego nową wartość $11 można odczytać w 110 cyklu maszynowym drugiej linii obrazu. W drugiej linii obrazu linii pustej LINIA1 Antic "kradnie" tylko 9 cykli maszynowych przeznaczonych na odświeżanie pamięci (dmar) - inne rodzaje dma nie występują. Przerwanie dli ustawione jest w trzeciej instrukcji programu dl. Fragment procedury przerwania dli ma postać:

start   sta $d40a
        cmp 0
        lda $d40b vcount
        ...

Procedura przerwania dli została napisana w taki sposób, że zapis w instrukcji STA $D40A przypada kolejno na ostatni 113 cykl maszynowy pierwszej linii obrazu linii pustej linia1 oraz na następne cykle maszynowe drugiej linii obrazu linii pustej LINIA1. Przyjmijmy, że zapis w instrukcji STA $D40A przypada na z-ty cykl maszynowy w linii. Jeśli z komórki $D40B zostaje odczytana wartość $10, to mamy przypadek:

...z1w...w23...

Pierwsza instrukcja po STA $D40A czyli CMP 0 rusza od 2 taktu w 104 cyklu maszynowym w linii, a wartość $10 zostaje odczytana w 109 cyklu w linii (103 + 3-1 + 4 = 109). Możemy zatem stwierdzić, że odświeżanie pamięci (dmar) nie wystąpiło w z+1 cyklu maszynowym w linii. Jeśli natomiast z komórki $D40B zostaje odczytana wartość $11, to mamy przypadek:

...zdw...w123...

Pierwsza instrukcja po STA $D40A czyli CMP 0 rusza od 1 taktu w 104 cyklu maszynowym w linii, a wartość $11 zostaje odczytana w 110 cyklu w linii (103 + 3 + 4 = 110). Możemy zatem stwierdzić, że odświeżanie pamięci (dmar) wystąpiło w z+1 cyklu maszynowym w linii. Należy więc zapamiętać numer z+1 cyklu a następnie w podobny sposób zbadać pozostałe cykle w linii. Po zakończeniu testu na ekranie wypisywane są numery cykli w linii, w których Antic odświeża pamięć.

Opis interfejsu:

Test 3 Wyniki testu 3 dla komputera Atari 800XE.

Test 4

Test 4 ma na celu określenie, w którym cyklu maszynowym w linii rozpoczyna się przerwanie dli. Źródła testu 4 dostępne są tu.

Przerwanie dli należy do grupy przerwań niemaskowalnych (ang. Non-Maskable Interrupt). Oznacza to, że żądanie tego przerwania nie może zostać zignorowane przez procesor. Przerwanie niemaskowalne zostaje zainicjowane, jeśli na nóżce NMI procesora pojawi się stan 0. Wejście NMI jest wrażliwe na opadające zbocze, a nie na poziom sygnału równy 0. Innymi słowy, skok sygnału z 1 na 0 wymusi przerwanie, ale trwające nadal 0 nie zainicjuje następnego przerwania. W odpowiedzi na żądanie przerwania NMI procesor wykonuje następujący ciąg działań:

Rozpoczyna procedurę przerwania:

W tym miejscu należy wyjaśnić co oznacza sformułowanie "przerwanie rozpoczyna się w x-tym cyklu maszynowym w linii". Otóż oznacza ono, że procedura przerwania rozpocznie się po instrukcji, której jeden z taktów przypada na x-ty cykl w linii. Zdanie "kończy wykonanie bieżącego rozkazu" odnosi się właśnie do tej instrukcji. Zakończenie instrukcji, której jeden z taktów przypada na x-ty cykl w linii może trwać od 1 do 7 cykli. Jeśli rozpoczęcie przerwania przypada na ostatni takt instrukcji, to jej zakończenie potrwa 1 cykl. Jeśli rozpoczęcie przerwania przypada na pierwszy cykl 7 taktowej instrukcji, to jej zakończenie potrwa 7 cykli. Nie bierzemy tu pod uwagę nie publikowanych rozkazów 6502, których wykonanie może zabrać więcej niż 7 taktów. Sama procedura przerwania trwa 7 cykli. Zatem może upłynąć od 8 do 14 cykli zanim procesor rozpocznie program przerwania. Jeśli przerwanie dli rozpoczyna się w 8 cyklu w linii, to program przerwania rozpocznie się w przedziale od 16 do 22 cyklu w linii.

Program przerwania musi zostać zakończony instrukcją RTI (ang. ReTurn from Interrupt). Po napotkaniu tego rozkazu procesor wykonuje następujący ciąg działań:

W procesorze jest jeszcze nóżka IRQ (ang. Interrupt ReQuest). Sygnał dochodzący tutaj jest traktowany podobnie jak w przypadku NMI, ale:

Opis testu:

Fragment programu dl ma postać:

dlist   dta b($70)
        dta b($70)
        dta b($70)

linia1  dta b($20+$80)
        ...

Instrukcja $20+$80 programu dl generuje linię pustą, która składa się z trzech linii obrazu. Przerwanie dli jest wywoływane w trzeciej linii obrazu linii pustej LINIA1. Fragment procedury testowej ma postać:

start   lda #0
        lda #1
        ...

Wykonanie instrukcji LDA #0 zajmuje 2 cykle maszynowe. Procedura testowa została napisana w taki sposób, że drugi takt instrukcji LDA #0 przypada kolejno na 0 cykl maszynowy trzeciej linii obrazu linii pustej LINIA1 oraz na następne cykle maszynowe w tej linii. W trzeciej linii obrazu linii pustej LINIA1 rozpoczyna się przerwanie dli. Przyjmijmy, że drugi takt instrukcji LDA #0 przypada na z-ty cykl maszynowy w linii, a przerwanie dli rozpoczyna się w x-tym cyklu maszynowym w linii, gdzie z jest mniejsze lub równe x. Jeśli przerwanie dli rozpocznie się w x-tym cyklu w linii, a program przerwania stwierdzi w akumulatorze wartość 1, to pierwszy i drugi takt instrukcji LDA #0 na pewno nie przypada na x-ty cykl w linii, bo wtedy program przerwania stwierdziłby w akumulatorze wartość 0. Możemy zatem wywnioskować, że przerwanie dli nie rozpoczyna się w z-tym cyklu w linii. Zwiększamy teraz wartość z o 1 i powtarzamy test aż do momentu, gdy program przerwania stwierdzi w akumulatorze wartość 0. Jeśli program przerwania stwierdzi w akumulatorze wartość 0, to przerwanie dli rozpoczęło się w drugim takcie instrukcji LDA #0. Możemy zatem wywnioskować, że przerwanie dli rozpoczyna się w z-tym cyklu maszynowym w linii. Po zakończeniu testu na ekranie wypisywany jest numer cyklu w linii, w którym rozpoczyna się przerwanie dli.

Opis interfejsu:

Test 4 Wyniki testu 4 dla komputera Atari 65XE.

Test 5

Test 5 ma na celu określenie, w którym cyklu maszynowym w linii Antic sygnalizuje wystąpienie przerwania dli. Źródła testu 5 dostępne są tu.

Opis testu:

Fragment program dl ma postać:

dlist   dta b($70)
        dta b($70)
        dta b($70)

linia1  dta b($20+$80)
        ...

Instrukcja $20+$80 programu dl generuje linię pustą, która składa się z trzech linii obrazu. Przerwanie dli jest wywoływane w trzeciej linii obrazu linii pustej LINIA1. Fragment procedury testowej ma postać:

start   lda $d40f nmist

        cmp #$9f
        beq nmi
        ...

Procedura testowa została napisana w taki sposób, że odczyt w instrukcji LDA $D40F przypada kolejno na 0 cykl maszynowy trzeciej linii obrazu linii pustej LINIA1 oraz na następne cykle maszynowe w tej linii. W trzeciej linii obrazu linii pustej LINIA1 Antic sygnalizuje wystąpienie przerwania dli. W poniższym rozumowaniu zakładamy, że Antic sygnalizuje wystąpienie przerwania dli przed jego rozpoczęciem. Przyjmijmy, że odczyt w instrukcji LDA $D40F przypada na z-ty cykl maszynowy w linii. Jeśli z komórki $D40F zostaje odczytana wartość $1F, to Antic nie zasygnalizował wystąpienia przerwania dli w z-tym cyklu. Zwiększamy zatem wartość z o 1 i powtarzamy test aż do momentu, gdy z komórki $D40F zostanie odczytana wartość $9F. Jeśli z komórki $D40F zostaje odczytana wartość $9F, to Antic zasygnalizował wystąpienie przerwania dli w z-tym cyklu w linii. Po zakończeniu testu na ekranie wypisywany jest numer cyklu w linii, w którym Antic sygnalizuje wystąpienie przerwania dli.

Opis interfejsu:

Test 5 Wyniki testu 5 dla komputera Atari 65XE.

Credits

Inne testy wykonali: Buster, Dely, Marok, Miker, Newton i Pixel.

Strona główna