| Start | Super Packer | Atari Graphics Studio / AGS | Graph2Font / G2F | Mads | MadPascal |   http://madteam.atari8.info  
SKŁAD GRUPY
PRODUKCJE
scena
gry
użytki
vbxe
SPRZĘT
Sio2SD / Pajero
Sio2SD / Rocky
Stereo / Pajero
GTIA / Psychol
ANTIC + VBXE test
ARTYKUŁY
DEMO EFFECTS
LINKI
   

Piotr Fusik (Fox/Taquart)
Tryby graficzne 9++ oraz 10++
Atarynka #2/2002

Najczęściej używanym trybem jest chyba tzw. "tryb Konopa" użyty po raz pierwszy właśnie przez Konopa/Shadows w "Asskickerze". Od lat jest on wykorzystywany i nie pojawił się chyba żaden tryb będący równie "szybki" i dający podobne parametry ekranu (czyli proporcjonalne piksele, niedużą pamięć ekranu, 16 odcieni, ewentualnie inny tryb GTIA).

lewiS/AiDS "32 odcienie w trybie dziewiątym" (artykuł zamieszczony w "Atarynce" nr 1/2002)

W niniejszym artykule przedstawię sposób uzyskania trybu, który wizualnie różni się od "trybu Konopa" (znanego też jako tryb 9+) brakiem pustych linii i nazywa się, w zależności od użytego trybu GTIA, trybem 9++ lub 10++.

Zalety nowego trybu
  1. Tryb ten jest szybszy od trybu z pustymi liniami (9+).
  2. Display List jest znacznie krótszy (każda linia trybu jest tworzona przez jedną instrukcję DL).
  3. Dzięki temu, że DL dla tego trybu może ładować licznik pamięci obrazu tylko na początku, przy dwubuforowaniu nie jest wymagane tworzenie dwóch DL, a wystarczy zmienianie adresu obrazu zapisanego w DL.
  4. Można łatwo ustawić dowolną (do 16) wysokość linii trybu (np. 3,5 lub 6 zamiast 4).
  5. Wygląda to ładniej - jest to rzecz gustu, ale moim zdaniem kolory w trybie 10 GTIA wyglądają znacznie lepiej - tradycyjne czarne linie zmniejszają jasność i nasycenie.
Wady
  1. Tryb zapewnia mniejsze zużycie cykli przez ANTIC, kosztem dodatkowej pracy, jaką musi wykonać 6502. Operacji, które musi wykonać CPU, jest mało, niestety muszą one być odpowiednio zsynchronizowane z obrazem. W praktyce oznacza to, że uzyskanie zalety 1 nie jest takie proste, tj. wymaga pewnego nakładu pracy programistycznej.
  2. Jak wiadomo, istnieją problemy z wyświetleniem grafiki w ostatniej linii ekranu. Nie jest to przeszkodą dla trybu 9+, bowiem na końcu DL można umieścić rozkaz JVB, uzyskując 60 linii. W trybie 9++/10++ pozostaje nam zadowolić się 59 liniami lub... skorzystać z zalety 4 i zmniejszyć wysokość górnej lub dolnej linii do 3.
Idea

Pomysł jest prosty - sprawić, by ANTIC wyświetlał tę samą linię kilka razy, wykorzystując swoją wewnętrzną pamięć. Sytuacja taka ma miejsce np. w trybie 8 (systemowy GRAPHICS 3), gdzie dane są pobierane tylko w pierwszej linii, a potem już tylko z pamięci ANTICa.

Teoria

ANTIC posiada wewnętrzny 4-bitowy rejestr DCTR, który zlicza nr linii ekranowej. Normalnie dla każdej linii trybu zlicza on od zera do wartości zależnej od trybu (w interesującym nas przypadku trybu ANTICa 15 jest to 0). Sytuacja wygląda inaczej po włączeniu pionowego skrola. W pierwszej takiej linii DCTR liczy od VSCROL do 0, w następnych normalnie, a w ostatniej skrolowanej linii od 0 do VSCROL. "Liczy od a do b" należy rozumieć następująco: na początku do DCTR jest ładowana wartość a, pod koniec każdej linii DCTR jest porównywany w wartością b, jeśli jest równość, podejmowana jest decyzja o pobraniu kolejnej instrukcji Display List. W przeciwnym przypadku DCTR jest zwiększany o 1.

