Spis Treści
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.
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.
Tab.1 Operacje wykonywane w trakcie tworzenia ramki obrazu
| 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 |
Każde z zadań możemy opisać bardziej szczegółowo w sposób następujący:
- 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.
- 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.
- 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.
- 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.
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:
- OUT FDH,A - wyłącza generator przerwań NMI
- OUT FEH,A - włącza generator przerwań NMI
- IN A, FEH - wyłącza generator HSYNC (tylko gdy przerwania
NMI są wyłączone)
- 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.
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.
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.
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.

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. UKŁ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.
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.
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:
- Układ ULA odczytuje kod znaku i umieszcza go w rejestrze CHRLATCH.
- Układ ULA wymusza stan niski na liniach D0-D7 magistrali danych.
- Mikroprocesor interpretuje to jako instrukcję NOP.
- Układ ULA generuje część adresu w tablicy z matrycami znaków, a mikroprocesor
generuje wskaźnik tej tablicy przy pomocy rejestru I.
- 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.
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:
- 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.
- Przy opadającym zboczu impulsu T2 ULA wymusza stan 0 na wszystkich liniach
magistrali danych D0-D7 dla procesora.
- Przy narastającym zboczu impulsu
T3 stan niski na liniach magistrali danych zostaje
zinterpretowany przez mikroprocesor jako rozkaz NOP.
- 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.
- 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.
- Jeśli bit 7 pobranego kodu znaku ma stan 1, to wyprowadzane do telewizora bity
matrycy znaku są odwracane w negatyw.
- Mikroprocesor zwiększa licznik rozkazów i pobiera następny kod znaku.
- Proces ten jest powtarzany aż do napotkania w bloku DFILE instrukcji HALT -
czyli znaku CHR$ 118 - NEWLINE.
- Kod HALT ma ustawiony na 1 bit nr 6 i dlatego nie jest zamieniany przez ULA na
NOP - procesor wykonuje ten rozkaz.
- ULA generuje impuls synchronizacji poziomej HSYNC niezależnie od przebiegów
czasowych mikroprocesora, a licznik linii LINECTR jest zwiększany o 1.
- 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.
- 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).
- Mikroprocesor powraca z przerwania maskowanego i wznawia "wykonywanie" kodów
znakowych z bloku DFILE.
- 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:
- ULA ładuje kod znaku do rejestru adresowego CHRLATCH.
- ULA wymusza niski stan na liniach D0-D7 magistrali
danych.
- Mikroprocesor interpretuje to jako rozkaz NOP.
- ULA generuje część adresu tablicy wzorów w ROM.
Mikroprocesor generuje bardziej znaczący bajt adresu przy pomocy swojego
rejestru
I.
- 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.

Rys.8 Przebiegi czasowe dla pseudografiki
Dokładny ciąg operacji dla każdego znaku jest następujący.
- 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.
- Przy opadającym zboczu impulsu T2 ULA wymusza stan 0 na wszystkich liniach
magistrali danych D0-D7 dla procesora.
- Przy narastającym zboczu impulsu T3 stan niski na liniach magistrali danych
zostaje zinterpretowany przez mikroprocesor jako rozkaz NOP.
- 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.
- 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.
- Jeśli bit 7 pobranego kodu znaku ma stan 1, to wyprowadzane do telewizora bity
matrycy znaku są odwracane w negatyw.
- Mikroprocesor zwiększa licznik rozkazów i pobiera następny kod znaku.
- Proces ten jest powtarzany aż do napotkania w bloku DFILE instrukcji RET,
która powoduje powrót do procedury grafiki pseudohires.
- Kod
RET ma również ustawiony na 1 bit nr 6 i dlatego nie jest
zamieniany przez
ULA na NOP - procesor wykonuje ten
rozkaz.
- 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.
- Mikroprocesor powraca z procedury pseudohires i wznawia "wykonywanie" kodów
znaków z DFILE.
- 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:
- Mikroprocesor wykonuje każdą z 32 czterotaktowych instrukcji NOP.
- Podczas cyklu T3/4 (odświeżanie) na liniach adresowych pojawia się zawartość rejestru I
(A8-A15) i R (A0-A7).
- 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.
Rys.9 Przebiegi czasowe dla pełnej grafiki
Dokładny ciąg operacji dla każdego bajtu hires jest następujący:
- Mikroprocesor wykonuje pierwszy kod rozkazu w LBUF - LDA R,A.
- Następnie zostają wykonane kolejno 32 rozkazy NOP w LBUF.
- Rozkaz NOP mikroprocesor wykonuje przy narastającym zboczu taktu T3.
- Podczas taktu T3/4 generowany jest adres przy pomocy rejestru R na liniach A0-A7
i rejestru I na A8-A15.
- 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.
- Mikroprocesor zwiększa licznik rozkazów oraz zawartość rejestru R i pobiera
kolejną instrukcję NOP oraz następny bajt hires.
- Proces ten powtarza się 32 razy.
- Ostatnim kodem rozkazu w LBUF jest JP (IX), którego wykonanie powoduje powrót do
procedury HR.
- ULA generuje impuls synchronizacji poziomej.
- 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.
- Proces ten jest powtarzany 192 razy.
- 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.
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
;-----------------------------------------------------------
|
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.
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 ------------------
|
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
|
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.