Ramka Atari by Kaz 2009-09-05 18:09:46

Paweł "Pavros" Rosowski (dawniej ksywa Ikplus):

Ramka (ang. border) to obszar na obrzeżach ekranu, otaczający właściwe pole obrazu. Z założenia jest to obszar, gdzie nic się nie wyświetla. Ramka pełni funkcję marginesu i jest (a w zasadzie była) konieczna ze względu na krągłości kineskopu oraz to, że rożne monitory i telewizory mają różnie poustawiane wysokości i szerokości wyświetlanego pola obrazu czy jego przesuniecie w pionie i poziomie. Komputery 8- i 16-bitowe posiadają zazwyczaj oddzielny rejestr do ustawiania koloru ramki, dzięki czemu jest on niezależny od kolorów właściwego obrazu. Tak jest na przykład w C64.



Ze względu na swoją niedostępność narzuconą przez konstruktorów sprzętu ramka stanowiła wielkie wyzwanie i była częstym celem ataków różnych koderów, którzy udowadniali, że jak najbardziej można na jej obszarze wyświetlać obraz. Powstawały nawet dema dedykowane tej kwestii, np. „Death of the left border” na Atari ST. Efekt osiągano różnymi metodami. Na ogół udawało się wymusić DMA obrazu (Atari ST) albo używało się sprite’ów (C64) po uprzednich zręcznych zmianach zawartości odpowiednich rejestrów w odpowiednim czasie . Wyłączenie ramki górnej i dolnej jest mało kosztowne czasowo, ponieważ dla jednej i drugiej czynność tą wykonuje się raz na klatkę obrazu. Pozbycie się ramek bocznych jest za to bardzo kosztowne, ponieważ trzeba wyłączać je w każdej linii obrazu.

Ramka w Atari

Ramka w małym Atari nigdy nie budziła wielu emocji ponieważ jej istnienie bądź nieistnienie jest kwestią odpowiedniej konfiguracji ekranu. Aby pozbyć się ramki lewej i prawej wystarczy włączyć tak zwane "szerokie pole" poprzez ustawienie odpowiedniej wartości w rejestrze DMACTL ($D400). Natomiast aby pozbyć się ramki górnej i dolnej należy zmodyfikować DisplayList tak, aby pokrywał ona wszystkie dostępne linie obrazu czyli 240. O ile jednak w komputerach z NTSC ta liczba linii pokrywa cały ekran, o tyle w komputerach PAL nie. Mamy więc na górze i dole ekranu nieduży niedostępny obszar ramki, zawsze w kolorze czarnym.

Z ramką w Atari jest pewien problem, gdy jednak zależy nam żeby była. A dokładnie gdy chcemy ją mieć w trybach 4 kolorowych, w szczególności w trybie E Antica (GR.15). Na przykład chcemy mieć czarną ramkę oraz obrazek 160x200 w 4 kolorach, ale żaden z nich nie jest czarny. Albo chcemy w trakcie wyświetlania takiego obrazka wizualizować proces dekompresji w tle jakichś danych poprzez wyświetlanie kolorowych pasków na ramce. Tego się nie da zrobić. Problem polega na tym, że nie można ustawić koloru ramki niezależnie od kolorów obrazu, tak jak w C64. Kolor ramki jest bowiem ustawiany w rejestrze colbak ($D01A) i jest on jednocześnie jednym z czterech kolorów obrazu. Nie ma takiego problemu jedynie w trybach hires gdzie są tylko dwa kolory obrazu ustawiane w colpf1 ($D017) i colpf2 ($D018) oraz właśnie niezależny kolor ramki w colbak.

Tryb E+

Na szczęście okazuje się, że w Atari można uzyskać niezależny kolor ramki w trybach 4-kolorowch. W tym celu trzeba wykorzystać znany trick polegający na włączeniu trybu GTIA (dowolnego), a następnie wyłączeniu go w trakcie trwania linii obrazu. Niestety jest to dość kosztowny trick, ponieważ to podwójne przełączenie należy wykonywać w każdej linii obrazu. Trick ten stosowany jest przeważnie do uzyskania jednocześnie trzech różnych trybów graficznych obok siebie: hires – GTIA – lores 4-kolorowy. Nas interesuje jednak tylko ten ostatni i dlatego przełączenia na tryb GTIA i z powrotem dokonujemy w trakcie tak zwanej "przerwy poziomej", pomiędzy dwoma liniami obrazu. W DisplayList ustawiamy tryb hires czyli na przykład tryb F Antica, jeżeli chcemy uzyskać tryb E. Oczywiście to co uzyskujemy to nie jest prawdziwy tryb E tylko bardzo do niego zbliżony. Ja nazwałem go wstępnie E+ (ponieważ mamy w nim 4 kolory + niezależny kolor ramki) albo też F2E (ponieważ powstaje on przez zamianę trybu F na E). Różnica jest taka, że ANTIC nadaje dane w formacie dla trybu F, a GTIA interpretuje je jako dane dla trybu E. Dzięki temu zmieniają się przypisania rejestrów kolorów do konkretnych kombinacji bitów obrazu. Tabela poniżej obrazuje te przypisania a także stan magistrali pomiędzy układami ANTIC i GTIA (AN2,AN1,AN0):

kombinacja bitów obrazu - kolor rejestr trybu E AN2-AN0 trybu E rejestr trybu E+ AN2-AN0 trybu E+
00 – kolor 0 colbak ($D01A) 000 colpf0 ($D016) 100
01 – kolor 1 colpf0 ($D016) 100 colpf1 ($D017) 101
10 – kolor 2 colpf1 ($D017) 101 colpf2 ($D018) 110
11 – kolor 3 colpf2 ($D018) 110 colpf3 ($D019) 111
ramka colbak ($D01A) 000 colbak ($D01A) 000


Zdjęcia poniżej ukazują efekt wyświetlania różnokolorowych pasków na ramce poprzez zmianę wartości rejestru colbak w trybie E oraz E+:

Paski z użyciem rejestru colbak w trybie E (GR.15)


Paski z użyciem rejestru colbak w trybie E+


Tryb E+ nie jest jakimś nowym odkryciem, raczej stanowi odmienne podejście do trybu 4-kolorowego. Emulatory, które pozwalają wyświetlić wspomniany trick z trzema trybami graficznymi w linii, z pewnością wyświetlą też poprawnie ten tryb. Praktyczne zastosowanie trybu E+ jest bardzo ograniczone ze względu na wspomniany koszt czasowy. Ponadto ramkę można też zasymulować przy pomocy obiektów PMG co, wydawałoby się, czyni ten tryb zupełnie niepotrzebnym, no ale może przecież wystąpić sytuacja, w której wszystkie PMG są wykorzystane do podkolorowania obrazka i wtedy E+ będzie jedynym wyjściem. Na koniec jedna dość ważna uwaga techniczna. Teoretycznie do włączenia E+ należy włączyć na chwilę dowolny tryb GTIA. W praktyce należy zawsze włączać tryb GR.11 (wartość $C0 w rejestrze $D01B), ponieważ przy pozostałych dwóch trybach występują pewne niestabilności w miarę nagrzewania się układu GTIA.

Wysoka ramka 300/i600 w PAL

Całkiem niedawno Gary "Rybags" Ryan wyjaśnił na czym polega bug ANTIC-a objawiający się zrywaniem synchronizacji pionowej, gdy ostatnia 240-sta linia ekranu jest wyświetlana w trybie hires (tryb 2, 3 albo F ANTIC-a). Okazało się, że linie AN2, AN1 i AN0 magistrali między układami ANTIC i GTIA w momencie uaktywnienia bugu zostają ustawione na stałe na 1 (stan wysoki) i utrzymują taką wartość wtedy, gdy włączone jest DMA obrazu. Oznacza to, że ANTIC nadaje do GTIA informację, że wyświetlanie obrazu nadal jest aktywne. GTIA odbierając 1 z linii AN2 nadal jest skłonna wyświetlać treść odbieraną od ANTIC-a na liniach AN1 i AN0. Ostatecznie to co jest wyświetlane po linii 240 to obraz w trybie hires składający się z samych jedynek. DMA obrazu niestety nie działa, choć jest włączone. Nie można więc wyświetlić normalnego obrazu, ale przynajmniej można wpływać na wyświetlany kolor. To oznacza, że jednak można ingerować w niedostępny dotąd obszar poniżej, a także powyżej środkowych 240-stu linii. Powyżej też, ponieważ działanie bugu rozciąga się aż do przekręcenia licznika linii ANTIC-a na 0, czyli do pierwszej linii z DisplayList następnej klatki. Oczywiście należy pamiętać, że z powodu bugu ANTIC-a nie jest generowany sygnał synchronizacji pionowej i trzeba go wygenerować programowo – podobnie jak robi to Rybags dla trybu interlace. W naszym przypadku trzeba to jednak robić w każdej klatce, a nie w co drugiej.

