ساخت ماشین مجازی LC-3 با ۲۵۰ خط C
خلاصهٔ کاملتر
Justin Meiners و Ryan Pendleton تو این آموزش نشون میدن چطور یه ماشین مجازی (VM) بنویسی، یعنی برنامهای که مثل یه کامپیوتر رفتار میکنه و CPU و حافظه رو شبیهسازی میکنه. خروجی نهایی حدود ۲۵۰ خط C هست و میتونه برنامههای اسمبلی مثل یه بازی 2048 یا یه Roguelike رو اجرا کنه. نویسندهها میگن فقط باید C پایه و حساب دودویی بلد باشی.
نویسندهها اول توضیح میدن VMها به چه دردی میخورن. بعضیها مثل شبیهساز NES یه سختافزار واقعی رو تقلید میکنن. بعضی دیگه مثل JVM یه معماری خیالی میسازن تا یه برنامه بدون تغییر روی هزارها دستگاه اجرا بشه. VM همچنین میتونه کد رو ایزوله اجرا کنه؛ مثلاً قراردادهای هوشمند Ethereum داخل VMای اجرا میشن که به فایل و شبکه دسترسی نداره. هزینهش هم سربار اجرا (overhead) هست.
معماری انتخابی LC-3 هست، یه کامپیوتر آموزشی که تو دانشگاهها برای درس اسمبلی استفاده میشه. ۶۵۵۳۶ خونهٔ حافظهٔ ۱۶ بیتی داره (کلاً ۱۲۸KB)، ۱۰ رجیستر (۸ تا عمومی، یکی PC و یکی COND) و فقط ۱۶ opcode. هر دستور ۱۶ بیته و ۴ بیت سمت چپش opcode (یعنی نوع کاری که CPU باید بکنه) رو مشخص میکنه.
قلب VM یه حلقهٔ سادهست: دستور رو از آدرس PC بخون، PC رو یکی زیاد کن، opcode رو دربیار و بر اساسش کار رو انجام بده. پرشها هم با عوضکردن PC انجام میشن، برای همین حلقه هیچوقت دستور کم نمیاره:
uint16_t instr = mem_read(reg[R_PC]++);
uint16_t op = instr >> 12;بعد نویسندهها دو دستور ADD و LDI رو کامل پیاده میکنن. ADD دو حالت داره: تو حالت register عدد دوم از یه رجیستر میاد، تو حالت immediate یه عدد ۵ بیتی داخل خود دستوره. اون عدد ۵ بیتی باید sign extend بشه، یعنی برای عدد منفی بیتهای اضافه با ۱ پر بشن تا مقدارش عوض نشه:
uint16_t sign_extend(uint16_t x, int bit_count)
{
if ((x >> (bit_count - 1)) & 1) {
x |= (0xFFFF << bit_count);
}
return x;
}هر دستوری هم که رجیستری رو عوض کنه باید پرچمهای شرط (مثبت، صفر، منفی) رو آپدیت کنه. LDI یعنی بارگذاری غیرمستقیم: آدرسی که حساب میشه خودش آدرس دادهٔ اصلیه، شبیه یه اشارهگر تو C. نویسندهها میگن بقیهٔ دستورها هم با همین چند ایده (sign extend، حالتها و آپدیت پرچمها) ساخته میشن.
نکات کلیدی:
- کد نهایی VM حدود ۲۵۰ خط C هست و نسخهٔ unix و windows داره.
- LC-3 فقط ۱۶ opcode، ۱۰ رجیستر ۱۶ بیتی و ۶۵۵۳۶ خونهٔ حافظه داره.
- هر دستور ۱۶ بیته و ۴ بیت بالاش opcode هست.
- حالت immediate تو ADD فقط یه عدد ۵ بیتی جا میده و باید sign extend بشه.
- آموزش به سبک literate programming نوشته شده، یعنی کل کد VM داخل خود متن آموزشه.