Spis Treści

1. WPROWADZENIE
2. PODSTAWY WYŚWIETLANIA OBRAZU W ZX81
3. WIDEO W TRYBIE SLOW
4. WIDEO W TRYBIE FAST
5. UKŁAD WYŚWIETLANIA OBRAZU W ZX81
6. UKŁAD ZNAKOWEGO TRYBU WIDEO
7. UKŁAD TRYBU PSEUDO HIRES
8. UKŁAD TRYBU TRUE HIRES
9. PRZEBIEGI CZASOWE DLA TRYBU ZNAKOWEGO
10. PRZEBIEGI CZASOWE DLA TRYBU PSEUDO HIRES
11. PRZEBIEGI CZASOWE DLA TRYBU TRUE HIRES
12. PROCEDURY WIDEO DLA TRYBU SLOW
13. PROCEDURY WIDEO DLA TRYBU FAST
14. PROCEDURY DLA TRYBU TRUE HIRES
15. PROCEDURY DLA TRYBU PSEUDO HIRES

1. WPROWADZENIE

Gdy przypadkowe okoliczności połączą nowatorskie pomysły techniczne z ekonomicznym projektem i zapotrzebowaniem rynkowym na produkt, zawsze zdarzają się ciekawe rzeczy. W roku 1980 Sinclair nie zawitał jeszcze szeroko pod przysłowiowe strzechy i był bardziej znany być może za sprawą swojego zegarka cyfrowego i kalkulatora niż komputera osobistego ZX80. Jednakże doświadczenie rynkowe zdobyte na sprzedaży ZX80 oraz pojawienie się taniej technologii układów scalonych o dużej skali integracji olśniło go i dało mu możliwość wprowadzenia dostępnej dla wszystkich, łatwej w użyciu i masowo produkowanej wersji komputera ZX80, która posiadała arytmetykę zmiennoprzecinkową oraz stabilny obraz. Narodził się ZX81, a "reszta to historia".

Kluczem taniego projektu ZX81 było połączenie systemu tworzenia obrazu z ZX80, który wykorzystywał mikroprocesor Z80 do większości swoich zadań, z małym obwodem elektronicznym, dostępnym również dla ZX80, tworzącym tryb wyświetlania SLOW - jednoczesne obliczenia oraz generacja obrazu telewizyjnego. Gdy obwód ten został wstawiony do układu logicznego ULA, stał się on nie tylko tani w produkcji, lecz okazał się bardzo wszechstronny i z możliwościami wyświetlania obrazu wykraczającymi znacznie poza pierwotne cele jego twórców.

2. PODSTAWY WYŚWIETLANIA OBRAZU W ZX81

Standardowy ekran wideo dla ZX81 wyświetla 24 wiersze po 32 znaki. Każdy znak posiada wysokość 8 lini skanujących i szerokość 8 pikseli. Znaki do wyświetlenia są zlokalizowane w bloku pamięci zwanym DFILE. Zestaw 128 możliwych do wyświetlenia znaków zawiera 64 zwykłe (tzn. nie w negatywie) duże litery, cyfry, symbole i znaki graficzne oraz ich negatywy. Kody znakowe komputera ZX81 CHR$ 0-63, CHR$ 118 i CHR$ 128-191 są niestandardowe (nie ASCII). Pewien zbiór kodów jest stosowany również dla słów kluczowych, funkcji oraz rozkazów, lecz one zawsze są rozwijane do znaków drukowalnych przed ich wydrukiem w bloku DFILE.

Blok DFILE jest sformatowany poczynając od Sinclairowskiego odpowiednika znaku-CR (powrót karetki - ang. carriage return) o kodzie CHR$ 118, za którym następuje do 32 kodów znakowych, co jest powtarzane 24 razy, a na końcu znów umieszczany jest kod CHR$ 118.

początek DFILE: CHR$ 118  
wiersz nr 0: do 32 znaków CHR$ 118
wiersz nr 1: do 32 znaków CHR$ 118
... do 32 znaków CHR$ 118
wiersz nr 22: do 32 znaków CHR$ 118
wiersz nr 23: do 32 znaków  
koniec DFILE: CHR$ 118  

Znak CHR$ 118 jest kodem instrukcji HALT mikroprocesora Z80 z powodów wyjaśnionych dalej w tym artykule. Pozostałe kody znaków są niedozwolone i jeśli zostaną załadowane do bloku DFILE, najprawdopodobniej spowodują krach systemu (pod symulatorem może się to nie zdarzyć, chyba że masz bardzo dobry symulator, który dokładnie emuluje sprzęt wideo ZX81 - np. eightyOne)..

Zwinięty blok DFILE jest używany w komputerach ZX81 posiadających pamięć RAM o pojemności 1KB lub 2KB w celu minimalizacji wymagań pamięciowych przez obraz. Jeśli na ekranie nic nie jest wyświetlane, to zwinięty blok DFILE składa się jedynie z 25 kodów CHR$ 118. Każdy wiersz jest odpowiednio rozwijany, gdy są drukowane w nim znaki. Powoduje to możliwość powstania błędu braku pamięci przy prostej próbie wyświetlenia czegoś na ekranie!

Jeśli ZX81 posiada 4KB lub więcej pamięci RAM, DFILE jest inicjowane na pełny rozmiar 24 wierszy po 32 znaki CHR$ 0 (spacja) oraz 25 znaków CHR$ 118 kończących każdy wiersz plus jeden na początku bloku.

Kody znaków nie są wy świetlane bezpośrednio lecz raczej używa się ich jako wskaźników adresowych w tablicy matryc znaków przechowywanej na końcu pamięci ROM. Bajty tych matryc są adresowane przez kombinację kodów znaków odczytanych z DFILE oraz układów ZX81 i ładowane do rejestru przesuwnego wideo, skąd trafiają do modulatora telewizyjnego przesyłającego obraz do telewizora. Bit 7 kodu znaku w DFILE jest wykorzystywany przez sprzęt tworzący obraz wideo do odwracania pikseli wyprowadzanych z rejestru przesuwnego do modulatora - jeśli jest ustawiony na 1 (kod znaku > 127), otrzymujemy negatyw matrycy znaku.

Obraz na ekranie powstaje ze strumienia bitowego pikseli wyprowadzanych z rejestru przesuwnego, który włącza i wyłącza strumień elektronów w lampie kineskopowej odbiornika telewizyjnego, gdy ten przebiega po powierzchni ekranu pokrytej wewnątrz luminoforem powodując zaświecanie i gaszenie odpowiednich punktów obrazu. W pełni rozwinięty blok DFILE z 24 wierszami po 32 znaki na wiersz wyświetla 6144 bajtów matrycowych lub 49152 pikseli na jednym obrazie. W ciągu jednej sekundy tworzone jest 50 takich obrazów.

3. WIDEO W TRYBIE SLOW

W trybie SLOW mikroprocesor dzieli swój czas na wykonywanie programu oraz tworzenie obrazu wideo. Do obsługi wideo i klawiatury zużywa on około 80% czasu, a pozostałe 20% przeznaczone jest dla uruchomionych aplikacji. W rzeczywistości czas pracy procesora podzielony jest na cztery oddzielne zadania przy każdej ramce obrazu tv, co pokazano w tablicy 1. Zadania są przełączane za pomocą generatora Przerwań Niemaskowalnych (NMI), który wywołuje procedurę obsługi przerwań NMI kontrolującą przełączanie zadań od asynchronicznego programu aplikacji do procedur tworzenia wideo w czasie rzeczywistym.
 

1. Tworzenie VSYNC, liczenie ramek, obsługa klawiatury NMI wyłączone
2. Wyświetlanie górnego marginesu i wykonywanie programu aplikacji NMI włączone
3. Procedura Wyświetlania Obrazu Wideo NMI wyłączone
4. Wyświetlanie dolnego marginesu i wykonywanie programu aplikacji NMI włączone

Tab.1 Operacje wykonywane w trakcie tworzenia ramki obrazu

