Big-endian i little-endian to terminy, które mogą wydawać się skomplikowane na pierwszy rzut oka, ale ich zrozumienie jest kluczowe, gdy zajmujemy się konwersją danych w różnych systemach komputerowych. Chodzi tutaj o sposób przechowywania danych binarnych w pamięci komputerów, a dokładniej o kolejność bajtów w reprezentacji liczb.
Większość z nas przyzwyczaiła się do zapisu liczb w systemie dziesiętnym. W kulturach, które używają arabskiego systemu numeracyjnego, liczby zapisujemy od lewej do prawej, zaczynając od największej jednostki. Na przykład, liczba 450 to połączenie trzech cyfr: 4 (setki), 5 (dziesiątki) i 0 (jedności). Liczba 450 to więc 4 setki, 5 dziesiątek i 0 jedności, co wpisuje się w nasze naturalne rozumienie porządku. Jednak komputer nie używa systemu dziesiętnego do reprezentacji liczb; zamiast tego liczby są zapisane w postaci binarnej, a sposób ich przechowywania może się różnić w zależności od systemu.
W systemie komputerowym, gdy liczba wymaga więcej niż jednego bajtu, pojawia się problem kolejności tych bajtów. W kontekście big-endian i little-endian chodzi o to, czy większa część liczby (najwyższy bajt) ma być zapisana na początku, czy na końcu.
Przykład na liczbie 450 w systemie binarnym: w systemie big-endian pierwsza bajt (reprezentujący wartość 256) będzie zapisana jako 00000001, a drugi bajt (reprezentujący wartość 194) jako 11000010. Łącznie daje to zapis 0000000111000010. Z kolei w systemie little-endian bajt o wartości 194 zapisany zostanie jako pierwszy, a bajt o wartości 256 jako drugi, co daje zapis 1100001000000001.
Choć w teorii moglibyśmy przyjąć system big-endian jako naturalny, współczesne komputery zazwyczaj używają systemu little-endian, jak np. procesory x86-64 (Intel, AMD) lub ARM64 (Apple, Qualcomm). Jednak mimo tego dominującego trendu, istnieją systemy, które korzystają z big-endian, takie jak starsze komputery Macintosh, które stosowały ten porządek bajtów na architekturze mikroprocesora 68K.
Sytuacja jest bardziej skomplikowana, ponieważ dane przesyłane przez internet, niezależnie od tego, czy urządzenie odbiorcze korzysta z little-endian, są zazwyczaj przesyłane w porządku big-endian. To powoduje konieczność konwersji bajtów w tle, co zachodzi w momencie, gdy dane trafiają z internetu do urządzenia.
Aby lepiej zrozumieć tę problematykę, warto przyjrzeć się przykładom, jak ta konwersja jest używana w praktyce, szczególnie w kontekście pracy z danymi graficznymi w starych systemach operacyjnych, jak w przypadku programu MacPaint.
W przypadku zapisu plików w starym formacie MacBinary, który jest używany przez starsze systemy Macintosh, należy przejść przez kilka etapów przetwarzania danych, aby prawidłowo zapisać je w odpowiednim formacie. Na przykład, konwersja danych obrazu z funkcji dither() wymaga kilku kroków, takich jak przygotowanie danych (przekształcenie bajtów na bity), kodowanie długości uruchomienia (run-length encoding) oraz dodanie nagłówków wymaganych przez specyfikację MacBinary.
Dodatkowo, ważnym aspektem jest dodanie odpowiedniego nagłówka MacPaint, który, mimo że w większości przypadków jest wypełniony zerami, wymaga umieszczenia specjalnego identyfikatora w trzecim bajcie. Dzięki tym wszystkim krokom można stworzyć plik, który będzie poprawnie odczytywany przez starsze systemy Macintosh.
Często, aby obejrzeć takie pliki graficzne, niezbędne jest posiadanie odpowiedniego oprogramowania do dekompresji plików MacBinary, takich jak program MacBinary lub popularny w tamtych czasach Stuffit Expander. Obecnie, dla tych, którzy chcą uzyskać wrażenia z retro komputerów, dostępne są emulatory klasycznych komputerów Macintosh, które pozwalają na uruchomienie starych systemów operacyjnych i programów, takich jak MacPaint.
Emulatory, takie jak Mini vMac, umożliwiają odtworzenie prawdziwego doświadczenia komputerów Macintosh z lat 80-90. Dzięki tym narzędziom możliwe jest odczytanie plików, które zostały zapisane w dawnych formatach, bez potrzeby posiadania fizycznego starego komputera. Choć dla wielu osób zdobycie autentycznego retro komputera może być trudne, emulacja daje szansę na doświadczenie klasycznej technologii w prostszy sposób.
Warto również pamiętać, że choć praca z retroformatami i emulacją starych komputerów to świetna zabawa i podróż w czasie, nowoczesne systemy komputerowe, w tym standardy przechowywania danych, znacząco różnią się od tych stosowanych w przeszłości. Dziś mamy do czynienia z zupełnie innymi metodami przechowywania i przetwarzania danych, jednak zrozumienie podstawowych zasad, takich jak big-endian i little-endian, może pomóc w pracy z różnymi systemami i technologiami, zwłaszcza gdy trzeba dokonać konwersji danych między różnymi środowiskami komputerowymi.
Jak działa emulator NES: od podstaw do zaawansowanego programowania
Stworzenie emulatora NES w czystym Pythonie jest zadaniem wymagającym i ambitnym. Zwykle celem takich projektów nie jest osiągnięcie pełnej kompatybilności z grami, a raczej zrozumienie działania konsoli, jej sprzętu i oprogramowania. W tym przypadku stworzymy emulator NES, którego wydajność na współczesnym komputerze nie pozwala na pełne odwzorowanie tej konsoli w czasie rzeczywistym. Możliwe jest jednak ulepszenie emulatora za pomocą Cython, rozszerzeń C lub innych technik, które umożliwią osiągnięcie pełnej prędkości działania. Wszelkie optymalizacje pozostawiamy jako ćwiczenie dla czytelnika.
Emulator NES jest jednym z bardziej wymagających projektów w tej książce. Zakłada się, że przed rozpoczęciem tej części masz doświadczenie z projektami przedstawionymi w rozdziałach 1, 2 i szczególnie 5, gdzie omawiano tworzenie emulatora CHIP-8. Zrozumienie tych projektów jest kluczowe, ponieważ w tym rozdziale znajdziesz podobne koncepcje. Praca nad tym projektem wymaga solidnego fundamentu w programowaniu i znajomości działania mikroprocesorów oraz systemów komputerowych.
Zanim zdecydujesz się na implementację emulatora, pamiętaj, że w wielu krajach ROM-y gier komercyjnych są chronione prawami autorskimi. Podobnie jak w przypadku wszelkich projektów związanych z emulacją, przed rozpoczęciem pracy warto zapoznać się z przepisami prawa w swoim kraju, by uniknąć nieprzyjemnych konsekwencji prawnych. Ważne jest również, abyś nie pobierał chronionych ROM-ów z nielegalnych źródeł, ponieważ w repozytorium źródłowym książki dostępne są gry, które zostały udostępnione na licencjach open-source lub znajdują się w domenie publicznej.
Podstawy sprzętowe NES
NES (Nintendo Entertainment System) to jedna z najlepiej sprzedających się konsol w historii, która zrewolucjonizowała rynek gier wideo. Wydana po raz pierwszy w Japonii w 1983 roku jako Famicom, a następnie na rynku międzynarodowym w 1985 roku, NES zdołał zdobyć serca graczy na całym świecie, pomimo że w momencie premiery przemysł gier wideo istniał zaledwie dekadę. Konsola była wyposażona w mikroprocesor, który na tle współczesnych rozwiązań może wydawać się dość prymitywny – był to klon mikroprocesora MOS 6502, produkowany przez firmę Ricoh, działający z prędkością zaledwie 2 MHz.
Mimo swojej prostoty, mikroprocesor 6502 stanowił serce NES i pozwalał na realizację zaskakująco zaawansowanych funkcji. Pomimo braku takich instrukcji jak mnożenie czy dzielenie, które musiały być implementowane w oparciu o bardziej podstawowe operacje, NES osiągał wydajność, której współczesne komputery o podobnej specyfikacji sprzętowej mogłyby pozazdrościć.
PPU: Procesor graficzny NES
Jednym z kluczowych elementów NES był Picture Processing Unit (PPU), który miał zdolność wyświetlania grafiki opartej na kafelkach oraz zarządzania sprite'ami. PPU miał 2 KB pamięci, które przechowywały informacje o tle, 256 bajtów pamięci do zarządzania sprite'ami, oraz 28 bajtów na dane palety kolorów. Dzięki temu NES był w stanie wyświetlać różnorodne i barwne grafiki, które stały się jednym z wyróżników tej konsoli.
Pomimo że NES obsługiwał zaledwie 54 kolory, z czego jednocześnie na ekranie mogło znajdować się tylko 25, jego zdolności graficzne były wystarczające do wyświetlania przyciągających wzrok, chociaż prostych, scen gier wideo. Zbudowane na tej platformie gry, takie jak Super Mario Bros, The Legend of Zelda czy Metroid, do dziś pozostają klasykami gier wideo.
System pamięci i rejestry
NES był wyposażony w bardzo ograniczoną pamięć RAM – zaledwie 2 KB, co w dzisiejszych czasach wydaje się nie do pomyślenia. Mimo tego ograniczenia, cała logika działania gry była przechowywana w pamięci ROM znajdującej się na kartridżu. To oznacza, że większość gry była przechowywana poza systemem, a pamięć wbudowana w konsolę służyła głównie do przechowywania stanów i zmiennych potrzebnych do działania gry.
Komunikacja między różnymi elementami sprzętu NES odbywała się za pośrednictwem pamięci mapowanej do sprzętu. Rejestry pamięci umożliwiały m.in. odczyt stanu kontrolera, zarządzanie sprite’ami czy sprawdzanie kolizji. Przykładowo, aby sprawdzić, czy przycisk na kontrolerze został naciśnięty, program odczytywałby zawartość określonego rejestru pamięci (np. 0x4016). Dzięki temu każda operacja była bezpośrednio związana z odpowiednim adresem w pamięci, co czyniło całość bardzo wydajną, ale także trudną do zaimplementowania na poziomie emulatora.
Karty gier: ROM i dodatkowe elementy
Karty gier dla NES składały się głównie z dużych układów ROM, które zawierały dane o grze – grafikę i kod programu. Część kart zawierała także dodatkową pamięć RAM, czasem z baterią, umożliwiającą zapisywanie stanu gry. Dodatkowo, w późniejszych wersjach kart gier zaczęły pojawiać się bardziej zaawansowane układy, takie jak logiczne układy scalone wspierające tzw. bank switching, co pozwalało na zaadresowanie większej ilości pamięci niż standardowo przewidywał to procesor 6502.
Ważnym aspektem kart gier była również ich różnorodność. Początkowe kartridże mogły mieć od 24 KB do 40 KB pamięci ROM, a późniejsze wersje oferowały nawet 768 KB pamięci, co pozwalało na przechowywanie bardziej rozbudowanych gier. Pomimo tego, że pamięć ROM była podstawowym źródłem przechowywania danych, to właśnie jej pojemność i różne technologie wykorzystywane w kartach gier decydowały o ich wydajności i funkcjonalności.
Oprogramowanie
NES nie posiadał BIOS-u ani systemu operacyjnego. Wszystkie gry były zapisywane bezpośrednio na kartach gier, które kontrolowały procesor, PPU oraz APU bezpośrednio, bez żadnych warstw abstrakcji. Gry na NES były pisane w asemblerze 6502, co było standardem w tamtych czasach w przypadku aplikacji wymagających maksymalnej wydajności. Praca w asemblerze pozwalała na bezpośrednią kontrolę nad sprzętem, ale wymagała zaawansowanej wiedzy programistycznej.
Podsumowanie
Zrozumienie podstawowego działania NES, zarówno w kontekście sprzętu, jak i oprogramowania, jest niezbędne do tworzenia emulatora. Projektowanie emulatora konsoli takiej jak NES pozwala na głębsze zrozumienie, jak działa sprzęt komputerowy i jak programy mogą bezpośrednio wpływać na działanie procesora oraz innych komponentów. Implementacja emulatora NES to wyzwanie, które pozwala na eksperymentowanie i naukę poprzez praktykę.
Zajmowanie się tym tematem pozwala także na odkrycie, jak w przeszłości ograniczenia sprzętowe zmuszały programistów do kreatywności w rozwiązywaniu problemów. W dzisiejszych czasach technologia jest o wiele bardziej zaawansowana, ale sama koncepcja emulacji pozostaje aktualna i pozwala na zachowanie dziedzictwa starych gier.
Jak skutecznie stosować zasadę najmniejszych uprawnień w środowisku SQL i Azure
Jak uzyskać doskonałe oświetlenie w fotografii produktów?
Jakie są kluczowe właściwości kompozytów funkcjonalnych w nowoczesnych technologiach?
Jak działają i czym różnią się protokoły Foundation Fieldbus, Profibus i MPI w automatyce przemysłowej?

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский