Terkadang muncul ide untuk menyingkirkan yang sangat sulit. Ini terjadi pada saya.
Saya memutuskan untuk membuat mesin virtual (VM), mengingat pada saat itu saya tidak punya ide, menurut saya ini adalah ide yang bagus. Jika Anda tertarik, maka pergi ke cut!
Teori
Pertama, sedikit teori. Apa itu mesin virtual secara umum? Ini adalah program atau serangkaian program yang memungkinkan Anda untuk meniru beberapa jenis platform perangkat keras, dengan kata lain, sebuah emulator komputer.
Mesin virtual sendiri berbeda, misalnya, Virtual Box adalah mesin virtual klasik yang memungkinkan Anda untuk meniru komputer nyata, tetapi misalnya, JVM (mesin virtual Java) tidak dapat melakukan ini.
Versi VM saya akan sedikit mirip dengan JVM hanya karena ini adalah proyek pelatihan yang lebih daripada bertujuan untuk menciptakan VM yang kuat.
Memori
Jadi, sekarang mari kita mencari tahu ingatannya. Untuk membuat memori, saya memutuskan untuk menggunakan array int yang tidak ditandatangani. Ukuran array ditentukan menggunakan makro, dalam versi saya ukuran memori adalah 4096 byte (ada 1024 elemen dalam array, dan karena pada kebanyakan platform 4 byte dialokasikan untuk data int yang tidak ditandatangani, maka 1024 * 4 = 4096), antara lain, kami akan menetapkan 8 register dengan 8 sel di masing-masing akan sudah 256 byte (8 * 8 * 4 = 256). Ini terlihat seperti ini:
#define MEMSIZE 1024 unsigned int memory[MEMSIZE]; unsigned int reg[8][8];
Pemrograman
Kami memiliki memori, tetapi sekarang bagaimana menulis kode untuk VM kami? Sekarang kita akan membahas masalah ini, untuk memulainya, kita akan menentukan perintah yang akan dijalankan mesin kita:
enum commands { CRG = 1, CRC, PRG, PRC };
Setiap tim memiliki bendera sendiri yang mendefinisikan beberapa parameter tambahan.
kami akan menjelaskan bendera:
enum flags { STDI = 1, STDA };
Perintah standar memiliki bentuk: [command] [flag] [data] (tampilan beberapa perintah mungkin berbeda), berdasarkan ini kita akan menulis penerjemah sederhana:
if (memory[cell] == CRG && memory[cell + 1] == STDI) { indxX = memory[cell + 2]; cell++; } else if (memory[cell] == CRC && memory[cell + 1] == STDI) { indxY = memory[cell + 2]; cell++; } else if (memory[cell] == PRG && memory[cell + 1] == STDI) { reg[indxX][0] = memory[cell + 2]; cell++; } else if (memory[cell] == PRC && memory[cell + 1] == STDI) { reg[indxX][indxY] = memory[cell + 2]; cell++; }
indxX & indxY adalah variabel yang menyimpan posisi kursor saat ini di register reg.
Sel adalah variabel yang menyimpan posisi kursor saat ini dalam array memori.
Tetapi pemrograman dengan angka sangat tidak nyaman, jadi dengan menggunakan preprosesor C kita akan menggambarkan assembler kita. Saya mengerti bahwa menulis asm dengan makro tidak terlalu baik, tetapi solusi ini bersifat sementara.
Kode asm kami terlihat seperti ini:
#define $CRG {memory[memIndx++] = CRG;} #define $CRC {memory[memIndx++] = CRC;} #define $PRG {memory[memIndx++] = PRG;} #define $PRC {memory[memIndx++] = PRC;} #define _$STDI {memory[memIndx++] = STDI;} #define _$STDA {memory[memIndx++] = STDA;} #define _$DATA memory[memIndx++] =
memIndx adalah variabel yang menyimpan posisi kursor saat ini dalam array memori.
Dan di sini adalah kode pada asm kami memasukkan 123 ke register di alamat [1] [0] (register pertama, nol sel):
$CRG _$STDI _$DATA 1; $CRC _$STDI _$DATA 0; $PRC _$STDI _$DATA 123;
Selamat, kita sekarang memiliki kemiripan ASM untuk mobil kita!
Luncurkan program
Kami berhasil membuat mesin kami untuk menjalankan program, tetapi kode tidak memiliki portabilitas dari satu mesin ke mesin lainnya, jadi sekarang kami akan membuat generator kode mesin dari asm (dan saya mengingatkan Anda bahwa, tidak seperti komputer nyata, mesin kami memiliki kode mesin yang tidak disajikan dalam bentuk biner, dan angka desimal), pada prinsipnya, tidak begitu sulit, tetapi pertama-tama, mari kita pikirkan tentang implementasinya.
Pertama kita memiliki kode asm, sekarang kita perlu menerjemahkannya ke dalam angka, kemudian menulis kode mesin yang dihasilkan ke file .ncp (program kode numerik, sebenarnya itu adalah file teks, tetapi untuk membedakannya dari yang lain, saya datang dengan ekstensi saya sendiri), setelah itu kita perlu menjalankan file .ncp, itu mudah dilakukan, karena penerjemah yang kita tulis sebelumnya, mengenali angka-angka; kita hanya perlu mengekstrak data dari file dan mengubahnya menjadi angka menggunakan atoi ().
Mari kita beralih dari kata-kata ke perbuatan:
Membaca kode dan menulisnya ke file:
if (memory[i] == CRG && memory[i + 1] == STDI) { fprintf(code, "%d %d ", CRG, STDI); i++; } else if (memory[i] == CRC && memory[i + 1] == STDI) { fprintf(code, "%d %d ", CRC, STDI); i++; } else if (memory[i] == PRG && memory[i + 1] == STDI) { fprintf(code, "%d %d ", PRG, STDI); i++; } else if (memory[i] == PRC && memory[i + 1] == STDI) { fprintf(code, "%d %d ", PRC, STDI); i++; }
Kode ini adalah bagian dari isi fungsi ncpGen ().
Membaca file dan pelaksanaannya:
if (prog != NULL) { fread(txt, 1, len, prog); tok = strtok(txt, " "); while (tok != NULL) { memory[i] = atoi(tok); tok = strtok(NULL, " "); if (argc == 3 && strcmp(argv[2], "-m") == 0) { printf("%d\n", memory[i]); } i++; } memInter(); } else { perror("Fail"); }
Sekarang, mari kita mendefinisikan makro sehingga alih-alih menafsirkan asm, kode berubah menjadi .ncp:
#define _toNCP(name) {strcpy(filename, name);} {ncpGen();}
Jika ada, maka artikel tidak menampilkan semua kode, tetapi hanya sebagian kecil saja!
Kode lengkap ada di
repositori proyek.
Terima kasih banyak sudah membaca!