Każde z zadań możemy opisać bardziej szczegółowo w sposób następujący:

  1. Podczas tworzenia impulsu synchronizacji pionowej VSYNC dla odbiornika telewizyjnego, gdy żaden obraz właściwie nie jest wyświetlany, mikroprocesor wykonuje procedurę VSYNC o ustalonej liczbie taktów maszynowych, która zwiększa licznik ramek obrazu telewizyjnego FRAMES (4034H - 16436) i odczytuje 8 wierszy danych z klawiatury wraz z bitem trybu 50/60Hz (wersja amerykańska ZX81 generuje 60 ramek na sekundę, podczas gdy wersja europejska tylko 50). Dowolna operacja wejścia/wyjścia z linią adresową A0 = 0 (np. FEH) adresuje port klawiatury w układzie ULA. Powoduje ona również, iż układ ULA rozpoczyna impuls synchronizacji pionowej przez zwarcie wyjścia wideo do poziomu synchronizacji 0V i jednocześnie resetuje 3 bitowy licznik linii matrycy znaku (LCNTR). Po przetworzeniu wszystkich danych klawiatury (400µs później) mikroprocesor wykonuje rozkaz OUT FFH,A (w sumie każdy OUT dałby ten sam efekt), co przywraca wyjście wideo układu ULA na normalny "biały poziom z impulsami synchronizacji poziomej" i zwalnia reset licznika LCNTR. Na końcu procedury VSYNC określana jest liczba pustych linii u góry ekranu ze zmiennej systemowej MARGIN (4028H - 16424). Następnie włączany jest generator przerwań NMI i mikroprocesor przechodzi do wykonywania zadań aplikacji.
  2. Podczas wykonywania kodu aplikacji mikroprocesor otrzymuje przerwania co 64µs z generatora NMI i w tym samym czasie układ ULA generuje impulsy synchronizacji poziomej. Procedura obsługi przerwania NMI zwiększa licznik pustych linii obrazu umieszczony w zapasowym rejestrze A' i powraca do aplikacji, jeśli jest jeszcze dla niej czas procesora. Gdy licznik pustych linii osiągnie wartość 0, procedura obsługi NMI wyłącza generator NMI i przełącza się na procedurę obsługi WYŚWIETLANIA WIDEO poprzez wskaźnik w rejestrze IX.
  3. Procedura obsługująca wyświetlanie wideo ustawia wskaźnik pliku wideo DFILE oraz liczniki wiersza i linii, włącza przerwania maskowane INT i wykonuje skok JP (HL) pod adres DFILE + 32K. Każdy znak w bloku DFILE interpretowany jest jako rozkaz NOP, z wyjątkiem znaku NEWLINE - CHR$ 118, który kończy wiersz. Na końcu każdego wiersza procedura obsługi przerwań maskowanych uaktualnia liczniki wierszy i linii i powraca do wykonania pozostałych wierszy DFILE. Po 192 liniach (24 wiersze po 8 linii) procedura wyświetlania wideo kończy się włączeniem generatora NMI i procesor znów wraca do wykonywania kodu aplikacji.
  4. Jak poprzednio podczas rysowania na ekranie górnego marginesu, procedura obsługi przerwań NMI zlicza liczbę pozostałych pustych linii obrazowych. Na końcu ostatniej dolnej linii procedura obsługi NMI przełącza się na procedurę VSYNC i cały proces powtarza się od początku.

4. WIDEO W TRYBIE FAST

W kompatybilnym z ZX80 trybie FAST mikroprocesor wykonuje albo procedurę obsługi wideo, albo dowolny inny program, lecz nie oba jednocześnie, co jest powodem znanego skakania obrazu przy przełączaniu się pomiędzy tymi zadaniami. Gdy zostaje uruchomiony program aplikacji, jest on wykonywany ze 100% szybkością procesora. Jedynie przy zatrzymaniu aplikacji (w trybie rozkazowym) lub przy oczekiwaniu na wprowadzenie danych z klawiatury dla INPUT, albo w trybie PAUSE, obraz telewizyjny jest wyświetlany. Sprzęt wideo jest aktywowany w identyczny sposób jak w trybie SLOW, lecz przerwania NMI są zawsze wyłączone. Dodatkowo puste linie u góry i u dołu obrazu są również generowane programowo, co powoduje kompatybilność pamięci ROM ZX81 ze sprzętem komputera ZX80.

5. UKŁAD WYŚWIETLANIA OBRAZU W ZX81

Obwód wideo w ZX81 składa się z mikroprocesora Z80, pamięci stałej ROM, pamięci RAM oraz większej części układu scalonego ZX81 Sinclair Logic Chip (zwykle zwanego ULA), co pokazuje Rys.3, na którym znajdują się wszystkie istotne połączenia, łącznie z rezystorami separującymi R. Dla prostoty pokazana jest tylko pamięć RAM 2KB. Układ ULA zawiera kwarcowy oscylator 6,5MHz oraz dzielnik częstotliwości, który generuje impulsy synchronizacji poziomej na wyjściu wideo oraz impulsy przerwań NMI na wyjściu NMI. Wyjścia HSYNC oraz NMI można kontrolować za pomocą następujących operacji wejścia/wyjścia:

  1. OUT FDH,A - wyłącza generator przerwań NMI
  2. OUT FEH,A - włącza generator przerwań NMI
  3. IN A, FEH - wyłącza generator HSYNC (tylko gdy przerwania NMI są wyłączone)
  4. OUT FFH,A - włącza generator HSYNC

Wyjście wideo z układu ULA przełącza się pomiędzy 3 poziomami napięć. Zwykle znajduje się na poziomie +5V, który odpowiada bieli i jest wykorzystywany do kreślenia pustych linii poza obrazem. Znaki są wyświetlane jako czarne piksele, gdy poziom napięcia spadnie do +2,5V. Wąskie impulsy synchronizacji poziomej oraz szerokie impulsy synchronizacji pionowej mają poziom 0V, co pokazano na przebiegu fali na rys.1 Podane poziomy logiczne zostają zmniejszone przez dzielnik oporowy do 1V, 0,5V i 0V (Anglia/USA) na wejściu modulatora sygnału telewizyjnego.

obrazek

Rys.1 Przebieg sygnału telewizyjnego na wyjściu ULA

Impulsy synchronizacji poziomej HSYNC trwają przez 5µs, a odstęp pomiędzy nimi wynosi 64µs. Impuls synchronizacji pionowej VSYNC ma szerokość 400µs i występuje co 16,6ms (USA) lub co 20ms (Europa). Impuls VSYNC wykorzystywany jest do synchronizacji generatora obrazu w odbiorniku telewizyjnym oraz rozpoczęcia wyświetlania linii obrazu u góry ekranu. Impuls ten rozpoczyna się w momencie wykonania rozkazu IN A,FEH (używanego do skanowania klawiatury), który zwiera wyjście wideo do poziomu SYNC. 400µs później rozkaz OUT FFH,A zwalnia SYNC i włącza impulsy HSYNC pojawiające się co 64µs. Impulsy synchronizacji poziomej HSYNC są generowane niezależnie od mikroprocesora aż do następnego impulsu synchronizacji pionowej VSYNC.

obrazek

Rys.2 Obraz generowany przez ZX81

Mikroprocesor wykonuje kod aplikacji podczas wyświetlania pustych linii u góry i u dołu ekranu, gdy generator przerwań NMI przerywa CPU co 64µs, a ten w procedurze obsługi tego przerwania zwiększa licznik pustych linii w celu określenia, czy nadszedł już czas dla procedur wyświetlania obrazu wideo lub generacji impulsu synchronizacji pionowej VSYNC.

6. UKŁAD ZNAKOWEGO TRYBU WIDEO

Generator wyświetlania znaków w ZX81 składa się z mikroprocesora Z80, pamięci stałej ROM, pamięci RAM oraz większej części układu scalonego ZX81 Sinclair Logic Chip (zwykle zwanego ULA), co pokazuje Rys.3, na którym znajdują się wszystkie istotne połączenia, łącznie z rezystorami separującymi R. Dla prostoty pokazana jest tylko pamięć RAM 2KB.

 

obrazek

Rys.3 Obwód wyświetlania znaków w ZX81

7. UKŁAD TRYBU PSEUDO HIRES

Na obwód wyświetlania pseudografiki w ZX81 składają się mikroprocesor Z80, pamięć stała ROM, pamięć RAM oraz większa część układu scalonego ULA, co pokazuje Rys.4, na którym znajdują się wszystkie istotne połączenia, łącznie z rezystorami separującymi R. Dla prostoty pokazana jest tylko pamięć RAM 2KB.

obrazek

Rys.4 Obwód wyświetlania pseudo grafiki

Jedyną różnicą pomiędzy obwodem pseudo hires a obwodem wyświetlania znaków jest rejestr LCNTR oraz wykorzystanie wejścia INT. Większość procedur obsługi pseudografiki nie wykorzystuje wejścia INT (normalnie służy ono do wznawiania pracy procesora po zatrzymaniu rozkazem HALT - CHR$ 118 na końcu wyświetlanego wiersza) a licznik linii znaku LCNTR jest resetowany na 0 przy każdej linii poziomej obrazu (normalnie adresuje on kolejne bajty w matrycy znaku w zależności od numeru linii ekranowej w wierszu znaków). Jedynym wyjątkiem jest XTRICATOR, która wykorzystuje INT i korzysta podwójnie z rejestru I w trybie INT 2 jako część adresu wektora RST, gdy pojawi się przerwanie na końcu każdej pionowej linii oraz w czasie odświeżania jako wskaźnik tablicy wzorców.

8. OUKŁAD TRYBU TRUE HIRES

Elementami układów ZX81 wymaganymi do pracy w trybie TRUE HIRES są mikroprocesor Z80, pamięć RAM, rejestr przesuwny wideo oraz układ synchronizacji w ULA, co pokazano na rys.5 wraz ze wszystkimi istotnymi połączeniami. Znów dla prostoty ograniczyliśmy się do pokazania połączeń z pamięcią RAM 2KB, lecz ten sam schemat odnosi się do większej pamięci statycznej. Jeśli będzie zastosowane rozszerzenie 16KB RAM, to układ pamięci musi być nieco zmodyfikowany, co przedstawimy później, w celu umożliwienia odczytu danych z pamięci w trakcie cyklu odświeżania, gdyż wymaga tego zastosowana metoda tworzenia obrazu.

