Emulering ( engelsk emulering ) i datoranvändning är ett komplex av mjukvara, hårdvara eller en kombination av dem, utformad för att kopiera (eller emulera ) funktionerna hos ett datorsystem ( gäst ) till ett annat, annorlunda än det första, datorsystem ( värd ) i på ett sådant sätt att det emulerade beteendet matchade det ursprungliga systemet ( gäst ) så nära som möjligt. Målet är att återge beteendet så exakt som möjligt, till skillnad från olika former av datorsimulering som efterliknar beteendet hos någon abstrakt modell. Att simulera en orkan eller en kemisk reaktion är till exempel inte emulering.
Emulering avser förmågan hos ett datorprogram i en enhet att emulera ( simulera ) ett annat program eller annan enhet. Till exempel är många skrivare utformade för att efterlikna HP Laserjet- skrivare eftersom det finns en stor mängd programvara tillgänglig för dessa skrivare. Om en icke-HP-skrivare emulerar en HP-skrivare, kommer alla program som är utformade för HP-skrivare att kunna arbeta med en icke-HP-skrivare och producera identisk utdata.
Hårdvaruemulering representeras av emulatorer gjorda som en separat enhet. Till exempel DOS-kompatibla tilläggskort som Centris 610 och Performa 630, som installerades i vissa Macintosh för att tillåta körning av DOS-program från en PC . Ett annat exempel är FPGA -baserade hårdvaruemulatorer .
Teoretiskt, enligt Church-Turing-avhandlingen , kan vilken verksamhetsmiljö som helst efterliknas på en annan. Men i praktiken är detta ofta extremt svårt eftersom det exakta beteendet hos det emulerade systemet inte är dokumenterat och endast kan fastställas genom omvänd ingenjörskonst. Avhandlingen säger inte heller att om emuleringsprestandan är lägre än originalsystemets, så kommer den emulerade programvaran att köras betydligt långsammare än den borde på den ursprungliga hårdvaran, med möjlig förekomst av emuleringsstopp eller instabil prestanda.
Emulering är ett av sätten att elektroniskt arkivera åldrande datorsystem. I denna tolkning är målet med emulering att troget återge den ursprungliga digitala miljön, vilket kan vara svårt och tidskrävande att uppnå, men är värdefullt på grund av möjligheten att uppnå en nära relation med ett autentiskt digitalt objekt [1] .
Emulering adresserar hård- och mjukvarumiljön för den ursprungliga digitala enheten och återskapar den på en modern maskin [2] . Emulering tillåter användaren att komma åt alla typer av applikationsprogram eller operativsystem på en modern plattform, där programvaran körs som den skulle i den ursprungliga miljön [3] . Jeffrey Rothenberg, en av de tidiga förespråkarna för användningen av emulering för elektronisk arkivering, tror att "idealet skulle vara en enda utbyggbar långsiktig lösning som skulle kunna utvecklas en gång för alla och som skulle tillämpas enhetligt, automatiskt och synkront ( till exempel varje uppdateringscykel) till alla typer av dokument och media” [4] . Han noterar vidare att denna lösning inte bara bör gälla äldre system, utan också vara lätt att överföra till ännu okända framtida system [5] . I praktiken, om en ny version av en applikation släpps för att säkerställa kompatibilitet och migrering av alla dess komponenter, är det nödvändigt att skapa en emulator för denna applikation som ger tillgång till alla nämnda komponenter.
Eftersom mediekonst huvudsakligen skapas i digitalt format är emulering oerhört viktig för den som ett medel för elektronisk arkivering. Figurer som Cory Arcangel återvinner föråldrade teknologier och använder dem i sitt arbete, och inser vikten av en decentraliserad och informell process för att bevara den digitala kulturen.
Emulering används ofta inom mediekonsten som ett sätt att bevara digital information som senare kommer att reproduceras oförändrad, oavsett utrustning som är föremål för åldrande och föråldrad. Paradoxen är att emulering och emulatorer måste byggas för att köras på framtidens maskiner [11] .
Olika typer av emulering används i stor utsträckning vid utveckling och design av nya system. Emulering förenklar utvecklingen genom att göra det möjligt att identifiera, undersöka och korrigera konstruktionsbrister före fysisk implementering [12] . Emulering är särskilt användbar vid utveckling av system med flera kärnor, där parallella bearbetningskonflikter ofta är ganska svåra att identifiera och diagnostisera utan användning av virtuell kontrollerad hårdvara tillgänglig med emulering [13] . Dessutom låter emulering dig börja utveckla mjukvara innan den faktiska tillverkningen av hårdvaran [14] , och på så sätt kontrollera funktionerna som är inneboende i den.
De flesta befintliga emulatorer spelar bara . Således, om ett operativsystem lagrat i ROM eller annan programvara krävs, bör det erhållas ytterligare (dock kan det också emuleras). I framtiden kommer både operativsystemet och mjukvaran att tolkas av emulatorn på samma sätt som på den ursprungliga hårdvaran. Förutom tolken av emulerade binära maskinkoder måste även viss annan utrustning (till exempel in- och utgångsenheter) emuleras. Till exempel, om skrivning till ett specifikt minnesområde skulle visa något på skärmen, bör det beteendet också emuleras.
I gränsen bör emulatorn utgå från en modell skapad på grundval av parametrarna och funktionerna i den ursprungliga kretsdesignen, inklusive en virtuell strömförsörjning, men i praktiken skulle detta vara en exceptionell lösning. Som regel utgår emulatorer från en modell som bygger på den tillgängliga dokumentationen och enhetens logikdiagram. För emulering av vissa system är hög emuleringsnoggrannhet viktig, ner till klockhastigheten för enskilda element, odokumenterade funktioner, oförutsägbara analoga komponenter och fel. Detta är särskilt viktigt när du implementerar emulatorer av klassiska hemdatorer som Commodore 64 , program för vilka ofta används sofistikerade lågnivåprogrammeringstekniker utvecklade av spelets skapare och demoscenen .
Omvänt hade vissa andra enheter mycket begränsad direktåtkomst till hårdvaran. I sådana här fall kan ett enkelt kompatibilitetslager räcka. Systemförfrågningar för det emulerade programmet översätts till systemförfrågningar från värden, det vill säga FreeBSD , NetBSD och OpenBSD -system använder Linux-kompatibilitetslagret för att köra Linux - applikationer med sluten källkod. Till exempel var Nintendo 64 :s GPU helt programmerbar och de flesta spelutvecklare använde inbäddade fabriksprogram som var fristående och kommunicerade med spelet via en FIFO -buffert . Därför emulerar många emulatorer inte GPU alls, utan tolkar istället CPU-kommandon på samma sätt som originalprogrammet.
Utvecklare av program för inbyggda system och spelkonsoler bygger ofta sina produkter på mycket exakta emulatorer, kallade simulatorer , innan de körs på fysisk hårdvara. Detta görs för att kunna skapa och testa innan den slutliga hårdvaruversionen släpps, samt för att snabbt kunna felsöka programmet utan att slösa tid på att kopiera och introducera debuggerbiverkningar . I många fall är simulatorn byggd och tillhandahållen av hårdvarutillverkaren, vilket i teorin borde öka dess noggrannhet.
Math coprocessor emulering används för att köra program kompilerade med matematiska instruktioner på maskiner utan en coprocessor installerad, där den extra belastningen på CPU kan påverka prestandan negativt. Om samprocessorn inte är installerad och inte är inbyggd i CPU:n, när en matematisk instruktion körs, kommer ett avbrott (ingen samprocessor) att anropas, vilket startar matteemulatorsubrutinen. Efter att instruktionen har utförts, återgår kontrollen till programmet.
Som regel består emulatorn av flera moduler , som var och en motsvarar ett separat emulerat delsystem av den ursprungliga enheten. I det mest allmänna fallet består emulatorn av följande block:
Systembussar emuleras vanligtvis inte för att förenkla emulering och öka prestanda. Istället talar virtuell kringutrustning direkt till processorn eller minnesundersystemet.
Vid emulering är det fullt möjligt att mappa hela minnesundersystemet som en enkel array, vars varje element är lika stort som ett emulerat ord. Detta tillvägagångssätt är dock dömt att misslyckas eftersom i detta fall ingen logisk minnesadress kommer att matcha det fysiska minnet. Detta är mest uttalat när den ursprungliga hårdvaran har avancerad minneshantering (i vilket fall MMU- logiken måste implementeras i minnessubsystemmodulen , antingen som en separat modul eller som en del av den virtuella CPUn).
Men även om den emulerade enheten inte innehåller en MMU, finns det andra faktorer som bryter motsvarigheten av logiskt och fysiskt minne: många (om inte alla) arkitekturer har RAM -mappade I/O-portar; även de som inte har dem har ROM -mappade minnesblock . Detta betyder att arrayrepresentationen av minnet inte ska användas om ROM ska emuleras. Funktioner som bankväxling eller segmentadressering kan också göra minnesemulering svårare.
Som ett resultat har de flesta emulatorer minst två rutiner, en för att läsa från minnet och en för att skriva till minnet, som är ansvariga för att komma åt rätt område av rätt objekt.
För emulering av system med begränsad adressering, där minnesadresserna 0 till (ROM-storlek) - 1 är skrivskyddade, och alla andra tillhör RAM, är något i stil med följande ganska typiskt.
void WriteMemory ( ordadress , ordvärde ) { _ _ wordRealAddress ; _ RealAddress = Adress + BasRegister ; if (( RealAddress < LimitRegister ) && ( RealAddress > ROMSIZE )) { Memory [ RealAddress ] = Värde ; } annat { RaiseInterrupt ( INT_SEGFAULT ); } } word ReadMemory ( ordadress ) { _ wordRealAddress ; _ RealAddress = Adress + BasRegister ; if ( RealAddress < LimitRegister ) { return Memory [ RealAddress ]; } annat { RaiseInterrupt ( INT_SEGFAULT ); returnera NULL ; } }Som regel är CPU-modulen den mest komplexa delen av emulatorn. Många emulatorer använder förbyggda CPU-moduler för att fokusera på kvalitet och effektiv emulering.
En tolk är den enklaste formen av CPU-emulering. Det är ett program som följer flödet av programexekvering och, för varje maskininstruktion det stöter på, utför operationer semantiskt likvärdiga med de ursprungliga instruktionerna på värdprocessorn. Detta är möjligt genom att tilldela variabler till varje register och flagga för den emulerade CPU:n. Logiken för den emulerade CPU:n kan implementeras med större eller mindre komplexitet i en programalgoritm, vilket skapar en mjukvaruimplementering som mer eller mindre speglar den ursprungliga hårdvaran.
Följande exempel visar hur CPU kan emuleras med hjälp av tolken. I det här exemplet efterfrågas avbrott innan instruktionen exekveras, men på grund av låg prestanda används denna metod sällan i befintliga emulatorer (i allmänhet är det snabbare att använda en subrutin som fungerar som ett avbrott).
void Execute ( void ) { if ( Avbryt != INT_NONE ) { SuperUser = TRUE ; WriteMemory ( ++ StackPointer , ProgramCounter ); ProgramCounter = Avbrottspekare ; } switch ( ReadMemory ( ProgramCounter ++ )) { /* * Hantering av varje giltig instruktion * går här... */ standard : Interrupt = INT_ILLEGAL ; } }Tolkar är mycket populära för att simulera datorer, eftersom deras implementering är mycket enklare än andra prestandavinnande lösningar, eftersom deras hastighet ofta är tillräcklig för att efterlikna datorer som bokstavligen är tio år äldre än moderna maskiner.
Men att tillämpa tolkningen, med dess inneboende prestandastraff, kan vara ett problem när du vill emulera en dator med en processor som är en storleksordning snabbare än värdprocessorn. Fram till nyligen ansågs emulering i sådana fall av många vara värdelös.
Framsteg inom dynamiska kompileringstekniker har hjälpt till att övervinna dessa begränsningar. Att helt enkelt översätta emulerad programkod till exekverbar kod på värdarkitekturen är a priori omöjligt av flera skäl:
För att komma runt dessa problem används en mängd olika knep, inklusive den välkända " kompileringen i farten ". Kompilatorn väntar tills processorstyrflödet går in i en region som innehåller oöversatt kod. Först då ("on the fly") översätts kodblocket till kod som kan exekveras. Den bearbetade koden placeras i kodcachen medan originalkoden inte ändras. I det här fallet kommer även datablock att utsättas för meningslös översättning av kompilatorn, vars enda effekt kommer att vara att kompilatorns tid ökar.
I vissa fall, som när man kör gamla spel, kanske hög emuleringshastighet inte är önskvärd, eftersom spel skapades utan hänsyn till framtida datorers prestanda. I ett spel designat för en PC med en 30 MHz CPU kan spelaren ges 300 spelsekunder per spelnivå, om samma spel körs på en PC med en 300 MHz CPU kommer spelaren att ha 300 spelsekunder lika med 30 riktiga sekunder. Andra program, som vissa DOS-program, kommer inte att köras alls på en snabb dator. I praktiken, om ett system emuleras som var en "svart låda" utan förväntade förändringar i kärnan, kan programmen bero på vissa specifika hårdvaruparametrar (till exempel CPU-frekvens). För att korrekt emulera sådana applikationer krävs därför mycket exakt kontroll av emuleringshastigheten.
Som redan nämnts emuleras systembussar sällan. Varje I/O-enhet betraktas separat, eftersom emulatorn inte implementerar något universellt gränssnitt. Eftersom varje I/O-enhet kan anpassas perfekt till parametrarna för den emulerade enheten, resulterar detta i en prestandavinst. Lösningar baserade på standardiserade, enhetliga API :er kan dock fortfarande konkurrera med förenklade modeller om de är smart implementerade. En ytterligare fördel kommer att vara en "automatiskt" erhållen plugin-tjänst, genom vilken virtuella tredjepartsenheter kan arbeta med emulatorn. I enhetliga I/O API:er är det inte nödvändigt att upprepa hela bussens struktur: dess kretsar är begränsade till ett fåtal elektroniska komponenter, så i mjukvaruimplementering är det inte nödvändigt att ha ett system för att lösa konflikter med parallell beräkning.
Även i emulatorer som betraktar varje enhet separat, finns vanligtvis följande virtuella infrastruktur:
Ordet "emulator" myntades av IBM [15] när man utvecklade NPL-serien ( IBM System/360 ) med hjälp av "en ny kombination av mjukvara, mikrokod och hårdvara" [16] . De fann att för att köra program skrivna för äldre IBM-maskiner var användningen av hårdvara Microcode mycket mer produktiv än mjukvarusimulering. Tidigare, 1957, levererade IBM en mjukvarutolk för att kunna köra program för den äldre IBM 704 -datorn på IBM 709 och IBM 7090-datorerna [17] . 1964 myntade IBM-ingenjörer ordet "emulering" för att beskriva konceptet med den första användningen av mikrokod för att påskynda simuleringsprocessen.
Nyligen har användningen av denna term blivit vanlig i mjukvarusammanhang. Fram till 1980-talet hänvisade ordet "emulering" uteslutande till hårdvaruimplementering med mikrokod, medan mjukvaruemulering kallades "simulering" [18] . Till exempel var en dator speciellt utformad för att köra program skrivna för en annan arkitektur en emulator. Å andra sidan kan en simulator vara ett PC-program som kan simulera gamla Atari-spel. Även om purister fortsätter att påpeka denna terminologiska skillnad, är det nu allmänt accepterat att hänvisa till emulering som en komplett simulering av en maskin som kör binär kod, medan simulering i princip hänvisar till en datorsimulering som fungerar på en abstrakt modell. Datormodellering används i nästan varje vetenskaplig och ingenjörsverksamhet, inklusive datavetenskap, som har många applikationer för att arbeta med en abstrakt modell, såsom modellering av kommunikationsnätverk.
Logisk simulering är användningen av specifik programvara för att förutsäga beteendet hos digitala kretsar och hårdvarubeskrivningsspråk . Simulering kan göras på olika nivåer av fysisk abstraktion: transistornivå , logisk grindnivå , registeröverföringsnivå eller funktionsnivå. Modellering utförs efter utvecklingen av schemat i form av logiska ekvationer och före starten av dess fysiska produktion.
Funktionell modellering är användningen av ett datorprogram för att simulera exekveringen av ett annat datorprogram skrivet i assemblerspråk eller källkod , snarare än i binär maskinkod . Med hjälp av funktionell modellering kan en programmerare släppa och analysera arbetet i en utvald kodsektion för att upptäcka fel (buggar) utan att behöva ta till en binär kod. Detta skiljer sig från att köra binär kod, som är emulering.
Den första användningen av funktionell modellering gjordes av Autonetics runt 1960 för att testa assemblerspråksprogram som senare skulle köras på militärfordonet D-17B. Detta gjorde det möjligt för flygprogramvara att skrivas, exekveras och testas innan fysisk tillverkning av D-17B:s datorhårdvara. Samma företag använde senare funktionssimulering för att testa flygprogramvara som skulle köras på D-37C.
En spelkonsolemulator är ett program som låter en persondator eller spelkonsol emulera en annan konsol. Oftast används de för att köra gamla spel på PC eller mer moderna konsoler. Emulatorer används också för att skapa amatöröversättningar av spel, spelmodifieringar, samt för att utveckla användargenererat innehåll som demos och nya spel för äldre system. Internet spelade en stor roll i spridningen av denna typ av emulering , eftersom de flesta (om inte alla) emulatorer inte är tillgängliga i butiker. Några av emulatorerna som släppts under de senaste två decennierna är Dolphin , ZSNES , MAME , DeSmuME , ePSXe , Gens , VisualBoyAdvance , Jnes och Nestopia .
En terminalemulator är ett program för en modern PC eller annan enhet som tillåter interaktiv åtkomst till ett stordatoroperativsystem eller annat värdsystem, som HP-UX eller OpenVMS . Terminaler som IBM 3270 och VT100 har inte tillverkats på länge . Istället använder den ett program som körs på ett modernt operativsystem som efterliknar en "dum" terminal och kan visa grafiska och textliga element i värdapplikationen, skicka tangentbordsinmatning och bearbeta kommandon genom lämpligt terminalprotokoll. Några av dessa emulatorer inkluderar applikationer för Attachmate Reflection, IBM Personal Communications, EmuVM:s virtuella AlphaVM-maskin, Stromasys CHARON-VAX/AXP och Micro Focus Rumba.