3 puan yazan GN⁺ 2024-12-28 | 1 yorum | WhatsApp'ta paylaş
  • Bilgisayarların iç işleyişini ve programlama dillerinin nasıl yürütüldüğünü anlamak için, LC-3 eğitim mimarisi üzerinde assembly programları çalıştıran yaklaşık 250 satırlık C tabanlı bir VM doğrudan uygulanıyor
  • Uygulama hedefi; 65.536 adet 16 bit bellek konumu, 10 register, 16 opcode, koşul bayrakları, trap routine’leri ve bellek eşlemeli register’ları olan küçük bir bilgisayar modeli
  • Yürütme döngüsü, PC’nin işaret ettiği komutu okuyup artırdıktan sonra opcode’u yorumlayarak ADD, LDI, BR, JMP, TRAP gibi komutları çalıştıran fetch-decode-execute yapısıyla işliyor
  • Program yükleme, nesne dosyasındaki ilk 16 bit origin’i okuyup belleğe yerleştiriyor ve LC-3’ün big-endian biçimini, çoğu modern bilgisayarda kullanılan little-endian biçimine uydurmak için byte swap uyguluyor
  • Klavye girişi ve konsol çıktısı trap routine’leri ile KBSR/KBDR bellek eşlemeli register’ları üzerinden işleniyor; Unix/macOS ve Windows için farklı terminal giriş tamponlama kodları gerekiyor

Eğitimin hedefi ve varsayımlar

  • LC-3 sanal makinesini doğrudan uygulayarak assembly dili programlarını çalıştırma sürecini takip eder
  • Nihai kod C için yaklaşık 250 satırdır; Unix için lc3.c ve Windows için lc3-win.c sağlanır
  • Gereken ön bilgi temel C veya C++ okuma becerisi ve ikili aritmetiktir
  • Tüm kod GitHub repo’da bulunur; eğitimin kendisi literate program biçimindedir, yani kod blokları birleştirilerek nihai kaynak oluşturulur

Sanal makine ne yapar?

  • VM, CPU ve bazı donanım bileşenleri gibi davranan bir programdır
    • Aritmetik işlemler gerçekleştirir
    • Belleği okur ve yazar
    • I/O aygıtlarıyla etkileşime girer
    • Kendi makine dilini anlayarak program çalıştırır
  • VM’in amacına bağlı olarak gerçek donanımı sadakatle yeniden üretebilir ya da yazılım geliştirme kolaylığı için yeni bir sanal mimari sunabilir
  • JVM, standart bir yürütme platformu sağlayan VM’lerin başlıca örneklerinden biridir; JVM’in uygulandığı cihazlarda Java, Kotlin ve Clojure programları değişiklik yapılmadan çalıştırılabilir
  • İzole yürütme de VM’lerin önemli bir kullanım alanıdır
    • Garbage collection’da VM, çalışan programın dışından stack’i ve bellek referanslarını gözlemleyebilir
    • Ethereum smart contract’ları dosya sistemine, ağa, diske vb. erişemeyen bir VM içinde çalıştırılır

LC-3 mimari bileşenleri

  • Uygulama hedefi, üniversitelerde bilgisayar mimarisi ve assembly eğitiminde kullanılan LC-3’tür
  • LC-3 belleği 65.536 konuma sahiptir ve her konum 16 bitlik bir değer saklar
    • Toplam depolama kapasitesi 128KB’dir
    • C uygulamasında uint16_t memory[MEMORY_MAX] dizisiyle temsil edilir
  • Toplam 10 register vardır
    • R0~R7: 8 genel amaçlı register
    • PC: bir sonraki çalıştırılacak komutun bellek adresi
    • COND: önceki hesaplama sonucunun koşul bayrağı
  • LC-3 komutlarının tamamı 16 bittir ve soldaki 4 bit opcode’dur
    • 16 opcode tanımlıdır
    • OP_BR, OP_ADD, OP_LD, OP_ST, OP_JSR, OP_AND, OP_LDR, OP_STR, OP_RTI, OP_NOT, OP_LDI, OP_STI, OP_JMP, OP_RES, OP_LEA, OP_TRAP bunlara dahildir
  • Koşul bayrakları, önceki hesaplama sonucunun işaretini gösterir
    • FL_POS: pozitif
    • FL_ZRO: 0
    • FL_NEG: negatif