obrazek

Rys.5 Obwód wyświetlania pełnej grafiki

Z wyjątkiem metody WRX1K, która tworzy miniaturowy ekran na komputerze ZX81 z 1KB pamięci RAM, wszystkie programy hires wymagają 6KB pamięci na dane graficzne (HFILE). Niezbędną dla tego trybu pamięć możemy zaimplementować przez modyfikację standardowego rozszerzenia 16KB stosując parę diod oraz rezystor.

W celu umożliwienia odczytu danych w cyklu odświeżania moduł pamięci jest modyfikowany przez przerwanie linii RD i RFSH na złączu krawędziowym i zainstalowanie jedynie dwóch diod germanowych 1N34A oraz rezystora podciągającego 4.7K. Przeróbkę wykonaj na własne ryzyko.

obrazek

Rys.6 Modyfikacja modułu RAMPACK dla celów grafiki hires

9. PRZEBIEGI CZASOWE DLA TRYBU ZNAKOWEGO

Wyświetlanie obrazu zbudowanego ze znaków w komputerze ZX81 rozpoczyna się po wyświetleniu ostatniej pustej linii górnego marginesu ekranu. Wtedy procedura obsługująca tworzenie obrazu wideo wykonuje skok do adresu DFILE+32K. Adres taki ma zawsze ustawioną linię adresową A15 na 1. Układ ULA rozpoznaje wykonywanie przez mikroprocesor kodu maszynowego w górnej połówce pamięci RAM właśnie po stanie tej linii adresowej oraz po stanie niskim na linii M1, która zeruje się na początku każdego cyklu maszynowego. Pamięć zostaje przeadresowana przez układ ULA dla procesora z powrotem do oryginalnego obszaru DFILE. Jest to konieczne, ponieważ pod adresem > 32K w zwykłym ZX81 nie znajduje się żadna pamięć. Wykonywanie programu w górnej połówce pamięci jest zawsze traktowane przez ULA jako generacja obrazu wideo. Wynika z tego, iż w obszarze tym nie mogą być umieszczane procedury w języku maszynowym mikroprocesora Z80, jednakże dane można tam przechowywać bez problemu - na tej zasadzie opierają się rozszerzenia pamięci ZX81 większe niż 16KB. Poniżej podajemy skrótową procedurę pobierania danych do wyświetlenia na ekranie telewizora:

  1. Układ ULA odczytuje kod znaku i umieszcza go w rejestrze CHRLATCH.
  2. Układ ULA wymusza stan niski na liniach D0-D7 magistrali danych.
  3. Mikroprocesor interpretuje to jako instrukcję NOP.
  4. Układ ULA generuje część adresu w tablicy z matrycami znaków, a mikroprocesor generuje wskaźnik tej tablicy przy pomocy rejestru I.
  5. Bajt z fragmentem matrycy znaku jest ładowany do rejestru przesuwnego wideo VSHFTREG w układzie ULA.

Można by zatem powiedzieć, iż blok DFILE jest dosłownie wykonywany za pomocą instrukcji NOP, które zastępują każdy kod znaku. Instrukcja NOP jest wykonywana przez mikroprocesor Z80 w czterech cyklach zegarowych przy częstotliwości 3,25MHz lub w czasie przesunięcia 8 pikseli w rejestrze przesuwnym wideo przy częstotliwości 6,5MHz.

obrazek

Rys.7 Przebiegi czasowe sygnałów dla trybu znakowego w ZX81

Dokładny ciąg operacji dla każdego znaku jest pokazany na rys. 7 oraz opisany poniżej:

  1. Każdy bajt kodu znaku w echu bloku DFILE jest adresowany rejestrem PC licznika rozkazów w mikroprocesorze Z80. ULA przekształca ten adres do normalnego położenia DFILE w RAM poprzez przejęcie kontroli nad linią adresową A15 mikroprocesora. Przy narastającym zboczu impulsu zegarowego T2 zaadresowany bajt zostaje załadowany z DFILE do układu ULA: bity b0-b5 są umieszczane w 6 bitowym rejestrze adresowym CHRLATCH, natomiast bit b7 jest umieszczany w przerzutniku kontrolującym odwracanie kolorów punktów wyświetlanej matrycy znaku.
  2. Przy opadającym zboczu impulsu T2 ULA wymusza stan 0 na wszystkich liniach magistrali danych D0-D7 dla procesora.
  3. Przy narastającym zboczu impulsu T3 stan niski na liniach magistrali danych zostaje zinterpretowany przez mikroprocesor jako rozkaz NOP.
  4. Podczas impulsu T3/4 mikroprocesor wykonuje cykl odświeżania pamięci dynamicznych RAM, w trakcie którego umieszcza on na górnych liniach A8-A15 magistrali adresowej zawartość rejestru I, a na dolnych liniach A0-A7 zawartość rejestru R. Jednakże ULA zmienia stan linii adresowych w sposób następujący:
    linie A9-A15 - 7 najstarszych bitów rejestru I
    linie A3-A8  - zapamiętane 6 bitów kodu znaku z DFILE podawane z rejestru CHRLATCH
    linie A0-A2  - zawartość 3 bitowego licznika linii LINECTR (licznik zlicza linie obrazu modulo 8, dając w wyniku numer bajtu w matrycy wyświetlanego znaku)
    Tak spreparowany adres wyznacza bajt matrycy znaku zawartego w tablicy umieszczonej w pamięci ROM.
  5. Przy opadającym zboczu impulsu T4 bajt matrycy znaku z ROM jest ładowany do rejestru przesuwnego wideo VSHFTREG, z którego bity są wysuwane z częstotliwością 6,5MHz.
  6. Jeśli bit 7 pobranego kodu znaku ma stan 1, to wyprowadzane do telewizora bity matrycy znaku są odwracane w negatyw.
  7. Mikroprocesor zwiększa licznik rozkazów i pobiera następny kod znaku.
  8. Proces ten jest powtarzany aż do napotkania w bloku DFILE instrukcji HALT - czyli znaku CHR$ 118 - NEWLINE.
  9. Kod HALT ma ustawiony na 1 bit nr 6 i dlatego nie jest zamieniany przez ULA na NOP - procesor wykonuje ten rozkaz.
  10. ULA generuje impuls synchronizacji poziomej HSYNC niezależnie od przebiegów czasowych mikroprocesora, a licznik linii LINECTR jest zwiększany o 1.
  11. Zatrzymany mikroprocesor kontynuuje wykonywanie instrukcji NOP, zwiększając rejestr R oraz testując stan linii INT przy narastającym zboczu każdego impulsu T4.
  12. Linia adresowa A6 jest połączona bezpośrednio z wejściem INT. Jeśli A6 przyjmie stan 0 podczas cyklu odświeżania (gdy bit 6 rejestru R wyzeruje się), mikroprocesor wykonuje procedurę obsługi przerwania maskowanego (umieszczoną poniżej 32K, zatem ULA nie ingeruje w wykonywane kody).
  13. Mikroprocesor powraca z przerwania maskowanego i wznawia "wykonywanie" kodów znakowych z bloku DFILE.
  14. Proces ten powtarzany jest 192 razy, a następnie procedura obsługi przerwań maskowanych INT wraca do głównej procedury tworzenia obrazu wideo, włącza generator przerwań NMI i przełącza się z powrotem do kodu aplikacji.

10. PRZEBIEGI CZASOWE DLA TRYBU PSEUDO HIRES

Do pracy w trybie pseudo hires wymagane jest układ pokazany na rys.4, który różni się od standardowego obwodu drobnymi modyfikacjami wymaganymi do otrzymania standardowego ekranu zbudowanego ze 192 linii po 32 wzory pseudografiki. Tryb ten różni się od zwykłego wyświetlania znaków tym, iż każdy znak ma wysokość jedynie jednej linii zamiast normalnych 8. Osiągane to jest przez zerowanie licznika LINECTR przy każdej wyświetlonej linii. W efekcie z tablicy matryc znaków pobierany jest tylko pierwszy bajt każdej matrycy. Standardowa matryca nie bardzo się nadaje do pracy w tym trybie, ponieważ większość pierwszych bajtów matryc znaków jest zerowa. Dlatego tablicę tę lokalizuje się w innym miejscu pamięci ROM. Programista ma wtedy dla każdego z 64 możliwych do wyświetlenia znaków różne układy bitów, które jednakże mogą się powtarzać. Oprócz podstawowych 64 wzorów dostępne jest również 64 negatywy przy ustawionym na 1 najstarszym bicie kodu znaku.

Wyświetlanie rozpoczyna się gdy zostanie zakończona ostatnia pusta linia górnego marginesu.  Procedura tworzenia obrazu wykonuje skok do echa 6KB bloku DFILE zlokalizowanego ponad adresem 32K. Układ ULA przejmuje kontrolę nad każdym wykonywanym przez mikroprocesor kodem rozkazu o adresie w górnej połowie przestrzeni adresowej (A15=1 i M1 = 0) oraz z wyzerowanym bitem nr 6. W rzeczywistości blok DFILE musi się znajdować poniżej adresu 32K - ULA przeadresowuje pamięć przy pobieraniu przez mikroprocesor kodu rozkazu - uwaga ta dotyczy komputera ZX81 z rozszerzeniem pamięci ponad 16KB. Echo bloku DFILE nie istnieje fizycznie w obszarze ponad 32K, jest tam tylko "widziane" przez mikroprocesor dzięki temu, iż ULA wyłącza linię A15 dla kodów rozkazów. Dla danych linia A15 pełni swoją normalną funkcję, zatem w obszarze ponad 32K można przechowywać wszelkie zmienne. ULA rozpoznaje cykl rozkazowy procesora po stanie linii M1 - M1=0 - procesor wykonuje pierwszy cykl maszynowy, czyli pobranie z pamięci kodu rozkazu.

W skrócie dane wideo są ładowane do układu ULA w pięciu krokach:

  1. ULA ładuje kod znaku do rejestru adresowego CHRLATCH.
  2. ULA wymusza niski stan na liniach D0-D7 magistrali danych.
  3. Mikroprocesor interpretuje to jako rozkaz NOP.
  4. ULA generuje część adresu tablicy wzorów w ROM. Mikroprocesor generuje bardziej znaczący bajt adresu przy pomocy swojego rejestru I.
  5. Wzór pseudografiki hires jest ładowany z ROM do rejestru przesuwnego w ULA.

Każda instrukcja NOP jest wykonywana w czasie 4 taktów zegara przy częstotliwości 3,25MHz lub 8 pikseli wyprowadzanych z rejestru przesuwnego w ULA przy częstotliwości 6,5MHz.

obrazek

Rys.8 Przebiegi czasowe dla pseudografiki

Dokładny ciąg operacji dla każdego znaku jest następujący.

  1. Każdy kod znaku jest adresowany w echu bloku DFILE przez rejestr licznika rozkazów mikroprocesora Z80. ULA przekształca ten adres do normalnego położenia DFILE w RAM poprzez przejęcie kontroli nad linią adresową A15 mikroprocesora. Przy narastającym zboczu impulsu zegarowego T2 zaadresowany bajt zostaje pobrany z DFILE do układu ULA: bity b0-b5 są umieszczane w 6 bitowym rejestrze adresowym CHRLATCH, natomiast bit b7 jest umieszczany w przerzutniku kontrolującym odwracanie kolorów punktów wyświetlanej matrycy znaku.
  2. Przy opadającym zboczu impulsu T2 ULA wymusza stan 0 na wszystkich liniach magistrali danych D0-D7 dla procesora.
  3. Przy narastającym zboczu impulsu T3 stan niski na liniach magistrali danych zostaje zinterpretowany przez mikroprocesor jako rozkaz NOP.
  4. Podczas impulsu T3/4 mikroprocesor wykonuje cykl odświeżania pamięci dynamicznych RAM, w trakcie którego umieszcza on na górnych liniach A8-A15 magistrali adresowej zawartość rejestru I, a na dolnych liniach A0-A7 zawartość rejestru R. Jednakże ULA zmienia stan linii adresowych w sposób następujący:
    linie A9-A15 - 7 najstarszych bitów rejestru I
    linie A3-A8  - zapamiętane 6 bitów kodu znaku z DFILE podawane z rejestru CHRLATCH
    linie A0-A2  - wyzerowane, ponieważ LINECTR jest zerowany po wyświetleniu każdej linii
    Tak spreparowany adres wyznacza pierwszy bajt matrycy znaku zawartego w tablicy umieszczonej w pamięci ROM. Bajty te są rozmieszczone w tablicy co 8 adresów. Pozostałe bajty matrycy znaku nie są wykorzystywane, ponieważ znak w trybie pseudohires ma jedynie 1 linię wysokości.
  5. Przy opadającym zboczu impulsu T4 bajt matrycy znaku z ROM jest ładowany do rejestru przesuwnego wideo VSHFTREG, z którego bity są wysuwane z częstotliwością 6,5MHz.
  6. Jeśli bit 7 pobranego kodu znaku ma stan 1, to wyprowadzane do telewizora bity matrycy znaku są odwracane w negatyw.
  7. Mikroprocesor zwiększa licznik rozkazów i pobiera następny kod znaku.
  8. Proces ten jest powtarzany aż do napotkania w bloku DFILE instrukcji RET, która powoduje powrót do procedury grafiki pseudohires.
  9. Kod RET ma również ustawiony na 1 bit nr 6 i dlatego nie jest zamieniany przez ULA na NOP - procesor wykonuje ten rozkaz.
  10. ULA generuje impuls synchronizacji poziomej HSYNC niezależnie od przebiegów czasowych mikroprocesora, a licznik linii LINECTR jest zwiększany o 1. Jednakże procedura obsługująca tworzenie grafiki pseudohires zeruje licznik LINECTR po każdej wyświetlonej linii - dzięki temu z tablicy matryc są pobierane tylko pierwsze bajty.
  11. Mikroprocesor powraca z procedury pseudohires i wznawia "wykonywanie" kodów znaków z DFILE.
  12. Proces ten jest powtarzany 192 razy, a następnie procedura hires kończy się uruchomieniem generatora NMI i przełączeniem się z powrotem na kod aplikacji.

11. PRZEBIEGI CZASOWE DLA TRYBU TRUE HIRES

Chociaż w opisie będę się opierał na procedurze hires WRX, to inne procedury opracowane niezależnie są bardzo podobne. Wyświetlanie w trybie TRUE HIRES rozpoczyna się, gdy zostanie wyświetlona ostatnia pusta linia górnego marginesu obrazu. Wtedy procedura obsługi NMI skacze poprzez rejestr IX do procedury obsługującej rzeczywistą grafikę hires. Procedura ta ustawia odpowiednio rejestry I oraz R, aby wskazywały blok z danymi graficznymi w pamięci - HFILE, a następnie skacze do echa procedury LBUF ponad adresem 32K i ładuje rejestr R oraz przechodzi do wykonania pierwszej instrukcji NOP. ULA ładuje rejestr przesuwny wideo danymi spod adresu I:R w trakcie cyklu odświeżania pamięci RAM, gdy kod wykonanej instrukcji miał ustawiony na 0 bit nr 6.

Dane hires są ładowane w 3 krokach:

  1. Mikroprocesor wykonuje każdą z 32 czterotaktowych instrukcji NOP.
  2. Podczas cyklu T3/4 (odświeżanie) na liniach adresowych pojawia się zawartość rejestru I (A8-A15) i R (A0-A7).
  3. Bajt hires zaadresowany przez I i R jest ładowany do rejestru przesuwnego w układzie ULA.

LBUF składa się z 32 kodów NOP, każdy wykonywany w czasie 4 cykli zegarowych mikroprocesora. Podczas wykonania drugiej części rozkazu rejestry I oraz R adresują bajt hires w HFILE, który ULA ładuje do rejestru przesuwnego wideo. Adres dla tablicy matryc wygenerowany przez ULA nie jest tutaj wykorzystywany, gdyż nie powstaje sygnał ROMCS - rejestr I (linie adresowe A8-A15) wskazuje lokację w pamięci RAM, wewnątrz HFILE.

obrazek

Rys.9 Przebiegi czasowe dla pełnej grafiki

Dokładny ciąg operacji dla każdego bajtu hires jest następujący:

  1. Mikroprocesor wykonuje pierwszy kod rozkazu w LBUF - LDA R,A.
  2. Następnie zostają wykonane kolejno 32 rozkazy NOP w LBUF.
  3. Rozkaz NOP mikroprocesor wykonuje przy narastającym zboczu taktu T3.
  4. Podczas taktu T3/4 generowany jest adres przy pomocy rejestru R na liniach A0-A7 i rejestru I na A8-A15.
  5. Na opadającym zboczu taktu T4 bajt danych hires z HFILE jest ładowany do rejestru przesuwnego wideo w ULA i 8 pikseli wideo zostaje z niego wysuniętych z częstotliwością 6,5MHz.
  6. Mikroprocesor zwiększa licznik rozkazów oraz zawartość rejestru R i pobiera kolejną instrukcję NOP oraz następny bajt hires.
  7. Proces ten powtarza się 32 razy.
  8. Ostatnim kodem rozkazu w LBUF jest JP (IX), którego wykonanie powoduje powrót do procedury HR.
  9. ULA generuje impuls synchronizacji poziomej.
  10. Procedura HLINE zwiększa parę rejestrów I/R o 32 i skacze z powrotem do echa procedury LBUF z 32 instrukcjami NOP ponad adresem 32K.
  11. Proces ten jest powtarzany 192 razy.
  12. Procedura HIRES może wywołać procedurę znakową Sinclaira dla dolnego wiersza i odtworzenia rejestrów w celu powrotu do kodu aplikacji.

Podobnie do innych procedur hires, procedura WRX przechwytuje obsługę wideo Sinclaira przez załadowanie nowego wektora procedury wideo do rejestru IX.

12. PROCEDURY WIDEO DLA TRYBU SLOW

Jak pokazano w tab.1, mikroprocesor dokonuje podziału czasu wykonania procedur wideo i programu aplikacji w 4 przedziałach czasu.

1. PROCEDURY PRZEDZIAŁU CZASU IMPULSU SYNCHRONIZACJI PIONOWEJ VSYNC

