Emulator
Emulator – program komputerowy (czasem wraz z koniecznym sprzętem), który uruchomiony w danym systemie komputerowym duplikuje funkcje innego systemu komputerowego. Pierwszy system nazywany jest gospodarzem (ang. host), a drugi gościem (ang. guest). Mówimy, że drugi system jest emulowany przez pierwszy.
Jedną z form emulatorów są programy, które umożliwiają uruchamianie aplikacji na komputerze lub systemie operacyjnym innym niż ten, na który zostały napisane np. uruchomienie emulatora Amigi w systemie operacyjnym Windows, czy emulatora konsoli do gier Nintendo w systemie Linux. Emulatory są tak programowane, aby jak najdokładniej potrafiły ‘udawać’ emulowaną maszynę z lepszym lub gorszym efektem (są np. trudności z poprawnym oddaniem palety barw, czy dźwięków oraz z obsługą urządzeń zewnętrznych takich jak np. pady, jednak wiele emulatorów posiada praktycznie 100% zgodność z oryginalną maszyną).
Programy te mogą też emulować poszczególne funkcje oprogramowania i sprzętu standardowo niedostępne w ramach danego systemu, np. karty dźwiękowe. Tworzone są też emulatory kalkulatorów Texas Instruments, BBS-ów i wielu innych systemów informatycznych.
Działanie emulatora
edytujZwykle emulator jest podzielony na moduły, które odpowiadają ogólnie podsystemom emulowanego komputera. Najczęściej emulator składa się z następujących modułów:
- emulator CPU lub symulator CPU (w tym wypadku zwykle można obu pojęć używać zamiennie)
- moduł pamięci
- emulatory urządzeń wejścia-wyjścia
W celu osiągnięcia lepszej wydajności i prostoty emulatora szyny nie są zwykle emulowane. Wirtualne urządzenia komunikują się bezpośrednio z procesorem i pamięcią.
Symulacja CPU
edytujSymulator CPU to najbardziej złożona część emulatora. Wiele emulatorów jest pisanych przy użyciu już gotowych symulatorów CPU po to, aby móc skoncentrować się na pełnej emulacji innych części konkretnego komputera.
W najprostszej formie symulator CPU to interpreter, który wykonuje po jednej instrukcje emulowanego programu.
Poniższy przykład pokazuje jak można symulować CPU poprzez interpreter. W tym przypadku przerwania są sprawdzane i obsługiwane przed każdą kolejną instrukcją, jednak takie zachowanie jest rzadkie w prawdziwych emulatorach z powodu małej wydajności.
void Wykonaj(void)
{
if(Przerwanie!=PRZERW_BRAK)
{
Superużytkownik=TRUE;
ZapiszPamięć(++WskaźnikStosu, LicznikRozkazów);
LicznikRozkazów=WskaźnikPrzerwania;
}
switch(OdczytajPamięć(LicznikRozkazów++))
{
/*
* Tutaj znajduje się obsługa wszystkich
* pojedynczych instrukcji procesora.
*/
default:
Przerwanie=PRZERW_BŁĄD;
}
}
Interpretacja to bardzo popularna metoda symulacji procesora, ponieważ jest o wiele prostsza w implementacji niż szybsze metody, a jej prędkość jest wystarczająca do emulacji komputerów około dziesięcioletnich na komputerach współczesnych.
Mimo to prędkość interpretacji jest niewystarczająca do emulacji procesorów, których prędkość jest tego samego rzędu wielkości co prędkość głównego komputera. Jeszcze do niedawna emulację w takich przypadkach uznawano za zupełnie niepraktyczną.
Większa prędkość emulacji jest możliwa dzięki dynamicznej rekompilacji. Proste tłumaczenie a priori kodu emulowanego programu na docelowy komputer jest zwykle niemożliwe z wielu powodów:
- kod może być samomodyfikujący się, nawet gdyby ta samomodyfikacja była dokonywana jedynie przez emulowany system operacyjny przy odczytywaniu kodu programów użytkownika (np. z dysku).
- może nie istnieć sposób na odróżnienie danych (które nie powinny być tłumaczone) od kodu wykonywalnego.
Różne formy dynamicznej rekompilacji, w tym popularna technika Just In Time próbują obejść te problemy poprzez dokonywanie tłumaczenia bloków kodu na nowy procesor dopiero przy napotkaniu przez wykonywany kod instrukcji skoku na nieprzetłumaczone miejsce i przechowywanie już przetłumaczonych części w cache.
Z drugiej strony prędkość emulacji może być zbyt duża, np. przy emulacji procesora 1 MHz na procesorze 1 GHz. Część emulowanych programów (zwłaszcza z konsoli do gier) nie jest przystosowanych do działania na różnych prędkościach procesora i emulator musi ograniczać prędkość wykonywania rozkazów do oryginalnej.