Budowa ZX-Spectrum

Według dzisiejszych standardów ZX Spectrum jest prostą konstrukcją elektroniczną, jednak w latach 80-tych był dużym osiągnięciem technicznym. Co prawda swoimi parametrami ustępował komputerom Commodore C64 i Atari 800XL, lecz był od nich tańszy.

https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/ZXSpectrum48k.jpg/220px-ZXSpectrum48k.jpg
ZX Spectrum - $125
http://newsimg.bbc.co.uk/media/images/42684000/jpg/_42684671_commodore_64.jpg
Commodore 64 - $600

Atari 800XL - $400

Atutem ZX Spectrum była olbrzymia liczba dostępnych programów. Na komputer ten oprócz gier powstawały wszelakie programy użytkowe. Sam korzystałem przez jakiś czas z procesora tekstu Tasword wyprodukowanego przez firmę Tasman Software. W początkowym okresie komputery ZX Spectrum były używane w Polsce na lekcjach informatyki. Zakłady Elwro produkowały w 1986 klon pod nazwą Elwro Junior 800. Komputery te pozwalały nawet tworzyć proste sieci LAN.

http://lootmuchow.wodip.opole.pl/informatyka/elwro_800jr_01_middle.jpg

Polski ZX Spectrum - Elwro 800 Junior

Rozpatrując komputer ZX Spectrum należy pamiętać, iż celem Sir Clive'a Sinclaira było stworzenie komputera taniego, dla mas. Cel ten udało mu się znakomicie osiągnąć. Jednakże oszczędności musiały wpłynąć na parametry komputera. Po ściągnięciu obudowy oczom naszym ukazywał się taki widok (model 48k):

Po lewej stronie u góry w metalowym pudełku znajdował się modulator TV, który posiadał gniazdo RF (ang. Radio Frequency – częstotliwość radiowa) z wyjściem antenowym dla sygnału do telewizora. Modulator tworzył obraz telewizyjny w standardzie PAL. W owym czasie w Polsce królował system SECAM, niekompatybilny z PAL, jeśli chodzi o kodowanie kolorów. Po podłączeniu komputera ZX Spectrum do telewizora z systemem SECAM obraz był czarno-biały, a kolory pojawiały się jako różne odcienie szarości. Dodatkowym efektem były ukośne paski, które przebiegały po kolorowych płaszczyznach – zapewne efekt złego filtrowania sygnału PAL w polskich telewizorach pracujących w systemie SECAM. ZX Spectrum nie posiadał wyjścia monitorowego. Podłączenie monitora było możliwe dopiero po pewnych przeróbkach sprzętowych na płycie. Zadanie zupełnie nie dla zwykłego użytkownika.

Dalej mamy dwa gniazda mini jack:  słuchawkowe (EAR) i mikrofonowe (MIC). Gniazda służyły do połączenia z magnetofonem kasetowym, na którym komputer zapisywał swoje programy i dane w postaci odpowiednio ukształtowanej fali dźwiękowej. W latach 80-tych takie rozwiązanie było całkowicie do przyjęcia. Stacje dysków elastycznych kosztowały majątek, o dyskach twardych nawet nie wspomnę.

Za gniazdami mini jack widzimy prymitywne złącze krawędziowe. Na złącze to nasuwane były gniazda różnych rozszerzeń sprzętowych. Widoczna szczelina odpowiadała występowi we wtyczce. Dzięki niej wtyczkę dawało się włożyć tylko w jeden sposób, no chyba że użytkownik był uparty i ćwiczył kulturystykę. Podobne złącza są stosowane do dzisiaj na płytach głównych PC, np. w pamięciach DIMM. W ZX Spectrum złącze krawędziowe nie było blokowane zatrzaskiem, zatem należało uważać przy podłączaniu rozszerzeń. Drobna niestabilność na stykach i komputer mógł się zawiesić lub nawet uszkodzić.

Na koniec po prawej stronie mamy gniazdo zasilania, do którego wkładało się wtyczkę zasilacza. Komputer nie posiadał przycisku RESET i w przypadku zablokowania się użytkownik po prostu wyciągał i wkładał wtyczkę do tego złącza, a komputer startował od nowa. Co ciekawe, start ZX Spectrum zajmował około 2 sekund. Porównaj to ze startem dzisiejszych komputerów PC.

Z gniazd mamy jeszcze dwa na płycie głównej. Jedno znajduje się po lewej stronie (5 styków), a drugie po prawej (8 styków). W gniazda te wsuwane były taśmy stykowe klawiatury. Klawiatura w ZX Spectrum wykonana była jako folia stykowa, niezbyt trwała. Zewnętrzne klawisze jedynie przekazywały nacisk na pola stykowe folii. Zatem rozwiązanie to niewiele różniło się od rozwiązania stosowanego w ZX81 (klawiatury współczesnych komputerów PC też wykorzystują te rozwiązanie).

Na płycie głównej mamy trzy większe układy scalone. Idąc kolejno od lewej do prawej:

ULA (IC1 żółty) – specjalizowany układ scalony wyprodukowany przez firmę FERRANTI na zamówienie Sinclair Research Ltd. Zadaniem tego układu jest generowanie obrazu dla odbiornika TV, odczyt klawiatury oraz sterowanie głośnikiem i wyjściami dla magnetofonu. Dzięki układowi ULA mikroprocesor mógł zająć się w pełni wykonywaniem programu użytkownika (w poprzedniku ZX Spectrum, ZX81, mikroprocesor aktywnie uczestniczył w tworzeniu obrazu TV). We współczesnych płytach głównych również występują podobne układy - nazywa się je chipsetem.