Assembly ve makine dili

  • LC-3 VM’in gerçekte çalıştırdığı şey, insan tarafından okunan assembly değil, 16 bit makine dili komut dizisidir
  • Assembler, metin olarak yazılmış LC-3 assembly’sini 16 bit ikili komutlara dönüştürür
  • Hello World örneği şu akışa sahiptir
    • .ORIG x3000: programın yükleneceği bellek adresini belirtir
    • LEA R0, HELLO_STR: string adresini R0’a yükler
    • PUTS: R0’ın işaret ettiği string’i yazdırır
    • HALT: programı durdurur
    • .STRINGZ "Hello World!": string verisini programın içinde saklar
  • .ORIG, .STRINGZ CPU komutları değil, assembler yönergeleridir
  • Koşullar ve döngüler BRn LOOP gibi gotoya yakın dallanma komutlarıyla uygulanır

Yürütme döngüsünün temel adımları

  • VM yürütmesi aynı adımları tekrarlar
    • PC register adresinden komutu okur
    • PC’yi artırır
    • Komutun üst 4 bitinden opcode’u alır
    • Opcode’a karşılık gelen uygulama kodunu çalıştırır
    • Sonraki komutu yeniden okur
  • Varsayılan başlangıç adresi 0x3000’dir
  • Bazı komutlar yürütme akışını atlatmak için PC’yi doğrudan değiştirir
    • Dallanma ve jump komutları sayesinde, sadece PC’yi artıran bir yapıda bile döngüler ve koşullu yürütme mümkün olur
  • main döngüsü switch (op) ile opcode’a göre işleme kodunu çağırır
    • OP_ADD, OP_AND, OP_NOT, OP_BR, OP_JMP, OP_JSR, OP_LD, OP_LDI, OP_LDR, OP_LEA, OP_ST, OP_STI, OP_STR, OP_TRAP işlenir
    • OP_RES, OP_RTI kullanılmayan opcode’lardır ve abort() ile ele alınabilir

Komutların uygulanma biçimi

  • ADD iki değeri toplar, hedef register’a yazar ve koşul bayraklarını günceller
  • ADD için iki mod vardır
    • Register modu: ikinci operand başka bir register’dan okunur
    • Immediate modu: ikinci operand komutun alt 5 biti olan imm5’ten okunur
  • imm5 gibi 16 bitten kısa değerler, sign extension ile 16 bitlik değere genişletilmelidir
    • Pozitifler 0 ile doldurulur
    • Negatifler özgün değeri korumak için 1 ile doldurulur
  • Register’a değer yazan komutlar update_flags ile R_COND’u günceller
    • Değer 0 ise FL_ZRO
    • En yüksek bit 1 ise FL_NEG
    • Diğer durumlarda FL_POS
  • LDI, “load indirect” komutudur
    • Komutun PCoffset9 değerine sign extension uygulanır
    • Geçerli PC’ye eklenerek bellek adresi elde edilir
    • O konumda saklanan değer yeniden adres olarak kullanılarak nihai veri okunur
    • Okunan değer hedef register’a yazılır ve koşul bayrakları güncellenir

Başlıca komut kümesi

  • Aritmetik ve bit işlemleri
    • ADD: toplama
    • AND: bit düzeyinde AND
    • NOT: bit düzeyinde NOT
  • Kontrol akışı
    • BR: koşul bayraklarıyla komutun koşul bitlerini karşılaştırarak PC’yi taşır
    • JMP: belirtilen register değerini PC olarak ayarlar
    • RET: belirtimde ayrı bir anahtar sözcüktür, ancak JMP’in özel bir durumudur
    • JSR, JSRR: geçerli PC’yi R7’ye kaydeder ve subroutine konumuna atlar
  • Bellek okuma
    • LD: PC tabanlı offset adresinden okur
    • LDI: dolaylı adresi bir kez daha izleyerek okur
    • LDR: base register ve offset ile hesaplanan adresten okur
    • LEA: effective address’in kendisini register’a kaydeder
  • Bellek yazma
    • ST: PC tabanlı offset adresine yazar
    • STI: dolaylı adresi izleyerek yazar
    • STR: base register ve offset ile hesaplanan adrese yazar

Trap routine ve I/O

  • LC-3, ortak işler ve I/O aygıtlarına erişim için trap routine sağlar
  • Trap routine, LC-3’ün işletim sistemi veya API’si gibi düşünülebilir
  • Trap code’lar şöyle tanımlanır
    • TRAP_GETC = 0x20: klavyeden karakter girişi alır, terminale echo etmez
    • TRAP_OUT = 0x21: karakter çıktısı verir
    • TRAP_PUTS = 0x22: word string çıktısı verir
    • TRAP_IN = 0x23: karakter girişi alır ve terminale echo eder
    • TRAP_PUTSP = 0x24: byte string çıktısı verir
    • TRAP_HALT = 0x25: programı durdurur
  • Resmi LC-3 simülatöründe trap routine’ler assembly ile yazılmıştır; bu VM’de ise C fonksiyonları olarak uygulanır
  • PUTS, R0’da saklanan adresten başlayarak x0000 ile karşılaşana kadar karakterleri yazdırır
    • LC-3 string’leri C string’leri gibi 1 bayt biriminde değil, her bellek konumunda bir karakter saklar
    • Her bellek konumu 16 bit olduğundan C çıktısında char’a dönüştürülerek yazdırılır
  • HALT trap’i "HALT" çıktısını verir ve yürütme bayrağını 0 yaparak VM döngüsünü sonlandırır

Program imajı yükleme

  • LC-3 assembly programı makine diline dönüştürüldüğünde, komut ve veri dizilerini içeren bir dosya oluşturulur
  • Nesne dosyasının ilk 16 biti, programın bellekte nereye yerleştirileceğini gösteren origin’dir
  • Loader önce origin’i okur, kalan veriyi origin adresinden itibaren belleğe kopyalar
  • LC-3 programları big-endian biçimdedir
    • Çoğu modern bilgisayar little-endian olduğundan, yüklenen her uint16_t için swap16 uygulanır
    • Eski PPC Mac gibi big-endian bilgisayarlarda swap yapılmamalıdır
  • read_image, dosyayı binary modda açar, read_image_file’ı çağırır ve ardından dosyayı kapatır

Bellek eşlemeli register’lar

  • Genel register tablosuyla erişilmeyen özel register’lar belirli bellek adreslerine eşlenir
  • LC-3’te uygulanması gereken iki bellek eşlemeli register vardır
    • MR_KBSR = 0xFE00: keyboard status register
    • MR_KBDR = 0xFE02: keyboard data register
  • KBSR bir tuşa basılıp basılmadığını gösterir; KBDR ise hangi tuşa basıldığını saklar
  • GETC, giriş gelene kadar yürütmeyi bloke eder; ancak KBSR ve KBDR, aygıt durumunu polling ederek giriş beklerken bile programın tepki vermeye devam etmesini sağlar
  • Bellek okuma, doğrudan dizi okumak yerine mem_read üzerinden yapılır
    • Adres MR_KBSR ise check_key() ile klavye durumu kontrol edilir
    • Tuş varsa KBSR’nin en yüksek biti set edilir ve KBDR’ye getchar() değeri yazılır
    • Tuş yoksa KBSR 0 olarak ayarlanır

Platforma özgü terminal işlemleri

  • Klavye girişi ve terminal davranışını doğru işlemek için platforma özgü giriş tamponlama ayarları gerekir
  • Linux/macOS/UNIX uygulaması termios, select vb. kullanır
    • canonical mode ve echo devre dışı bırakılır
    • Girişin mümkün olup olmadığı select ile kontrol edilir
  • Windows uygulaması GetStdHandle, GetConsoleMode, SetConsoleMode, _kbhit vb. kullanır
    • echo ve line input ayarlanır
    • Tuş girişi WaitForSingleObject ve _kbhit ile kontrol edilir
  • Program başlarken disable_input_buffering() çağrılır, çıkarken restore_input_buffering() çağrılır
  • SIGINT alınırsa terminal ayarları geri yüklenir, satır sonu yazdırılır ve program sonlandırılır

VM çalıştırma ve hata ayıklama

  • VM build örneği şöyledir
gcc lc3.c -o lc3-vm
  • Çalıştırmak için derlenmiş LC-3 nesne dosyasını argüman olarak verin
lc3-vm path/to/2048.obj
  • Örnek olarak sağlanan nesne dosyaları 2048.obj ve rogue.obj’dir
  • 2048 örneği WASD tuşlarıyla kontrol edilir
  • Program doğru çalışmıyorsa sorun büyük olasılıkla komut uygulamasındaki bir hatadır
    • LC-3 assembly kaynağını okurken debugger ile VM komutlarını tek tek yürütme yöntemi önerilir
    • Beklenen komuta gidilmeyen bir nokta varsa ilgili komutun belirtimini ve uygulamasını yeniden kontrol edin

İsteğe bağlı: C++ generic tabanlı uygulama

  • Daha kısa bir C++ uygulama tekniği de isteğe bağlı olarak ele alınır
  • Birçok komut sign extension, PC tabanlı offset, dolaylı adres hesaplama gibi tekrarlanan işleri paylaştığından, komut yürütme küçük işlem adımlarından oluşan bir pipeline olarak görülebilir
  • C++ template’leri ve bit flag’leri kullanılarak her opcode için yalnızca gereken işlem adımları derleme zamanında dahil edilir
  • Bu yöntem kod tekrarını azaltır ve her işlem adımının çip üzerinde fiziksel alan kapladığı gerçek donanım kablolama biçimine daha yakındır
  • Fikrin kaynağı olarak Bisqwit’s NES emulator belirtilir

Kaynaklar ve katkılar

  • atul-g, tüm sistem davranışını özetleyen reference card’ı katkı olarak sağladı
  • Farklı dillerdeki uygulamalar GitHub topic’i lc3 altında derlenmiştir
    • C, C++, Go, Haskell, Java, JavaScript, Kotlin, Lua, OCaml, Python, Ruby, Rust, Swift, TypeScript, Zig vb. dahildir
  • Kendi uygulamanızın listede görünmesini istiyorsanız GitHub topic’i olarak lc3 eklemeniz yeterlidir
  • Windows platform desteği inkydragon tarafından katkı olarak sağlandı
  • Projede entegrasyon testleriyle ilgili bir good first issue bulunur

1 yorum

 
GN⁺ 2024-12-28
Hacker News yorumları
  • Gençliğimde community college'daki bilgisayar bilimine giriş dersinde basit bir CPU komut kümesi tasarlamış, kendi sanal makinemizi ve assembler'ımızı yapıp assembly programları yazıp çalıştırmıştık.
    Şaşırtıcı derecede kolaydı ve bilgisayarlar çok daha az gizemli gelmeye başlamıştı.
    FPGA için gerçek bir CPU tasarımından basit bir işletim sistemi ve onun üzerinde çalışan programlar yazmaya kadar, bilişimin tüm katmanları bu yöntemle öğrenilebilir gibi geliyor.
    Modern bilişimin gerektirdiği performans ve güvenliği bir kenara bırakıp hedefi “çalışsın yeter” olarak koyarsanız, bu alan beklenmedik ölçüde basit.

    • Eğlenceli bir ders gibi duruyor; https://www.nand2tetris.org/ ya da Charles Petzold'un Code kitabına çok benziyor.
    • Başlangıçtaki hayali CPU'dan 80286 gibi erken dönem gerçek, seri üretilmiş CPU'lara geçtiğiniz anda karmaşıklık hızla artıyor.
      Hafızam beni yanıltmıyorsa en azından bellek segmentasyonu, korumalı kip ve MMU işin içine giriyor.
    • CS 101 dersimizde de böyle bir sistem vardı.
      PDP üzerinde BASIC ile yazılmış basit bir bilgisayar/assembler'dı; ödevlerden biri de döngüyle toplama yaparak basit çarpmayı gerçekleştirmekti.
      Bir arkadaşım bunun yerine programı değiştirip yeni bir MUL komutu oluşturdu; öğretmen bundan hiç hoşlanmadı.
    • Basit yapı taşlarının kendisi gerçekten kolay, ama gerçek kullanıcıların bilgisayarda gördüğü ve dokunduğu ticari düzeydeki çıktılara ulaşmak için arada yüzlerce katman var.
      Meraklı ve öğrenmek isteyen biri bu temel katmanları kolayca öğrenebilir; ama “hızlı para kazanıp olabildiğince çabuk işe girebilir hâle gelmek” isteyen biri için aynı şey geçerli değil.
    • nand2tetris kursu tam da bunu yapıyor gibi.
  • Önerilen kitaplar:

    1. Smith ve Nair'in Virtual Machines: Versatile Platforms for Systems and Processes kitabı — konuyu kapsamlı biçimde tarayan bir kitap gibi görünüyor.
    2. Iain Craig'in Virtual Machines kitabı — diller ve sanal makineler üzerine daha uygulamalı bir kitap gibi görünüyor.
    3. Bill Blunden'ın Virtual Machine Design and Implementation in C/C++ kitabı — uygulama/gerçekleme odaklı bir pratik kitap gibi duruyor.
      Bu kitapları okumuş biri yorum eklerse herkes için faydalı olur.
    • Bu konunun tek bir kitapla genel bakış sunulabilecek kadar dar olduğundan emin değilim.
      Nintendo emülatörü, VT-x kullanan bir hipervizör, geleneksel çok görevli işletim sistemi, yeni bir betik dilinin yorumlayıcısı, SQL sorgu en iyileyicisi, düzenli ifade eşleştiricisi, oyun sunucusunda güvenilmeyen oyuncu kodunu çalıştıran bir güvenlik gözetleyicisi vb. neredeyse hiç ortak değerlendirme noktası yokmuş gibi görünse de hepsi sanal makine.
      Karakter hücreli terminal kaçış dizilerini belirleyen terminfo biçiminin içinde bile yığın tabanlı bir sanal makine var.
      Derine inince, bugünkü anlamıyla bilgisayarı bilgisayar yapan şey sanal makinedir; Turing'in 1936 tarihli Entscheidungsproblem makalesi de sanal makinelerin birbirini taklit edebilmesine dayanıyordu.
  • Ben Eater'ın breadboard CPU serisini izledikten sonra tek istediğim kendi CPU'mu tasarlayıp emüle etmek.
    Oturup bunu tasarlayacak zamanı bulabilsem keşke.

  • Brookshear Machine veya Little Computer gibi eğitim amaçlı mimarilerin gerçek mimarilere hiç benzemediği için faydasız olmanın ötesinde zararlı olduğunu düşünüyorum.
    Bu tür şeylerin kullanıldığı dersleri alan öğrencilerin, hiç ders almamış kişilere göre bilgisayarları daha çarpık anladığını gördüm.
    Kendi bilgisayarının nasıl çalıştığını biraz öğrenmek isteyen çoğu kişi için işletim sistemleri dersi daha iyi; burada da yalnızca kısa bir eğitime zaman varsa “Writing my own bootloader”ı öneririm.
    https://dev.to/frosnerd/writing-my-own-boot-loader-3mld
    Bu, “Write your own VM” eğitimlerinin kötü olduğu anlamına gelmiyor; benim deneyimime göre onu yapacak kişilerin çoğu için başka konuların daha yararlı olduğu anlamına geliyor.

    • Az önce LC-3 yaptım ve mevcut projemde LC-3'ü uygunsuz bir hedef makine olarak kullanıp dinamik yeniden derlemeyi biraz öğrenmeye çalışıyorum.
      Bilgisayar mimarisini öğrenmek için LC-3'ün neden kötü olduğunu biraz daha açıklayabilir misin?
      Gerçek donanımdan tamamen farklı ve aşırı basit olduğunu anlıyorum, ama CPU emülatörü yazma açısından da kötü olup olmadığını merak ediyorum.
    • Knuth'un eski MIX'i aklıma geliyor.
      1960'larda yapılmış olabilecek türden onluk bir makineydi, ama 1970'lerden sonra kimse böyle bir şey üretmedi.
      Bu tür sistemler pek çok temel bilgiyi öğretebilir, ancak https://en.wikipedia.org/wiki/Hacker%27s_Delight içindeki teknikler çoğunlukla yaygın sayı temsil biçimlerine dayandığı için öğrenmesi zor olur.
    • LC-3'ün özellikle hangi yanını sevmediğini merak ediyorum.
      Pek bilmediğim için Wikipedia'ya kısaca baktım; karikatürü görünce tuhaf bir şey beklemiştim ama ilk bakışta o kadar da şok edici görünmedi.
      s/360, biraz x86, çok az ARM ya da başka RISC ailesi mimarilerinin karışımı gibi; atlanan ve tuhaf kısımlar çok, ama hedef hızlıca çalışan bir uygulamaya ulaşmak gibi görünüyor.
      Eğitim amaçlı olarak neden “faydasız olmanın ötesinde zararlı” gördüğünü bilmek isterim.
    • Eski 8 bit mimarilerden 6502 veya Z80 kullanmayı öneririm.
      Hindistan'daki birçok bilgisayar bilimi dersinde hâlâ 8086/8088 kullanılıyor gibi.
    • LC-3'ün adresleme biçimi epey tuhaf.
      Özellikle ortadaki PC'ye göreli sözcük üzerinden çift dolaylı yükleme yapabiliyorsunuz.
      Buna rağmen çıkarma işlemini olumsuzlamadan, olumsuzlamayı da NOT ve ADD ,,#-1 ile oluşturmanız gerekiyor.
      Sınırlı komut kodlama alanı düşünüldüğünde NOT d,s = XOR d,s,#-1 daha iyi bir kullanım olurdu gibi geliyor.
  • Katı bir ayrım yapacaksak bu bir sanal makine değil, emülatör
    Betimleyici anlamda bu terim uygulanabilir ve donanım sanallaştırmasından önceki dönemde belli bir belirsizlik de vardı; ancak günümüzde “Virtual Machine” ifadesinin ezici çoğunlukla yaygın kullanımı, VT-x gibi donanım sanallaştırma özelliklerini kullanan ortamları ifade eder

    • Bu terimin “ezici çoğunlukla yaygın” olduğuna katılmıyorum ve bunun tamamen doğru bir ayrım olduğunu da düşünmek zor
      JVM yaygın biçimde dağıtılıyor, Ethereum VM’e EVM deniyor, https://www.linuxfoundation.org/hubfs/LF%20Research/The_Stat... da BPF ve eBPF’yi tekrar tekrar “virtual machines” olarak tanımlıyor, https://webassembly.org/ ise “WebAssembly (kısaca Wasm), yığın tabanlı bir sanal makine için ikili komut biçimidir” diye başlıyor
      “Sanal makine”, sanal bir makineyi adlandırmak için hâlâ en yaygın ifade
      Şahsen “fictive machine”, “fictious machine”, “imaginary computer”, “fantastic automaton” gibi ifadeleri daha çok seviyorum ama benimsenmeleri pek olası görünmüyor
      “Sanal makine” yerine her zaman “emülatör” kullanılamaz
      wasmtime’a emülatör denebilir belki ama WebAssembly’nin kendisine emülatör demek doğru olmaz; WebAssembly, wasmtime’ın emüle ettiği sanal makinedir
      Emülatörlere sanal makine demek de yaygındır; çalışmakta olan bir emülatör örneği de başka bir anlamda sanal makinedir
      Donanım sanallaştırma ortamına “sanal makine” demek de geçerlidir ve bu son anlamla bir ölçüde örtüşür
      Mevcut ortamda bu kullanım ezici çoğunlukla yaygın olabilir, ama başka yerlerde bunun mutlaka böyle olması gerekmez
    • Saygıyla katılmakta zorlanıyorum
      En saf anlamıyla sanal makine, uydurulmuş/yaratılmış bir bilgisayardan ibarettir; ne için kullanılacağını ya da nasıl çalıştığını ima etmez
      Yazıda klasik konsol emülasyonu örnek veriliyor, ancak sunulan tanıma göre mümkün olan sanal makinelerin çok daha fazla olduğu açık
      Asıl nokta, sanal makinenin soyut bir kavram olması ve çok sayıda türünün bulunması
      Simülatörler, emülatörler, hipervizörler vb. hepsi sanal makinedir; henüz adı konmamış tuhaf sanal makine biçimleri de vardır
      Kaba konuşmaya çalışmıyorum; tam tersine saygılı olmaya çalışıyorum ve öğrenmek isteyenler için bu terimi netleştirmek istiyorum
    • Savunduğunuz ayrımın gerçekte var olmadığını düşünüyorum
      “Sanal makine”, nedeni ne olursa olsun makine kodu ya da bayt kodu çalıştıran her türlü yazılım için yaygın biçimde kullanılır
      Sanallaştırmayı içerebilir, ancak Java’nın JVM’i veya Ruby’nin YARV’ı (Yet Another Ruby VM) gibi dil çalışma zamanları için de sıkça kullanılır
      Bu terimi o kadar sık duymadığınız alan daha ziyade emülasyondur; bunun bir nedeni de modern emülatörlerin çoğunun tüm sistemi emüle etmektense, emüle edilen yazılımı dinamik yeniden derleme tekniklerine yönelmiş olmasıdır
    • Bu, JVM’de, yani Java Virtual Machine’de kullanılan anlamıyla VM
      Java’nın “ezici çoğunlukla yaygın kullanım” kapsamına girdiği söylenebilir