W systemie PAL w trybie interlace klatka obrazu składa się z 625 linii, z czego 25 jest zawsze wygaszonych (w Atari mamy 624 linie w trybie interlace sprzętowym i 312 normalnie). Pozostałe 600 zawiera treść obrazu, choć w praktyce widoczne jest jakieś 520-580 zależnie od monitora/telewizora. Oznacza to, że w trybie bez interlace’u, czyli takim jaki mamy standardowo w Atari, treść obrazu może być wyświetlana aż w 300 liniach. W załączonych przykładach faktyczna wysokość obrazu to 296 linii w trybie standardowym i 592 linii w trybie interlace. Dokładnie tyle udało się zobaczyć na monitorze Commodore 1084S po maksymalnym zwężeniu obrazu w pionie. Takiej ilości linii nie da się wyświetlić raczej na żadnym telewizorze. Nie ma jednak problemu (w kodzie), by zwiększyć tę ilość do odpowiednio 300 i 600, a nawet więcej, choć to pewnie zakończyłoby się zerwaniem synchronizacji. Można zatem uznać, że w Atari mamy możliwość ingerencji w treść obrazu na jego pełnej wysokości zdefiniowanej dla systemu PAL.

W przypadku wysokiej ramki w trybie interlace (sprzętowym) sprawa jest nieco bardziej skomplikowana niż w trybie standardowym, ponieważ konieczne jest generowanie sygnału synchronizacji pionowej na dwa sposoby – w zależności od tego, który półobraz ma być wyświetlany. Zdjęcie poniżej pokazuje przebieg złożonego sygnału synchronizacji dla obu półobrazów. Kod, który zaprezentował Rybags, generuje dokładnie taki sygnał, jaki widzimy w liniach 313-315. Na podstawie zależności czasowych w jego kodzie udało mi się napisać analogiczny dla linii 1-3. Co ciekawe, linie drugiego półobrazu („Drugie pole”) czyli tego rozpoczynanego przez kod Rybagsa wyświetlane są o pół linii wyżej niż linie pierwszego półobrazu. Wydawałoby się że powinno być odwrotnie, ale tak nie jest. Być może ma to związek z faktem, że Atari generuje 624 a nie 625 linii.

Złożony sygnał synchronizacji w systemie PAL


Jest pewna wada wysokiej ramki na którą nie ma rady. Mianowicie jest ona tylko tak szeroka jak szerokie pole wyświetlania. Jak wiadomo, szerokie pole nie jest symetryczne względem standardowego. Z lewej strony jest go trochę mniej niż z prawej. To powoduje, że mamy lekkie ubytki wysokiej ramki, oczywiście tylko w obszarze poza standardowymi 240-stoma liniami. Widać to na zdjęciach w lewym górnym i lewym dolnym rogu. Obraz na monitorze 1084S jest jednak trochę zwężony. Na większości monitorów/telewizorów nie powinno być widać tej niedogodności.

Wysoka ramka a obiekty PMG

Okazuje się, że GTIA może wyświetlać obiekty PMG (sprite’y) na wysokiej ramce. Oczywiście poza standardowymi 240-stu liniami DMA sprite’ów nie działa podobnie jak DMA obrazu. Można jednak wpływać na kształt sprite’ów poprzez rejestry $D00D-$D011. To daje możliwość wyświetlania nieskomplikowanej grafiki na wysokiej ramce. Należy pamiętać, że wysoka ramka to tryb hires z samymi jedynkami. To oznacza, że wszystkie piksele ramki mają zawsze priorytet nad sprite’ami jeżeli chodzi o jasność, natomiast przejmują barwę sprite’ów. Aby uzyskać pełną niezależność kolorów sprite’ów od koloru ramki oraz ich wyższy priorytet należy użyć jednego z trybów GTIA lub opisanego wcześniej E+. W trybach GR.9 i GR.11 nie można uzyskać dowolnego koloru ramki, co wynika ze specyfiki tych trybów oraz z faktu, że treść obrazu ramki stanowią same jedynki. W trybie GR.10 oraz w E+ możemy ustawić dowolny kolor ramki. W trybie E+ kolor wysokiej ramki ustawiamy w rejestrze colpf3 ($D019). W trybie GR.10 również w rejestrze colpf3 dla większości powierzchni ramki oraz dodatkowo w colbak($D01A) dla pierwszego piksela (kolumny) od lewej. Powiązanie pierwszego piksela z rejestrem colbak ma związek z faktem przesunięcia o jeden piksel właśnie całego obrazu w trybie GR.10 względem obrazu w trybach GR.9 i GR.11. W trybie GR.9 jasność wysokiej ramki jest maksymalna (15) a o barwie decyduje rejestr colbak. W trybie GR.11 barwa wysokiej ramki jest pomarańczowo-brązowa (15) a o jasności decyduje rejestr colbak. W załączonych przykładach używany jest tryb GR.10.

Paski i sprite’y na wysokiej ramce


Sprite’y na wysokiej ramce


Paski i sprite’y na wysokiej ramce w sprzętowym trybie interlace


Sprite’y na wysokiej ramce w sprzętowym trybie interlace


Praktyczne wykorzystanie wysokiej ramki jest dość ograniczone. Przede wszystkim dlatego, że nie można założyć takiej jej wysokości, dla której byłaby pewność, że jest ona widoczna na wszystkich monitorach/telewizorach. Niemniej jednak cieszy fakt, że w małym Atari możemy mieć kontrolę nad całą powierzchnią ekranu, a nie tylko nad 240 liniami. Niestety efektu wysokiej ramki nie zobaczymy na żadnym z istniejących emulatorów. Przykładowe programy wyświetlające wysoką ramkę nie będą też działać poprawnie na komputerach w systemie NTSC.

Uwaga! Powyższe zdjęcia w wyższej rozdzielczości (1024x768) oraz pliki ilustrujące efekty opisane w artykule dostępne są tutaj.

-----
Update z dnia 9 września 2009 roku: Pavros podesłał źródła użytych programów.
Kaz 2009-09-05 22:23:07

Rewelacyjny tekst, napisany jasno i przystepnie nawet dla takiego amatora jak ja. Dzieki Pavros.

Mam tez pytanie: czy ten tryb E+ mozna by stosowac w obrazkach podkolorowanych jak w G2F, gdzie w wierszu wystepuje ograniczona liczba zmian? W ten sposob mozna by juz na wstepie miec 6 kolorow w trybie 2x1 (w sensie - ramka jako niezalezny kolor i 5 dowolnych kolorow w srodku).

Ramos 2009-09-05 22:45:35

Ciekawy artykuł.

mono 2009-09-05 23:21:34

Świetny artykuł Pavros!

Tezz 2009-09-05 23:22:56

Very informative and well written.

tebe 2009-09-06 00:06:32

na podstawie analizy programu przerwania DLI, teoretycznie powinny być możliwe 3 zmiany na linię (aktualnie w G2F dla ekranu standardowej szerokości limit zmian na linie =4, dla szerokiego limit =3), oprócz właściwej zmiany/przywrócenia wartości rejestru GTICTL ($D01B)

teoretycznie także w trybie znakowym, piszę "teoretycznie" bo nie sprawdzałem tego

czyli teoretycznie to co Kaz napisał, 5 kolorów + czarny kolor ramki

pavros 2009-09-06 00:38:34

Bardzo się cieszę się, że artykuł się podoba.