Mikroprocesor NEC D780C (IC2 zielony), kompatybilny z mikroprocesorem Z80 firmy Zilog. Opis mikroprocesora Z80 znajdziesz tutaj.

Pamięć ROM o pojemności 16KB (IC5 niebieski), w której zawarto cały system operacyjny ZX Spectrum oraz bardzo dobry interpreter języka BASIC. Zawartość ROM znajdziesz tutaj.

Osiem małych układów po lewej stronie u dołu (IC6...IC13 czerwone) to pamięć dynamiczna RAM o pojemności 16KB. Następne 8 układów w dwóch rzędach po 4 (IC15...IC22 fioletowe) to pamięć RAM o pojemności 32 KB. W tańszym modelu ZX Spectrum 16K układy te nie były wmontowane. Podział pamięci RAM na dwie części 16KB i 32KB (w sumie 48KB) miał też dodatkowe konsekwencje. W pamięci RAM 16KB umieszczony był obszar ekranu, do którego miał dostęp układ ULA. Ponieważ obraz musiał być ciągle generowany, to ULA czasami podkradał cykle mikroprocesorowi, jeśli oba te układy operowały jednocześnie na tym samym bloku pamięci. Zwykle nie miało to żadnych konsekwencji w języku BASIC, chyba że mikroprocesor w sposób programowy generował dźwięk. Kradzież cykli objawiała się wtedy charczeniem w głośniku. Aby dźwięk był czysty, procedurę jego generacji należało umieszczać w drugim bloku pamięci 32KB, do któregu ULA nie miał już dostępu, bo i po co.

Pozostałe układy to różne bufory i bramki logiczne (za wyjątkiem układu IC14 LM1889N: modulator TV, który widzimy po lewej stronie ULA). Na koniec po prawej stronie u dołu znajduje się mały głośniczek, dzięki któremu ZX Spectrum mógł generować różne piski i trzaski. Za pomocą odpowiednich procedur możliwe było odtwarzanie prostej muzyki. Lepsze efekty muzyczne osiągalne były dopiero po dołączeniu poprzez złącze krawędziowe specjalnej przystawki z układem AY-3-8912. W późniejszych modelach układ ten był montowany standardowo na płycie głównej.

Pamięć ZX Spectrum

Komputer ZX Spectrum początkowo sprzedawany był w dwóch wersjach, które różniły się wielkością dostępnej pamięci RAM. Tańsza wersja ZX Spectrum posiadała 16 KB RAM, w droższej było zainstalowane dodatkowe 32 KB. Musimy pamiętać, że na początku lat 80-tych pamięć RAM kosztowała dosyć sporo. Istniały wtedy dwa typy pamięci: statyczna i dynamiczna. Pamięć statyczna była bardzo droga, dlatego popularnością cieszyła się tańsza pamięć dynamiczna. Czym się różnią te pamięci? Oczywiście budową wewnętrzną. W pamięci statycznej każdy bit jest pamiętany w układzie tzw. przerzutnika. W pamięci dynamicznej natomiast bit zapamiętuje się w postaci ładunku elektrycznego. Jest to dużo prostsze rozwiązanie i wymaga mniej elementów elektronicznych od pamięci statycznej. Jednakże komórki pamięci dynamicznej muszą być co pewien czas odświeżane, inaczej przechowywany przez nie ładunek rozpłynie się i informacja ulegnie zniszczeniu. Stąd pochodzi nazwa tej pamięci - informacja jest utrzymywana dynamicznie w układzie. Odświeżanie komórek pamięci wymaga cyklicznych odczytów. Na szczęście, mikroprocesor Z80 (w ZX Spectrum pracował odpowiednik tego procesora produkowany przez firmę NEC) posiada w swojej strukturze odpowiednie układy, które wykonują ten odczyt odświeżający w sposób automatyczny.

http://cdn.cpu-world.com/CPUs/Z80/L_NEC-D780C-1.jpg

Mikroprocesor Z80 posiada 16 bitową szynę adresową. Pozwala mu to na dostęp do pamięci o całkowitej wielkości 216 komórek, czyli 65536 lub 64KB. Przestrzeń ta podzielona była na dwa obszary: ROM i RAM.

Pamięć ROM to tzw. pamięć stała. Zawartość jest określana na etapie produkcji i później nie można jej zmienić. ZX Spectrum w pamięci ROM przechowywał swój system operacyjny oraz interpreter języka BASIC. Jeśli interesuje cię, co dokładnie zawierała ta pamięć, to zapraszam do tego artykułu.

Umieszczenie całego systemu operacyjnego w ROM ma swoje zalety. Dzisiejsze komputery odczytują swój system operacyjny z dysku i start może trwać nawet kilka minut. ZX Spectrum był gotowy do pracy w 2 sekundy do włączeniu zasilania.

Obszar ROM zajmował pierwsze 16 KB (szesnastkowo adresy od 0000 do 3FFF). ROM mógł być podmieniany przez różne kartridże, przez co komputer uzyskiwał zupełnie nowe funkcje – np. w ten sposób działało rozszerzenie Interface 1.

