Hur fungerar en emulator?

En emulator är ett program som i princip återger beteendet hos hårdvaran i en gammal maskin (ex: grafikkort, CPU, moderkort, RAM). Människor som programmet emulatorer måste först få lite information om konsolen de vill efterlikna; till exempel: Vad är de operationer som utförs av CPU. Hur delas RAM?
Emulering är en mycket en komplicerad process ansökan (emulator) agerar som (efterlikna) en annan plattform/processor/dator/etc.

En vanligen emulerade plattform är den spelkonsol, inklusive system som Nintendo Game Boy, Nintendo Entertainment System, Sony Playstation, Sega Genesis, NeoGeo Pocket Color för att nämna några, även om, vad som helst kan emuleras, från datorer till miniräknare, till spelkonsoler. Även den dator som används i rymdfarkosten för Apollo rymduppdrag har varit emuleras.

Den grundläggande processen för emulering ser ut så här:

  1. Hämta den aktuella anvisningen från minne (RAM).
  2. Tolka det anvisningen. (Tolkningen tar en instruktion som är tänkt för att köra på en annan plattform och köra eller gör den motsvarande instruction(s) på maskinen som gör den efterlikna/kör emulator programmet.)
  3. Öka den emulerade PC (programräknaren, ett register som pekar på instruktionen för närvarande verkställande) lämplig mängd.
  4. (VALFRITT) Låt maskinen köra emulatorn programmet till sömn/vila eller avbryter exekveringen av emulatorn för en viss tid att reglera bildfrekvens (FPS; Inramar Per understöder) eller emulerad plattformens processorhastighet.
  5. (VALFRITT) Göra andra saker som måste göras. (Rita en emulerad skärmen, processen efterliknas ljud, etc.)
  6. Upprepa processen.

Förhoppningsvis det gör någon mening att den person som ställde denna fråga. Emulering är inte slags saker som kan förklaras i detalj till en icke-programmerare eller icke-techie.

Om du vill skriva en emulator själv, och känner att du vet tillräckligt för att komma igång, gör sedan följande:

  1. Få så mycket info på det system du vill emulera som möjligt! Detta är extremt viktigt, annars har du ingen aning vad jag ska göra i nästa steg.
  2. Plocka ett lämpligt programmeringsspråk att använda. Använder ett skriptspråk eller ett språk/verktyg som tolkas är nog inte den bästa idén om du vill emulera en snabb plattform.
  3. Räkna ut hur du ska emulera registrerar, RAM, etc. En av de enklaste sätten att efterlikna RAM är att skapa ett stort utbud för att sätta alla emulerade RAM innehållet i. Register kan göras på flera sätt, men min Pia GB emulator helt enkelt använder char variabler, eftersom en röding är 8 bitar (1 byte) i storlek, vilket är storleken på de flesta av GB: s register. (Den GB 16-bitars register emuleras använda shorts.)
  4. Börja kodning! Ta det lugnt ändå. Se till att du inte gör för många misstag. Förutsatt att du efterlikna någon form av "komplett" plattform (en plattform med allt behöver köra och fungera), emulering av CPU och RAM är vad du bör fokusera på första. (Kom ihåg! Fokusera på noggrannhet och rätt emulering först. Du kan påskynda saker senare, när din emulator faktiskt gör något!)
  5. Debug. Detta är vad som kommer att göra du vill skjuta dig själv. Emulatorer kommer att kräva massor av felsökning.
  6. Upprepa steg 4 och 5 många, många, många, många, många gånger.

När det gäller information, bör du ha flera resurser för att jämföra med och få information från. Jag använder Google och Wikipedia för att få min info. Du kan behöva söka efter info för ett tag att få vad du vill. (Jag tog ungefär två dagar att hitta och bokmärke tillräckligt med info som jag tror att jag behöver.)

Du vill förmodligen kod din emulator i C/C++ eller ASM. Jag vet vissa människor ens koden emulator i Java, men förvänta dig inte en emulator i Java för att köra så fort som en i C/C++ eller ASM.

Om du vill, du kan titta på en mycket grundläggande version av min kod för min Pia GameBoy emulator nedan (Använd så mycket du vill):

Detta sker i C++ med MinGW och Code::Blocks IDE
Definiera våra RAM, VRAM, register, etc:

int InterpretInstruction();

char gb_a, gb_f; Emulerade register A och F. Ibland ihop som en 16-bitars register
char gb_b, gb_c; Fler register. Ibland ihop som en 16-bitars register
char gb_d, gb_e; //...
char gb_h, gb_l; //...
korta gb_pc; Emulerade Program Counter register (16-bitars)
korta gb_sp; Emulerade buntpekaren register

char * gb_ram_main; Emulerade RAM
char * gb_ram_video; Emulerade Video-RAM
char * gb_cart_rom; Emulerade innehållet i ROM
char * gb_cart_ram; Emulerade RAM i några patroner

int main)
{
load_rom_data_bin();

gb_pc = 0x0100;
gb_pc_ = 0x0099;
gb_sp = 0x0000;
gb_ram_main = ny char [8192];
gb_ram_video = ny char [8192];

load_rom_into_ram();

medan (sant)
{
om (InterpretInstruction() == 0) //My tolkning funktionen returnerar 0 på OK
{
Ingenting. PC uppräkning hanteras i InterpretInstruction()
}
annat
{
Exit(1); Avbryta om det finns ett fel.
}
}

Return 0;
}

int InterpretInstruction()
{
/*
Det sägs att switch satser är ineffektivt för en fråga som denna, men det verkar bero. Enligt vissa källor, detta endast gäller för växlar med ett litet antal fall, som kommer att sammanställa till en kedja av if()... annat if()... uttalanden - medan med större antal villkor [100-200 +] en switch kommer att sammanställa i ett hoppa bord och således vara effektivare än att undvika switch-satser.
*/

Switch (gb_ram_main [gb_pc])
{
fall 0x00: //NOP instruktion
{
gb_pc ++;
Return 0; Allt gick OK
bryta;
}

fall 0xc3: //JMP instruktion hoppa till 16-bitars adressen som följer efter denna anvisning
{
gb_pc = Form_16_Bit_Address_Using_Two_Bytes_Ahead_Of_This_Instruction();
Return 0;
bryta;
}

standard: / / fel!
{
tillbaka 1.
bryta;
}
}
}