W kwestii 6 kolorów tzn. 5 kolorów w obrazku i niezależnego koloru ramki to niestety odpowiedź brzmi nie (ale to nie ma związku z G2F). ANTIC przekazuje dane do GTIA po magistrali 3-bitowej AN2-AN0, co oznacza, że mamy 8 możliwych kombinacji stanu tej magistrali. 3 kombinacje używane są do celów synchronizacji (synchronizacja pionowa, przerwa pozioma ustawiająca hires, przerwa pozioma ustawiająca lores). Pozostałe 5 kombinacji oznacza, który z 5-ciu rejestrów koloru z zakresu $D016-$D01A ma być użyty do aktualnego piksela. Czyli maksymalna liczba używanych rejestrów kolorów obrazu to 5. Tryb E+ ma przewagę nad E, że wykorzystuje kombinację, której niewykorzystuje tryb E, czyli 111 (zobaczcie w tabelce w artykule). Tryby 5-cio kolorowe (tylko znakowe) takie jak tryb 4 ANTICa też wykorzystują tą dodatkową kombinację, choć dostęp do niej wygląda inaczej (decyduje najstarszy bit w numerze znaku).

tebe 2009-09-06 01:07:53

czyli nie ma możliwości ustawienia 5-go koloru znaków (invers znaków)

Kaz 2009-09-06 01:31:10

Czyli uzytecznosc trybu E+ w praktyce sprowadza sie do:

a) dodatkowego koloru (na ramke) w trybie GR15. Ale chyba jest to bezcelowe, poniewaz tryb GR15 moze byc zastapiony przez GR12, gdzie 5 kolor tez mozna zuzyc na tlo obrazka i ramka bedzie miala inny kolor niz tlo.

b) dodatkowego koloru (na ramke) w trybie potrojnym (hires-GTIA-GR15). Tutaj to juz mialoby sens, bo tam nie da sie zastapic GR15 przez GR12.

Czy dobrze rozumuje?

tebe 2009-09-06 02:00:57

w trybie znakowych tak samo jak w GED+ (bo metoda Pavrosa to taki program zmian rastra na przerwaniu DLI) każda pierwsza linia nowego wiersza jest "dziurawa"

Rybags 2009-09-06 05:25:36

I only had a brief play with PMGs while playing with the Interlace mode. They don't work "normally" of course, because GTIA expects the HSync signal from ANTIC which alerts it that the next HALT sequence will be for the DMA fetch of the data.

But, not all is lost... you should be able to resume normal PMG DMA conditions by setting the Playfield Width bits to "11" (3).

By doing so, Antic should generate normal scanlines - of course they'll have the unmodifyable data going through to GTIA, to counter that you simply set PF0 and PF1 to colour 00 (as I do anyway).

The other problem is that you still need to do the VSync stuff - leaving the Playfield DMA enabled during VSync means that a proper VSync signal isn't generated.

That's easily countered too - just ensure that you set DMACTL back to 00 a couple of lines before VSync is due.

The timing is critical when you change DMACTL back to 00 because if it occurs during the display portion of a horizontal line, GTIA will receive a HSync command which can cause screen corruption if not done properly. The time to change DMACTL back to 00 is during HBlank - that way, the normal sequence of events shouldn't be disrupted.

Kaczor 2009-09-06 10:49:41

Żeby tak jak ten artykuł, ktoś napisał książkę o assemblerze, było by miło. W taki sposób łatwo dotarły do mojej czachy wyżej wymienione zagadnienia o ramce. Poezja dla chłonących wiedzę inaczej.

irwin 2009-09-06 11:14:56

Pavros - wielkie dzięki za kawał dobrze napisanego artka! Więcej takich tekstów! Takie teksty mogą rzucić nowe spojrzenie na dane zagadnienie, spojrzenie od strony niekoderskiej - vide pytanie Kaz'a całkiem słuszne zresztą. A ponadto świetnie piszesz.

pavros 2009-09-06 11:35:31