0229 DISPLAY_1:      ;zmniejszenie licznika ramek FRAME
023E DISPLAY_2:      ;sprawdzenie klawiatury (początek impulsu VSYNC)
0277 OUT 0FFH,A      ;koniec impulsu synchronizacji VSYNC
0292 DISPLAY_3:      ;umieszczanie wskaźnika procedury wideo w IX (0281), powrót do aplikacji

2. PROGRAM APLIKACJI

0066 NMI:            ;zliczanie pustych linii, powrót do aplikacji lub poprzez JP (IX) do 0281

3. PROCEDURY WYŚWIETLANIA OBSZARU DFILE

0281 VIDEO_1:         ;ustawianie parametrów wyświetlania, wywołanie 2B5 (Powrót poprzez INT)
02B5 DISPLAY_5:       ;ustawienie parametrów wyświetlania, włączenie przerwań, JP (DFILE)
XXXX (DFILE)          ;wykonanie instrukcji HALT oraz wymuszonych NOP w DFILE
0038 INT:             ;zmniejszenie liczników wierszy/linii, powrót do DFILE lub do 028B
0292 DISPLAY_3:       ;zabezpieczenie wskaźnika procedury wideo (028F)

4. PROGRAM APLIKACJI

0066 NMI:             ;zliczanie pustych linii, powrót do aplikacji lub przez JP (IX) do 028F 
028F VIDEO_2: JP 229H ;powrót do licznika ramek w bloku 1

Poniżej zamieściłem w pełni skomentowany listing ROM ZX81 procedur związanych z wyświetlaniem obrazu wideo.

L0038:                ;PROCEDURA OBSŁUGI PRZERWAŃ INT
     DEC  C           ;zmniejsz licznik linii skanujących w rejestrze C
     JP   NZ,0045H    ;skocz do SCAN-LINE : powtarzane 8 razy dla każdego wiersza znaków w DFILE
     POP  HL          ;pobierz adres początku następnego wiersza DFILE ze stosu (adres powrotny za HALT)
     DEC  B           ;zmniejsz licznik wierszy w rejestrze B
     RET  Z           ;jeśli się wyzerował, wróć do 028B
     SET  3,C         ;załaduj licznik linii skanujących w rejestrze C wartością 8
 
L0041:                ;WAIT-INT
     LD   R,A         ;w rejestrze R umieść wartość DDH
     EI               ;włącz przerwania INT
     JP   (HL)        ;wykonaj sekwencję instrukcji NOP w echu DFILE
 
L0045:                ;SCAN-LINE
     POP  DE          ;porzuć adres powrotny, ponieważ ten sam wiersz musi być wykonany 8 razy
     RET  Z           ;opóźnienie (powrót nigdy nie następuje)
     JR   0041H       ;przejdź do WAIT-INT
                      ;----------------------------------------------------------
 
L0066:                ;PROCEDURA OBSŁUGI PRZERWAŃ NMI
                      ;Przerywa program aplikacji co każde 64µs (HSYNC)
     EX   AF,AF'      ;odzyskaj w A licznik pustych linii marginesu ekranu
     INC  A           ;następna pusta linia
     JP   M,006DH     ;powróć poprzez 006D (do NMI-EXIT), jeśli A jest liczbą ujemną U2
     JR   Z,006FH     ;Przy ostatniej linii skocz do NMI-CONT

L006D:
     EX   AF,AF'      ;zapamiętaj licznik pustych linii
     RET              ;powróć do aplikacji lub do NMI-EXIT
 
L006F:                ;NMI-CONT
     EX   AF,AF'      ;przełącz na główny zestaw rejestrów AF
     PUSH AF          ;zapisz rejestry programu aplikacji na stosie
     PUSH BC
     PUSH DE
     PUSH HL
     LD   HL,(DFILE)  ;pobierz wskaźnik DFILE
     SET  7,H         ;ustaw w HL adres echa DFILE powyżej adresu 32K
     HALT             ;synchronizacja do jednego taktu: ten rozkaz HALT używany jest ze specjalnym
                      ;obwodem podłączonym do linii mikroprocesora WAIT i HALT, i zostaje zwolniony
                      ;oraz zsynchronizowany z opadającym zboczem impulsu NMI
 
L007A:                ;NMI-EXIT
     OUT  0FDH,A      ;wyłącz generator NMI
     JP   (IX)        ;skocz do VIDEO-1 lub VIDEO-2
                      ;---------------------------------------------------------
 
L0229:                ;DISPLAY-1
     LD   HL,(FRAMES) ;pobierz zmienną systemową FRAMES
     DEC  HL          ;zmniejsz ją przy każdej ramce
     .....
     LD   (FRAMES),HL ;i zachowaj wynik w pamięci
 
L023E:                ;DISPLAY-2
     CALL 02BBH       ;odczytaj stan klawiatury i załaduj MARGIN liczbą pustych linii
     .....            ;rozpocznij również impuls synchronizacji pionowej VSYNC

L0277:
     OUT 0FFH,A       ;zakończ impuls VSYNC
     LD  HL,(DFILE)   ;(tylko dla FAST VIDEO) - ustaw HL tna pierwszą instrukcję HALT dla pustych linii
     SET 7,H          ;(tylko dla FAST VIDEO) - ustaw adres echa DFILE ponad 32K

L027E:
     CALL 0292H
 
L0281:                ;VIDEO-1
                      ;ten wektor jest zapisywany w rejestrze IX w punkcie 0292
     LD   A,R         ;opóźnienie
     LD   BC,1901H    ;ustaw parametry INT dla pierwszego rozkazu HALT w (DFILE)
     LD   A,0F5H      ;ustaw rejestr R dla pierwszego HALT w (DFILE)
     CALL 02B5H       ;kontynuuj ustawienia dla obrazu z DFILE i powróć poprzez INT

L028B:                ;tutaj powróć z ostatniego INT
     DEC  HL          ;(tylko dla FAST VIDEO) - ustaw HL na ostatni rozkaz HALT dla pustych linii
     CALL 0292H       ;zapisz wektor VIDEO w IX, oblicz puste linie, pobierz rejestry ze stosu
 
L028F:
     JP   0229H       ;VIDEO-2
                      ;ten wektor jest zapisywany w rejestrze IX w 0292
 
L0292:                ;DISPLAY-3
     POP  IX          ;IX=0281H lub 028FH jako wektor do VIDEO-1 lub VIDEO-2
     LD   C,(IY+56H)  ;pobierz liczbę pustych linii z MARGIN (1F dla opcji 60Hz)
     BIT  7,(IY+59H)  ;sprawdź bit FAST/SLOW
     JR   Z,02A9H     ;(FAST VIDEO)  skocz do generacji pustych linii
     LD   A,C         ;C=(MARGIN)=1F dla 60 Hz
     NEG              ;utwórz liczbę ujemną U2
     INC  A
     EX   AF,AF'      ;podczas NMI w 0066 - AF' jest zwiększane i testowane na zero
     OUT  (0FEH),A    ;włącz generator NMI
     POP   HL         ;odtwórz rejestry programu aplikacji
     POP   DE
     POP   BC
     POP   AF
     RET              ;powróć do programu aplikacji przerywanego przy każdym impulsie HSYNC przez NMI
                      ;-----------------------------------------------------------
 
L02B5:                ;DISPLAY-5
     LD    R,A        ;R zwiększa się o 1 przy każdym rozkazie na liniach od A0 do A7 podczas RFSH
                      ;aż linia A6 przyjmie stan niski, co wygeneruje sygnał INT.
     LD    A,0DDH     ;ustaw lewy margines dla wszystkich pozostałych linii, ładowany do R w 0041
     EI               ;gdy jest ustawiony R, włącz reagowanie na INT
     JP    (HL)       ;"wykonaj" DFILE poczynając od HALT i czekając na pierwsze przerwanie INT
                      ;-----------------------------------------------------------

13. PROCEDURY WIDEO DLA TRYBU FAST

W celu przyspieszenia czasu wykonania programu aplikacji tryb FAST przeznacza dla niego 100% czasu mikroprocesora, lecz są chwile, gdy program aplikacji wykonuje operacje jałowe. Gdy program jest zatrzymany, wykonuje polecenie PAUSE lub czeka na dane z klawiatury dla INPUT, klawiatura jest sprawdzana i jeśli żaden klawisz nie jest wciśnięty, generowany jest obraz niezależnie od impulsów NMI. W rzeczywistości procedurę wideo w trybie FAST opracowano, tak aby była kompatybilna ze sprzętem ZX80 i pamięć ROM z kodem mogła być stosowana jako uaktualnienie pamięci ROM w ZX80. Ponieważ ZX81 tworzy programowo puste linie, tak samo postępuje w trybie FAST ROM komputera ZX81.

Pętla procedur VIDEO dla trybu FAST rozpoczyna się od procedury FRAME/KBD/VSYNC pod adresem 229H:

0229 ZMNIEJSZANIE LICZNIKA RAMEK
023D WYJŚCIE, JEŚLI FRAMES=0 (KONIEC PAUSE)
023E SPRAWDZENIE KLAWIATURY
0260 WYJŚCIE, JEŚLI NACIŚNIĘTO NOWY KLAWISZ
0292 UMIESZCZENIE WSKAŹNIKA WIDEO W IX (0281)
029B JR Z 02A9 DO PROCEDURY RYSOWANIA PUSTEJ LINII
02A9 TWORZENIE PUSTYCH LINII
02B3 JP (IX) DO  0281
0281 TWORZENIE OBRAZU DFILE
0292 ZACHOWANIE WSKAŹNIKA VIDEO (028F)
029B JR Z 02A9 DO PROCEDURY RYSOWANIA PUSTEJ LINII
02A9 TWORZENIE PUSTYCH LINII
02B3 JP (IX) DO 028F
028F JP 229  Z POWROTEM DO LICZNIKA RAMEK

Ponieważ większość z tych procedur opisałem w poprzednim podrozdziale, tutaj opiszę jedynie różnice. Przy wejściu do tej pętli w trybie SLOW z końca procedury rysowania pustych linii zapamiętywane na stosie są rejestry programu aplikacji, a przy wyjściu są one odtwarzane na końcu procedury 0292. Natomiast w trybie FAST nie są zapamiętywane żadne rejestry, a procedura 0292 jest pomijana. Wykonywane jest to w 029B po sprawdzeniu znacznika trybu FAST i skoku do mniej znanej procedury zwanej DISPLAY-4.

L02A9:               ;DISPLAY-4
     LD   A,0FCH     ;najpierw opóźnienie R do INT
     LD   B,01H      ;jeden wiersz
     CALL 02B5H      ;wyświetl puste linie
     DEC  HL         ;wskaż z powrotem na HALT
     EX   (SP),HL    ;opóźnienie 19 T
     EX   (SP),HL    ;opóźnienie 19 T
     JP   (IX)       ;IX = 0281 lub 028F

Procedura pod adresem 02A9H jest wywoływana dwukrotnie przy każdej ramce do utworzenie pustych linii w górnym i dolnym marginesie obrazu z zawartością HL wskazującą albo na pierwszy rozkaz HALT na początku DFILE lub na ostatni HALT na końcu DFILE. Rejestr C zawiera liczbę pustych linii a rejestr B jest ustawiany na 1 wiersz. Po VSYNC tworzone jest 31 górnych linii marginesu przez wywołanie procedury wyświetlania pod adresem 02B5 i wykonanie 31 razy pierwszego HALT na początku DFILE. Po powrocie z procedury wyświetlania para HL wskazuje na adres ostatniego HALT + 1 i wymagane jest DEC HL, aby wskaźnik wrócił z powrotem na ostatnie HALT w DFILE.  Po zapisie adresu w IX procedura 02A9H jest ponownie wywoływana z HL wskazującym na ostatnie HALT i tworzy 31 pustych linii dolnego marginesu wykonując tą instrukcję HALT na końcu DFILE.

14. PROCEDURY DLA TRYBU TRUE HIRES

Procedury trybu true hires różnią się od opisanych głównie tym, ią jako wskaźnik danych graficznych wykorzystuje się parę rejestrów I oraz R. Jedynym pozostałym warunkiem jest wykonanie 32 instrukcji NOP (lub podobnych) na jedną linię poziomą, a następnie uaktualnienie rejestrów i oraz R w czasie impulsu synchronizacji poziomej HSYNC. W celu zwiększenia szybkości pracy programu aplikacji może być użytych więcej linii marginesu nad oraz pod obrazem.

WRX16 - 1984 autorstwa Wilfa Rigtera

Tutaj przedstawiam procedury stosowane w programach autorstwa Freda Nachbaura i Grefa Hardera. Tworzą one obraz o rozdzielczości 256x192 w tablicy o długości 6144 bajtów, która rozpoczyna się ponad obszarem RAMTOP. W tablicy tej można umieszczać dane za pomocą rozkazu POKE z poziomu języka BASIC.

START jest używane do rozpoczęcia wyświetlania hires a STOP przywraca standardowy obraz Sinclaira.

Część 1 wywołuje 192 razy LBUF wyświetlając 256x192 pikseli, oblicza liczbę pustych linii do wyświetlenia w marginesach ekranu, zapisuje wskaźnik do Części 2 w rejestrze IX i powraca do kodu aplikacji.

Część 2 wywołuje VSYNC itp., zlicza puste linie, zapisuje wskaźnik do Części 2 w IX i powraca do wykonania kodu aplikacji

       .ORG 16516   ;szesnastkowo 4084
 
HFILE  .EQU $4004   ;HFILE umieszczone jest ponad używaną pamięcią
LBUF:  ;Wyświetla linię 256 pikseli
       ;------------------------------
 
       ;podobnie jak w przypadku DFILE, procedura ta jest wywoływana ponad
       ;z adresem 32K like DFILE w celu aktywacji układów wideo w ULA
       ;ustawiając bit nr 7 kodów NOP mozna uzyskiwać negatyw grafiki.
       ;dane graficzne są umieszczane w rejestrze przesuwnym wideo w ULA
       ;podczas cykli odświeżania przy wykonywaniu 32 instrukcji NOP
       ;przy sekwencyjnym adresowaniu rejestrami I oraz R wskazującymi 
       ;zawartość bloku HFILE o długości 6144 bajtów
 
       LD   R,A               ;ładuj młodszy bajt adresu HFILE do rejestru R
       .BYTE 0,0,0,0,0,0,0,0  ;32 instrukcje NOP
       .BYTE 0,0,0,0,0,0,0,0
       .BYTE 0,0,0,0,0,0,0,0
       .BYTE 0,0,0,0,0,0,0,0
       JP  (IX)               ;powróć do HR
 
 
HR:   ;PROCEDURA HIRES - CZĘŚĆ 1
      ;-------------------------

      LD   B,4                ;opóźnienie w celu synchronizacji z impulsami HSYNC

HR0:  DJNZ HR0
      LD   HL,(HFILE)         ;RAMTOP wskazuje pierwszy bajt HFILE
      LD   B,0C0H             ;192 linii poziomych
      LD   IX,HR1             ;zapisz wektor powrotu w IX (dla JP (IX) na końcu LBUF)
      JR   HR2                ;przy pierwszym obiegu pętli przeskocz do HR1

HR1:  LD   DE,0020H           ;długość linii 256 pikseli w HFILE - 32 bajty
      ADD  HL,DE              ;dodaj do HL, aby wskazać początek następnej linii w HFILE
      DEC  B                  ;powtarzaj 192 razy
      JP   Z,HR3              ;jeśli jest to ostatnia linia, skocz do HR3

HR2:  LD   A,H                ;adres w HL jest umieszczany w rejestrze I
      LD   I,A
      LD   A,L                ;a podczas wykonywania LBUF również w rejestrze R
      JP   LBUF+8000H         ;skocz do LBUF w górnej połówce pamięci, aby uruchomić ULA

HR3:  LD   IX,HR4             ;zapisz wektor wideo, aby procedura NMI powróciła do HR4
      JR   HR5                ;rysuj pustą linię i powróć do kodu aplikacji
 
HR4:  ;PROCEDURA HIRES - CZĘŚĆ 2
      ;-------------------------

      CALL 220H               ;zapisz najpierw rejestry na stosie i skocz do VSYNC
      LD   IX,HR              ;zapisz wektor wideo do IX, aby NMI powróciło do HR

HR5:  LD   A,(4028H)          ;33 lub 19 pustych linii w zmiennej systemowej MARGIN
      JP   29EH               ;zapisz liczbę pustych linii, uruchom NMI, pobierz rejestry ze stosu i powróć
 
      ;--------------------- koniec listingu ---------------------

Procedura hires jest uaktywniana i zatrzymywana przez zmianę adresu w rejestrze IX, który wykorzystuje NMI, aby skoczyć JP (IX) do procedury wideo. Poniższe procedury są zsynchronizowane z wyświetlaniem, aby zmiana trybu wideo odbywała się bez przerw w wyświetlaniu.

STOP:  ;zatrzymuje hires wideo i powraca do wideo Sinclaira
       ;---------------------------------------------------
       LD   HL,0281H          ;wskaźnik do procedury wideo Sinclaira
       LD   A,1EH             ;adres tablicy z matrycami znaków w ROM (1E00)
       LD   I,A               ;trafia do rejestru I
       JR   SYNC
 
START: ;Start procedury hires wideo
       ;----------------------------
       LD   HL,HR             ;wskaźnik procedury hires wideo
 
SYNC:  ;używane przez START i STOP do płynnej zmiany trybu wideo
       ;---------------------------------------------------------
       PUSH HL
       LD   HL,4034H          ;licznik ramek - FRAMES
       LD   A,(HL)            ;pobierz stare FRAMES
SYNC1: CP   A,(HL)            ;porównuj z nowym FRAMES
       JR   Z,SYNC1           ;powtarzaj, aż będą się różnić
       POP  IX                ;procedura wideo Sinclaira. 
 
       ;-------------- koniec listingu ---------------

GUUS-FLATER, autor - ENNO BORGESTEEDE (1984)