Po pamięci ROM w obszarze adresowym mikroprocesora Z80 umieszczona była pamięć RAM. W tańszym modelu, ZX Spectrum 16K, RAM zajmowała obszar od 4000 do 7FFF, czyli 16KB. W modelu droższym, ZX Spectrum 48K, pamięć RAM zajmowała obszar od 4000 do FFFF, czyli 48KB. W latach 80-tych to było bardzo dużo.

Początkowe 6KB pamięci RAM zajmował bufor ekranu, bufor drukarki oraz różne zmienne i dane systemowe. Po nich w RAM umieszczany był program w języku BASIC. Jeśli użytkownik nie korzystał z tego języka, to cała pozostała pamięć była do jego dyspozycji (może niedokładnie cała, część pamięci jednak należało zarezerwować na proste polecenia w BASIC'u, najczęściej pamięć rezerwowało się przez ustawienie zmiennej systemowej RAMTOP za pomocą polecenia CLEAR adres).

Poniższy program wypisuje zawartość pamięci ROM.

10 FOR i=0 TO 16383
20 PRINT "ADR:";i,"BYTE:";PEEK i
30 NEXT i

Kolejny program najpierw w dosyć dziwny sposób wypełnia ekran pikseli, a później ekran atrybutów. Budowę i sposób korzystania z ekranu opiszemy w dalszym części rozdziału.

10 FOR i=16384 TO 23295
20 POKE i,INT (RND*256)
30 NEXT i
40 IF INKEY$="" THEN GO TO 40

Mikroprocesor

W komputerze ZX Spectrum zastosowano klon mikroprocesora Zilog Z80 produkowany przez japońską firmę NEC o oznaczeniu D780C. Był to prawdopodobnie najlepszy mikroprocesor 8-mio bitowy w latach 80-tych. O jego jakości świadczy fakt, że jest produkowany do dzisiaj w zmodernizowanej wersji (wersja z zegarem do 20MHz). Mikroprocesor Z80 dysponował dosyć dużą mocą obliczeniową i posiadał cechy zarówno mikroprocesora 8-mio jak i 16-to bitowego. Zamknięty był w 40-to nóżkowej obudowie:

Mikroprocesor ten posiadał następujące parametry:

Częstotliwość zegara 3,54MHz
Magistrala adresowa 16 linii od A0 do A15.
Przestrzeń adresowa 216 bajtów, czyli 65536 komórek o adresach od 0000 do FFFF.
Magistrala danych 8 linii od D0 do D7, co czyniło z mikroprocesora układ 8-mio bitowy. Dostęp do danych 16-to bitowych wymagał dwóch cykli odczytu/zapisu pamięci.
Rodzaj pamięci pamięć statyczna (nie stosowana w ZX Spectrum) lub pamięć dynamiczna.
Liczba instrukcji 158. Z80 jest rozbudowaną wersją poprzedzającego go mikroprocesora Intel 8080, który potrafił wykonywać tylko 78 różnych instrukcji. Z80 potrafił bez problemów wykonywać programy napisane dla 8080, co również przyczyniło się do jego popularności, ponieważ w latach 80-tych istniała olbrzymia baza programów dla mikroprocesora Intela.
Liczba rejestrów 22. Rejestry są jakby pamięcią podręczną mikroprocesora. Rozkazy operujące na zawartości rejestrów wykonują się bardzo szybko. Duża liczba rejestrów do dyspozycji programisty upraszcza programowanie. W porównaniu do 8080 doszedł alternatywny zestaw rejestrów, który mógł być przełączany z głównym zestawem. Doszły również dwa rejestry indeksowe IX oraz IY, które upraszczały operacje na tablicach.
  W głównym zestawie rejestrów mamy tzw. pary rejestrów, czyli po dwa rejestry 8-mio bitowe, które mogą również tworzyć jeden rejestr 16-to bitowy.

Ważną funkcję pełni tutaj rejestr akumulatora A (ang. Accumulator), ponieważ uczestniczy on w dużej liczbie operacji arytmetycznych i logicznych, jest zatem najbardziej uniwersalnym ze wszystkich rejestrów. Niektóre operacje mogą być wykonane wyłącznie na zawartości akumulatora. Również ważnym rejestrem jest jego towarzysz F (ang. Flags), który przechowuje tzw. znaczniki. Znaczniki określają stan mikroprocesora oraz wynik różnych operacji.

Z kolejnych rejestrów bardzo ważna jest para HL, która wykorzystywana jest intensywnie do adresowania danych w pamięci.

Rejestr I jest rejestrem wykorzystywanym przez przerwania (ang. Interrupts).

Rejestr R (ang. Refresh) pozwala cyklicznie odświeżać pamięci dynamiczne.

Rejestr SP (ang. Stack Pointer) adresuje w pamięci RAM tzw. stos, na którym mikroprocesor umieszcza adresy powrotne z podprogramów oraz różne dane, które należy chwilowo zapamiętać.

Na koniec rejestr PC (ang. Program Counter) to tzw. licznik rozkazów, wykorzystywany przez mikroprocesor do adresowania w pamięci kolejno wykonywanych instrukcji maszynowych.

Mikroprocesor Z80 jest układem bardzo skomplikowanym. Pełny opis znajdziesz tutaj.

Dźwięk

Komputer ZX Spectrum posiadał na swojej płycie głównej mały głośnik, za pomocą którego można było wytwarzać różne dźwięki. Tworzenie dźwięku odbywało się na drodze programowej, tzn. mikroprocesor wykonywał odpowiednią procedurę o dokładnie wyliczonych opóźnieniach i na zmianę przesyłał do głośnika sygnał logiczny 1 lub 0. W ten sposób powstawał dźwięk jednotonowy o przebiegu prostokątnym.

Z poziomu interpretera języka BASIC można było generować jednotonowe dźwięki poleceniem:

BEEP czas trwania, wysokość dźwięku

Czas trwania podawany w sekundach, również wartości ułamkowe.

Wysokość dźwięku podawana w liczbie półtonów od środkowego dźwięku C:

Liczba półtonów również może być ułamkowa, co w zasadzie pozwala odtworzyć dźwięki również innych skal muzycznych. Wpisz do ZX Spectrum poniższy program (zamiast rzeczywistego komputera może być jego dowolny emulator):

10 DATA 0,2,4,5,7,9,11,12,11,9,7,5,4,2,-1
20 RESTORE
30 READ n
40 IF n=-1 THEN GO TO 20
50 BEEP 0.25,n
60 GO TO 30

Program gra kolejne dźwięki gamy C.

Programując w kodzie maszynowym mamy większą kontrolę nad tworzonym dźwiękiem. Istniały programy, które potrafiły nawet syntezować mowę ludzką (z mniejszym lub większym skutkiem). Procedury obsługujące dźwięk umieszcza się w bloku pamięci RAM 32 KB, gdzie nie są zakłócane przez układ ULA tworzący obraz. Dostęp do głośniczka mamy poprzez port 254 (FE) i bit nr 4 (pozostałe bity pełnią inne funkcje). Poniższy program tworzy niski, buczący dźwięk w języku BASIC:

10 OUT 254,BIN 11111111
20 OUT 254,BIN 11101111
30 GO TO 10

Klawiatura

https://www.tsiopos.com/emulators/zxspectrum48/spectkey.png

Komputer ZX-Spectrum był wyposażony w klawiaturę o 40 przyciskach. Klawisze były gumowe i wystawały nieco ponad obudowę. Jednakże wewnątrz wciąż panowała folia stykowa, tak samo jak w poprzedniku ZX-81. Jakość zastosowanej gumy nie była zbyt wysoka (prawdopodobnie chodziło o maksymalne obniżenie kosztów produkcji) i po pewnym czasie intensywnego użytkowania znikały z klawiszy wydrukowane na nich symbole. Nie był to specjalnie duży problem, ponieważ wiele niezależnych firm oferowało dobre klawiatury dla ZX Spectrum. Poniżej widok klawiatury dk'tronics z profesjonalną klawiaturą kontaktronową (działa do dzisiaj!):

https://www.rockpapershotgun.com/images/12/apr/spec6.jpg

W języku BASIC odczyt klawiatury dokonywał się za pomocą funkcji INKEY$. Zwracała ona tekst ze znakiem odpowiadającym naciśnietemu klawiszowi lub pusty łańcuch, jeśli żaden klawisz nie był naciśniety. Poniższy program wypisuje w rogu ekranu kolejne literki alfabetu do momentu naciśnięcia dowolnego klawisza (za wyjątkiem Caps Shift i Symbol Shift).

10 LET a=65
20 PRINT AT 0,0; CHR$ a
30 LET a=a+1
40 IF a=91 THEN GO TO 10
50 IF INKEY$= "" THEN GO TO 20
60 IF INKEY$<>"" THEN GO TO 60

Polecenie INKEY$ umożliwiało odczyt tylko pojedynczego klawisza. Poniższy programik jest czymś w rodzaju prymitywnej maszyny do pisania:

10 LET a$= INKEY$ : IF a$="" THEN GO TO 10
20 PRINT a$;
30 IF INKEY$<>"" THEN GO TO 30
40 GO TO 10

Do sprzętowego odczytu stanu klawiatury służy port 254. Numer portu jest w tym przypadku 16-bitowy. Górne 8 bitów wyznaczają 5-cio klawiszowy segment klawiatury, który zostanie odczytany z portu. Stan klawiszy danego segmentu znajduje się w 5 młodszych bitach. Gdy bit jest wyzerowany, odpowiadający mu klawisz jest naciśniety. Numery portów (dziesiętne) oraz odpowiadające im segmenty klawiatury są następujące (klawisze są ustawione w kolejności bitów od b4 do b0):

65278:  V C X Z SHT     ‭61438‬:  6 7 8 9 0
‭65022‬:  G F D S A       ‭57342‬:  Y U I O P
‭64510‬:  T R E W Q       ‭49150‬:  H J K L ENTER
‭63486‬:  5 4 3 2 1       ‭32766‬:  B N M SYM SPACE

Kolejny program wypisuje literkę X, jeśli naciśnieto jednocześnie klawisze Z i V:

10 IF IN 65278=173 THEN PRINT AT 0,0;"X":GO TO 10
20 PRINT AT 0,0;" ":GO TO 10

Z poziomu języka BASIC nie jest to specjalnie wygodne, lecz w kodzie maszynowym nie sprawia kłopotów. Gry na ZX Spectrum tworzone były głównie w kodzie maszynowym, a tam odczyt portów jest rzeczą zupełnie naturalną. Należy jednak zwrócić uwagę na fakt, że odczyt klawiatury często zawodził, jeśli naciśnieto naraz więcej niż 2 klawisze. Wynikało to ze sposobu podłączenia linii klawiatury do portu 254.

EKRAN

Komputer ZX Spectrum był reklamowany jako komputer potrafiący wyświetlać obraz kolorowy (Spektrum braw). Dzisiaj pewnie nikogo by to nie zainteresowało. Ale musimy pamiętać, że maszyna ta pojawiła się w roku 1982, a wtedy kolor naprawdę coś znaczył.

Bardzo szybko okazało się, że kolor w ZX Spectrum nie jest swobodny, lecz ograniczony do siatki znaków. Ekran podzielony został na dwie części: część pikselową (bitową: 1 bit = 1 piksel) oraz część zawierającą tzw. atrybuty kolorów. Atrybuty można sobie wyobrazić jako filtry o rozmiarze 8x8 pikseli, które nałożone na treść obrazu pikselowego odpowiednio go barwią. W obrębie atrybutu, czyli grupy 8x8 pikseli można było niezależnie definiować kolor piksela 0 (tło) i kolor piksela 1 (tusz). Dodatkowo istniała możliwość zwiększenia jasności tuszu i wprowadzenie migotania (naprzemienna zamiana kolorów tła i tuszu).

Oprócz samego ekranu istniał również brzeg, czyli obszar dookoła ekranu, który mógł przyjmować osiem kolorów. Poniższy program prezentuje grafikę tekstową ZX Spectrum:

       10 FLASH 0: BRIGHT 0: PAPER 0: INK 7: BORDER 0: CLS
  20 PRINT AT 0,8;"KOLORY ZX SPECTRUM"
  30 PRINT INK 1;AT 1,11;"NIEBIESKI"
  40 PRINT INK 2;AT 2,12;"CZERWONY"
  50 PRINT INK 3;AT 3,11;"FIOLETOWY"
  60 PRINT INK 4;AT 4,12;"ZIELONY"
  70 PRINT INK 5;AT 5,13;"CYJAN"
  80 PRINT INK 6;AT 6,13;"ZOLTY"
  90 PRINT INK 7;AT 7,13;"SZARY"
100 BRIGHT 1
110 PRINT INK 1;AT 8,8;"JASNONIEBIESKI"
120 PRINT INK 2;AT 9,9;"JASNOCZERWONY"
130 PRINT INK 3;AT 10,8;"JASNOFIOLETOWY"
140 PRINT INK 4;AT 11,9;"JASNOZIELONY"
150 PRINT INK 5;AT 12,10;"JASNY CYJAN"
160 PRINT INK 6;AT 13,11;"JASNOZOLTY"
170 PRINT INK 7;AT 14,13;"BIALY"
180 FOR i=1 TO 7: PRINT INK 7-i;PAPER i;AT 16,11+i;"X":NEXT i
190 FLASH 1
200 FOR i=1 TO 7: PRINT INK 7-i;PAPER i;AT 18,11+i;"X":NEXT i
210 BRIGHT 0: FLASH 0: PAPER 0: INK 7

Z punktu widzenia sprzętowego ekran jest obszarem pamięci podzielonym na dwie rozłączne części: obszar pikseli i obszar atrybutów, które następują kolejno po sobie:

Obszar pikseli zawiera ‭6144‬ bajtów, co odpowiada 192 liniom pikselowym po 32 bajty w każdej. Jedna linia pikseli zawiera ich 256 (32 x 8). Pozwala to wyświetlić na ekranie 24 wiersze po 32 znaki w matrycy 8x8 pikseli. Wbrew intuicji kolejne wiersze w pamięci ekranu nie odpowiadają  kolejnym wierszom na ekranie. Można się o tym w prosty sposób przekonać wpisując do obszaru pikseli kolejne bajty za pomocą instrukcji POKE:

FOR i=16384 TO 22527: POKE i,255: NEXT i

Jedynym wyjaśnieniem takiej nieliniowej struktury ekranu są cięcia kosztów w produkcji ZX Spectrum. Kolejne bajty w każdym wierszu odnoszą się do kolejnej grupy 8 pikseli na ekranie. Jednakże następny wiersz nie rozpoczyna się zwykle od kolejnego bajtu za ostatnim bajtem w bieżącym wierszu. Obowiązuje tutaj dosyć zawiła reguła. Aby ją ogarnąć, musimy spojrzeć na adres bajtu z 8 pikselami w systemie dwójkowym.

Każdy wiersz znaków składa się z 8 linii pikselowych (po 256 pikseli, czyli 32 bajty):

Bajty w linii pikselowej są ułożone w pamięci jeden za drugim. Ekran składa się z 24 wierszy znakowych po 8 linii w każdym (co daje w pionie 192 linie). Wiersze są ułożone w trzech bankach po 8:

Dwa ostatnie wiersze w banku 2 (22 i 23) są normalnie niedostępne z poziomu języka BASIC, ponieważ system przeznacza je na komunikaty oraz na wprowadzanie danych instrukcją INPUT. Oczywiście w kodzie maszynowym takie ograniczenie nie istnieje.

Każdy bank zawiera 8 x 8 x 32 = 2048 bajtów. Cały obszar pikselowy zawiera 3 x 2048 = 6144 bajtów. W obszarze pamięci każdego banku najpierw są ułożone linie nr 0 kolejnych 8 wierszy. Po nich następują linie nr 1, 2... 7.

Oznaczmy:

BB → dwubitowy numer banku: 00, 01 i 10 (0...2)
WWW → trzybitowy numer wiersza w obrębie banku: 000, 001, 010, 011, 100, 101, 110 i 111 (0...7)
LLL → trzybitowy numer linii w wierszu znakowym: 000, 001, 010, 011, 100, 101, 110 i 111 (0...7)
KKKKK → pięciobitowy numer kolumny znakowej: od 00000, 00001, 00010 ... 11111 (0...31)

Adres bitowy posiada następującą budowę:

010BBLLLWWWKKKKK

Na przykład, chciałbym zapełnić obszar znaku leżącego w banku nr 1, w wierszu 3 tego banku i w kolumnie 12. Wartości te zapisuję binarnie i otrzymuję:

BB = 01
WWW = 011
KKKKK = 01100

Bajt 000 pod adresem: 0100100001101100, dziesiętnie ‭18540‬
Bajt 001 pod adresem: 0100100101101100, dziesiętnie ‭‭18796‬
Bajt 010 pod adresem: 0100101001101100, dziesiętnie ‭‭19052‬
Bajt 011 pod adresem: 0100101101101100, dziesiętnie ‭‭19308‬
Bajt 100 pod adresem: 0100110001101100, dziesiętnie ‭‭19564‬
Bajt 101 pod adresem: 0100110101101100, dziesiętnie ‭‭19820‬‬
Bajt 110 pod adresem: 0100111001101100, dziesiętnie ‭‭20076‬
Bajt 111 pod adresem: 0100111101101100, dziesiętnie ‭‭20332‬‬

Zauważ, że kolejne bajty znaku znajdują się w odległości co 256 bajtów. Ułatwia to zapełnianie pozycji znakowej. Poniższy program zapełnia kolejno bajty poszczególnych pozycji znakowych ekranu:

  10 LET X = 1
  20 FOR B=0 TO 2
  30 FOR W=0 TO 7
  40 FOR K= 0 TO 31
  50 FOR L= 0 TO 7
  60 LET A=16384+2048*B+256*L+32*W+K
  70 POKE A,X
  80 LET X=X+X
  90 IF X=256 THEN LET X=1
100 NEXT L
110 NEXT K
120 NEXT W
130 NEXT B
140 IF INKEY$="" THEN GO TO 140
150 IF INKEY$<>"" THEN GO TO 150

Pozostaje jeszcze sprawa przeliczenia pozycji znakowej na ekranie podanej jako wiersze i kolumny na adres pierwszego bajtu znaku w obszarze ekranu. Tutaj akurat sprawa jest prosta. Bierzemy numer wiersza jako wartość binarną 5-bitową. Dwa najstarsze bity tworzą numer banku BB. Pozostałe 3 bity określają numer wiersza WWW w obrębie banku. Pozycję kolumnową KKKKK nie zmieniamy. Całość łączymy w adres wg podanego schematu i otrzymujemy dostęp do pierwszego bajtu danej pozycji. Kolejne bajty znajdują się co 256 bajtów począwszy od tego adresu. Kolejny losuje wiersz i kolumnę, po czym zapełnia pozycję znakową losowymi wartościami. Przerwanie programu następuje po naciśnięciu dowolnego klawisza alfanumerycznego.

  10 RANDOMIZE
  20 LET K=INT (32*RND)
  30 LET W=INT (24*RND)
  40 LET B = INT (W/8)
  50 LET W=W-8*B
  60 FOR L=0 TO 7
  70 POKE 16384+2048*B+256*L+32*W+K,INT (256*RND)
  80 NEXT L
  90 IF INKEY$="" THEN GO TO 20
100 IF INKEY$<>"" THEN GO TO 100

Szybkość pracy programów w języku BASIC nie jest porażająca. Dopiero w kodzie maszynowym uzyskujemy prawdziwe korzyści z tej wiedzy. Natomiast w BASICU zwykle korzysta się z funkcji udostępnianych przez system w ROM (PRINT, PLOT).

Za obszarem pikseli znajduje się obszar atrybutów od adresu 22528 do 23295. Każdy atrybut jest bajtem i odnosi się do pozycji znakowej na ekranie pikselowym, czyli do pola 8 x 8 pikseli. Atrybut określa w tym polu kolor pikseli 0 (tło – PAPER) oraz pikseli 1 (tusz – INK). Dodatkowo w atrybucie jest informacja o podwyższonej jasności tuszu oraz o mruganiu, czyli cyklicznej zamianie kolorów tła i tuszu.

Na atrybut należy spojrzeć w systemie dwójkowym. Składa się z 8 bitów o następujących znaczeniach:

Jak widzimy, trzy najmłodsze bity atrybutu określają kolor tuszu, czyli pikseli o wartości 1. Każdy z tych trzech bitów odpowiada za jedną barwę podstawową: b0  niebieska, b1  czerwona, b2  zielona, Jeśli bit ma wartość zero, to barwa jest zgaszona (nie występuje w kolorze). Jeśli bit ma wartość 1, jego barwa pojawia się jako składnik w kolorze wynikowym. Barwy podstawowe mogą być mieszane, co daje nam dodatkowe kolory na ekranie (telewizja kolorowa opiera swoje działanie na mieszaniu trzech kolorów podstawowych, czerwonego R, zielonego G i niebieskiego B, stąd często pojawia się termin RGB, czyli Red, Green, Blue).  W poniższej tabelce przedstawiamy możliwe kolory do uzyskania w ZX Spectrum:

 

Nr G R B Kolor wynikowy
0 0 0 0  
1 0 0 1  
2 0 1 0  
3 0 1 1  
4 1 0 0  
5 1 0 1  
6 1 1 0  
7 1 1 1  

Identyczne znaczenie mają następne trzy bity atrybutu, lecz definiują one kolor tła, czyli pikseli o wartości 0.

Kolejny bit, b6 powoduje rozjaśnienie wszystkich barw podstawowych, dzięki czemu piksele w obrębie pola znakowego na ekranie skojarzonego z danym atrybutem stają się jaśniejsze (nie dotyczy to koloru czarnego, który dalej pozostaje czarny).

10 PRINT BRIGHT 0; PAPER 2; INK 6;" Witaj "
20 PRINT BRIGHT 1; PAPER 2; INK 6;" Witaj "

Dzięki bitowi intensywności liczba kolorów ZX Spectrum osiąga 15, lecz nie są to kolory niezależne. Jeśli zastosujemy w atrybucie rozjaśnienie, to zostaną rozjaśnione kolory tła i tuszu, zatem nie można mieć np. jaśniejszych znaków na tle o normalnej intensywności (chyba że jest to tło czarne). Oszczędności dają znać na każdym kroku.

Najstarszy bit, b7, kontroluje mruganie znaku. Polega ono na cyklicznej zamianie ze sobą kolorów tła i tuszu. Opcja przydatna, jeśli chcemy przykuć uwagę użytkownika:

10 PRINT FLASH 1; PAPER 2; INK 6;" UWAGA!!! "
20 PRINT " Zaraz zaczynamy "

Ostatnim elementem koloru ekranu jest jego brzeg. Kolor brzegu ustawia się poprzez zapis do portu 254 (w języku BASIC mamy rozkaz BORDER).

10 FOR i=0 TO 7: OUT 254,i: NEXT i
20 IF INKEY$="" THEN GO TO 10
30 IF INKEY$<>"" THEN GO TO 30

W kodzie maszynowym da się wycisnąć z brzegu więcej – pamiętam, że istniała pewna gra, w której brzeg był przedłużeniem kolorów na ekranie głównym. Takie efekty są możliwe przy wykorzystaniu przerwań mikroprocesora.

Ograniczeniem ZX Spectrum jest to, że kolory odnoszą się do pozycji znakowych (matryca 8 x 8 pikseli) ekranu, a nie do pojedynczych pikseli. Powoduje to niechciane efekty w grafice pikselowej:

10 BORDER 0: PAPER 0: CLS
20 INK 2: PLOT 0,0: DRAW 100,100
30 INK 4: PLOT 100,0: DRAW -100,100
40 IF INKEY$="" THEN GO TO 40
50 IF INKEY$<> "" THEN GO TO 50
60 BORDER 7: PAPER 7: INK 0: CLS

Linia czerwona zmieniła kolor w okolicach linii zielonej, która była narysowana później w wierszu 40, ponieważ jej piksele znalazły się na tej samej pozycji znakowej, co piksele linii zielonej, a kolor tuszu tej pozycji został zmieniony na zielony. Pomimo tych ograniczeń mistrzowie programowania potrafili wycisnąć z ZX Spectrum niesamowite na owe czasy efekty graficzne. Przykładem jest gra Light Force z 1986 roku, gdzie bardzo starannie dopasowano atrybuty do grafiki pikselowej:

Atrybuty są rozmieszczone liniowo za obszarem graficznym. Każdy wiersz znakowy posiada 32 atrybuty dla poszczególnych znaków. Poniższy program wypełnia obszar atrybutów przypadkowymi wartościami.

10 FOR a=22528 TO 23295: POKE a, INT(RND*256): NEXT a
20 IF INKEY$= "" THEN GO TO 10
30 IF INKEY$<> "" THEN GO TO 30
 

 

Pliki

ZX Spectrum był systemem taśmowym. Dane zapisywano na taśmie magnetofonowej, ponieważ w latach 80-tych stacje dyskietek były horrendalnie drogie. Oczywiście, później powstały konstrukcje ZX Spectrum współpracujące ze stacjami dysków elastycznych, chociażby model ZX Spectrum +3, który jednak nigdy nie stał się takim standardem jak zwykłe ZX Spectrum.

Zapis i odczyt danych na taśmie magnetofonowej był tanim rozwiązaniem. W latach 80-tych każdy użytkownik komputera posiadał w domu jakiś magnetofon, a komputer dosyć dobrze go wspierał. Do współpracy z magnetofonem ZX Spectrum posiadał z tyłu obudowy dwa gniazda AUDIO (MIC: mikrofonowe i EAR: słuchawkowe):

Za pomocą tych gniazd i kabla dostarczanego wraz z komputerem użytkownik podłączał magnetofon kasetowy. Dobrze, jeśli taki magnetofon był wyposażony w licznik taśmy. Umożliwiało to później przewinięcie taśmy do miejsca, w którym były zapisane dane. Ja zapisywałem swoje programy na kilku taśmach, ponieważ nośnik ten łatwo było uszkodzić, a wtedy żegnajcie godziny pracy z komputerem. Dzisiaj wydaje się niewiarygodne, że tak pracowano na komputerach, lecz w tatach 80-tych nie było specjalnie innej alternatywy, a przynajmniej nie za małe pieniądze. W każdym razie zabawa była przednia.

Zapis danych odbywał się w formie plików. Przez plik rozumiemy tutaj spójny ciąg danych. ZX Spectrum posiadał dosyć rozbudowane rozkazy do zapisu danych na taśmie magnetofonowej. Pełny ich opis znajdziesz tutaj. Rozkazy zapisu (SAVE) języka Basic tworzyły dwa bloki dla każdego pliku. Pierwszy 19-to bajtowy blok nagłówka oraz drugi blok danych o zmiennej długości. Każdy blok posiadał następującą budowę:

Rozbiegówka   8063 impulsy dla bloku nagłówka lub 3223 impulsy dla bloku danych, każdy impuls o długości 2168 taktów zegara dla 1 i 0.
Synchronizacja 1   impuls 0 o długości 667 taktów
Synchronizacja 2   impuls 1 o długości 735 taktów.
Dane   Bit 0 kodowany dwoma impulsami o długości 855 taktów, bit 1 kodowany dwoma impulsami o długości 1710 taktów. Bajty zapisywane w kolejności od najniższych adresów.

Rozbiegówka miała na celu zasygnalizowanie początku bloku. Przy zapisie rozbiegówki na obramowaniu ekranu były widoczne przesuwające się jasnoniebieskie i czerwone pasy:

Dodatkowo z głośniczka wydobywał się charakterystyczny pisk. Po rozbiegówce komputer generował impulsy synchronizacyjne i zapisywał blok danych. Dla pliku były to dwa bloki: nagłówek i właściwe dane. Nagłówek miał na celu identyfikację pliku i był zbudowany zawsze z 19 bajtów:

Bajt Długość Opis
0 1 Znacznik nagłówka, bajt o wartości 0
1 1 Typ danych (0,1,2,3)
2 10 Nazwa pliku (uzupełniona spacjami do 10 znaków)
12 2 Długość bloku danych
14 2 Parametr 1
16 2 Parametr 2
18 1 Suma kontrolna nagłówka

Na początku znajduje się jeden bajt o wartości 0, który służy do identyfikacji bloku jako 19-bajtowego nagłówka. Kolejny bajt określa rodzaj bloku danych, który następuje za nagłówkiem. ZX Spectrum rozróżnia 4 bloki danych:

0 – program, w polu Parametr 1 był umieszczony numer wiersza startowego lub wartość ponad 32767, jeśli taki wiersz nie był zdefiniowany, Parametr 2 zawierał położenie obszaru zmiennych względem początku programu.

1 – tablica liczbowa, bajt na pozycji 15 określa nazwę tablicy

2 – tablica znakowa, bajt na pozycji 15 określa nazwę tablicy

3 – blok pamięci, Parametr 1 przechowuje adres początku bloku, Parametr 2 zawiera 32768. Zapis ekranu (polecenie SAVE nazwa SCREEN$) był traktowany jako zapis bloku o adresie 16384 i długości 6912 bajtów.

Kolejne 10 bajtów zawiera nazwę pliku. Jeśli nazwa jest krótsza od 10 znaków, to zostaje uzupełniona spacjami.

Na końcu bloku nagłówka występują dwa parametry po 2 bajty, których znaczenie zależy od typu zapisanych danych.

Ostatni bajt zawiera sumę kontrolną. Powstaje ona przez wykonanie operacji XOR pomiędzy poszczególnymi bajtami wchodzącymi w skład nagłówka. Na jej podstawie komputer stwierdzał, czy odczytano poprawne dane.

Zapisowi danych towarzyszył również charakterystyczny dźwięk. Dodatkowo na obramowaniu ekranu pojawiały się szybko zmienne pasy żółte i niebieskie.

Blok danych zapisywany po nagłówku posiadał następującą strukturę:

Bajt Długość Opis
0 1 Znacznik bloku danych, bajt o wartości FF
1 n Dane, n-bajtów
n+1 1 Suma kontrolna nagłówka

Pierwszy bajt o wartości FF (dziesiętnie 255) był znacznikiem bloku danych i nie wchodził w ich skład. Służył do identyfikacji bloku jako dane. Było to dosyć istotne, ponieważ w trakcie wczytywania komputer odczytywał początki kolejno napotykanych bloków i sprawdzał ich nazwy i typ z nazwą i typem podanymi w poleceniu LOAD. Jeśli wystąpiła zgodność, następował proces odczytu. Dzięki znacznikom komputer odróżniał szybko blok nagłówka od bloku danych (bloki danych były ignorowane).

Po bajcie znacznika następowało n bajtów danych. Liczba bajtów, czyli długość bloku, była określana w nagłówku (bajty 12 i 13).

Na końcu bloku znajdował się bajt sumy kontrolnej, która powstawała identycznie jak dla bloku nagłówka – przez wykonywanie operacji XOR na kolejnych bajtach bloku.

 



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



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

©2017 mgr Jerzy Wałaszek

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