Załóżmy, że mamy następujący DL: $2F$0F oraz VSCROL=13 (dziesiętnie). Wtedy na ekranie widzimy:

  1. pierwszą linię 4 razy
    (wartości DCTR 13,14,15,0 - następuje "przekręcenie" z 15 na 0, gdyż DCTR jest 4-bitowy)
  2. drugą linię 14 razy (wartości DCTR od 0 do 13)

Natomiast dla VSCROL=3:

  1. pierwszą linię 14 razy
  2. drugą linię 4 razy

Co ważne, dane obrazu wyświetlane w kolejnych liniach ekranowych, są pobierane z pamięci tylko raz.

Uzyskanie trybu

Jak nietrudno się domyślić, żeby każda linia została wyświetlona 4 razy, tworzymy następujący Display List:

 b($6f),a(ekran)
 b($0f)
 b($2f),b($0f)...

i musimy tylko w odpowiednich momentach zmieniać zawartości rejestru VSCROL.

W zrozumieniu działania trybu powinien pomóc zamieszczony rysunek. Zostały na nim schematycznie przedstawione dwie linie trybu, czyli 8 linii ekranowych. Jest to zarazem zobrazowanie czasu (bez zachowania skali), który płynie wraz z wyświetlaniem każdej linii od lewej do prawej. Na początku rejestr VSCROL musi zawierać 13 (jest to rejestr 4-bitowy, więc górna połówka bajtu zapisywanego pod $D405 może być dowolna). Gdy ANTIC przepisze tę wartość do DCTR, gwarantuje to poprawne wyświetlanie pierwszej linii. Następnie będzie wyświetlana druga linia trybu i dopiero pod koniec jej ostatniej linii ekranowej wymagane jest, aby zawartość VSCROL wynosiła 3.

Mamy więc bardzo dużo czasu na wpisanie wartości 3 do VSCROL. Można to zrobić np. na przerwaniu DLI w pierwszej linii trybu. Gorzej jest z przygotowaniem do wyświetlenia kolejnej, tj. trzeciej linii trybu. Na rysunku został zaznaczony mały obszar, w którym powinniśmy wpisać 13 do VSCROL i rzeczywiście jest to niewielki przedział czasu.

            DCTR |                                                      |
           -----------------------------------------------------------------
VSCROL=13  * 13  |                                                      |
             14  |                                                      |
             15  | pierwsza linia trybu (bit 5 w rozkazie DL ustawiony) |
             0   |                                                      |
           -----------------------------------------------------------------
             0   |                                                      |
             1   |  druga linia trybu (bit 5 w rozkazie DL skasowany)   |
             2   |                                                      |
             3   | * tutaj startuje przerwanie DLI                      |   * VSCROL=3
           -----------------------------------------------------------------  VSCROL=13
                 |                                                      |
                  <----------------- widoczny obraz ------------------->

Możliwe realizacje

Aktualizację rejestru VSCROL, możemy wykonywać:

  1. używając przerwania DLI,
  2. wplatając ją w rozpętlony kod naszego efektu,
  3. używając jednego z przerwań liczników POKEY-a

Rozwiązanie a) jest niewątpliwie najprostsze w realizacji, niestety jest też najwolniejsze. Optymalna jest realizacja b), niestety można ją zastosować tylko w przypadku prostych efektów, jak np. bump mapping. Ciekawa jest realizacja c), która ma tę przewagę nad a), że przerwanie licznika POKEY-a można ustawić z dokładnością do cyklu, dzięki czemu nie musimy "wytracać" czasu po odebraniu przerwania. Niestety rozwiązanie to w praktyce (czyli w grze lub produkcji scenowej) odpada, gdyż liczniki POKEY-a służą jednocześnie do generowania dźwięku, a nie chcielibyśmy znacznie pogarszać muzyki (mniej kanałów) tylko dlatego, że chcemy włączyć ciekawy tryb graficzny.

Procedura przerwania DLI

Zależy nam na tym, aby obsługa tego przerwania zajmowała jak najmniej czasu. Okazuje się wystarczające użycie DLI co drugą linię trybu, tj. co 8 linii ekranowych, w rozkach DL ze skasowanym bitem 5. Przerwanie zostaje zgłoszone dość blisko początku ostatniej linii ekranowej linii trybu (patrz rysunek).