Ta procedura hires używa genialnego sposobu na przechwycenie wektora wideo. Zamiast zmieniania zawartości rejestru IX, GUUS-FLATER przechwytuje wykonanie na początku DFILE przez zmianę pierwszych 4 bajtów łącznie z HALT na DI i JP 409FH, co jest startem procedury hires. Na końcu ekranu hires program po prostu powraca do procedury ROM pod adresem xxxx. DFILE posiada charakterystyczną zawartość rozpoczynającą się od DI i JP 409FH, a HFILE zaczyna się od (4004H).

(400C)  DI                     ;te bajty zostają załadowane do DFILE
        JP   409FH             ;jako wektor do procedury hires

        .ORG 409FH

L409F:  LD   B,08              ;opóźnienie
LP1:    DJNZ LP1               ;opóźnienie
        LD   A,R               ;opóźnienie
        LD   B,0C0H            ;192 linie
        LD   DE,20H            ;32 bajty na linię
        LD   HL,(4004)         ;plik hires (HFILE) rozpoczyna się od adresu RAMTOP
L40AD:  LD   A,H               ;MSB adresu HFILE
        LD   I,A               ;ładuj MSB wskaźnika HFILE
        LD   A,L               ;LSB adresu HFILE
        JP   0C0B6H            ;skok ponad 32K
L40B6:  LD   R,A               ;ładuj LSB wskaźnika HFILE
        .BYTE "COPYRIGHT 1984 ENNO BORGESTEEDE " ; to samo co 32 instrukcje NOP
        JP   40DBH             ;skocz poniżej 32K
L40DB:  ADD  HL,DE             ;następna linia hires
        DJNZ 40ADH             ;linia hires powtarza się 192 trazy
        LD   A,1EH             ;przywróć wskaźnik tablicy matryc znaków w ROM
        LD   I,A               ;załaduj go do rejestru I
        RET                    ;połącz się z procedurą wideo Sinclair'a w toku

WRX16K - 1996, autor - Wilf Rigter

Oryginalne procedury grafiki hires WRX napisano w 1984 roku, lecz ostatni wzrost zainteresowania tym tematem wymusił opracowanie nowszej i bardziej wydajnej wersji. WRX16K 1996 jest najbardziej zoptymalizowaną wersją procedur WRX, a pomimo swojej niewielkiej objętości obsługuję grafikę hires w rozdzielczości ekranu 256x192 piksele. Została opracowana do pracy ze zmodyfikowanym modułem pamięci 16K RAMPACK lub z 16K pamięcią SRAM. Przed jej załadowaniem należy najpierw obniżyć RAMTOP rozkazem POKE 16389,96 oraz wykonać polecenie NEW.

Tryb hires można uruchomić i zatrzymać przy pomocy tych samych procedur, które pojawiły się na listingu WRX16 powyżej. Proste START jest używane do uruchomienia trybu hires poprzez zmianę adresu wektora wideo w rejestrze IX. Tryb hires jest zatrzymywany przez wywołanie wewnętrznej procedury BREAK, która synchronicznie powraca do trybu wideo Sinclaira po naciśnięciu klawisza spacji. HFILE jest liniowym buforem rozpoczynającym się pod adresem (4004H), lecz można je łatwo umieścić w innym obszarze pamięci. Pamiętaj jednakże, iż HFILE musi się rozpoczynać od adresu podzielnego przez 32 z uwagi na to, iż rejestr R posiada jedynie 7 aktywnych bitów.

       .ORG 16516              ;hex 4084
 
START: LD   IX,HR              ;prosty start trybu hires
       RET
 
LBUF:  LD   R,A                ;załaduj LSB adresu HFILE
       .BYTE 0,0,0,0           ;32 instrukcje NOP = 256 pikseli
       .BYTE 0,0,0,0 
       .BYTE 0,0,0,0 
       .BYTE 0,0,0,0 
       .BYTE 0,0,0,0 
       .BYTE 0,0,0,0 
       .BYTE 0,0,0,0
       .BYTE 0,0,0,0
       RET  NZ                 ;zawsze następuje powrót

HR:    LD   B,7                ;opóźnienie

HR0:   DJNZ HR0                ;opóźnienie
       DEC  B                  ;wyzeruj znacznik Z
       LD   HL,(4004H)         ;HFILE rozpoczyna się pod adresem RAMTOP lub HSCRN (notka poniżej)
       LD   DE,20H             ;32 bajtów na linię
       LD   B,0C0H             ;192 linii na ekran hires

HR1:   LD   A,H                ;pobierz MSB adresu HFILE
       LD   I,A                ;i umieść go w rejestrze I
       LD   A,L                ;pobierz LSB adresu HFILE
       CALL LBUF+8000H
       ADD  HL,DE              ;następna linia
       DEC  B                  ;zmniejsz licznik linii
       JP   NZ,HR1             ;kontynuuj wyświetlanie

HR2:   CALL 292H               ;powróć do programu aplikacji
       CALL 220H               ;dodatkowe umieszczenie rejestrów na stosie oraz VSYNC
BREAK:                         ;ten kod jest opcjonalny
       CALL 0F46H              ;sprawdź, czy naciśnięto BREAK
       LD   A,1EH              ;odtwórz wektor tablicy matryc znaków w ROM
       LD   I,A
       JR   NC,STOP            ;jeśli naciśnięto BREAK, pomiń ładowanie wektora HR do IX
       LD   IX,HR              ;załaduj wektor do HR
STOP : JP   2A4H               ;powróć do kodu aplikacji
 
HSCRN  .WORD 2000H             ;używane z pamięcią SRAM w obszarze 8K - 16K
 
;Uwaga:
 
;HFILE można przemieścić w przypadku posiadania pamięci SRAM w obszarze 8 do 16K zmieniając
;LD HL,(4004) na LD HL,(HSCRN).
 
 
;------------------ koniec listingu ------------------

WRX1K - 1996, autor - Wilf Rigter

Ten malutki program hires jest specjalny, ponieważ działa na zwykłym ZX81 z pamięcią 1K/2K RAM. Tworzy on miniaturowy obraz o rozdzielczości 64x48 pikseli w tablicy 384 bajtów, która umieszczona jest pod adresem (RAMTOP) i w której wartości można umieszczać przy pomocy polecenia POKE z poziomu języka BASIC. Przy wywołaniu START zostaje zwinięty bufor DFILE Sinclaira i rozwinięty bufor hires ponad RAMTOP w celu efektywnego wykorzystania pamięci 1K. Przy wywołaniu STOP odzyskiwana jest pamięć ponad RAMTOP, aby otrzymać więcej miejsca dla DFILE.

      .ORG 16516               ;hex 4084
 
LBUF:  ;Plik obrazowy
       ;-------------
 
       ;podobnie jak dla DFILE, wywoływany jest pod adresem w górnej połówce pamięci
       ;ponad 32K w celu aktywacji układu ULA. Z kodów wykorzystywany jest jedynie
       ;bit nr 7 do tworzenia negatywu. Dane hires są ładowane do rejestru przesuwnego
       ;wideo w ULA podczas cyklu odświeżania przy wykonywaniu 8 instrukcji NOP, gdy
       ;zawartość rejestrów I oraz R sekwencyjnie adresuje 8 bajtów danych hires w
       ;obrębie 384-bajtowego bufora HFILE.
       ;Uwaga: w tym szczególnym przypadku krótkich (8 bajtów) linii wideo opóźnienia
       ;(E3 i 40) posiadają ustawiony na 1 bit 6 w celu uniemożliwienia wyświetlania
       ;obrazu na początku i na końcu każdej linii poziomej.
 
       .BYTE 0E3H,0E3H,0E3H,0E3H  ;opóźnienie 76 cykli zegara

       LD   R,A                   ;teraz załaduj rejestr R LSB adresu HFILE

LBYTE: .BYTE 0,0,0,0,0,0,0,0      ;8 bajtów po 8 pikseli
       .BYTE 40H,40H,40H,40H      ;opóźnienie 20 cykli zegara
       .BYTE 40H                  ;opóźnienie 4 cykli zegara

       JP   (IX)                  ;powróć do HR
 
START: ;robi miejsce ponad RAMTOP i włącza procedurę hires
       ;--------------------------------------------------

       LD   IX,HR                 ;początek nowej procedury wideo
       LD   BC,180H               ;dla obrazu 64x48 potrzeba 384 bajtów
       CALL 0EC5H                 ;czy jest miejsce, aby obniżyć RAMTOP?
       LD   HL,(4004H)            ;pobierz stare RAMTOP (1K/2K)
       CCF                        ;oblicz wartość nowego RAMTOP
       SBC  HL,BC                 ;odejmując długość HFILE 

STACK: ;używane przez START i STOP do zmiany RAMTOP bez NEW
 
       OUT  0FDH,A                ;wyłącz generator NMI podczas przesuwania stosu
       LD   (4004H),HL            ;uaktualnij RAMTOP
       DEC  HL                    ;HL wskazuje pierwszy bajt poniżej RAMTOP
       LD   (HL),3EH              ;zaznacz go przy pomocy 3E
       DEC  HL
       LD   SP,HL                 ;umieść stos pod RAMTOP
       DEC  HL
       DEC  HL
       LD   (4002),HL             ;zapisz wskaźnik błędu na stosie
       OUT  0FEH,A                ;włącz NMI
       JP   676H                  ;wznów wykonywanie BASICU od następnej linii
 
 