@Kaz:
a) Tak jak pisałem w artykule, tryb E+ ma rzeczywiście niewielkie zastosowanie, ale jednak ma, bo są sytuacje, gdzie nie da się zrobić inaczej. Natomiast zastąpienie E+ przez tryb 4 (GR.12) nie zawsze jest możliwe bo ten drugi to tryb tekstowy. A co do niezależnej ramki w trybie 4 to wcale nie jest to takie proste. Trzeba by użyć szerokiego pola, przeznaczyć jeden znak na ramkę (wypełniony samymi jedynkami), umieścić ten znak na obrzeżach obrazka jako znak w inwersie i nie używać inwersu w samym obrazku. Wtedy w colpf3 mielibyśmy niezależny kolor ramki. W sumie jednak włączenie szerokiego pola to mniejszy koszt niż przełączanie GTIA/nie GTIA w każdej linii obrazu, więc po części masz rację.
b) W trybie potrójnym (hires-GTIA-GR15) czyli właściwie (hires-GTIA-E+) niezależny kolor ramki w colbak mamy automatycznie.

Idea trybu E+ polega na zmianie interpretacji danych graficznych przez GTIA z hires no lores. Trick ten stosuje się więc tylko do trybów hires czyli 2,3,i F ANTICa. Zastosowanie go do trybu 2 (GR.0) da w efekcie coś na kształt tybu 4 (GR.12). Różnica będzie jednak taka, że użycie znaku w inwersie nie będzie powodowało użycia 5-tego koloru, lecz faktyczne zanegowanie bitów w wyglądzie znaku. To będzie oznaczać w lores zamianę miejscami kolorów 0 z 3 oraz 1 z 2 w obrębie znaku. Ten efekt mógłby mieć pewne zastosowanie, gdyby tak dobrać wygląd znaków, że ich inwersy również mogą być wykorzystane w obrazku. Wtedy niejako mielibyśmy do dyspozycji 256 różnych znaków zamiast standardowych 128.

@Kaczor: Dziekuję za te piękne słowa :-)

pavros 2009-09-06 11:39:54

@ Irwin: Dzięki. Planuję coś jeszcze :-)

pavros 2009-09-06 11:55:24

@Rybags: Well, I set wide playfield by setting 3 in DMACTL in fact in my examples. But the sprite DMA does not work indeed. So I'm almost sure that it's impossible to have sprite DMA outside of standard 240 scanlines. But still not in 100%. Regarding the other things, I do exactly what you wrote, and that's why it works, I think. :-). BTW, thanku you for explaining ANTIC 240-line bug and for hardware interlace! This was really breakthrough. The high 300/600i scanlines border is just a side effect of your discovery.

BLB 2009-09-06 13:51:11

szkoda ze tv nie potrafi wyswietlic szerokiego ekranu z ramka, zyskalibysmy wyzsza rozdzielczosc poziomia (zawsze to mniejszy piksel).

Rybags 2009-09-06 14:07:32

@ pavros: You're right there - Antic doesn't seem to do PMG DMA outside the normal 240 scanline area. I did a program with VBI/DLI to alter DMACTL to give a stable screen with no blacked out regions... PMs just display whatever is left in their GRAF register, so it looks like any "sprites in the border" demos would need the program to manually load the registers in those regions.

By setting DMA Width to 3 once you've enacted the "Scanline 240 bug", you cause a stable display because Antic still sends the HSync commands at the correct timings. But for the 3 scanlines where VSync occurs, you need to turn DMACTL off so that the VSync pulses are generated properly.

pavros 2009-09-06 14:32:42

@Rybags: Thank you for confirming no ANTIC PMG DMA outside the standard area.

Kaczor 2009-09-06 21:27:48

@ Pavros - słowa uznania ci się należą. Nie znam się na kodowaniu i na pewno nie wyklikam żadnego programu używając porad jakie w tym artku wyczytałem, aby ramka miała taki kolor czy inny. Ale, przynajmniej mam coraz to większą wiedzę o zasadach działania naszego 8-bitowca. Szczerze powiedziawszy, odkąd czytam atarionline to moja wiedza wielu tematach zwiększyła się o 80% do tego co wiedziałem przed. Pozdrawiam!

Factor6 2009-09-07 18:43:07

Very interesting article, thanks!

Kaz 2009-09-09 00:57:51

I added program sources from Pavros.
Dodalem zrodla programow przyslane przez Pavrosa.