W ogólnym przypadku po odebraniu przerwania NMI należy sprawdzić jego rodzaj (DLI czy VBLKI) i zapamiętać rejestry (co najmniej akumulator). Mimo wszystko pozostaje dość dużo czasu, zanim powinniśmy wpisać 13 do VSCROL. Najprościej wytracić ten czas (i jednocześnie zapewnić właściwą synchronizację) korzystając z WSYNC. Następnie zapisujemy 13 do VSCROL i okazuje się, że jest już wystarczająco późno, aby wpisać tam 3. Jak widać na załączonym listingu, przerwanie jest też wywoływane przed pierwszą linią trybu, tj. w rozkazie tworzenia dwóch pustych linii. Zadając sobie dodatkowy trud, można zaoszczędzić nieco cykli wpisując zamiast tego 13 do VSCROL, np. na przerwaniu VBLANK i wywołując inną procedurę przerwania DLI w pierwszej linii trybu, która to procedura nie będzie musiała oczekiwać, a jedynie wpisze 3 do VSCROL.

To, co może nie być oczywiste na pierwszy rzut oka, to dlaczego w procedurze DLI wpisujemy 3 do VSCROL na końcu, zamiast np. przed zapisem do $D40A? Przecież na rysunku jest zaznaczone, że wartość VSCROL w drugiej linii trybu jest sprawdzana pod koniec linii ekranowej. Otóż istotnie właśniee tam następuje sprawdzenie, czy należy zakończyć wykonywanie aktualnego rozkazu DL.

Natomiast, jeśli jest wykorzystywane przerwanie DLI, musi ono być wywołane w ostatniej linii ekranowej linii trybu, dlatego występuje drugie (a pierwsze w kolejności wykonania) porównanie DCTR z VSCROL. Wobec tego VSCROL musi zawierać 3 już w momencie zgłaszania przerwania.

Ile cykli zyskujemy?

To pytanie jest ważne, bo przecież jako pierwsza zaleta tego trybu została wymieniona szybkość. Jedna linia trybu 9+ może zostać opisana w Display List następująco:

 b($0f),b($00)
 b($4f),a(ekran)
 b($00)

Razem: 6 cykli na DL + (64 lub 80) cykli na ekran (w zależności od szerokości). Dla trybu 9++ jest to jedna instrukcja DL, czyli 1 cykl na DL + (32 lub 40) cykli na ekran. Dodatkowo 6502 musi zaktualizować VSCROL, co trwa 6 cykli. Licząc cały ekran (instrukcja dwóch pustych lini, 59 linii trybu, w pierwszej linii trzeba podać adres ekranu - 2 cykle, rozkaz JVB) otrzymujemy:

    Wąski ekran:
  1. 9+: 1+59*(6+64)+2+3=4136
  2. 9++: 1+59*(1+32+6)+2+3=2307
  3. Normalny ekran:
  4. 9+: 1+59*(6+80)+2+3=5080
  5. 9++: 1+59*(1+40+6)+2+3=2779

Z grubsza zyskujemy więc ok. 6-7% czasu procesora. Niestety jest tak tylko w przypadku optymalnym, tj. wplataniu aktualizacji VSCROL w kod. Jeśli użyjemy przerwania DLI w przedstawionej postaci, okaże się, że tryb 9++ jest niestety nieco wolniejszy od trybu 9+ (ale wciąż wyraźnie szybszy od "trdycyjnego" trybu bez pustych linii). Jest tak ze względu na tracenie czasu w instrukcji "STA $D40A".

Dobrym (chociaż trudnym) rozwiązaniem jest wykorzystanie tego czasu np. na jakieś pożyteczne obliczenia. Nie należy też zapominać o innych zaletach trybu 9++, które mogą okazać się decydujące. Dodatkową zaletą jest to, że jeśli wykorzystujemy już przerwanie DLI, możemy niewielkim kosztem dokonać zmiany koloru tła w różnych miejscach ekranu.

Piotr Fusik (Fox/Taquart)


;	MODE 9++

	org $2000

	mwa #dli $200

	mva #$22 $22f
 
	mwa #dl $230

	mva #$40 $26f

	mva #$c0 $d40e

	jmp *


dli	pha
	sta $d40a
 
	lda #13
	sta $d405

	lda #3
	sta $d405

	pla
	rti

dl	dta $90,$6f,a($f000)	; 2 puste linie, 1 linia trybu
	:29 dta a($2f8f)		; $8f,$2f powtorzone 29 razy => 58 linii
  	dta $41,a(dl)

P.S. Opisaną metodę można zastosować do uzyskania innych ciekawych trybów, jak np. sprzętowy tryb tekstowy 40x40 znaków.



Zebrane produkcje z ostatnich lat dla Atari 8bit XE/XL (11 MB)
 

madteam.atari8.info © MadTeam, hosted: www.atari8.info