HR:    ;CZĘŚĆ 1 wywołuje LBUF 48 razy wyświetlając 64x48 pikseli, oblicza puste linie
       ;zapisuje wskaźnik do CZĘŚCI 2 w IX i powraca do kodu aplikacji.
       ;CZĘŚĆ 2 wywołuje VSYNC itp., sprawdza klawisz BREAK, oblicza puste linie,
       ;zapisuje wskaźnik do CZĘŚCI 1 w IX i powraca do kodu aplikacji.
 
       LD   B,04                  ;załaduj opóźnienie

HR0:   DJNZ HR0                   ;opóźnienie 56 taktów w celu synchronizacji z impulsami HSYNC.

       LD   HL,(4004H)            ;RAMTOP wskazuje na pierwszy bajt HFILE
       LD   B,30H                 ;48 linii poziomych
       LD   IX,HR1                ;zapisz wektor powrotu w IX (dla JP (IX) na końcu LBUF)
       JR   HR2                   ;przy pierwszym obiegu pętli pomiń HR1

HR1:   LD   DE,08                 ;ta wartość jest dla 8 bajtów lub 64 pikseli na linię
       ADD  HL,DE                 ;dodaj ją do HL, aby wskazać na początek następnej linii poziomej
       DEC  B                     ;powtórz to 48 razy
       JP   Z,HR3                 ;przy ostatniej linii skocz do HR3

HR2:   LD   A,H                   ;Adres z HL zostaje przeniesiony do
       LD   I,A                   ;rejestru I
       LD   A,L                   ;a podczas LBUF również do rejestru R
       JP   LBUF+8000H            ;skocz do echa LBUF w górnej połówce pamięci, aby rozpocząć obraz wideo

HR3:   LD   IX,HR4                ;zapisz wektor wideo, aby NMI powróciło do CZĘŚCI 2
       JR   HR5                   ;wyświetl puste linie i powróć do kodu aplikacji
 
HR4:   ;CZĘŚĆ 2
 
       CALL 0220H                 ;umieść na stosie rejestry i skocz do VSYMC
       CALL 0F46H                 ;testuj klawisz BREAK
       JR   NC,STOP               ;i wyjdź z HR, jeśli naciśnięto ten klawisz
       LD   IX,HR                 ;zapisz wektor wideo w IX, aby NMI powróciło do CZĘŚCI 1

HR5:   LD   A,(4028H)             ;33 lub 19 pustych linii ze zmiennej systemowej MARGIN
       ADD  A,47H                 ;dodatkowe 71 pustych linii w celu szybszego wykonywania aplikacji
       JP   29EH                  ;zapisz puste linie, rozpocznij NMI, pobierz rejestry ze stosu i powróć

STOP:  ;wychodzi z procedury hires odtwarzając RAMTOP oraz wideo Sinclaira

       LD   A,1EH                 ;adres tablicy matryc znakowych w ROM (1E00)
       LD   I,A                   ;zapisujemy go w rejestrze I
       LD   HL,(4004H)            ;pobierz bieżące RAMTOP
       LD   DE,180H               ;długość HFILE
       ADD  HL,DE                 ;jest dodawana do bieżącego RAMTOP
       LD   IX,0281H              ;procedura wideo Sinclaira
       JR   STACK                 ;wyjdź z HR poprzez STACK, aby zmienić RAMTOP
 
;------------------ koniec listingu ------------------

15. PROCEDURY DLA TRYBU PSEUDO HIRES

Oprogramowanie trybu pseudo hires wykorzystuje kody znaków oraz rejestr I do adresowania jednego z 64 bajtów z wzorem w pamięci ROM. Kody znaków są ograniczone do przedziału od 0 do 63 oraz do ich negatywów (kody od 128 do 191), natomiast zawartość rejestru I jest tak wybrana, aby wskazywała blok bajtów z wzorkami w ROM o dużej przypadkowości i z jak najmniejszą liczbą duplikatów. Metoda ta nosi nazwę "pseudo" hires, ponieważ dostępne jest do wyświetlania mniej niż 50% z 256 wymaganych dla true hires układów bitów. Powoduje to, iż pewnych układów pikseli brakuje w generowanej grafice, lecz dla wieli zastosowań (np. gier) nie stanowi to problemu. Zaletą tej metody jest to, iż działa ona w standardowym systemie ZX81 z pamięcią 16K RAMPACK bez żadnych modyfikacji. Wiele emulatorów obsługuje ten tryb wyświetlania obrazu - np. eightyOne.

3DHIRES, autor nieznany

W tym przykładzie procedur pseudo hires rozwinięty blok DFILE znajduje się pod adresem 6700H.

START:  LD   A,4        ;wybierz interesującą tablicę wzorków
        LD   I,A        ;zapisz wektor tej tablicy w rejestrze I
        LD   IX,PHR     ;załaduj wektor procedury pseudo hires do rejestru IX
        RET
 
PHR:    LD   HL,0E6DFH  ;HL jest używane w charakterze wskaźnika DFILE
        LD   DE,21H     ;32 znaków + RET = 33 bajty na linię
        DI              ;INT nieużywane
        LD   C,0FEH     ;wyzeruj licznik linectr w ULA
        LD   B,16H      ;opóźnienie

LP1:    DJNZ LP1        ;opóźnienie
        LD   B,0C0H     ;192 linie po 33 bajty

PHR1:   IN   A,(C)      ;zastosuj reset w liczniku linii
        OUT  0FFH,A     ;zwolnij licznik linii
        ADD  HL,DE      ;następna linia z DFILE (E700,E721, itd.)
        CALL PHR2       ;"wykonaj" "DFILE" poprzez JP (HL) pod adresem PHR2
        DEC  B          ;zmniejsz licznik linii
        JP   NZ,PHR1    ;ostatnia? powtarzaj 192 razy.
        CALL 292H       ;odtwórz ze stosu główne rejestry, powróć do aplikacji
        CALL 220H       ;umieść na stosie rejestry i wykonaj VSYNC
        LD   IX,PHR     ;wektor procedury pseudo hires do IX
        JP   2A4H       ;odtwórz pierwotne rejestry, powróć do aplikacji
PHR2:   JP   (HL)       ;skocz do echa obszaru hires "DFILE" ponad 32K

XTRICATOR, autor - firma Software Farm

Ta niezwykła procedura tworzenia pseudografiki przechwytuje obsługę wideo ustawiając tryb przerwań 2, w którym generujące przerwanie urządzenie dostarcza część adresu procedury obsługi. Ponieważ nieaktywna magistrala danych znajduje się w stanie 0FFH, a rejestr I jest ustawiony na 40, to wektor obsługi INT wynosi 4000, gdy linia A6 wyzwala przerwanie na końcu linii poziomej.

4083    LD   HL,40A5H   ;wektor powrotu
4086    PUSH HL         ;zapisz go na stosie
4087    LD   HL,0E500H  ;bufor grafiki hires
408A    PUSH HL         ;zapisz wektor na stosie
408B    LD   B,7        ;opóźnienie
408D    DJNZ 408DH      ;opóźnienie
408F    LD   A,1EH      ;wzorki z Sinclair ROM
4091    LD   I,A        ;załaduj wektor tablicy wzorków
4093    LD   DE,0C201H  ;D = 194 linie
4096    DEC  E          ;ustaw znacznik Z
4097    JP   Z,409AH    ;opóźnienie
409A    POP  HL         ;HL = E500
409B    DEC  D          ;zmniejsz licznik linii
409C    RET  Z          ;po ostatniej linii powróć do 40A5
409D    SET  0,E        ;E = 01
409F    JP   40A2H      ;opóźnienie
40A2    LD   A,0        ;opóźnienie
40A4    JP   (HL)       ;skocz do echa bufora 6500 ponad 32K
 
40A5    LD   A,4        ;"specjale" wzorki z ROM
40A7    LD   I,A        ;załaduj wskaźnik tablicy wzorków
40A9    RET
 
40AA    LD   A,40H      ;MSB adresu obsługi tryby 2 przerwań INT
40AC    LD   I,A        ;umieść MSB wektora obsługi przerwań w trybie 2
40AE    IM2             ;włącz tryb 2 przerwań INT
40B0    RET
 
40B1    LD   A,1EH      ;wzorki Sinclaira w ROM
40B3    LD   I,A        ;załaduj wskaźnik tablicy wzorków do rejestru I
40B5    IM1             ;przywróć tryb INT 1
40B7    RET
 
40B8    LD   HL,6500H   ;na początku HFILE umieść instrukcję:
40BB    LD   B,0C1H
408D    LD   (HL),0CDH  ;CALL 4096H
408F    INC  HL
40C0    LD   (HL),96H
40C2    INC  HL
40C3    LD   (HL),40H
40C5    INC  HL
40C6    LD   A,20H      ;wygeneruj 6144 spacji poczynając od 
40C8    LD   (HL),0     ;adresu 6503H
40CA    INC  HL
40CB    DEC  A
40CC    JR   NZ,40C8H
40CE    DJNZ 40C6H 
40D0    RET


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe