من الترجمة إلى التنفيذ: تصميم نظام كامل (مترجم + معالج)
في إطار مشروع هندسي، أتيحت لنا الفرصة لتصميم نظام حاسوبي شامل: من تعريف لغة مصدرية عالية المستوى إلى تنفيذها المحاكى على معالج مع خط أنابيب. سمح لنا هذا المشروع باستكشاف جميع طبقات حوسبة النظام: الترجمة، التجميع، البنية المادية، إدارة الذاكرة، تنفيذ التعليمات وحتى كشف مخاطر البيانات.
هدف المشروع
استند عملنا على ركيزتين رئيسيتين:
- إنشاء مترجم يترجم لغة قريبة من C إلى مجمّع موجه للذاكرة.
- تصميم معالج قادر على تنفيذ كود مجمّع موجه للسجلات، عبر بنية خط أنابيب.
بين هذين العالمين، طورنا أيضًا مترجمًا متقاطعًا ومفسرًا، مما سمح بربط جميع مراحل تحويل البرنامج.

الجزء الأول - تصميم المترجم (LEX/YACC)
اللغة المصدرية بسيطة عمدًا لكنها قريبة من C: نجد فيها أنواع int و bool، شروط، حلقات (for، while، do-while) ومعظم المعاملات المعتادة.
تم إيلاء اهتمام كبير لتحسين الكود الوسيط، خاصة في إدارة المتغيرات المؤقتة.
| مثال C | كود غير محسّن | كود محسّن |
|---|---|---|
int a = 2; | MOVi 0 2MOV 1 0 // @a = 1 | MOVi 0 2 // @a = 0 |
int a = 2 + 2; | MOVi 0 2MOVi 1 2ADD 2 0 1 | MOVi 0 2MOVi 1 2ADD 0 0 1 |
bool a = (4+5) <= (10-1) | ... | LE 0 0 1 // @a = 0 |
يتم إدارة كتل if/else، for، وwhile بعناوين مؤقتة يملأها المترجم ديناميكيًا بعد التحليل، مما يضمن تنفيذًا سلسًا بدون قفزات خاطئة.
الجزء الثاني - مجمّع موجه للذاكرة ومفسر
يتبع تنسيق إخراج المترجم بنية ثابتة OP @A @B @C، حيث يتم ترميز كل تعليمة على 32 بت. إليك التعليمات الأكثر استخدامًا:
| الفئة | التعليمات المتاحة |
|---|---|
| حسابية | ADD، SUB، MUL، DIV، MOD |
| منطقية | AND، OR، NOT |
| مقارنات | EQ، NEQ، LT، LE، GT، GE |
| التحكم في التدفق | JMP، JMPZ، JMPNZ، CALL، RET |
| متنوعة | MOV، MOVi، PRI، INCO، DECO |
ينفذ المفسر كود المجمّع هذا سطرًا بسطر من خلال محاكاة ذاكرة، ومؤشر تعليمات، والعمليات الكلاسيكية للمعالجة.
الجزء الثالث - تصميم المعالج مع خط الأنابيب
طورنا بنية من 5 مراحل: Fetch، Decode، Execute، Memory و Write Back. يتم تنفيذ كل مرحلة بطريقة نمطية، مع إدارة دقيقة لتعارضات السجلات.
من بين المكونات الرئيسية:
- تنفذ ALU جميع العمليات، مع مراعاة الأعلام
Z،N،O،C. - تحتوي ROM على التعليمات المراد تنفيذها.
- تسمح RAM بالتخزين المؤقت.
- بنك من 16 سجلاً يخزن بيانات 8 بت.
- يكتشف
data_hazards_managerالقراءات المتزامنة للسجلات ويدرج NOPs إذا لزم الأمر.

الجزء الرابع - الترجمة المتقاطعة (ذاكرة ← سجل)
يولد المترجم الأولي كودًا موجهًا للذاكرة. لتنفيذ هذا الكود على معالجنا الموجه للسجلات، صممنا مترجمًا متقاطعًا بـ Python.
المبدأ: استبدال كل تعليمة ذاكرة بتسلسل سجل مكافئ، بإدراج تعليمات التحميل والحفظ.
| كود الذاكرة | كود السجل المكافئ |
|---|---|
ADD @A @B @C | LDR 0 @BLDR 1 @CADD 1 1 0STR @A 1 |
تسمح هذه الآلية بتحويل أي كود تم إنشاؤه بواسطة مترجمنا تلقائيًا إلى برنامج قابل للتنفيذ على المعالج.
الجزء الخامس - التكامل النهائي والاختبارات
بعد التطوير النمطي للمكونات، قمنا بالتحقق من صحة التكامل الكامل:
- ترجمة برنامج مصدر إلى مجمّع ذاكرة
- التحويل بواسطة المترجم المتقاطع إلى مجمّع سجل
- تنفيذ الكود على محاكي خط الأنابيب
تنتج كل خطوة ملف إخراج يصبح مدخل الخطوة التالية، مما يسمح بسلسلة ترجمة موثوقة.
الخلاصة
كان هذا المشروع تجربة مكثفة وتكوينية. سمح لنا بلمس الطبقات البرمجية (التحليل المعجمي، النحوي، الدلالي، توليد الكود) والمادية (البنية، التنفيذ، خط الأنابيب، السجلات) معًا.
نحتفظ بمهارات رئيسية:
- تصميم لغة باستخدام LEX/YACC
- توليد كود محسّن ومنظم
- محاكاة خط أنابيب وإدارة مخاطر البيانات
- تحويل بنيات الذاكرة إلى السجل
يعكس هذا العمل قدرتنا على التصميم والبرمجة والاختبار ودمج الأنظمة المعقدة.
شكر وتقدير
نشكر مشرفينا على دعمهم طوال المشروع. تم إنجاز العمل المقدم هنا بالكامل من قبل فريقنا، من المترجم إلى المعالج، بدقة وشغف.
يمكنك العثور على الكود المصدري الكامل لهذا المشروع على GitHub