أهلاً بك في المساق الكامل 👋
هذا الملف هو كتاب تفاعلي كامل بُني وفق سيلابوس ربيع 2026 الرسمي، ويغطي 15 محاضرة مرتّبة زمنياً تماماً كما في المساق: من تمثيل الأعداد وجبر المفاتيح، مروراً باللوجيك التوافقي والتتابعي وآلات الحالات والتوقيت، وصولاً إلى بناء معالج RISC-V كامل (أحادي الدورة، متعدد الدورات، وخط الأنابيب).
كيف تستخدم هذا الملف؟
كل محاضرة مبنية بالتسلسل التالي: شرح نظري معمّق من الصفر ← عناصر تفاعلية وأمثلة صغيرة مدمجة داخل الشرح لترسيخ الفهم ← أمثلة شاملة وأسئلة بمستوى الامتحان مع حلول مخفية. جرّب حل كل سؤال بنفسك قبل فتح الحل!
- ✅ ضَع علامة في مربع كل محاضرة في القائمة الجانبية عند إنهائها — شريط التقدّم يُحفظ تلقائياً في متصفحك.
- 💡 الصناديق البرتقالية = تلميحات قابلة للفتح. الصناديق الخضراء = حلول مخفية.
- 🎛 الصناديق المتقطعة الحدود = أدوات تفاعلية: جرّب، غيّر القيم، وشاهد النتيجة.
- 🌙 زر أعلى القائمة الجانبية للتبديل بين الوضع الفاتح والداكن.
💡 نصيحة ذهبية قبل أن تبدأ
هذا المساق تراكمي بشدة: خرائط كارنو تُبنى على جبر المفاتيح، وآلات الحالات تُبنى على الـFlip-Flop، والمعالج المخطّط يُبنى على كل ما سبق. لا تقفز فوق محاضرة! وإذا شعرت أن موضوعاً «سهلاً» — اذهب مباشرة لأسئلة الامتحان في نهايته وجرّب نفسك؛ ستكتشف بسرعة إن كان فهمك حقيقياً.
مقدمة المساق ومعمارية RISC-V: من فكرة الحاسوب إلى أول برنامج بلغة التجميع
1.1 ما هو الحاسوب أصلاً؟ ولماذا نبدأ من هنا؟
قبل أن نغرق في البوابات والسجلات، يجدر أن نسأل السؤال الأبسط والأعمق: ما الذي يجعل آلةً ما «حاسوباً»؟ الجواب الجوهري: إنها آلة قابلة للبرمجة — عتاد واحد ثابت يستطيع تنفيذ عدد لا نهائي من المهام المختلفة، لمجرد أننا نغيّر البرنامج الذي نطعمه إياه. هذه الفكرة، التي تبدو اليوم بديهية، هي واحدة من أعظم القفزات الفكرية في القرن العشرين.
تاريخياً، يُعتبر Colossus (بريطانيا، 1944) أول حاسوب رقمي إلكتروني قابل للبرمجة في العالم — بُني سراً لكسر الشيفرات الألمانية في الحرب العالمية الثانية (قصة Enigma الشهيرة). لكن انتبه إلى تفصيلة تاريخية مهمة: كولوسوس كان يُبرمَج بالمفاتيح والأسلاك الفيزيائية، لا ببرنامج مخزَّن في ذاكرة — أي أنه سبق ولادة أهم فكرة في هذا المجال، وهي فكرة «البرنامج المخزَّن» التي سنلتقيها بعد قليل.
واليوم؟ الحاسوب لم يعد صندوقاً على مكتب. في عام 2026 تحيط بنا طبقات كاملة من الحوسبة: هواتف ذكية وأجهزة شخصية محمولة، ذكاء اصطناعي مدمج في كل شيء («AI Inside»)، أجهزة طرفية على حافة الشبكة (Network Edge Devices)، وفي الخلفية حواسيب بحجم مستودعات (Warehouse-Scale Computers) تشغّل محركات البحث والسحابة. المدهش أن كل هذه الطبقات — من الساعة الذكية حتى مركز البيانات — مبنية من نفس اللبنات التي سنتعلمها في هذا المساق.
1.2 الأفكار السبع العظيمة في هندسة الحواسيب
كل ما ستراه في هذا المساق — وكل معالج صُنع يوماً — يقف على سبع أفكار كبرى. لا تحفظها كقائمة؛ افهم لماذا كانت كل واحدة منها ضرورية، وستجد أنها تعود للظهور محاضرةً بعد محاضرة:
لماذا لا نمثّل المعلومات بجهد كهربائي متصل؟ نظرياً، قيمة جهد واحدة دقيقة تستطيع تمثيل كمية «لا نهائية» من المعلومات — كفاءة مذهلة! لكن هذا التمثيل لا يمكن تمريره بموثوقية: كل سلك وكل مكوّن يضيف ضجيجاً، والضجيج على قيمة متصلة يتراكم بلا رجعة حتى تضيع المعلومة.
الحل الرقمي عبقري في تواضعه: نسمح بعدد صغير فقط من القيم «الشرعية» (اثنتان في التمثيل الثنائي: 0 و1)، وكل قيمة مستقبَلة تُصحَّح إلى أقرب قيمة شرعية — هذا ما يسمى إعادة التوليد. نعم، نخسر كفاءة نظرية، لكننا نربح شيئاً لا يقدَّر بثمن: نظاماً يعمل بشكل صحيح حتى فوق مكوّنات رديئة. كل بوابة منطقية هي في الحقيقة «مصحّح إشارة» صغير، وهذا سرّ قدرتنا على سلسلة ملايين البوابات دون انهيار.
العتاد («المعالج») ثابت — وهذا ممتاز صناعياً: تصميم واحد يُنتَج بملايين النسخ فينخفض سعره. أما المرونة فتأتي من مكان آخر: المعالج يقرأ الأوامر من الذاكرة، واحداً تلو الآخر، وينفّذها. غيّر محتوى الذاكرة — يتغيّر سلوك الآلة كلياً. البرنامج نفسه صار بيانات.
وللأمانة العلمية: توجد بدائل لهذا النموذج — عتاد قابل لإعادة التشكيل مثل FPGA (تعيد توصيل الدارة نفسها حسب الحاجة)، وحوسبة داخل الذاكرة (In-Memory Computing). لكن النموذج المخزَّن هو الذي بنى عالم الحوسبة الحديث، وهو الذي سنبنيه نحن في المحاضرات 13–15.
لا يستطيع عقل بشري التفكير في مليار ترانزستور دفعة واحدة. الحل: سلّم من الطبقات، كل طبقة تخفي تفاصيل ما تحتها وتقدّم لما فوقها واجهة بسيطة:
لغة عليا (C) ← يترجمها الـCompiler ← لغة تجميع (Assembly) ← يحوّلها الـAssembler ← لغة آلة (أنماط بتات!) ← تفسّرها بنية العتاد ← المنفَّذة بـدارات منطقية
والجملة المفتاحية التي تلخص كل شيء: أي شيء يمكن تمثيله كعدد — البيانات والأوامر على حد سواء. سطر C مثل temp = v[k] يصبح أمر lw في الأسمبلي، ثم يصبح 32 بتاً مثل 0000 1001 1100 0110... في لغة الآلة — والذاكرة لا تفرّق بينه وبين أي عدد آخر.
قانون مور: ملاحظة غوردون مور (أحد مؤسسي Intel): عدد الترانزستورات على الشريحة يتضاعف كل سنتين تقريباً. لعقود، كانت هذه «الريح في الشراع» التي جعلت كل جيل أسرع وأرخص — والمهندس الجيد يصمم لما سيكون عليه العتاد عند اكتمال التصميم، لا لما هو عليه اليوم.
مبدأ المحلية والتسلسل الهرمي للذاكرة: البرامج لا تلمس ذاكرتها عشوائياً — تميل للعودة إلى نفس البيانات (محلية زمنية) وجيرانها (محلية مكانية). لذلك نبني هرماً: قليل من الذاكرة السريعة قريباً من المعالج (سجلات، ثم Cache)، وكثير من الذاكرة البطيئة بعيداً (DRAM). ستلمس هذا المبدأ بيديك في هذه المحاضرة نفسها: سجلات مقابل ذاكرة.
التوازي: إذا لم نستطع جعل العملية الواحدة أسرع، فلننفّذ عمليات كثيرة معاً. من الـPipeline (محاضرة 15) حتى مراكز البيانات — التوازي هو مصدر الأداء الحديث الأول.
المكوّنات تفشل — هذه حقيقة فيزيائية. كيف نبني نظاماً موثوقاً من مكوّنات غير موثوقة؟ بالتكرار: ننفّذ الحساب على ثلاث وحدات متطابقة ونصوّت على النتيجة. إذا قالت وحدتان $1+1=2$ وقالت الثالثة $1+1=1$ — الأغلبية تفوز والوحدة المعطوبة تُكشف وتُعزل، والنظام كله لا يسقط. ولاحظ الترابط الجميل بين الأفكار: قانون مور جعل الترانزستورات رخيصة، فجعل ثمن التكرار مقبولاً. (ستقابل التكرار مجدداً في أكواد كشف الأخطاء وفي فحص العتاد).
لنتتبع مقطع C الشهير الذي يبدّل عنصرين متجاورين في مصفوفة، وهو المثال الكلاسيكي لسلّم التجريد:
temp = v[k]; v[k] = v[k+1]; v[k+1] = temp; — منطق واضح لإنسان: «بدّل الجارين». لا ذكر لسجلات ولا عناوين.lw، lw) ثم تخزينهما متبادلَين (sw، sw). لاحظ: «التبديل» اختفى كمصطلح — بقيت خطوات نقل أولية فقط.0000 1001 1100 0110 1010 1111 0101 1000 — أعداد خالصة. لو قرأتَها كبيانات لما ميّزتها عن أي أعداد أخرى!1.3 الـISA: العقد المقدّس بين البرمجيات والعتاد
وظيفة وحدة المعالجة المركزية (CPU — وتسمى أيضاً نواة، Core) هي شيء واحد: تنفيذ الأوامر. والأوامر هي العمليات البدائية للمعالج — وأفضل تشبيه لها هو الجملة اللغوية: فعل (العملية) يُطبَّق على مفاعيل (المعاملات)، والجمل تُقرأ بالتسلسل... مع أوامر خاصة تغيّر هذا التسلسل (القفزات — سنصل إليها).
قصة فلسفتين: CISC ضد RISC
في العقود الأولى ساد توجّه طبيعي: كل جيل معالجات يضيف أوامر أكثر وأعقد، لتقريب لغة الآلة من لغات البرمجة العليا. بلغ هذا التوجه ذروته الكاريكاتورية في معمارية VAX التي احتوت أمر آلة واحداً لضرب كثيرات الحدود! المشكلة: كل أمر معقد يجعل العتاد كله أعقد وأبطأ — حتى الأوامر البسيطة تدفع الثمن.
في ثمانينيات القرن الماضي جاء الرد الثوري من ثلاثة باحثين — Cocke في IBM، وPatterson في بيركلي، وHennessy في ستانفورد — تحت اسم RISC: Reduced Instruction Set Computing:
وما هو RISC-V تحديداً؟
RISC-V (تُقرأ «ريسك فايف») هو الجيل الخامس من تصاميم RISC في جامعة بيركلي، وله ميزة تاريخية فريدة: إنه مواصفة ISA مفتوحة، بلا رخص وبلا إتاوات — أي معهد أو شركة تستطيع تصميم معالج RISC-V دون إذن من أحد. النتيجة: تبنٍّ متسارع في الصناعة والأكاديميا، تطبيقات مفتوحة المصدر وتجارية، ومنظومة برمجيات مشتركة تنمو باستمرار، ومؤسسة غير ربحية (RISC-V Foundation، بعشرات الأعضاء الكبار) ترعى المعيار. وهو يغطي كل المستويات: من المتحكمات الدقيقة حتى الحواسيب الفائقة، بنسخ 32 و64 و128 بتاً.
1.4 السجلات: «متغيرات» يصنعها العتاد
هنا أول صدمة ثقافية لمن قادم من عالم C أو Java: لغة التجميع لا تعرف المتغيرات التي تحبها. لا أسماء وصفية، لا أنواع، لا تصريحات. بدلاً منها تقدم لك الآلة شيئاً أكثر بدائية وأقرب لما يستطيع العتاد البسيط دعمه مباشرة: السجلات (Registers) — عدد محدود من الخانات الخاصة لحفظ القيم، مبنية داخل المعالج نفسه، وكل العمليات الحسابية تجري عليها وعليها فقط.
- يوجد 32 سجلاً، يُشار إليها بالأرقام
x0حتىx31(ولها أسماء رمزية اصطلاحية سنتعلمها لاحقاً مع بروتوكول الدوال). - عرض كل سجل 32 بتاً — وهذه هي «الكلمة» (word) في RV32.
- لماذا 32 سجلاً بالضبط؟ مبدأ التصميم الحاكم: الأصغر أسرع (Smaller is faster) — ملف سجلات أصغر يعني وصولاً أسرع. لكن الأصغر مما يلزم سيّئ: سنضطر لزيارة الذاكرة البطيئة باستمرار. 32 هي نقطة التوازن التي اختارها المصممون.
- السجل قد يحمل عنوان ذاكرة — لذلك عرض السجل يحدّ حجم الذاكرة القابلة للعنونة: بـ32 بتاً يمكن عنونة $2^{32}$ بايتاً = 4GB فقط (تذكّر هذا الرقم — سيظهر في سؤال بنهاية المحاضرة!).
x0 خاص: قيمته صفر دائماً وإلى الأبد. أي محاولة كتابة إليه تُهمَل بصمت. أي أن لدينا عملياً 31 سجلاً فقط لحمل قيم متغيرة. لماذا «نهدر» سجلاً على الصفر؟ لأن الصفر يظهر في البرامج طوال الوقت، ووجوده كسجل جاهز يتيح حيلاً أنيقة: نسخ سجل (add x3,x4,x0)، تصفير سجل، مقارنة بصفر، وقفزات غير مشروطة — كلها دون أوامر خاصة. أسئلة امتحان كاملة بُنيت على سلوك x0 هذا.int fahr; أو char a;) ولا يمكنه حمل إلا قيماً من نوعه. في الأسمبلي: السجلات بلا أنواع إطلاقاً — السجل يحمل 32 بتاً وحسب، والعملية المطبَّقة هي التي تقرر كيف تُفسَّر محتوياته: نفس البتات قد تُعامل كعدد موقّع في أمر، وكعدد غير موقّع في أمر آخر، وكعنوان في ثالث. هذا التحرر من الأنواع قوة وخطر معاً — والمسؤولية كلها عليك.وأخيراً، لماذا كل هذا الحرص على العمل داخل السجلات؟ السرعة. السجلات مبنية في قلب المعالج، والوصول إليها أسرع من ننو-ثانية — وللإحساس بالمقياس: الضوء نفسه لا يقطع في الننو-ثانية الواحدة سوى 30 سنتيمتراً تقريباً! مقابل ذلك، سعتها الإجمالية هزيلة: 32 كلمة = 128 بايتاً فقط، بينما ذاكرة DRAM تمتد لمليارات البايتات (2–32GB في الحواسيب الشائعة) لكنها أبطأ بـ100 إلى 500 مرة في زمن الوصول الواحد. هذا هو التسلسل الهرمي للذاكرة (الفكرة العظيمة #5) في أوضح تجلياته — والبرنامج الجيد هو الذي يُبقي بياناته الساخنة في السجلات أطول وقت ممكن.
1.5 أول أوامر RISC-V: الحساب والفوريّات
حان وقت كتابة أول أسطر أسمبلي. القاعدة التركيبية بسيطة وصارمة:
add x1, x2, x3 # x1 = محتوى x2 + محتوى x3
- أول كلمة: رمز العملية (opcode) — الفعل.
- أول معامل: سجل الوجهة (Destination) — أين تُكتب النتيجة. (انتبه: الوجهة أولاً! عكس اتجاه القراءة الحدسي عند البعض).
- ثم سجلا المصدر الأول والثاني.
- الرمز
#يبدأ تعليقاً حتى نهاية السطر — استخدم التعليقات بسخاء، فالأسمبلي بلا تعليقات يصبح ألغازاً خلال أيام.
لتكن المطابقة: $a \leftrightarrow x10$، $b \leftrightarrow x1$، $c \leftrightarrow x2$، $d \leftrightarrow x3$، $e \leftrightarrow x4$. كيف نترجم السطر a = b + c + d - e;؟
لا يوجد أمر «اجمع ثلاثة واطرح رابعاً» — فلسفة RISC تقول: فكّك! نبني النتيجة تدريجياً في سجل الوجهة نفسه:
add x10, x1, x2 # temp = b + c
add x10, x10, x3 # temp = temp + d
sub x10, x10, x4 # a = temp - e
لاحظ درسين: (1) سطر C واحد قد يتحول لعدة أوامر آلة — هذا طبيعي تماماً في RISC. (2) استخدمنا سجل الوجهة كمخزن وسيط دون سجل إضافي — عادة اقتصادية مهمة مع 31 سجلاً فقط.
الفوريّات (Immediates): الثوابت مواطنون من الدرجة الأولى
الثوابت العددية تظهر في الكود باستمرار (i++، حدود حلقات، إزاحات...)، فمن الإسراف تحميلها من الذاكرة كل مرة. لذلك توجد أوامر خاصة تحمل الثابت داخل الأمر نفسه:
السطر f = g - 10 (مع $f \leftrightarrow x3$، $g \leftrightarrow x4$) يُترجم إلى:
addi x3, x4, -10 # f = g + (-10)
لا يوجد أمر «subi» — ولا حاجة له: الفوري يمكن أن يكون سالباً، والجمع بسالب هو الطرح. بساطة RISC مرة أخرى.
ومثال ثانٍ يستحق التأمل: كيف ننسخ سجلاً إلى آخر (f = g)؟
add x3, x4, x0 # f = g + 0 = g
ها هو x0 يثبت فائدته: لا حاجة لأمر نسخ خاص — الجمع مع الصفر الدائم يقوم بالمهمة.
1.6 الذاكرة: البايتات والكلمات وسرّ الـLittle-Endian
128 بايتاً من السجلات لا تكفي لبرنامج حقيقي — الصور والمصفوفات والنصوص تسكن الذاكرة. وهنا يفرض RISC-V انضباطاً صارماً هو جوهر ما يسمى معمارية Load/Store: الـALU لا يلمس الذاكرة أبداً. للتعامل معها أمران فقط: تحميل من الذاكرة إلى سجل (Load)، وتخزين من سجل إلى الذاكرة (Store). كل حساب يتم في السجلات حصراً: حمّل ← احسب ← خزّن.
- البيانات غالباً أصغر من 32 بتاً لكن نادراً ما تكون أصغر من 8 بتات (نوع char مثلاً) — لذا وحدة العنونة هي البايت (8 بتات): كل بايت في الذاكرة له عنوان خاص.
- الكلمة = 4 بايتات ← عناوين الكلمات المتتالية تبعد 4 عن بعضها: 0، 4، 8، 12، ...
- عنوان الكلمة = عنوان أصغر بايتاتها، وهذا البايت الأصغر عنواناً هو البايت الأدنى قيمةً (Least Significant Byte) — هذه هي اتفاقية Little-Endian التي يعتمدها RISC-V: «الصغير أولاً».
| العنوان | +3 | +2 | +1 | +0 |
|---|---|---|---|---|
| البتات داخل الكلمة | [31:24] | [23:16] | [15:8] | [7:0] الأدنى |
g = h + A[3]
معطى int A[100]; والسجل x13 يحمل عنوان بداية المصفوفة (مؤشر إلى A[0])، وx12 يحمل $h$. المطلوب حساب $g$ في x11.
الخطوة الحاسمة — حساب الإزاحة: العنصر A[3] يبعد عن البداية 3 عناصر، وكل عنصر int يشغل 4 بايتات:
lw x10, 12(x13) # x10 = A[3] : اقرأ الكلمة من العنوان x13+12
add x11, x12, x10 # g = h + A[3]
الصيغة offset(base) — «إزاحة(قاعدة)» — هي نمط العنونة الوحيد للبيانات في RISC-V: العنوان الفعلي = محتوى سجل القاعدة + الثابت.
A[10] = h + A[3]
lw x10, 12(x13) # x10 = A[3]
add x10, x12, x10 # x10 = h + A[3]
sw x10, 40(x13) # A[10] = x10 : الإزاحة 10×4=40
سؤال دفاعي يطرحه المحاضر: لماذا يجب أن يكون كلٌّ من $x13+12$ و$x13+40$ من مضاعفات الأربعة؟ لأن نقل كلمة كاملة يفترض محاذاة (Alignment) على حدود الكلمات — نقل غير محاذٍ يقع بين كلمتين فيزيائيتين، والعتاد البسيط لا يدعمه. (احتفظ بهذه النقطة — سؤال المراجعة الختامي يحاول الإيقاع بك فيها).
نقل البايتات المفردة: lb و-sb وامتداد الإشارة
إضافة إلى نقل الكلمات، يوفر RISC-V نقل بايت واحد: lb (تحميل بايت) وsb (تخزين بايت)، بنفس صيغة العنونة. لكن هنا سؤال دقيق: البايت 8 بتات والسجل 32 بتاً — بماذا نملأ البتات الـ24 المتبقية؟
lb x10, 3(x11): يُنسخ البايت المقروء إلى البتات [7:0] من السجل، ثم يُنسخ بتُه الأعلى (بت الإشارة، البت رقم 7) إلى كل البتات [31:8]. أي أن بايتاً قيمته 0x80 أو أكثر (بتُه السابع 1) سيملأ السجل بـ0xFFFFFF.. — عدد سالب! هذه النقطة مسؤولة عن نصيب وافر من إجابات الامتحان الخاطئة، وسؤالنا الأول في نهاية المحاضرة مبني عليها بالكامل.استخدم المحوّل لبناء حدسك قبل سؤال الـlb: جرّب 245 (0xF5) ولاحظ بته السابع، ثم جرّب 3:
ما قيمة x12 في نهاية التشغيلة التالية؟ (افترض أن x5 يحمل عنواناً محاذى صالحاً)
addi x11, x0, 0x3f5
sw x11, 0(x5)
lb x12, 1(x5)
خطوة 1 — ماذا يوجد في x11؟ 0x3f5 بالثنائي: $0011\,1111\,0101$، وككلمة 32-بت كاملة: 0x000003f5.
خطوة 2 — كيف تُخزَّن في الذاكرة؟ Little-Endian: البايت الأدنى في العنوان الأصغر:
| العنوان | x5+0 | x5+1 | x5+2 | x5+3 |
|---|---|---|---|---|
| البايت | 0xf5 | 0x03 | 0x00 | 0x00 |
خطوة 3 — ماذا يقرأ lb من العنوان x5+1؟ البايت 0x03. بتُه السابع = 0 ← امتداد الإشارة يملأ الباقي أصفاراً ← x12 = 0x00000003. ✔ الإجابة: ج.
📌 لاحظ الفخّين المزروعين: من نسي الـLittle-Endian اختار «ب» (0xf من البايت الأول)، ومن ظن أن الامتداد يحدث دائماً بالواحدات اختار «د».
1.7 الأوامر المنطقية والإزاحات: جراحة البتات
كثيراً ما نحتاج للعمل على حقول بتات داخل الكلمة — حرف 8-بت معبأ داخل كلمة، أعلام حالة، أقنعة... لهذا الغرض توجد العمليات المنطقية، وهي تطابق مؤثرات C التي تعرفها:
| العملية المنطقية | مؤثر C/Java | أمر RISC-V |
|---|---|---|
| AND بتاً-بتاً (إخفاء/قناع) | & | and |
| OR بتاً-بتاً (إشعال بتات) | | | or |
| XOR بتاً-بتاً (قلب بتات) | ^ | xor |
| إزاحة لليسار منطقية | << | sll / slli |
| إزاحة لليمين منطقية | >> | srl / srli |
slli x11, x12, 2 — أزح محتوى x12 بتّين لليسار (البتات المطرودة من اليسار تسقط، وأصفار تدخل من اليمين):
قبل: 0000 0000 0000 0000 0000 0000 0000 0010 (= 2)
بعد: 0000 0000 0000 0000 0000 0000 0000 1000 (= 8)
الأثر الحسابي: إزاحة $k$ بتات لليسار = ضرب في $2^k$ (هنا: $2\times2^2=8$ ✔). وبالتناظر، srli (أصفار تدخل من اليسار) = قسمة على $2^k$ — للأعداد غير السالبة. تذكّر حساب الإزاحة offset=12 في مثال المصفوفة؟ المترجم ينفّذ «الفهرس × 4» بإزاحة slli بمقدار 2 — أرخص بكثير من الضرب الحقيقي.
للأعداد السالبة (متمّم لـ2) توجد إزاحة يمين حسابية: srai تدخل نسخاً من بت الإشارة من اليسار بدل الأصفار، حفاظاً على السالبية. مثال من الشرائح: x10 يحمل $-25$:
1111 1111 1111 1111 1111 1111 1110 0111 (= -25)
srai x10, x10, 4:
1111 1111 1111 1111 1111 1111 1111 1110 (= -2)
لكن انتبه: $-25/16$ في لغة C يساوي $-1$ (القسمة الصحيحة في C تقرّب نحو الصفر)، بينما srai أعطت $-2$ (تقرّب نحو الأسفل، $-\infty$). أي أن srai لا تكافئ القسمة على $2^k$ للأعداد السالبة الفردية — والمترجمون يعرفون ذلك ويضيفون تصحيحاً عند الحاجة. نقطة امتحانية من الطراز الأول.
1.8 اتخاذ القرار: القفزات وبنى التحكم
حتى الآن برامجنا خط مستقيم: أمر يتلو أمراً. لكن جوهر الحوسبة هو القرار: «إذا كان كذا افعل كذا». في العتاد لا توجد if — يوجد شيء أبسط وأقوى: القفزة (Branch)، أي تغيير مسار تنفيذ الأوامر:
- قفزات مشروطة — تُنفَّذ فقط إذا تحقق شرط على سجلّين:
beq r1, r2, L— اقفز إلى الوسم L إذا تساوى المحتويان (Branch if EQual).
bne r1, r2, L— اقفز إذا اختلفا (Branch if Not Equal).
blt r1, r2, L— اقفز إذا كان الأول أصغر (مقارنة موقّعة).
bge r1, r2, L— اقفز إذا كان الأول أكبر أو يساوي (موقّعة). - قفزة غير مشروطة:
j L— اقفز دائماً.
0xFFFFFFFF هي $-1$ إذا فسّرناها موقّعة، و$4{,}294{,}967{,}295$ إذا فسّرناها غير موقّعة. لذلك توجد نسختان من مقارنة الترتيب: blt تعامل السجلات كأعداد موقّعة، وbltu (Unsigned) تعاملها كأعداد غير موقّعة. اختيار الأمر هو الذي «يعطي النوع» للبتات — تجسيد مباشر لمبدأ «العملية تحدد التفسير».النمط الأول: ترجمة if
if (i == j) f = g + h;
بالمطابقة $f,g,h,i,j \leftrightarrow x10,x11,x12,x13,x14$:
bne x13, x14, Exit # إذا i != j تخطَّ الجسم
add x10, x11, x12 # f = g + h
Exit:
توقف هنا وتأمل الحيلة — فهي أهم من المثال نفسه: الشرط في C هو المساواة (==)، لكن الأمر الذي استخدمناه هو bne — عكس الشرط! لماذا؟ لأن منطق الآلة هو «متى أتخطى الجسم؟»: نقفز فوق الجسم عندما يفشل الشرط. هذا القلب المنطقي هو النمط القياسي في كل ترجمة تحكم، وإغفاله أشهر خطأ مبتدئين (وفخ خيارات مفضّل في الامتحان).
النمط الثاني: ترجمة if-else
if (i == j) f = g + h; else f = g - h;
bne x13, x14, Else # فشل الشرط؟ اذهب لفرع else
add x10, x11, x12 # فرع if: f = g + h
j Exit # مهم! لا تسقط في فرع else
Else: sub x10, x11, x12 # فرع else: f = g - h
Exit:
لاحظ الأمر j Exit: بدونه، بعد تنفيذ فرع if سيواصل المعالج «بالسقوط» إلى فرع else وينفّذهما معاً — خطأ صامت وقاتل. القفزة غير المشروطة هي «جدار» يفصل الفرعين.
النمط الثالث: الحلقة الكاملة — تتويج المحاضرة
المطلوب ترجمة:
int A[20];
int sum = 0;
for (int i = 0; i < 20; i++)
sum += A[i];
الترجمة (بافتراض x8 يحمل عنوان A):
add x9, x8, x0 # x9 = &A[0] مؤشر متحرك على المصفوفة
add x10, x0, x0 # sum = 0
add x11, x0, x0 # i = 0
addi x13, x0, 20 # x13 = 20 حد الحلقة
Loop: lw x12, 0(x9) # x12 = A[i] حمّل العنصر الحالي
add x10, x10, x12 # sum += A[i]
addi x9, x9, 4 # قدّم المؤشر عنصراً واحداً (4 بايتات!)
addi x11, x11, 1 # i++
blt x11, x13, Loop # ما دام i أصغر من 20 — كرّر
افحص كيف اجتمعت كل أدوات المحاضرة في تسعة أسطر: نسخ بـx0، فوريّات، lw بعنونة قاعدة+إزاحة، تقدّم مؤشر بالبايتات (4 لكل int — ها هي الإزاحة مجدداً)، وقفزة مقارنة موقّعة تغلق الحلقة. لاحظ الأسلوب الاحترافي: بدل إعادة حساب العنوان A + 4i في كل دورة، نمشي بالمؤشر نفسه خطوة-خطوة (addi x9,x9,4) — نمط «pointer walking» الذي ستراه في كل امتحان.
1.9 خلاصة المحاضرة: ماذا في جعبتك الآن؟
| الأمر | مثال | المعنى |
|---|---|---|
| add / sub | add x10, x1, x2 | جمع/طرح سجلّين إلى سجل وجهة |
| addi | addi x3, x4, -10 | جمع سجل مع ثابت فوري (الطرح: فوري سالب) |
| lw / sw | lw x10, 12(x13) | نقل كلمة بين الذاكرة وسجل، عنونة قاعدة+إزاحة |
| lb / sb | lb x10, 3(x11) | نقل بايت واحد — lb يمدّد الإشارة! |
| and / or / xor | and x5, x6, x7 | عمليات منطقية بتاً-بتاً |
| slli / srli | slli x11, x12, 2 | إزاحة منطقية: ضرب/قسمة على $2^k$ |
| srai | srai x10, x10, 4 | إزاحة يمين حسابية (نسخ بت الإشارة) |
| beq / bne | beq x1, x2, L | قفزة مشروطة بمساواة/اختلاف |
| blt / bge / bltu | blt x11, x13, L | قفزات ترتيب — موقّعة أو غير موقّعة (u) |
| j | j Loop | قفزة غير مشروطة |
وأربع جمل تختصر المحاضرة كلها: الـISA تحدد مجموعة الأوامر التي ينفّذها الحاسوب — إنها العقد بين البرمجيات والعتاد. السجلات توفر حفنة «متغيرات» فائقة السرعة تعمل عليها الأوامر. فلسفة RISC-V تُلزم البرمجيات بتفكيك العمليات المعقدة إلى سلاسل أوامر بسيطة — مقابل عتاد أبسط وأسرع. والأسمبلي ما هو إلا الصيغة المقروءة بشرياً للغة الآلة الثنائية، يحوّلها الـAssembler إلى بتات.
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية صحيح؟
أ خاطئ: هذه معمارية Load/Store: الأوامر الحسابية تعمل على سجلات وفوريّات فقط — لا يوجد معامل ذاكرة داخل add. الوصول للذاكرة حكر على عائلة lw/sw/lb/sb.
ب خاطئ: كلمة RV32 = 32 بتاً ← تعنون $2^{32}$ بايتاً = 4GB كحد أقصى، لا 8GB. (هذا بالمناسبة أحد أسباب وجود RV64).
ج خاطئ والفخ دقيق: شرط المحاذاة يقع على العنوان الفعلي $x10 + imm$ أن يكون مضاعفاً للأربعة، لا على الفوري وحده. فوري مثل 6 صالح تماماً إذا كانت القاعدة تجعل المجموع محاذى (مثلاً قاعدة 2). ✔ الإجابة: د.
السجل x10 يحمل القيمة $-25$ (أي 0xFFFFFFE7). نُفِّذ الأمر srai x10, x10, 4. ما القيمة الجديدة، وهل تطابق ناتج -25/16 في لغة C؟
srai تُدخل نسخاً من بت الإشارة (1 هنا) من اليسار: $\;1111...1110\,0111 \to 1111...1111\,1110 = -2$.
أما C: القسمة الصحيحة تقرّب نحو الصفر: $-25/16 = -1.5625 \to -1$. بينما srai كافأت التقريب نحو $-\infty$: $\lfloor-1.5625\rfloor = -2$. التطابق يفشل لكل عدد سالب لا يقبل القسمة — لذلك «srai = قسمة على $2^k$» صحيحة فقط للأعداد غير السالبة (أو السالبة التي تقسم بلا باقٍ). الخيار ج هو ناتج srli (المنطقية) — فخ التمييز الكلاسيكي بين الأمرين. ✔ الإجابة: أ.
بالمطابقة $f,g,h,i,j \leftrightarrow x10,x11,x12,x13,x14$، أي مقطع يترجم بشكل صحيح الكود: if (i == j) f = g + h; else f = g - h;؟
قاعدتان تحسمان السؤال: (1) اقلب الشرط: شرط C هو المساواة، والقفزة تتخطى فرع if عند فشله ← نستخدم bne نحو Else. (2) سُدّ الطريق: بعد فرع if يلزم j Exit وإلا «سقطنا» في فرع else ونفّذنا الفرعين معاً.
الخيار أ يستخدم beq (لم يقلب الشرط ← ينفّذ الجمع عندما $i \neq j$ — معكوس). الخيار ج ينسى القفزة الوسطى ← عند تحقق الشرط يُنفَّذ add ثم sub فتضيع النتيجة. الخيار د ينفّذ sub دائماً قبل الوصول لـExit. ✔ الإجابة: ب.
أي من الادعاءات التالية صحيح بخصوص RV32؟
أ خاطئ: الكتابة إلى x0 تُهمل بصمت — لا استثناء ولا خطأ؛ هذه ميزة تصميمية تُستغل عمداً (مثل القفز دون حفظ عنوان عودة).
ب خاطئ: السجلات بلا أنواع — 32 بتاً خاماً، والعملية (blt مقابل bltu مثلاً) هي التي تفرض التفسير.
ج صحيح: 32 سجلاً × 4 بايتات = 128 بايتاً، بزمن وصول دون الننو-ثانية، مقابل DRAM أبطأ بـ100–500 مرة — وهذا بالضبط مبرر التسلسل الهرمي للذاكرة وفلسفة Load/Store.
د خاطئ: RISC-V يعتمد Little-Endian: عنوان الكلمة = عنوان بايتها الأدنى قيمةً. ✔ الإجابة: ج.
جبر المفاتيح ودوالّ المفاتيح: اللغة الرياضية للعتاد الرقمي
2.1 لماذا يحتاج العتاد إلى جبر خاص به؟ قصة اكتشافٍ من طبقتين
في المحاضرة الأولى رأينا أن كل شيء داخل الحاسوب — أوامر وبيانات — يُختزل إلى أنماط من 0 و1. السؤال الطبيعي التالي: إذا كانت مداخل دارتنا ومخارجها كلها من عالم $\{0,1\}$، فما الأداة الرياضية التي تصف العلاقة بين المخارج والمداخل، وتسمح لنا بمقارنة دارتين والحكم بتكافئهما، وبتبسيط دارة معقدة إلى أرخص مكافئ لها؟ نحتاج إلى ما يشبه الجبر العادي، لكنه يعمل على قيم الحقيقة بدل الأعداد.
القصة التاريخية من فصلين: في منتصف القرن التاسع عشر وضع عالم الرياضيات جورج بول (George Boole) — في كتابيه «التحليل الرياضي للمنطق» (1847) و«بحث في قوانين الفكر» (1854) — نظاماً جبرياً تكون قيم متغيراته «صواباً» أو «خطأً» (نرمز لهما 1 و0)، وعملياته هي العطف المنطقي (AND، $\wedge$)، والفصل المنطقي (OR، $\vee$)، والنفي (NOT، $\neg$) — صياغة شكلية للعلاقات المنطقية تماماً كما يصوغ الجبر العادي العلاقات العددية. وبقي هذا «جبر بول» قرابة قرنٍ فكرةً منطقيةً مجردة، حتى جاء الفصل الثاني: في ثلاثينيات القرن العشرين لاحظ كلود شانون (Claude Shannon)، وهو يدرس دارات المفاتيح الكهربائية، أن قواعد جبر بول تنطبق على هذه الدارات انطباقاً مدهشاً — فولد جبر المفاتيح (Switching Algebra): الحالة الخاصة الثنائية من جبر بول، مطبَّقةً على العتاد. ومنذها صار «جبر المفاتيح» و«جبر بول» شبه مترادفين في سياقنا.
2.2 التعريف الرسمي: مجموعة من عنصرين وثلاث عمليات
جبر المفاتيح هو البنية المكوّنة من:
- المجموعة $\{0,1\}$ — وبالاتفاق المنطقي: الثابت 1 يمثل «الصواب» (TRUE) والثابت 0 يمثل «الخطأ» (FALSE) — وهذان هما «قيمتا الحقيقة».
- عمليتان ثنائيتان (تعملان على معاملَين): OR ويُرمز لها $+$ (أو |)، وAND ويُرمز لها $\cdot$ (أو &).
- عملية أحادية (تعمل على معامل واحد): NOT ويُرمز لها بالفاصلة العليا $x'$ أو الشرطة $\bar{x}$.
| $x$ | $y$ | $x \cdot y$ (AND) | $x+y$ (OR) |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 |
و‑NOT: $0'=1$، $1'=0$.
ونضبط المفردات: ثابت مفاتيح هو أحد القيمتين '0' أو '1'. ومتغير مفاتيح هو متغير (مثل $x, y, z$) لا يحمل إلا إحدى القيمتين. ومن ثنائية القيم تنبع خاصية صغيرة سنستعملها ضمنياً في كل برهان: إذا $x \neq 0$ فحتماً $x=1$، وإذا $x \neq 1$ فحتماً $x=0$ — لا توجد منطقة وسطى.
2.3 تعابير المفاتيح: قواعد بناء الجُمل في هذه اللغة
تعبير المفاتيح هو تركيب منتهٍ من متغيرات مفاتيح وثوابت مفاتيح وعمليات مفاتيح، يُعرَّف استقرائياً:
- كل متغير مفاتيح وكل ثابت مفاتيح هو تعبير مفاتيح (قاعدة الأساس).
- إذا كان $T_1$ و$T_2$ تعبيري مفاتيح، فكذلك $T_1+T_2$ و$T_1\cdot T_2$ و$(T_1)'$ (قاعدة التركيب).
- أي تركيب رموز لا يُبنى بهاتين القاعدتين ليس تعبير مفاتيح.
- $(x+y)\cdot z\cdot y$ — تعبير شرعي: بُني بالتدرج من متغيرات ثم جمع ثم ضرب.
- $z''''''$ — شرعي تماماً رغم غرابته! النفي عملية أحادية يمكن تكرارها كما نشاء (وست��لّمنا مطابقة النفي المزدوج لاحقاً أنه يساوي $z$ لأن عدد النفيات زوجي).
- $x{+}{+}y$ — ليس تعبيراً: لا توجد قاعدة تسمح بعمليتين ثنائيتين متتاليتين دون معامل بينهما.
قيمة تعبير تحت إسناد (השמה)
قيمة (حقيقة) تعبير $T$ تحت إسنادٍ لقيم متغيراته هي القيمة التي يعطيها التعبير عندما نضع مكان كل متغير قيمته المُسندة، ثم نحسب بالجداول. لنحسب مثال الشرائح حرفياً، بالخطوات الصغيرة:
2.4 المطابقات: قوانين اللعبة وإثباتها بالاستقراء الكامل
والآن، الترسانة الكاملة. احفظ هذا الجدول كما تحفظ جدول الضرب — وستلاحظ أنه مكتوب أزواجاً أزواجاً لسببٍ سيتضح فوراً بعده:
| # | القانون | صيغة OR | صيغة AND (الثنائية) |
|---|---|---|---|
| 1 | التطابق (Idempotence) | $x+x=x$ | $x\cdot x=x$ |
| 2 | القيم المحايدة والمسيطرة | $x+0=x\;$ و $\;x+1=1$ | $x\cdot 1=x\;$ و $\;x\cdot 0=0$ |
| 3 | التبديل (Commutativity) | $x+y=y+x$ | $x\cdot y=y\cdot x$ |
| 4 | التجميع (Associativity) | $(x+y)+z=x+(y+z)$ | $(xy)z=x(yz)$ |
| 5 | المتمّم (Complementation) | $x+x'=1$ | $x\cdot x'=0$ |
| 6 | التوزيع (Distributivity) | $x(y+z)=xy+xz$ | $x+yz=(x+y)(x+z)$ |
| 7 | الابتلاع الأول (Absorption) | $x+xy=x$ | $x(x+y)=x$ |
| 8 | الابتلاع الثاني | $x+x'y=x+y$ | $x(x'+y)=xy$ |
| 9 | الإجماع (Consensus) | $xy+x'z+yz=xy+x'z$ | |
| 10 | النفي المزدوج (Involution) | $(x')'=x$ | |
| 11 | دي-مورغان (De Morgan) | $(x+y)'=x'\,y'$ | $(xy)'=x'+y'$ |
مبدأ الثنائية (עקרון הדואליות): برهانٌ واحد بسعر اثنين
إذا صحّت المطابقة $$P(x,y,\dots,0,1,AND,OR,NOT)=Q(x,y,\dots,0,1,AND,OR,NOT)$$ صحّت أيضاً المطابقة الناتجة عن التبديل الشامل: $AND \leftrightarrow OR$ و $0 \leftrightarrow 1$ (مع بقاء المتغيرات و‑NOT كما هي): $$P(x,y,\dots,1,0,OR,AND,NOT)=Q(x,y,\dots,1,0,OR,AND,NOT)$$
جوهر البرهان: التماثل بين جدولي AND و‑OR: اقلب كل الأصفار آحاداً والآحاد أصفاراً في جدول AND — تحصل حرفياً على جدول OR. فأي برهان استقراء كامل لمطابقةٍ ما «ينقلب» تلقائياً برهاناً لثنائيّتها.
النتيجة العملية: يكفي إثبات مطابقة واحدة من كل زوج — والثانية مجانية. لهذا كُتب الجدول أعلاه بعمودين متقابلين: كل سطر زوجٌ ثنائي. مثال آلي على التحويل: ثنائيّ التعبير $(1+A)(B+0)$ هو $(0\cdot A)+(B\cdot 1)$.
إثباتات جبرية: القوانين تبني بعضها بعضاً
الاستقراء الكامل يثبت كل شيء، لكنه ممل مع كثرة المتغيرات. الطريق الثاني: الاشتقاق من مطابقات أُثبتت قبلاً — وهذا ما ستفعله في الامتحان. شاهد كيف تُبنى قوانين الابتلاع من القوانين الأبسط، بذكر رقم القانون المستعمل في كل خطوة (تماماً كأسلوب الشرائح):
قراءة الخطوات: أدخلنا المحايد ($x=x\cdot1$)، استخرجنا عاملاً مشتركاً بالتوزيع، ثم ابتلع المسيطر $1$ الجمعَ ($1+y=1$)، وعاد المحايد فاختفى. والصيغة الثنائية $x(x+y)=x$ تصح فوراً بمبدأ الثنائية — أو ببرهان مواز: $x(x+y)\overset{(2)}{=}(x+0)(x+y)\overset{(6ب)}{=}x+0\cdot y\overset{(2)}{=}x$.
لاحظ البطل الخفي: التوزيع الثاني «غير المدرسي» هو الذي فتح البرهان. والثنائية تعطينا مجاناً: $x(x'+y)=xy$. المعنى الحدسي يستحق ثانية من التأمل: في $x+x'y$، إذا كان $x=1$ فالنتيجة 1 أصلاً؛ وإذا $x=0$ فالحد الثاني يصبح $y$ — إذن العامل $x'$ لا يضيف معلومة: «إمّا $x$، وإلا فـ$y$ تكفي».
💡 جرّب أن تجد المثال المضاد بنفسك قبل فتحه
قانون الإجماع (קונצנזוס): الحدّ الزائد الذي يختفي
تشريح الخطوة الوسطى — أدقّ ما في المثال: داخل القوس طبّقنا الابتلاع الثاني على الزوج $y+x'y'$ باعتبار $y$ هو «$x$» القانونِ و$x'$ هو «$y$» القانونِ... التفصيل: $y+y'(x')=y+x'$ (القانون 8 بإحلال $y\to x,\ x'\to y$). ثم بقي $x'+y+x=(x+x')+y=1+y=1$. التعبير الثلاثي الحدود كلّه كان قناعاً للدالة $z$!
2.5 قوانين دي-مورغان: آلة قلب التعابير
قانونا القائمة (10) و(11) هما عدّة التعامل مع المتمّمات. النفي المزدوج $(x')'=x$ بديهي من الجدول. أما دي-مورغان فيقولان شيئاً عميقاً: نفي الجمع ضربُ نفيَين، ونفي الضرب جمعُ نفيَين — النفي «يعبر» القوس فيقلب العملية:
$$(x+y)'=x'\cdot y' \qquad\qquad (x\cdot y)'=x'+y'$$البرهان استقراء كامل قياسي (جدول من 4 أسطر يقارن $(x+y)'$ مع $x'y'$ — تطابق تام). المهارة المطلوبة امتحانياً هي التطبيق المتسلسل:
ثلاث خطوات، ثلاثة قوانين: دي-مورغان على الجمع الخارجي، ثم على الضرب الداخلي، ثم نفيٌ مزدوج ينظّف $(y')'$. لا تختصر الخطوات ذهنياً في البداية — الاختصار يأتي وحده مع التمرين.
بكلمات: لنفي تعبيرٍ كامل — انفِ كل حرف (literal)، بدّل كل ثابت، واقلب كل عملية. مثال فوري: $(x'+y+z)'=(x')'\,y'\,z'=x\,y'z'$.
وتنبيهان دقيقان من الشرائح نفسها: (1) النفيات الجاهزة على المتغيرات تنقلب هي أيضاً ($x'$ يصبح $x$) — قاعدة «انفِ كل حرف» تتكفل بذلك؛ (2) لا تخلط بين هذا وبين الثنائية: المعمَّم يعطيك متمّم التعبير (دالة جديدة تعاكس الأصل سطراً سطراً)، بينما الثنائية تعطي تعبيراً آخر لا علاقة قيمية مباشرة له بالأصل — الثنائية لا تنفي الحروف، والمعمَّم ينفيها. هذا الفرق هو مادة سؤال اختيار من متعدد جاهز.
2.6 من التعابير إلى الدوالّ: ما الذي «يوجد» فعلاً؟
جدول الحقيقة لـ$n$ متغيرات فيه $2^n$ أسطر. تحديد دالّة = اختيار 0 أو 1 لكل سطر باستقلال — أي اختيار متجه ثنائي بطول $2^n$، وعدد هذه المتجهات:
$$N=2^{\,2^n}$$للاطمئنان: $n=1$ يعطي 4 دوالّ، $n=2$ يعطي 16، $n=3$ يعطي 256، $n=4$ يعطي 65536 — انفجار مزدوج الأسّية. (نمط سؤال امتحان مضمون: «قُيّدت $k$ أسطر من الجدول — كم دالّة تحقق القيد؟» والجواب دائماً $2^{2^n-k}$).
ولحالة $n=2$ تحديداً، الدوالّ الـ16 كلها معروفة بالاسم — وهذا الجدول من الشرائح يستحق تأملاً حقيقياً:
| $x_1,x_2$ | 0 | NOR | $x_1'x_2$ | $x_1'$ | $x_1x_2'$ | $x_2'$ | XOR | NAND | AND | XNOR | $x_2$ | $x_1'{+}x_2$ | $x_1$ | $x_1{+}x_2'$ | OR | 1 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0,0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
| 0,1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
| 1,0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
| 1,1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| الرقم | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
💡 ما سرّ الترقيم الست-عشري 0…F في السطر الأخير؟
2.7 الصيغتان القانونيتان: هوية موحَّدة لكل دالّة
ما دامت الدالّة الواحدة تقبل تعابير كثيرة، نحتاج صيغة معيارية: شكل متفق عليه، وحيد لكل دالّة، يتيح المقارنة الفورية — تعبيران يمثلان نفس الدالّة إذا وفقط إذا كانت صيغتاهما القانونيتان متطابقتين (حتى تبديل ترتيب الحدود). نعرّف صيغتين متثانيتين:
الحدّ الأصغري (minterm): مضروبٌ يحتوي كل المتغيرات الـ$n$ (كل متغير كحرفٍ موجب أو منفي). خاصيته المميزة: يساوي 1 في سطر واحد بالضبط من الجدول — السطر الذي «يطابق توقيعه»: المتغير المنفي في المضروب يقابل 0 في السطر، والموجب يقابل 1.
البناء: بما أن جمع حدود يساوي 1 عندما يضيء أحدها على الأقل، فإن جمع الحدود الأصغرية المقابلة لأسطر الـ1 في الجدول يعيد إنتاج الدالّة بالضبط: $$f=\sum_{\text{أسطر } f=1} m_i$$ وتسمى الصيغة أيضاً DNF (Disjunctive Normal Form)، ولها اختزال رقمي أنيق: $f=\Sigma(\dots)$ بأرقام الأسطر العشرية.
معطى جدول حقيقة (بترتيب $x,y,z$ والترميز العشري للسطر) تضيء فيه الأسطر 0,2,3,6,7. نبني الحدّ الأصغري لكل سطر — التوقيع فوق كل مضروب:
$$f(x,y,z)=\underbrace{x'y'z'}_{000}+\underbrace{x'yz'}_{010}+\underbrace{x'yz}_{011}+\underbrace{xyz'}_{110}+\underbrace{xyz}_{111}$$تدرّب على القراءة العكسية أيضاً: من المضروب $xyz'$ نقرأ فوراً «السطر $110$ = السطر 6». ومثال أصغر للتحقق الذاتي: الدالّة التي تضيء في السطرين 0 و4 فقط هي $f=x'y'z'+xy'z'$.
بالثنائية الكاملة: الحدّ الأعظمي (maxterm) هو مجموعٌ يحوي كل المتغيرات الـ$n$، ويساوي 0 في سطر واحد بالضبط (توقيعه معكوس: المتغير الموجب يقابل 0 في السطر، والمنفي يقابل 1). وبما أن ضرب عوامل يساوي 0 عندما ينطفئ أحدها، فإن ضرب الحدود الأعظمية المقابلة لأسطر الـ0 يبني الدالّة: $$f=\prod_{\text{أسطر } f=0} M_i$$ وتسمى أيضاً CNF (Conjunctive Normal Form)، واختزالها $f=\Pi(\dots)$.
أسطر الصفر في مثالنا هي 1 ($001$)، 4 ($100$)، 5 ($101$). حدّها الأعظمي — اقلب كل بت إلى حرف: البت 0 يعطي المتغير موجباً، والبت 1 يعطيه منفياً:
$$f(x,y,z)=\underbrace{(x+y+z')}_{001}\underbrace{(x'+y+z)}_{100}\underbrace{(x'+y+z')}_{101}$$تحقّق من المنطق: خذ السطر 4 ($x=1,y=0,z=0$): العامل $(x'+y+z)=0+0+0=0$ فيصفّر الضرب كله — بينما في أي سطر آخر تضيء كل العوامل. هذا بالضبط دور الـmaxterm.
لاحظ الجمال: $f=\Sigma(0,2,3,6,7)=\Pi(1,4,5)$ — قائمتا الأرقام تتكاملان: كل سطر إمّا في قائمة الآحاد أو في قائمة الأصفار. ومن دي-مورغان المعمَّم ينبع الرابط الكامل مع المتمّم:
$$f'=\Sigma(1,4,5)=\Pi(0,2,3,6,7)$$أي: لنفي دالّة بصيغها الرقمية — بدّل القائمتين. وللاشتقاق اليدوي: خذ $f'$ كـSoP على أسطر الصفر، انفِه بدي-مورغان المعمَّم، فتتحول كل $m_i$ إلى $M_i$ — هكذا وُلدت صيغة PoS أصلاً في الشرائح.
تحويل تعبير حرّ إلى الصيغة القانونية — دون جدول حقيقة
- افحص كل مضروب في التعبير: إن كان حدّاً أصغرياً (يحوي كل المتغيرات) — انتقل للذي يليه.
- وإلا — التوسيع: اضرب المضروب بـ$(x_i+x_i')$ عن كل متغير $x_i$ غائب عنه، ثم افتح الأقواس واحذف المكررات ($m+m=m$ بالتطابق).
هنا نضيف المتغير الغائب إلى كل مجموع عبر $+x_ix_i'$ ثم نشطر بالتوزيع الثاني: العامل $x'$ ينقصه $y,z$: $$x' = x'+yy'+zz' = (x'+y+z)(x'+y+z')(x'+y'+z)(x'+y'+z')$$ والعامل $(y'+z)$ ينقصه $x$: $(y'+z+xx')=(x+y'+z)(x'+y'+z)$. نضرب الكل ونحذف العامل المكرر $(x'+y'+z)$: $$g=\Pi(2,4,5,6,7)=\Sigma(0,1,3)=x'y'z'+x'y'z+x'yz$$ تمرّن على قراءة أحد الأعظميات تحققاً: $(x+y'+z)$ صفرٌ فقط عند $x=0,y=1,z=0$ — السطر 2 ✔.
2.8 مبرهنة التوسيع لشانون/بول: البرهان الذي يقف خلف كل شيء
بقي سؤال نظري معلّق: قلنا إن «لكل دالّة صيغة قانونية» — لكن لماذا هذا مضمون دائماً؟ الجواب مبرهنة قصيرة ستلاحقك (لصالحك) حتى آخر المساق:
البرهان — استقراء كامل على $x_1$ وحده (وهذا لطفه: متغير واحد، حالتان): ضع $x_1=0$: الطرف الأيمن يصبح $0\cdot f(1,\dots)+1\cdot f(0,\dots)=f(0,x_2,\dots,x_n)$ — وهو الطرف الأيسر بالضبط عند $x_1=0$ ✔. وضع $x_1=1$: يصبح $1\cdot f(1,\dots)+0\cdot f(0,\dots)=f(1,x_2,\dots,x_n)$ ✔. ∎
المعنى الهندسي: المبرهنة تشطر أي دالّة إلى نصفين أبسط: «عالَم $x_1=1$» و«عالَم $x_1=0$»، مع $x_1$ نفسه حَكَماً يختار العالَم الساري. والآن شاهد كيف تلد الصيغةَ القانونية: طبّق التوسيع على $x_1$، ثم على $x_2$ داخل كل نصف:
$$f=x_1x_2 f(1,1,\dots)+x_1x_2' f(1,0,\dots)+x_1'x_2 f(0,1,\dots)+x_1'x_2' f(0,0,\dots)$$واصل حتى آخر متغير — تحصل على:
$$f=\sum_{\text{كل التوليفات}} (\text{الحد الأصغري})\cdot f(\text{التوليفة})$$2.9 دالّة XOR: نجمة الدوالّ الست-عشرة
من بين الـ16 دالّة الثنائية، تستحق $XOR$ (الرمز $\oplus$ — «أو الحصرية») ملفاً خاصاً، فهي عمود فقري في الحساب الثنائي وأكواد الأخطاء:
$x\oplus y=1$ إذا وفقط إذا اختلف المدخلان ($x=1$ أو $y=1$ لكن ليس كلاهما). قراءة مكافئة: جمع بمقياس 2 — باقي قسمة $x+y$ العددي على 2. الخواص (كلها قابلة للإثبات بالاستقراء الكامل):
| الخاصية | الصيغة |
|---|---|
| تبديل وتجميع | $A\oplus B=B\oplus A$، $A\oplus(B\oplus C)=(A\oplus B)\oplus C$ |
| توزيع AND عليها | $A(B\oplus C)=(AB)\oplus(AC)$ |
| كاشف الاختلاف | $A=B \iff A\oplus B=0$ |
| مع الثوابت | $A\oplus 0=A$، $A\oplus 1=A'$ |
| مع النفس والمتمّم | $A\oplus A=0$، $A\oplus A'=1$ |
| النفي «ينزلق» | $(A\oplus B)'=A'\oplus B=A\oplus B'=EQ(A,B)$ أي XNOR |
2.10 الأنظمة الكاملة وظيفياً: بأي عدّة نستطيع بناء «كل شيء»؟
سؤال الختام عملي بامتياز: مصنعك ينتج نوعاً واحداً أو نوعين من البوابات — هل يكفي ذلك لبناء أي دالّة مفاتيح مهما كانت؟
- $\{AND, OR, NOT\}$ كاملة — البرهان هو الصيغة القانونية نفسها: كل دالّة تُكتب SoP، والـSoP لا يستخدم إلا الضرب والجمع والنفي. ∎
- $\{AND, NOT\}$ و$\{OR, NOT\}$ كاملتان — دي-مورغان يصنع العملية الناقصة من الموجودتين: $x+y=(x'y')'$ والعكس.
- وبالتالي: أي مجموعة تستطيع تركيب (ضربٍ ونفي) أو (جمعٍ ونفي) — كاملة. هذا هو المعيار العملي الذي ستطبّقه في كل سؤال من هذا النوع.
المؤثّر $\downarrow$ (NOR: $x\downarrow y=(x+y)'$) يشكّل وحده نظاماً كاملاً — والمؤثّر الوحيد الكامل يسمى عالمياً (Universal). البرهان ببناء $\{OR,NOT\}$ منه:
$$x\downarrow x=(x+x)'=x' \quad\text{(نفيٌ — بتشعيب المعامل)}$$ $$(x\downarrow y)\downarrow(x\downarrow y)=\big((x+y)'\big)'=x+y \quad\text{(جمعٌ — نفي النفي)}$$وبالتناظر الثنائي الكامل، $NAND$ عالمية أيضاً: $NAND(x,x)=x'$ و$NAND$ بعد نفيٍ تعطي AND. لهذا السبب العميق ترى المعالجات مبنية بحراً من NAND/NOR — بوابة واحدة رخيصة، وكل الدوالّ في متناولها.
وكيف نثبت أن نظاماً ليس كاملاً؟
- الاستقصاء: إظهار — بفحص كل التركيبات الممكنة — أن دالّة محددة (عادة NOT أو AND) غير قابلة للبناء.
- الخاصية الصامدة (الأنجع): إيجاد خاصية $P$ تحققها كل عناصر المجموعة وتنتقل بالتركيب، ثم إبراز دالّة لا تحققها — فتكون خارج المدى إلى الأبد. (أشهر خاصيتين: «الخطيّة» و«الرتابة»).
- العدّ: إثبات أن عدد الدوالّ القابلة للتركيب أصغر من $2^{2^n}$.
جرّب أن تصنع ثابتاً أو نفياً من XOR وحدها: $a\oplus a=0$ (حصلنا على الثابت 0!) لكن $a\oplus 0=a$ — ندور في حلقة، ولا سبيل إلى 1 أو إلى $a'$. السبب البنيوي: XOR دالّة خطيّة (جمع بمقياس 2)، وكل تركيب لدوالّ خطية يبقى خطياً — بينما AND مثلاً ليست خطية؛ ومن جهة $\{XOR,AND\}$: كل ما نبنيه منهما يحافظ على الصفر ($f(0,\dots,0)=0$) فلا الثابت 1 ولا NOT قابلان للبناء. لكن لاحظ اللمسة الأخيرة من الشرائح: أضف الثابت 1 إلى العدّة — $\{XOR, AND, 1\}$ — فيولد النفي فوراً ($a\oplus1=a'$) ويكتمل النظام! نظامٌ كهذا، يكتمل بمجرد إتاحة الثوابت، يسمى نصف كامل (Half-Complete) — مصطلح سيلازمنا في أسئلة المكوّنات لاحقاً.
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية صحيح دائماً؟
أ خاطئ: الثنائية تحوّل مطابقةً صحيحة إلى مطابقة صحيحة — لكنها لا تجعل التعبير مساوياً لثنائيّه ($x+y \neq x\cdot y$). الفخ اللغوي المفضّل.
ب صحيح — دي-مورغان المعمَّم بحذافيره: نفيُ جمعِ مضاريب = ضربُ مجاميع بحروف منفية: كل مضروب $x'w$ يصبح مجموعاً منفي الحروف $\big((x')'+w'\big)=(x+w')$، وبالمثل $(yk')' = (y'+k)$ و$(zr')' = (z'+r)$، والجمع الخارجي ينقلب ضرباً. ✔
ج خاطئ: يكفي الإسناد $X=Y=0,\ Z=1,\ W=0$ لنقضه — تذكّر: لا اختزال ولا «تعويض» في هذا الجبر.
د خاطئ: عدد الأسطر $2^4=16$ لا 32. (لا تخلط بين عدد الأسطر $2^n$ وعدد الدوالّ $2^{2^n}$!). ✔ الإجابة: ب.
أي من الادعاءات التالية صحيح؟
أ خاطئ: $2^{2^3}=2^8=256$ دالّة. الرقم 8 هو عدد أسطر الجدول فقط.
ب خاطئ: وحدانية الصيغة القانونية (حتى ترتيب الحدود) هي مبرر وجودها أصلاً — بها نقارن الدوالّ.
ج خاطئ: SoP و‑PoS صيغتان لنفس الدالّة — متساويتان لا متمّمتان: $\Sigma(0,2,3,6,7)=\Pi(1,4,5)$. علاقة التمّم هي بين قائمتي $f$ و$f'$ (تبديل القائمتين)، لا بين صيغتي $f$ نفسها.
د صحيح — والبرهان بنّاء من سطرين: $XNOR(a,a)=(a\oplus a)'=0'=1$ — ولّدنا الثابت 1 دون أي ثوابت خارجية! ثم $a\oplus 1=a'$ — حصلنا على NOT. ومعنا AND: بالمعيار العملي $\{AND, NOT\}$ ⟸ النظام كامل. ✔ الإجابة: د.
معطاة الدالّة $f(x,y,z)=\Sigma(0,2,3,6,7)$. ما صيغتها القانونية PoS؟
أسطر الصفر هي المتكاملة مع قائمة الآحاد: $\{1,4,5\}$. نبني الحد الأعظمي لكل منها بقاعدة «البت 0 ← متغير موجب، البت 1 ← متغير منفي»:
السطر 1 ($001$): $(x+y+z')$؛ السطر 4 ($100$): $(x'+y+z)$؛ السطر 5 ($101$): $(x'+y+z')$ ← الخيار أ ✔.
الفخاخ: الخيار ج بنى الأعظميات بقاعدة معكوسة (نفي البت 0)؛ الخيار د هو $f'$ بصيغة SoP (متمّم الدالّة لا الدالّة!)؛ الخيار ب بنى الأعظميات على أسطر الآحاد. ثلاثة أخطاء نمطية في سؤال واحد — تعلّمها هنا أرخص من تعلمها في القاعة. ✔ الإجابة: أ.
ما أبسط صورة مكافئة للتعبير $\;x'y'z+yz+xz\;$؟
$$x'y'z+yz+xz \overset{(6)}{=} z(x'y'+y+x) \overset{(8)}{=} z(x'+y+x) \overset{(5)}{=} z\cdot(1+y) \overset{(2)}{=} z$$
الخطوة (8) هي المفصل: $y+y'x'=y+x'$ (ابتلاع ثانٍ). وللتحقق البديل الصاعق: ضع $z=0$ — كل حد يموت ← النتيجة 0؛ وضع $z=1$ — يبقى $x'y'+y+x$ وقد أثبتنا أنه 1 دائماً. إذن الدالّة تساوي $z$ حرفياً في كل سطر. من اختار «أ» توقف خطوة قبل النهاية — درسٌ في المثابرة الجبرية. ✔ الإجابة: ج.
أي من المجموعات التالية تشكّل وحدها (دون ثوابت خارجية) نظام عمليات كاملاً؟
ج صحيح: NOR عالمية: $x\downarrow x=x'$ يولّد النفي، و$(x\downarrow y)\downarrow(x\downarrow y)=x+y$ يولّد الجمع ← معنا $\{OR,NOT\}$ الكاملة. ✔
لماذا سقط الباقون؟ أ: بلا نفيٍ إطلاقاً — كل تركيب من AND/OR رتيب (رفع مدخل من 0 إلى 1 لا يُنزل الخرج أبداً)، وNOT ليست رتيبة ← مستحيلة. ب: كل تركيباتها تحافظ على الصفر ($f(0,\dots)=0$) ← لا ثابت 1 ولا NOT (نصف كاملة فقط — تكتمل بإضافة الثابت 1). د: النفي وحده لا يبني أي دالّة بمدخلين حقيقيين (لا AND ولا OR من نافٍ أحادي). ✔ الإجابة: ج.
اللوجيك التوافقي: التبسيط، البوابات، المكوّنات القياسية، والزمن الحقيقي
3.1 مشكلة التبسيط: ما معنى «أصغر تعبير» أصلاً؟
أنهينا المحاضرة السابقة بحقيقة مزدوجة: لكل دالّة صيغة قانونية وحيدة، لكنها غالباً مبذّرة — جمع مضاريب كاملة الحروف. وبما أن كل حرف في التعبير سيصبح مدخل بوابة حقيقياً يكلّف مساحةً وزمناً وطاقة، نحتاج تعريفاً دقيقاً للهدف قبل أي «تبسيط»:
- عدد المضاريب أصغري — الأولوية الأولى.
- ومن بين كل التعابير المحققة لـ(1): عدد الحروف (Literals) أصغري.
معطاة بصيغتها القانونية:
$$f(x,y,z)=\underbrace{x'yz'}_{a}+\underbrace{x'y'z'}_{b}+\underbrace{xy'z'}_{c}+\underbrace{x'yz}_{d}+\underbrace{xyz}_{e}+\underbrace{xy'z}_{f}$$دمج أول — نمزج $(a,b)$ و$(b,c)$ و$(d,e)$ و$(e,f)$: $$f=x'z'+y'z'+yz+xz \quad(8\text{ حروف})$$ جرّب أن تحذف أي مضروب أو حرف — يختل التكافؤ. إذن هذا تعبير غير قابل للتقليص. هل هو الأصغري؟ لا!
دمج ثانٍ — $(a,b)$ و$(c,f)$ و$(d,e)$: $$f=x'z'+xy'+yz \quad(6\text{ حروف})$$ ودمج ثالث — $(a,d)$ و$(b,c)$ و$(e,f)$: $$f=x'y+y'z'+xz \quad(6\text{ حروف})$$
ثلاثة دروس دفعة واحدة: (1) تعبير لا يُقلَّص أكثر ليس بالضرورة أصغرياً — قد تكون بدأت الدمج بطريق خاطئ؛ (2) التعبير الأصغري ليس وحيداً بالضرورة (حلّان بـ6 حروف!)؛ (3) اختيار «مَن يُدمج مع مَن» هو جوهر اللعبة — وهذا بالضبط ما ستجعله الخريطة بصرياً.
3.2 خريطة كارنو: جدول الحقيقة يرتدي نظّارة هندسية
الدمج الجبري $Ax+Ax'=A$ يتطلب أن تلاحظ زوجَي مضاريب لا يختلفان إلا بحرف واحد. فكرة كارنو: أعِد ترتيب جدول الحقيقة بحيث يصبح كل زوجين قابلَين للدمج جارَين هندسيين — فتتحول ملاحظة جبرية دقيقة إلى «بقعة» تراها العين. الطريقة ممتازة لعدد صغير من المتغيرات: 3 حتى 5.
خريطة 3 متغيرات — الأعمدة $xy$ بترتيب غراي والصفوف $z$، وفي كل خلية رقمُ سطرها في جدول الحقيقة (= رقم الحدّ الأصغري):
| z \ xy | 00 | 01 | 11 | 10 |
|---|---|---|---|---|
| 0 | 0 | 2 | 6 | 4 |
| 1 | 1 | 3 | 7 | 5 |
وخريطة 4 متغيرات — أعمدة $wx$ وصفوف $yz$ (احفظ مواقع الأرقام؛ نصف أخطاء الامتحان مصدرها خريطة مرسومة خطأ):
| yz \ wx | 00 | 01 | 11 | 10 |
|---|---|---|---|---|
| 00 | 0 | 4 | 12 | 8 |
| 01 | 1 | 5 | 13 | 9 |
| 11 | 3 | 7 | 15 | 11 |
| 10 | 2 | 6 | 14 | 10 |
انقر أي خلية للتبديل بين $0 \to 1 \to \phi$ — وجرّب عليها كل أمثلة هذه المحاضرة:
مكعّب $m$-بُعدي في خريطة $n$ متغيرات = تجمّع من $2^m$ خلايا تتطابق تمثيلاتها الثنائية في $n-m$ مواضع (وتتقلب في المواضع الـ$m$ الباقية بكل التوليفات). المبرهنة: مكعّب كهذا، إذا كانت كل خلاياه آحاداً، يُدمج إلى مضروب واحد من $n-m$ حرفاً — حروف المواضع الثابتة فقط؛ أما المتغيرات المتقلبة فتُلغى زوجاً بعد زوج بالمطابقة $Ax+Ax'=A$.
الحساب الذهني للامتحان: زوج خلايا ← $n-1$ حرفاً؛ رباعية ← $n-2$؛ ثمانية ← $n-3$؛ والخريطة كلها ← الدالّة 1 الثابتة.
المنهجية: غطِّ الآحاد بأقل عدد من أكبر مكعّبات ممكنة
خذ $f=\Sigma(0,2,3,4,5,7)$ على 3 متغيرات:
| z \ xy | 00 | 01 | 11 | 10 |
|---|---|---|---|---|
| 0 | 1 | 1 | 1 | |
| 1 | 1 | 1 | 1 |
ستة آحاد تشكّل «حلقة» مغلقة من أزواج متداخلة، ولا يوجد أي «1» له شريك وحيد. النتيجة: تغطيتان أصغريتان متناظرتان لا مفاضلة بينهما:
$$f=x'y+xz+y'z' \qquad\text{أو}\qquad f=x'z'+yz+xy'$$(تحقّق سريع للأولى: $x'y\to\{2,3\}$، $xz\to\{5,7\}$، $y'z'\to\{0,4\}$ ✔). هذا هو المثال القانوني على أن الأصغري ليس وحيداً — ويظهر في الامتحانات بصيَغ «كم تعبيراً أصغرياً للدالّة؟».
3.3 حالات اللامبالاة (Don't Care): حرية تُترجم إلى بوابات أقل
| yz \ wx | 00 | 01 | 11 | 10 |
|---|---|---|---|---|
| 00 | 1 | φ | ||
| 01 | φ | 1 | ||
| 11 | 1 | φ | φ | |
| 10 | 1 | φ | φ |
(أ) محوّل BCD إلى Excess-3 ($f(A)=A+3$): أربع دوالّ خرج $f_1f_2f_3f_4$ على نفس المداخل $wxyz$ مع نفس الـ$\phi(10\dots15)$؛ حلّ كل خريطة على حدة يعطي: $$f_1=w+xz+xy \quad f_2=x'z+x'y+xy'z' \quad f_3=y'z'+yz \quad f_4=z'$$ لاحظ كيف انهارت $f_4$ إلى حرف واحد — البت الأدنى في $A+3$ هو ببساطة عكس بت الآحاد.
(ب) حاصل قسمة رقم BCD على 3 (خرجان $u,v$): $$u=\Sigma(6,7,8,9)+\Sigma_\phi(10\dots15) \Rightarrow u_{min}=w+xy$$ $$v=\Sigma(3,4,5,9)+\Sigma_\phi(10\dots15) \Rightarrow v_{min}=xy'+wz+x'yz$$ تدرّب على $u$ ذهنياً: «8,9» مع كل $\phi$ العمود $w=1$ يبنون ثمانية؟ لا — $\{8,9,10,\dots,15\}$ ثمانية كاملة بشرط واحد $w=1$ ← الحرف $w$ وحده؛ و«6,7» مع $\phi_{14,15}$ رباعية $xy$ ✔.
- افترض مبدئياً أن كل $\phi$ تساوي «1» وعلّم أكبر مكعّبات ممكنة.
- تجاهل أي مكعّب يغطي حالات $\phi$ فقط.
- اختر أولاً كل مكعّب يغطي «1» أصلياً حصرياً (لا يغطيه سواه).
- أكمل بمكعّبات إضافية حتى تُغطى كل الآحاد الأصلية — الآحاد فقط، لا الـ$\phi$!
- تلقائياً: $\phi$ المغطاة بالحل صارت «1»، والباقية صارت «0».
3.4 البوابات، Verilog، وما الذي يجعل دارةً «توافقية»
// بوابة AND — وصف مباشر
module and_gate(
input logic a,
input logic b,
output logic out
);
assign out = a & b;
endmodule// NAND موصوفة هرمياً فوق AND
module nand_gate(
input logic x, input logic y,
output logic out
);
logic x_and_y;
assign out = ~x_and_y;
and_gate foo(.a(x), .b(y), .out(x_and_y));
endmoduleتأمل النموذج الثاني: وحدة تُركّب داخلها نسخة من وحدة أخرى (Instantiation) وتربط منافذها بالأسماء — هذا هو الوصف الهرمي، الفكرة التي تُبنى بها كل الشرائح الحديثة: بوابات ← مكوّنات ← وحدات ← معالج.
ركيب توافقي (Combinational Component): عتاد له (1) مدخل أو أكثر، (2) مخرج أو أكثر، (3) إسناد قيمة مفاتيح لكل مخرج عن كل توليفة مداخل — أي جدول حقيقة كامل، و(4) قيود توقيت فيزيائية — سنصل إليها في هذه المحاضرة نفسها.
دارة توافقية (Combinational Circuit): ركائب موصولة بينها بحيث:
- كل ركيب فيها توافقي.
- كل مدخل ركيبٍ موصول إمّا بمدخل الدارة أو بمخرج ركيب آخر.
- المخارج توصَل إلى مداخل فقط — يُمنع وصل مخرج بمخرج.
- لا حلقات (Cycles): كل مسار من المداخل نحو المخارج يمرّ بكل ركيب مرة واحدة على الأكثر.
- يجوز إعلان أي مدخل للدارة وأي مخرج ركيب كمخرج للدارة.
النتيجة المباشرة: دارة فيها ركيب يعود مخرجه إلى أحد مداخله (تغذية راجعة) ليست توافقية — خرجها لم يعد دالّة توليفة المداخل الحالية وحدها. (وهذه بالمناسبة هي الطريقة التي سنبني بها الذاكرة لاحقاً — الحلقة ليست خطأً دائماً، لكنها تُخرجنا من العالم التوافقي). وسمّيت «دارة/מעגל» بالوراثة من الهندسة الكهربائية رغم أنها بلا دوائر مغلقة — مفارقة تسمية يحبها المحاضرون كسؤال استيعاب.
أي من الأوصاف التالية يخرق شروط الدارة التوافقية؟
ج يصف حلقة — خرق مباشر للقاعدة 4، والدارة تفقد صفتها التوافقية (صار لها «ذاكرة» محتملة). أ مسموح تماماً (التشعيب Fanout مخرجٌ إلى مداخل)؛ ب تسمح به القاعدة 5 حرفياً؛ د مجرد مشاركة مداخل — مشروعة. ✔ الإجابة: ج.
لننفّذ $f(a,b,c)=\Sigma(2,5,6,7)=ac+bc'$:
- AND-OR مباشر: بوابتا AND ثم OR — الترجمة الحرفية لجمع المضاريب.
- NAND-NAND: بدي-مورغان $ac+bc'=\overline{\overline{ac}\cdot\overline{bc'}}$ — نفس البنية بطبقتي NAND (تذكّر: NAND عالمية!).
- NAND ثنائية المداخل فقط: نفكك أيضاً المقلوب $c'=NAND(c,c)$ — مفيد عندما يقدّم المصنع بوابة واحدة فقط.
ثلاث دارات مختلفة، دالّة واحدة. وأي منها «الأفضل»؟ الشرائح تجيب بمنظور تاريخي: حتى الستينيات كان الهدف أقل عدد بوابات مفردة؛ حتى الثمانينيات صار الهدف أقل عدد مكوّنات مركّبة (سنقابلها حالاً)؛ واليوم في الشرائح المتقدمة تتزاحم الأهداف: مساحة السيليكون، الهدر الكهربائي، زمن الحساب، وبساطة التطوير. «الأصغري» مفهوم نسبي لعصره — خذها فلسفة تصميم دائمة.
3.5 المكوّنات القياسية: مفردات التصميم الحديثة
البورر (Selector / Multiplexer / MUX)
💡 سؤال الشريحة 48: ما حجم جدول الحقيقة لبورر $4\to1$؟
بورر $2\to1$ بلا تمكين يحقق $z=S'D_0+SD_1$. الآن استبدل ذكياً: $S=A$، $D_0=B$، $D_1=B'$:
$$z=A'B+AB'=A\oplus B$$بورر واحد = XOR كاملة. ومع الثوابت (شريحة 51): $D_0=0,D_1=B,S=A$ يعطي $AB$ (بوابة AND)، و$D_0=1,D_1=0,S=A$ يعطي $A'$ (بوابة NOT) — أي أن البورر مع الثابتين 0 و1 نظام عمليات كامل. وسؤال البيت من الشريحة نفسها: هل البورر وحده كامل؟ الجواب الذي أثبتته التمارين: لا — بلا ثوابت لا يولّد نفياً؛ إنه نصف كامل (وسيعود هذا حرفياً في سؤال امتحان أدناه).
ننفّذ $f(w,x,y,z)=\Sigma(3,4,9,12,13,14)$:
المفكّك (Decoder) — وقلبه النابض في كل ذاكرة
الخرج ثلاثي الحالات، الناقل BUS، وCrossbar
ومن يضمن قانون «واحد على الأكثر»؟ المفكّك بالضبط — مخارجه one-hot بالبناء، فوصلُها بمفاتيح التمكين يجعل التصادم مستحيلاً بنيوياً. وعلى هذا المبدأ يُبنى مفتاح Crossbar — مصفوفة مسارات يتحكم بها مفكّكات، من مقاسم الهاتف التاريخية حتى بُنى الشبكات الحديثة.
المرمّز (Encoder) وميزان التعقيد
المرمّز يعكس المفكّك: $n$ مداخل يُفترض أن واحداً منها فقط '1'، والخرج ($m=\log n$ بتات) هو الكود الثنائي لرقم ذلك المدخل. وأما «فاتورة» هذه المكوّنات (شريحتا 64-65) فتُحسب هكذا لبورر بـ$K=2^n$ مداخل بيانات:
$$\underbrace{2(n{+}1)}_{\text{مقلوبات}}+\underbrace{(n{+}1)2^n}_{\text{طبقة AND مكافئة ثنائية}}+\underbrace{2^n-1}_{\text{شجرة OR}}=O(n\,2^n)=O(K\log K)$$والمفكّك كذلك $n2^n+2(n+1)=O(K\log K)$. الدرس التصميمي: كلاهما ينمو شبه خطياً مع عدد المخارج/المداخل مضروباً بلوغاريتمه — «رخيصان» بما يكفي ليكونا لبِنات كل ما سيأتي.
3.6 التجريد الكهربائي الرقمي: لماذا ينجو الـ«بت» في عالم تماثلي؟
حان الوقت لفتح الغطاء: البوابة الحقيقية تستقبل جهوداً متصلة وتنتج جهوداً متصلة. أين الـ0 والـ1 إذن؟ إنهما اتفاقية نطاقات:
- وعد المخرج: البوابة تُخرج '0' تحت $V_{OL}$، و'1' فوق $V_{OH}$ — نطاقان ضيقان «نظيفان».
- تسامح المدخل: البوابة تقرأ '0' كل ما دون $V_{IL}$، و'1' كل ما فوق $V_{IH}$ — نطاقان أوسع.
- بين $V_{IL}$ و$V_{IH}$: المنطقة المحرّمة — قراءة غير معرَّفة.
وللتجريد وجه ثانٍ: من زمن متصل إلى زمن منفصل. عند تبدّل مدخل، يعبر جهد المخرج المنطقةَ المحرّمة خلال زمن منتهٍ أكبر من صفر — لحظات لا معنى منطقياً للخرج فيها. الاتفاق: نغمض أعيننا أثناء العبور. كم نغمض؟ هذا بالضبط ما تجيب عنه نماذج التأخير.
3.7 نماذج التأخير الأربعة: zero · unit · physical · practical
$t_{CD}$ (زمن التلوّث): مدة مضمونٌ خلالها أن المخرج لن يبدأ بالاستجابة للتغيير. يُقاس من لحظة مغادرة المدخل قيمتَه المنطقية القديمة، حتى لحظة خروج جهد المخرج من النطاق الشرعي لقيمته القديمة. السيناريو الحاكم (الأسوأ): مدخل يتغير بحدّة فيستعجل المخرج.
$t_{PD}$ (زمن الانتشار): مدة مضمونٌ بعدها أن المخرج استقر على قيمته الجديدة. يُقاس من لحظة وصول المدخل قيمتَه الجديدة، حتى دخول المخرج النطاق الشرعي الجديد. السيناريو الحاكم: مدخل يتغير ببطء فيتلكأ المخرج.
الاثنان حدّان تعاقديان — «ضمانة مصنّع» — لا زمني تبديل فعليين: الفعلي يتقلب مع الحرارة والجهد وبين نسخة ونسخة؛ الحدّان يحيطان به من الجهتين ($t_{CD}$ من الأسفل، $t_{PD}$ من الأعلى).
- Zero Delay: الخرج يتبدل فوراً. للتحقق المنطقي الخالص — الزمن غير موجود.
- Unit Delay: كل بوابة تتأخر «وحدة» واحدة متطابقة. ممتاز لفهم ترتيب الأحداث وتحليل الـHazards.
- Physical Delay: لكل بوابة حدّاها $t_{CD}/t_{PD}$ — الخرج «غير معلوم» في النافذة بينهما. نموذج التعاقد الهندسي الحقيقي.
- Practical (50%) Delay: قياس عملي بين عبور المدخل والمخرج عتبة منتصف الجهد — لغة أوراق المواصفات والمختبر.
الدارة: $x=g_2(a,c)$، $y=g_1(c)$، $z=g_3(y,b)$، $f=g_4(x,z)$. مساران من المداخل إلى $f$: عبر $g_2{\to}g_4$، وعبر $g_1{\to}g_3{\to}g_4$.
| النموذج | $c\to y$ | $y,b\to z$ | $a,c\to x$ | $x,z\to f$ | الاستجابة الكلية حتى $f$ |
|---|---|---|---|---|---|
| Zero | 0 | 0 | 0 | 0 | 0 |
| Unit | 1 | 1 | 1 | 1 | 3 (المسار الأطول: ثلاث بوابات) |
| Physical | $t_{PD}(1)$ | $t_{PD}(3)$ | $t_{PD}(2)$ | $t_{PD}(4)$ | $\max[t_{PD}(1)+t_{PD}(3)+t_{PD}(4),\; t_{PD}(2)+t_{PD}(4)]$ |
القاعدة الذهبية المستخرجة: زمن استجابة الدارة التوافقية = زمن المسار الأطول فيها. احفر هذه الجملة — إنها الأساس الذي سيُبنى عليه كل حساب زمن دورة لاحقاً في المساق.
3.8 طاقة الحساب: عدّ التبديلات
لنثبّت: $x=AND(a,c)$، $y=NOT(c)$، $z=OR(y,b)$، $f=XOR(x,z)$، وانتقال المداخل $abc: 000\to001$:
- المدخل $c$ تبدّل، وهو يغذي مدخلين (في AND وفي NOT) ← 2 وحدتان.
- $y=c'$ ينقلب $1\to0$، ويغذي مدخلاً واحداً (في OR) ← 1.
- $x=AND(0,1)=0$ لم يتغير ← 0. أما $z=OR(y,b)$: كان $OR(1,0)=1$ وصار $OR(0,0)=0$ ← تبدّل، ويغذي مدخلاً في XOR ← 1.
- $f$ تغيّر أيضاً، لكنه مخرج الدارة لا مدخل بوابة ← لا يُحاسَب في نموذجنا. المجموع: 4 وحدات طاقة.
لاحظ عاملين يقفزان من المثال: (1) الطاقة تعتمد على التشعيب — إشارة تغذي مدخلين تدفع مرتين؛ (2) تعتمد على الزوج (القديم، الجديد) من التوليفات لا على الجديدة وحدها. لذلك خفضُ «النشاط التبديلي» — بترتيب الحسابات وتجميد ما لا يلزم — هو أول أسلحة توفير الطاقة (وستلتقي به لاحقاً باسم Clock Gating).
3.9 الـHazards: حين يكذب الخرج للحظة
اتفقنا ألا ننظر إلى الخرج قبل انقضاء $t_{PD}$. لكن ماذا يفعل الخرج أثناء إغماضتنا؟ أحياناً يمرّ بقيمة وسيطة خاطئة — وميض قد يكون قاتلاً إن كان أحد يصغي:
3.10 خلاصة العدّة
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية خاطئ؟
ب هو الخاطئ — وقد رأينا البرهان حيّاً مرتين: مثالُ $\Sigma(0,4,5,7,8,9,13,15)$ (تغطيتان مقنعتان بأحجام مختلفة) والخريطة الحلقية $\Sigma(0,2,3,4,5,7)$ (تغطيتان أصغريتان متكافئتان تماماً). لاحظ أن د يقول عكس ب حرفياً — في أسئلة «أيها خاطئ» ابحث عن أزواج التناقض، أحدها حتماً الجواب. أ صحيح بالتعريف، وج صحيح (حلقات غراي بأطوال زوجية غير قوى 2 موجودة). ✔ الإجابة: ب.
أي من الادعاءات التالية صحيح؟
أ صحيح: زمن الاستجابة (Latency) يُحسب من المسار الأطول بقيم $t_{PD}$ وحدها — متى يُضمن الاستقرار. أما $t_{CD}$ فدوره «من الجهة الأخرى»: متى يُضمن عدم التغير — وسيصبح حاسماً في قيود Hold بالتصميم المتزامن، لا في الاستجابة.
ب خاطئ: $t_{PD}$ حد علوي (الاستقرار على الأكثر بعده)، لكن $t_{CD}$ حد سفلي (لا تغيير قبله). ج خاطئ: جبهتا الصعود والهبوط تمرّان بفيزياء شحن/تفريغ مختلفة — لا مساواة عامة. د خاطئ: من التعريفين مباشرة $t_{CD} \le t_{PD}$ — ضمانة «لن يتغير قبل» لا يمكن أن تتجاوز ضمانة «سيستقر بعد». ✔ الإجابة: أ.
آفي يدّعي: بورر MUX $8\to1$ بدون مدخل enable هو نظام عمليات كامل.
بيني يدّعي: مفكّك Decoder $3\to8$ بدون enable ليس نظاماً كاملاً لكنه نظام نصف كامل.
جيلي تدّعي: Full Adder نظام كامل، بينما Half Adder ليس كاملاً ولا نصف كامل.
آفي مخطئ: رأينا في البند 3.5 أن البورر يبني AND وNOT مع الثوابت 0/1 — أي أنه نصف كامل فقط؛ وحده لا يولّد نفياً (سؤال البيت في شريحة 51).
بيني مخطئ بالاتجاه المعاكس: المفكّك فوق مدخلين هو نظام كامل (كما أُثبت في التمارين): مخارجه minterms، ومنها يُبنى النفي والضرب دون ثوابت.
جيلي مخطئة: الوضع معكوس عندها أيضاً — الـFull Adder نصف كامل (لا كامل): مخرجاه $S=a\oplus b\oplus c$ خطّي و$C_{out}$ رتيب، فلا نفي بلا ثوابت؛ ومع الثوابت يكتمل. ✔ الإجابة: هـ.
للدالّة $f=\Sigma(0,3,6,9)+\Sigma_\phi(10,\dots,15)$ (فاحص القسمة على 3 لرقم BCD)، ما التعبير الأصغري؟
ب هو حلّ الشريحة: كل «1» استعان بجيرانه من الـ$\phi$ ليكبر ($9$ صار رباعية $wz$، و$3$ زوجاً $x'yz$، و$6$ زوجاً $xyz'$)، والصفر بقي وحيداً بحدّه الكامل.
الفخاخ: أ هو الحل بتجاهل الـ$\phi$ (قانوني لكن 16 حرفاً — ليس أصغرياً هنا)؛ ج أضاف $wx$ الذي يغطي $\phi$ فقط — بوابة مجانية الضرر (خرق البند 2 من الخوارزمية)؛ د أسقط تغطية الـ«1» في السطر 0 — دالّة أخرى ببساطة. ✔ الإجابة: ب.
الدارة $H=y_1y_2+y_2'y_3$ (بمقلوب على $y_2$) تُظهر وميضاً ساكناً عند $y_1=y_3=1$ أثناء $y_2:1\to0$. أي تعديل يجعلها Hazard-Free دون تغيير الدالّة؟
العبور الحرج هو بين مكعّبَي $y_1y_2$ و$y_2'y_3$؛ الجسر الذي يغطي زوج الخلايا المتجاورتين $(y_1y_2y_3=111)$ و$(110)$... بدقة: الخليتين $111$ و$101$ — هو حدّ الإجماع $y_1y_3$: قيمته 1 طوال الانتقال ولا يضيف شيئاً منطقياً ($y_1y_3 \le y_1y_2+y_2'y_3$ تغطيةً). ب لا يساعد — تغيير الأزمنة يحرّك الوميض ولا يلغيه بضمانة (والحدّان تعاقديان أصلاً لا قيم مضبوطة)؛ أ يغيّر الدالّة؛ د ينفي تعريف Hazard-Free الذي صغناه حرفياً. ✔ الإجابة: ج.
أي من الادعاءات التالية صحيح؟
ج صحيح: مخارج المفكّك one-hot بالبناء — واحد مضاء على الأكثر (وصفر عند $E=0$) — فربطها بمداخل enable لمخارج ثلاثية الحالات يجعل التصادم مستحيلاً هيكلياً، لا اعتماداً على حسن سلوك البرمجيات. هذا حرفياً «المفكّك حيوي للـBUS» من الشرائح.
أ خاطئ: tri-state وحدها لا تمنع تفعيلَين متزامنين — القانون «واحد على الأكثر» يحتاج من يفرضه. ب خاطئ: 7 مداخل (4 بيانات + 2 تحكم + enable) ← $2^7=128$ سطراً. د خاطئ: الحساب أعطى $O(K\log K)$. ✔ الإجابة: ج.
معطاة: $f(w,x,y,z)=\Sigma m(0,1,3,4,7,9,15)+\Sigma\phi(2,8)$، ومعطاة $g$ التي minterms قيمها 1 هي (بعد فك التعبير الطويل): $\{3,7,11,12,14,15\}$ تقريباً وفق خريطتها المرسومة في الحل الرسمي. موطي يريد تنفيذ $h = f \oplus g$ بأقل عدد من بوابات NAND بمدخلين فقط. الخريطة الناتجة لـ$h$ (مع الاستفادة من $\phi$) تُبسَّط إلى: $$h = y\,\bar z + w\bar x + w\bar z$$ كم بوابة NAND يحتاج موطي كحد أدنى؟
خطوة 1 — دمج جبري ذكي قبل الترجمة: $$h = y\bar z + w(\bar x + \bar z) = y\bar z + w\,\overline{xz}$$ لاحظ: $\bar x+\bar z = \overline{xz}$ (دي-مورغان) — وفّرنا حداً كاملاً!
خطوة 2 — الترجمة إلى NAND: $$h=\overline{\overline{y\bar z}\cdot\overline{w\,\overline{xz}}}$$
- فرع $y\bar z$: بناء $\bar z$ ثم الدمج — 3 بوابات وفق عدّ الحل الرسمي.
- فرع $w\,\overline{xz}$: $\overline{xz}=NAND(x,z)$ بوابة، ثم $NAND(w,\cdot)$ — بوابتان.
- الدمج النهائي: $NAND(\overline{\alpha},\overline{\beta})$ — بوابة واحدة.
المجموع وفق الحل الرسمي: $3+2+1=\mathbf{6}$ بوابات NAND. ✔ الإجابة: أ. الدرس المهم: الاستخراج الجبري قبل الترجمة هو ما خفض العدد من 8–9 إلى 6 — طبّق دي-مورغان على الحدود المشتركة قبل عدّ البوابات.
دارة توافقية بأربعة مداخل $\{A,B,C,D\}$ وخرج $Q$: المدخل $A$ يصل للخرج فقط عبر سلسلة بوابات OR يتطلب تفعيلُها $B=0$، وفي الوقت نفسه يتطلب فرعٌ آخر على نفس المسار أن يكون $\overline{(B\cdot\bar C)}=0$ أي $B=1$. معطى جدول $T_{pd}/T_{cd}$ لكل بوابة. احسب $T_{pd}(A\to Q)$:
قبل جمع أزمنة أي مسار — افحص قابلية التفعيل (Sensitization): لكي «يرى» الخرجُ تغيّرَ $A$، يجب ضبط بقية المداخل بحيث يعبر التغيّر كل بوابة على المسار (لكل OR: بقية مداخله 0؛ لكل AND: بقية مداخله 1).
هنا يتطلب العبور $B=0$ و$B=1$ معاً — تناقض. جبرياً: فرع التعلق الوحيد بـ$A$ يحقق $A+B+\overline{B\bar C}=A+B+\bar B+C=1$ — ثابت لا يتأثر بـ$A$. هذا مسار زائف (False Path): طويل على الورق، ميت كهربائياً. ✔ الإجابة: هـ.
📌 أضِف لقاعدة «زمن الدارة = المسار الأطول» (البند 3.7) الحاشية الحاسمة: المسار الأطول القابل للتفعيل — الفخ المفضل لواضعي الامتحان.
دارة: المدخل $A$ موصول مباشرةً بأحد مدخلي بوابة AND، وموصول أيضاً عبر مقلوبين متتاليين بالمدخل الثاني؛ الخرج $Z$. تدخل على $A$ نبضة «1» بعرض 475ns (قبلها وبعدها $A=0$). المعطيات: $T_{pd}(NOT)=150,\ T_{cd}(NOT)=20,\ T_{pd}(AND)=80,\ T_{cd}(AND)=15$ (ns). ما العرض الأدنى للنبضة في الخرج $Z$؟
أسوأ حالة لتقصير النبضة: بدايتها في $Z$ تتأخر أقصى ما يمكن، ونهايتها تصل أسرع ما يمكن.
البداية (صعود $Z$): يتطلب «1» على كلا مدخلي AND؛ الفرع البطيء هو المقلوبان: $2\cdot T_{pd}(NOT)+T_{pd}(AND)=300+80=380$ns بعد بداية النبضة.
النهاية (هبوط $Z$): يكفي «0» واحد؛ المسار المباشر فوري، وأدنى استجابة للبوابة $T_{cd}(AND)=15$ns بعد نهاية النبضة (475ns).
$$W_{min}=(475+15)-380=\mathbf{110\,ns}$$✔ الإجابة: ب. لاحظ الربط بنماذج البند 3.7: حسبنا الصعود بحدود $T_{pd}$ (النموذج الفيزيائي، الجانب البطيء) والهبوط بحدود $T_{cd}$ (الجانب السريع) — النبضة تُقرَض من الجهتين.
الدالّة $f(x,y,z,v,w)$ منفَّذة كالتالي: مفكّكا ترميز $2\to4$ بمدخل enable موصول بـ$x$؛ الأول يقرأ $(y,z)$ والثاني يقرأ $(v,w)$، وجميع مخارج المفكّكين الثمانية تدخل إلى شجرة بوابات XOR واحدة كبيرة. ما الدالّة الناتجة؟
شجرة XOR تحسب زوجية عدد الآحاد في مداخلها (1 إذا كان عددها فردياً).
حالة $x=0$: المفكّكان معطّلان ← كل المخارج الثمانية 0 ← عدد الآحاد 0 (زوجي) ← $f=0$.
حالة $x=1$: كل مفكّك مفعّل يضيء مخرجاً واحداً بالضبط (خاصية one-hot الجوهرية من البند 3.5!) ← إجمالي الآحاد = 2 (زوجي دائماً) ← $f=0$.
في الحالتين $f\equiv 0$. ✔ الإجابة: ج.
معطاة $f(w,x,y,z)=\Sigma m(3,7,11,15)$.
أ. هل الدالّة تشكّل نظام عمليات كاملاً؟
ب. نفّذها بأقل عدد من البوررات (وبأقل عرض كأولوية ثانية). يمكن استخدام الثابتين 0 و1.
ج. نفّذها بأقل عدد من المفكّكات ذات enable (وبأقل عرض).
💡 تلميح: بسّط الدالّة أولاً!
👁 الحل الكامل خطوة بخطوة
التبسيط: $\Sigma m(3,7,11,15)$ = العمود $yz=11$ كاملاً ← $f = y\cdot z$ (بوابة AND بسيطة!).
أ. لا. $f(a,a,a,a)=AND(a,a)=a \neq \bar a$ — دالّة رتيبة لا تولّد نفياً أبداً ← ليست نظاماً كاملاً.
ب. بورر $2\to1$ واحد: التحكم $=y$، $D_0=0$، $D_1=z$: عندها $Z=\bar y\cdot 0 + y\cdot z = yz$ ✔ — بورر واحد بأصغر عرض ممكن.
ج. مفكّك $1\to2$ واحد مع enable: المدخل $=z$ و$enable=y$: المخرج $D_1 = y\cdot z$ ✔. الفكرة الأنيقة: مدخل الـenable يشارك في الدالّة كعامل ضرب مجاني.
أ. صمّم دارة توافقية تستقبل متجهين $A[0{:}n{-}1]$ و$B[0{:}n{-}1]$ (أعداد غير موقّعة) وتُخرج $\max\{A,B\}$ و$\min\{A,B\}$. المتاح: Full Adder، Full Subtractor (يُخرج $A-B$ وإشارة borrow)، MUX بعرض $n$، NOT، Decoder — بخمسة مكوّنات على الأكثر.
ب. باستخدام الدارة من (أ) كمكوّن جاهز، ابنِ دارة تفرز أربعة متجهات — بثمانية مكوّنات على الأكثر.
💡 تلميح للبند أ
👁 الحل الكامل
أ (3 مكوّنات فقط): مرّر $A,B$ إلى Full Subtractor واحد يحسب $A-B$؛ إشارة الـborrow $b=1 \iff A \lt B$. ثم:
- MUX 1 (بعرض $n$): تحكم $=b$، $D_0=A$، $D_1=B$ ← المخرج $\max$.
- MUX 2: تحكم $=b$، $D_0=B$، $D_1=A$ ← المخرج $\min$.
ب (5 وحدات max/min): شبكة فرز قياسية لأربعة عناصر: وحدة على $(A,B)$ ووحدة على $(C,D)$؛ ثم وحدة على الأكبرَين (← الأكبر النهائي) ووحدة على الأصغرَين (← الأصغر النهائي)؛ ووحدة خامسة على الوسيطين. خمس وحدات $\le 8$ ✔ — شبكة الفرز الزوجية-الفردية المعروفة.
الحساب والذاكرات: من المجمّع الكامل إلى ملف سجلات RISC-V
4.1 جمع الأعداد الثنائية: كل شيء يبدأ من عمود واحد
هذه المحاضرة تبني، بيدينا، أول «عضلات» حقيقية للمعالج: عتاد الحساب. والمدخل الصحيح هو أن نتذكر كيف نجمع نحن البشر على الورق — عموداً عموداً: في كل عمود نجمع ثلاث بتات (الحمل الداخل من العمود السابق + البتّان المكتوبان)، ونُنتج نتيجتين: بت مجموع العمود، وحملاً خارجاً للعمود التالي.
الحمل: 1 1 . .
1 0 1 1
+ 0 0 1 1
---------
1 1 1 0
الآن اللقطة المفهومية المهمة: بقراءة غير موقّعة هذا $11+3=14$؛ وبقراءة متمّم لـ2 هذا $(-5)+3=(-2)$. نفس البتات، نفس عملية الجمع، نفس العتاد — والتفسير وحده اختلف. هذه هدية المتمّم لـ2 التي وعدنا بها منذ المحاضرة الأولى: مجمّع واحد يخدم العالمين، ولذلك لن نبني في هذا المساق إلا مجمّعاً واحداً.
4.2 المجمّع الكامل (Full Adder): خلية العمود الواحد
// full adder - logical
module FullAdder2(
input logic a, b, cin,
output logic cout, s // carry and sum
);
assign s = a ^ b ^ cin;
assign cout = (a & b) | (a & cin) | (b & cin);
endmodule
💡 سؤالا الشريحة: ما $t_{PD}$ للخلية؟ وما $t_{PD}(C_{in}\to C_{out})$ تحديداً؟
4.3 مجمّع الحمل المتموّج (RCA): بسيط، أنيق… وبطيء خطياً
لجمع كلمتين بعرض $n$: نصفّ $n$ خلايا FA، حمل كل خلية يدخل التي تليها، و$C_0=0$. الحمل الخارج الأخير $C_n$ يشير لتجاوز السعة (غير الموقّع). الجمال في البساطة — والثمن في «الموجة»:
الحساب الساذج «$3$ وحدات لكل خلية ← $3n$» مبالغ فيه، لأن كل بوابات $A_i\oplus B_i$ في كل الخلايا تُحسب بالتوازي في الوحدة الأولى (مداخلها جاهزة منذ اللحظة صفر!). بعدها يركض الحمل عبر بوابتين لكل خلية:
$$t_{PD}(RCA) = \underbrace{3}_{\text{الخلية الأولى}} + \underbrace{2(n-1)}_{\text{بوابتان لكل خلية تالية}} \approx 2n$$زمن خطي في عرض الكلمة: مجمّع 32-بت يكلّف ≈65 وحدة زمنية. لعرض الكلمات الحديث هذا مؤلم — ومن هنا وُلد CLA.
// سلوكي: سطر واحد!
module RCA #(parameter n = 8) (
input logic [n-1:0] a, b,
input logic cin,
output logic [n-1:0] s,
output logic cout
);
assign {cout, s} = a + b + cin;
endmodule
والوصف البنيوي بشرائح البتات (bit-slices) الذي يرسم السلسلة صراحة. النقطة الحاسمة من الشريحة: المُركِّب (Synthesis) يحوّل الوصف السلوكي إلى تنفيذات بوابات مختلفة حسب قيود المساحة والزمن والطاقة المطلوبة — لا يوجد «تنفيذ وحيد» لكود Verilog. (تذكّر هذه الجملة في أسئلة نهاية المحاضرة).4.4 مجمّع استباق الحمل (Carry Look-Ahead): لا تنتظر الموجة — احسبها
لنشخّص الاختناق بدقة: المداخل $A_i,B_i$ كلها حاضرة منذ اللحظة صفر، والوحيد المتأخر هو $C_i$. لكن تأمل: هل نحتاج فعلاً انتظار $C_i$ دائماً؟
- توليد (Generate): $g_i \equiv A_iB_i$. إذا $g_i=1$ فالخلية تولّد حملاً بنفسها: $C_{i+1}=1$ دون أي انتظار لـ$C_i$.
- تمرير (Propagate): $p_i \equiv A_i+B_i$. إذا $p_i=1$ (وأحدهما فقط مضاء عملياً) فالحمل الداخل يعبر: $C_{i+1}=C_i$.
4.5 المجمّع-الطارح: سؤال الشريحة «لماذا يعمل هذا؟»
البنية: صف XOR أمام كل بتات $B$، مدخلها الثاني إشارة واحدة $SUB$، وهذه الإشارة نفسها توصَل إلى $C_0$. الشريحة تسأل بتحدٍّ: Why does it work? — فلنجب بدقة:
4.6 وحدة الحساب والمنطق ALU של RISC-V
الـALU هو المجمّع وقد «تمدّن»: خلية البت الواحد تحوي عدة وحدات عمل متوازية (AND، OR، FA) وبورراً صغيراً بإشارة Operation يختار أي نتيجة تخرج. 32 خلية متسلسلة (بحمل متموّج أو مع CLA) تعطي ALU بعرض الكلمة. فوق هذا الهيكل تُضاف اللمسات التي يتطلبها RISC-V:
- الطرح: إشارة
Binvert+ $C_0$ — حيلة البند السابق مدمجةً في الخلية. وللتناظر يضاف أيضاً قلبٌ لـ$a$ — به تُبنى NOR: $\overline{a+b}=\bar a\cdot \bar b$ (AND على المقلوبين). - SLT (Set-if-Less-Than): المطلوب: 1 في البت الأدنى إذا $A \lt B$ وأصفار في كل مكان آخر. التنفيذ الأنيق: نفّذ $A-B$ وخذ إشارة النتيجة (بت الـmsb، بعد تصحيح الفيض بعتاد كشف الفيض في الخلية الأخيرة): سلك
Setيخرج من خلية الـmsb ويعود ليدخل مدخلLessفي خلية الـlsb، بينما مداخلLessلسائر الخلايا مثبّتة صفراً. - Zero: «هل تساوى المعاملان؟» — نفّذ طرحاً وافحص أن كل بتات النتيجة أصفار: $Zero=\overline{R_{31}+R_{30}+\dots+R_0}$ (بوابة NOR عريضة). هذه الإشارة هي التي ستقود قفزات
beq/bneفي المعالج لاحقاً — ها هي أول خيوط الربط بين المحاضرة الأولى وبناء المعالج تُنسج.
// ALU سلوكي كما في الشريحة (رموز التحكم القياسية)
module RISCVALU (
input logic [3:0] ALUctl,
input logic [31:0] A, B,
output logic [31:0] ALUOut,
output logic Zero);
assign Zero = (ALUOut == 0); // true if ALUOut is 0
always_comb begin
case (ALUctl)
0: ALUOut = A & B;
1: ALUOut = A | B;
2: ALUOut = A + B;
6: ALUOut = A - B;
7: ALUOut = (A < B) ? 1 : 0; // SLT
12: ALUOut = ~(A | B); // NOR
default: ALUOut = 0;
endcase
end
endmodule
4.7 كشف الأعطال في الدارات التوافقية: الهندسة تلتقي بالاقتصاد
لماذا يدرّس مساقُ عتادٍ موضوعَ «فحص»؟ لأن التصنيع ليس مثالياً، والفحص بند تكلفة ضخم:
الدارة: بوابة AND (رقم 1) مداخلها السلكان $m$ (من $A$) و$n$ (من $B$)، وخرجها السلك $p$؛ وبوابة OR (رقم 2) مدخلاها $p$ والسلك $q$ (يحمل $C'$)، وخرجها $f$. الأعطال الممكنة: 8 (سلكان × حالتان لكل من $m,n,p,q$). نفترض عطلاً واحداً على الأكثر في كل لحظة:
4.8 نحو الذاكرة: ماذا يحدث عندما نغلق حلقة؟
حتى الآن التزمنا بقاعدة «لا حلقات» في الدارات التوافقية. حان وقت كسرها عمداً — لأن الذاكرة تسكن هناك:
4.9 قفل SR: أول ذاكرة قابلة للكتابة
ثنائي الاستقرار يحفظ… لكن لا أحد يستطيع الكتابة فيه. الحل: استبدل المقلوبين ببوابتَي NOR — فكل NOR «مقلوبٌ بمدخل تحكم إضافي»:
- حفظ ($S=R=0$): كل NOR يتصرف كمقلوب ← نعود لثنائي الاستقرار: الحالة القائمة تبقى.
- كتابة 1 (SET، $S=1,R=0$): فرع $\overline{Q}$ يُجبَر على 0، فيتحرر الفرع الآخر إلى $Q=1$.
- كتابة 0 (RESET، $S=0,R=1$): بالتناظر: $Q=0$.
- الحالة المحظورة ($S=R=1$): «بلبلة المخارج» — كلا المخرجين يُدفعان إلى 0 (لم يعودا متتامّين!).
وسمّي العنصر Latch («قفل») — الاسم مخصص لعناصر ذاكرة مداخلها حرّة التغيير في أي لحظة ومخارجها تتأثر فوراً.
4.10 من SR إلى D-Latch: بوابة على الباب
القفل المبوّب (Gated SR): نضيف مدخل $G$ (Gate) يحرس المدخلين: عندما $G=1$ القفل «مفتوح/شفاف»، وعندما $G=0$ القفل موصد ولا يتأثر بشيء. ثم الخطوة الحاسمة: بدل مدخلين خطرين $S,R$، نكتفي بمدخل بيانات واحد $D$ ونولّد داخلياً $S=D,\ R=\overline{D}$ (عبر $G$):
4.11 القافز D (D Flip-Flop): اللقطة على الجبهة
الـLatch الشفاف ما زال «سائلاً»: طوال نصف الدورة العالي، كل رعشة في $D$ تنسكب إلى $Q$. النظام المتزامن يريد شيئاً أصلب: لقطة واحدة في لحظة واحدة — جبهة صعود الساعة. هذا هو DFF، ويُبنى من قفلين شفافين بترتيب عبقري:
4.12 نظاما التوقيت — وMetastability: الشبح الفيزيائي
الساكن: كل ركيب توافقي يضمن: مداخل شرعية مستقرة مدة كافية ← خرج شرعي بعد التأخير المناسب.
الديناميكي — دستور المنظومات المتزامنة، أربعة بنود: (1) الدارة من ركائب توافقية وعناصر ذاكرة مُسوَّعة فقط؛ (2) لا حلقات توافقية — كل حلقة تمرّ بعنصر ذاكرة مُسوَّع واحد على الأقل؛ (3) دورة الساعة طويلة بما يكفي لكل متطلبات الزمن؛ (4) كل المداخل مستقرة المدد المطلوبة. التزم بالأربعة — يشتغل كل ما ستبنيه في بقية المساق.
افتح حلقة الـSR-Latch للحظة وانظر إليه كمكبّرين متتاليين، ثم أعد إغلاق الحلقة: القيد $V_{out}=V_{in}$ يرسم على منحنى النقل ثلاث نقاط تقاطع. اثنتان عند الجهود الشرعية — توازنان مستقران: أي إزاحة صغيرة (ضجيج) تُعاد بقوة نحو النقطة. أما الثالثة، في قلب المنطقة المحرّمة، فهي توازن هشّ لا تتنبأ به معادلاتنا المنطقية أصلاً (جهودها غير شرعية!): كرةٌ على قمة تلّ — أدنى نسمة تُسقطها يميناً أو يساراً، لكن متى تسقط؟ غير محدود نظرياً.
متى نزور هذه القمة؟ عند خرق setup/hold — لقطة أثناء تغيّر $D$ — أو سباق SR: الدارة قد تعلق قرب التوازن الهش وتخرج متأخرة بشكل عشوائي وإلى حالة عشوائية. لهذا نظام التوقيت الديناميكي ليس بيروقراطية — إنه سياجُ حماية من ظاهرة فيزيائية حقيقية. (وكيف نتعامل مع مداخل من العالم الخارجي غير الملتزمة بأي ساعة؟ مزامنات متسلسلة تقلّص الاحتمال أسّياً — قصة محاضرة قادمة).
4.13 السجل، ملف السجلات (RV32)، وسجل الإزاحة
- منفذ كتابة: مفكّك $\log n \to n$ يترجم «رقم السجل» إلى إشارة enable لسجل واحد بالضبط (one-hot — صديقنا من المحاضرة الماضية)، وناقل بيانات الكتابة يصل الجميع.
- منفذا قراءة: بورران عريضان $n\to1$ (لكل بت عمود بورر) — وضعُ رقمي سجلين يعطي محتوييهما فوراً (قراءة توافقية!). لماذا منفذان؟ الشريحة تجيب بجملة واحدة: «مناسب لحاسوب» — أمرُ
add rd, rs1, rs2يقرأ سجلّين في نفس الدورة.
module registerfile (Read1,Read2,WriteReg,WriteData,RegWrite,Data1,Data2,clock);
input logic [4:0] Read1, Read2, WriteReg; // أرقام سجلات القراءة والكتابة
input logic [31:0] WriteData;
input logic RegWrite, clock;
output logic [31:0] Data1, Data2;
logic [31:0] RF [31:0]; // 32 سجلاً × 32 بتاً
assign Data1 = RF[Read1]; // قراءة توافقية
assign Data2 = RF[Read2];
always_ff @(posedge clock) // كتابة متزامنة
if (RegWrite) RF[WriteReg] <= WriteData;
endmodule
لاحظ التقسيم النظيف: القراءة assign توافقية صرفة، والكتابة داخل always_ff على الجبهة وبإذن RegWrite — نفس إشارة RegWEn التي ستقودها وحدة التحكم في المعالج. (وتذكرة من المحاضرة الأولى: في RISC-V الحقيقي $x0$ مثبّت صفراً — إمّا بلا FF أصلاً أو بتجاهل كتابته).
4.14 أنواع الذاكرة: السجل ليس نهاية القصة
- سجلات (DFF): الأسرع؛ لكنها «سمينة» مساحةً — لا تصلح لبنى كثيفة متعددة البتات؛ متطايرة (تفقد المحتوى بانقطاع التغذية).
- ROM: أبطأ من الـFF؛ قراءة فقط؛ كثيفة جداً؛ غير متطايرة — مصفوفة بتات مثبّتة يقرأها مفكّك عناوين + بورر.
- RAM: قراءة وكتابة؛ كثيفة جداً؛ متطايرة؛ أبطأ. بنيتها المفهومية هي حرفياً ملف سجلات مكبَّر: مفكّك عناوين + صفوف خلايا + بورر خرج، مع ADDR/DATAIN/DATOUT/WE/EN.
واجهات RAM (أسماء تجارية ستقابلها في أوراق المواصفات): Single-Port — منفذ واحد للقراءة أو الكتابة بالتناوب؛ Dual-Port — منفذان كاملان مستقلان (A وB، وربما بساعتين مختلفتين!)؛ Two-Port — منفذ قراءة + منفذ كتابة منفصلان. لاحظ كيف يعيد التاريخ نفسه: ملف سجلات RV32 هو عملياً «Three-Port» (قراءتان + كتابة) — الاسم يتبع عدد الأبواب لا حجم الغرفة.
4.15 خلاصة
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية صحيح؟
أ خاطئ بوضوح — القاعدة العامة معاكسة ($2n$ مقابل قفزات رباعية). لكن ب خاطئ أيضاً — وهنا الفخ: كلمة «دائماً». لعرضٍ صغير (بتّ واحد أو بتّان) لا فرق فعلياً، بل قد يضيف عتاد الاستباق (حساب $G,P$ والبوابات العريضة) تأخيراً يجعل CLA غير أسرع؛ التفوق يظهر مع نموّ $n$. في أسئلة «دائماً/أبداً» ابحث عن الحالة الحدّية الصغيرة!
ج خاطئ بنص الشريحة الصريح: المُركِّب ينتج تنفيذات مختلفة لنفس الكود السلوكي حسب قيود مساحة/زمن/طاقة — assign {cout,s}=a+b+cin; قد يصبح RCA أو CLA أو غيرهما. ✔ الإجابة: د.
أي من الادعاءات التالية خاطئ؟
ج هو الخاطئ — والدليل بين يديك: دارة $AB+C'$ لها $2^3=8$ توليفات، لكن 4 فحوص ({011,101,111} الحيوية + واحد لكشف $q_0$) كشفت كل أعطال stuck-at المفردة الثمانية. جدول الأعطال يوجد أقل مجموعة مغطّية — نادراً ما تلزم كل التوليفات.
البقية صحيحة: أ من معادلة التكلفة (المردود في المقام!)؛ ب لأن هدف تجربة الكشف قرار سليم/معطوب — أول فشل يحسم؛ د لأن نموذج stuck-at يصف السلوك المنطقي الظاهري أياً كان مصدره الفيزيائي. ✔ الإجابة: ج.
أي من الادعاءات التالية خاطئ؟
أ هو الخاطئ: التوازن الهشّ ظاهرة لأي عنصر ثنائي استقرار خُرقت شروط التقاطه — السيد والتابع كلاهما قفلان قابلان لها (فكّر: إن خرج السيد من حالته الهشة قُبيل جبهة الهبوط تماماً، انتهك بدوره نافذة التقاط التابع!). لا حصانة لأحد.
ب صحيح — هذه بالضبط ضمانة «اللقطة تسبق التسريب» التي برهنّاها لسلسلة DFF. ج صحيح مبدئياً — أضف مفكّكات ومنافذ كتابة إضافية (مع تعريف سياسة للتصادم على نفس السجل)؛ لا مانع بنيوي. د صحيح — البند الثاني من دستور النظام الديناميكي حرفياً. ✔ الإجابة: أ.
مجمّع RCA بعرض $n=8$ مبني من خلايا FA بالبنية $C_{out}=AB+(A\oplus B)C_{in}$. بنموذج Unit-Delay، ما $t_{PD}$ الكلي للمجمّع؟
كل بوابات $A_i\oplus B_i$ تُحسب بالتوازي في الوحدة 1 (مداخلها جاهزة منذ الصفر). الخلية الأولى تنتج $C_1$ بعد 3 وحدات (XOR ثم AND ثم OR)، وكل خلية تالية تضيف بوابتين فقط على مسار الحمل (AND ثم OR، إذ الـ$\oplus$ جاهز): $$t_{PD}=3+2(n-1)=3+14=\mathbf{17}$$ الخيار أ هو الحساب الساذج «3 لكل خلية»، والخيار ج هو التقريب $\approx2n$ الذي تذكره الشريحة كتقدير — لكن السؤال طلب القيمة الدقيقة بالنموذج. اقرأ دائماً: تقريب أم حساب مضبوط؟ ✔ الإجابة: ب.
في قفل SR بِبنية NOR كان $S=R=1$، ثم هبط المدخلان إلى $S=R=0$ في اللحظة نفسها وبوابتا الدارة متساريتان تماماً. اختر الوصف الأدق لما قد يحدث:
عند $S=R=1$ كلا المخرجين 0. بعد الإفلات المتزامن، تحاول البوابتان رفع مخرجيهما معاً؛ أول من يرتفع يقفل الآخر — لكن بتساوي السرعات تدخل الدارة منطقة التوازن الهش (النقطة الثالثة على منحنى النقل): قد تبقى هناك زمناً غير محدود ثم «تسقط» نحو إحدى الحالتين المستقرتين بلا قدرة تنبؤ. أ يخترع أولوية لا وجود لها؛ ب يتجاهل أن $Q=\overline Q=0$ ليست مستقرة بعد تحرير المدخلين (كل NOR بمدخلين صفرين يريد إخراج 1!)؛ د يخلط مع الحلقة الفردية — بنيتنا زوجية التغذية لا مذبذب. ✔ الإجابة: ج.
أي من الادعاءات التالية صحيح بخصوص ملف سجلات RV32 والـALU كما بُنيا في المحاضرة؟
ب صحيح — وهو يلخص «لماذا صُمم هكذا»: أمر R-Type يحتاج معاملين معاً (منفذا قراءة توافقيان)، وbeq يحتاج حكماً فورياً بالمساواة (طرح + NOR عريضة ← Zero).
أ معكوس تماماً (القراءة توافقية assign؛ الكتابة على الجبهة بشرط RegWrite). ج خاطئ — SLT تُخرج $000\dots01$: بت واحد في الـlsb من إشارة الطرح المصححة، والبقية أصفار مثبّتة. د خاطئ — المفكّك one-hot بالبناء: مخرج واحد مضاء مهما كانت البيانات. ✔ الإجابة: ب.
آلات الحالات المنتهية: النظام الرقمي يتعلم التذكّر
5.1 لماذا لا يكفي التوافقي؟ ولادة «الحالة»
افتح شرائح هذه المحاضرة تجد في صدرها رسماً مفاجئاً: مخطط حالات ضخم بعقد مرقّمة 0–9 وإشارات تحكم غامضة (MemRead، IRWrite، PCWrite…). هذا ليس زخرفة — إنه وحدة التحكم لمعالج متعدد الدورات، الوجهة النهائية لهذا المساق. والرسالة الضمنية من المحاضِر واضحة: الأداة التي تتعلمها اليوم هي حرفياً الأداة التي ستدير بها معالجاً كاملاً بعد خمس محاضرات.
ما الذي ينقص العالم التوافقي؟ فيه، الخرج دالة توليفة المداخل الحالية فقط: $Z=f(X)$ — لا أمس ولا غداً. لكن المسائل الحقيقية تتطلب تاريخاً: قفل يتذكر الأرقام التي أُدخلت، مجمّع يتذكر حملاً من الخانة السابقة، معالج يتذكر في أي خطوة من الأمر هو. الحل المعماري:
نضيف للدارة التوافقية عنصر ذاكرة يخزّن «الحالة» — تلخيصاً مضغوطاً لكل التاريخ ذي الصلة. فتصبح المعادلتان الحاكمتان:
$$Z=f(X,S) \qquad\qquad NS=g(X,S)$$الخرج يعتمد على المدخل والحالة الحاضرة (PS)، والدارة تحسب أيضاً الحالة التالية (NS) التي ستُلتقط في الذاكرة. إذا كان عدد الحالات منتهياً فهذه آلة حالات منتهية (FSM) — وتوجد نظرياً آلات لا نهائية الحالات (الحاسوب المثالي مثلاً)، لكن كل عتاد فعلي منتهٍ. وفي الآلة المتزامنة، الانتقال بين الحالات لا يحدث إلا في لحظات محددة: جبهات الساعة — الساعة هي مايسترو الانتقالات، وذاكرة الحالة هي قافزات DFF من المحاضرة الماضية.
5.2 مثال 1 — القفل التسلسلي: أول مخطط حالات
قفل رقمي تسلسلته السرية 8 ثم 0 ثم 3. ماذا يجب أن «يعرف» القفل في كل لحظة؟ ليس كل ما أُدخل منذ الصباح — يكفيه مقدار التقدم في التسلسلة:
- $A$ — الحالة الابتدائية: لم يبدأ شيء صحيح بعد.
- $B$ — أُدخل 8 للتو.
- $C$ — أُدخل 8 ثم 0.
والخرج $Z$: 0 مقفول، 1 مفتوح. نرسم مخطط الحالات: دوائر للحالات وأسهم للانتقالات، وعلى كل سهم الدخل الذي سبّبه / الخرج المصاحب: من $A$ عند $X{=}8$ ننتقل لـ$B$ (بخرج 0)، وأي دخل آخر يعيدنا لـ$A$؛ من $B$ عند $X{=}0$ إلى $C$؛ ومن $C$ عند $X{=}3$: الخرج $Z{=}1$ — انفتح القفل. أي انحراف في أي نقطة يعيد إلى $A$.
5.3 مثال 2 — المسكّم الثنائي التسلسلي: الخط الكامل من الرسم إلى الدارة
مسألة جميلة بقدر ما هي عملية: جمع عددين ثنائيين بتاً بتاً عبر الزمن (LSB أولاً)، بمجمّع واحد صغير بدل مجمّع عريض — هذا هو «الجمع التسلسلي». ما الذي يجب تذكّره بين خطوة وخطوة؟ الحمل فقط! حالتان تكفيان: $A$ (الحمل 0) و$B$ (الحمل 1).
مخطط ميلي: على كل سهم زوج البتات الداخل $x_1x_2$ والخرج (بت المجموع): من $A$: $00/0$ و$01,10/1$ تبقيان في $A$، و$11/0$ تنقل إلى $B$ (وُلد حمل!). من $B$: $11/1$ و$01,10/0$ تبقيان، و$00/1$ تعيد إلى $A$ (الحمل استُهلك).
5.4 التعريف الرسمي — والتوقيت جزء من العقد
- مجموعة حالات منتهية $S=\{s_1,\dots,s_K\}$، إحداها ابتدائية. تمثيل $K$ حالة يتطلب $k=\lceil\log_2 K\rceil$ متغير حالة ثنائياً (كحد أدنى).
- مجموعة مداخل ثنائية $X$ ومجموعة مخارج ثنائية $Z$ منتهيتان.
- دالة الانتقال: (حالة حاضرة، توليفة مداخل) ← الحالة التالية.
- دالة الخرج — وهنا الانقسام الشهير: في آلة Mealy الخرج دالة (الحالة والمداخل)؛ في آلة Moore الخرج دالة الحالة وحدها.
- و— لا تنسَ أبداً — مواصفات التوقيت: قيود الدخل $t_S, t_H$ وضمانات الخرج $t_{cC\to Q}, t_{pC\to Q}$. الشرائح تدرجها داخل التعريف نفسه: آلة بلا عقد زمني ليست مكوِّناً هندسياً.
بنيوياً، الفرق بين النوعين هو من أين يتغذى لوجيك الخرج: في ميلي من (PS + المداخل) — فيوجد مسار توافقي مباشر من مدخل الآلة إلى خرجها؛ في مور من PS فقط — الخرج معزول عن المداخل بجدار من القافزات.
5.5 مثال 3 — كاشف «0101»: الدرس الأغلى في المحاضرة
آلة بدخل واحد وخرج واحد: $Z=1$ عند اكتمال النمط $0101$ (مع سماح بالتداخل: التتابع $010101$ يطلق الخرج مرتين). أربع حالات تلخص التقدم: $A$ (لا شيء)، $B$ (رأينا 0)، $C$ (رأينا 01)، $D$ (رأينا 010). جدول الحالات:
| PS | X=0 → NS,z | X=1 → NS,z |
|---|---|---|
| A | B,0 | A,0 |
| B | B,0 | C,0 |
| C | D,0 | A,0 |
| D | B,0 | C,1 |
أربع حالات ← متغيّرا حالة $y_1y_2$. والآن التجربة المزدوجة التي أجرتها الشرائح عمداً:
الإسناد الأول ($A{=}00, B{=}01, C{=}11, D{=}10$) يعطي بعد خرائط كارنو:
$$Y_1=xy_1'y_2+x'y_1y_2+xy_1y_2' \quad Y_2=x'y_1'+y_1'y_2+y_1y_2' \quad z=xy_1y_2'$$الكلفة: 15 بوابة ثنائية المداخل.
الإسناد الثاني ($A{=}00, B{=}01, C{=}10, D{=}11$) يعطي:
$$Y_1=x'y_1y_2'+xy_2 \qquad Y_2=x' \qquad z=xy_1y_2$$الكلفة: 6 بوابات فقط — $Y_2$ صارت مقلوباً واحداً حرفياً! نفس السلوك الخارجي تماماً، لكن ترميز الحالات الثاني «صادف» بنية الدوال بشكل أرحم.
5.6 التعابير المنتظمة: الرياضيات خلف كاشفات المحارف
- $\varnothing$ و$a$ (لكل حرف $a$) تعبيران منتظمان — يصفان اللغة الفارغة واللغة $\{a\}$.
- إذا كان $R,S$ منتظمين: $R\cup S$ يصف «كلمة من هذه أو تلك»، و$R\cdot S$ يصف «سلسلة من كلمةٍ من الأولى تليها كلمة من الثانية».
- $R^{*}$ (نجمة كليني): «أي عدد — بما فيه صفر — من كلمات $R$ متسلسلة».
5.7 من ميلي إلى مور: أربع طرق
5.8 مثال 4 — كاشف «11»: أصغر آلة مفيدة في العالم
المواصفة بلغة إشارات: معطى تيار دخل $x(n)$، والمطلوب $$z(n)=x(n)\cdot x(n-1)$$ مع شرط الحدود $z(0)=0$ — أي «أخرج 1 عندما يكون البت الحالي والسابق كلاهما 1». كم يجب أن نتذكر؟ البت الأخير فقط: حالتان $A$ (السابق 0) و$B$ (السابق 1).
الآلة: حالتان — $Q=0$ (آخر بت 0) و$Q=1$ (آخر بت 1). الخرج $z = Q\cdot x$. أدخل بتات وراقب:
5.9 توقيت الآلة: القواعد الأربع
الآلة المتزامنة فيها أربعة أصناف مسارات: قافز←قافز (عبر لوجيك الحالة)، دخلُ النظام←قافز، قافز←خرج النظام، ودخل←خرج (في ميلي). الشرائح تصوغ القيود الحاكمة — احفظها كصيَغ عمل:
- دورة الساعة: $$T \ge t_{pC\to Q}(FF) + t_{pd}(CL) + t_{SU}(FF)$$ أطول مسار قافز←قافز يحدد أدنى دورة — وريث مباشر لقاعدة «المسار الأطول» التوافقية.
- setup لمدخل النظام: $$t_{S}(input) \ge t_{pd}(CL) + t_{SU}(FF)$$ على المدخل الخارجي أن يستقر قبل الجبهة بزمن يكفي لعبور اللوجيك ثم إرضاء القافز.
- hold داخلي: $$t_{cd}(CL) + t_{cC\to Q}(FF) \ge t_{H}(FF)$$ أسرعُ تغيّرٍ بعد الجبهة يجب ألا يصل قبل انقضاء نافذة الالتقاط.
- hold لمدخل النظام: $$t_{H}(input) \ge t_{H}(FF) - t_{cd}(CL)$$
5.10 المنهجية السباعية + مثال ختامي: عدّاد مودولو-8
- افهم الوصف الكلامي: كم مدخلاً، كم مخرجاً، ماذا يجب أن يُتذكّر؟
- ابنِ مخطط/جدول الحالات.
- (قلّص الجدول — أدوات التقليص في محاضرة قادمة).
- اختر إسناد حالات وعناصر ذاكرة (عندنا: D-FF).
- اكتب جدولي الانتقالات والخرج المرمّزين.
- استخرج دوال الانتقال والخرج (خرائط كارنو).
- ارسم الدارة.
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية صحيح؟
أ خاطئ — مثال 0101 حسم الأمر تجريبياً: 15 بوابة مقابل 6 لنفس الآلة بإسنادين مختلفين.
ب خاطئ — الأدنى هو $\lceil\log_2 K\rceil$: أربع حالات ← قافزان (وone-hot الذي يستخدم $K$ قافزات هو خيار تصميمي لا حدّ أدنى).
ج خاطئ ود صحيح — وجهان لعملة القاعدتين (2) و(4): بوابات أكثر ترفع $t_{pd}$ و$t_{cd}$ معاً؛ فمتطلب setup للمدخل يكبر ($t_S(in) \ge t_{pd}+t_{SU}$)، بينما متطلب hold يصغر ($t_H(in) \ge t_H - t_{cd}$) وقد يصبح سالباً. ✔ الإجابة: د.
في المسكّم الثنائي التسلسلي (ميلي، حالتان: $A$ حمل 0، $B$ حمل 1) دخل في الدورات $t_1\dots t_4$ الأزواج: $(1,1), (0,1), (1,0), (0,0)$ ابتداءً من $A$. ما تسلسل الخرج $z$ والحالة النهائية؟
$t_1$: $PS{=}0$، دخل $(1,1)$: $z=1\oplus1\oplus0=0$، $NS=maj(1,1,0)=1$ ← إلى $B$.
$t_2$: $PS{=}1$، $(0,1)$: $z=0\oplus1\oplus1=0$، $NS=maj(0,1,1)=1$ ← يبقى $B$.
$t_3$: $PS{=}1$، $(1,0)$: $z=0$، $NS=1$ ← يبقى $B$.
$t_4$: $PS{=}1$، $(0,0)$: $z=0\oplus0\oplus1=1$، $NS=maj(0,0,1)=0$ ← عودة إلى $A$.
$z=0,0,0,1$ والحالة $A$ ✔ — وتحقق حسابي أنيق: جمعنا $LSB$-أولاً $1{+}3\cdot2\dots$ فعلياً $x_1=0101_2$ من الأعلى... الأبسط: $x_1=(1,0,1,0)\to 5$، $x_2=(1,1,0,0)\to 3$، والخرج $(0,0,0,1)\to 8=5+3$ ✔. الإجابة: ب.
حُوِّل المسكّم التسلسلي (ميلي بحالتين) إلى آلة مور مكافئة (بأسلوب شطر الحالات). كم عدد حالات نسخة مور الأدنى، ولماذا؟
في مور، الخرج ملتصق بالحالة؛ وفي ميلي الأصلية كل حالة (قيمة حمل) تُخرج 0 أو 1 حسب الدخل ← يجب شطر كل حالة إلى نسختين (خرج 0 / خرج 1). التوليفات (حمل، خرج) الأربع كلها قابلة للوصول فعلاً — وهذا بالضبط مخطط الشريحة: $A$(c0,z0)، $B$(c0,z1)، $C$(c1,z1)، $D$(c1,z0). القاعدة العامة: مور المكافئة قد تحتاج حتى (عدد الحالات × عدد قيم الخرج) حالة — وليس دائماً (بعض التوليفات قد لا تُزار). ✔ الإجابة: ج.
أي تعبير منتظم يصف لغة «كل السلاسل الثنائية التي تنتهي بـ11»؟
«أي بادئة كانت» = $(0\cup1)^{*}$، ثم الشرط الصلب «11 في الذيل» = التسلسل $\cdot1\cdot1$ ← الخيار ج. أ يقبل فقط تكرارات 11 الخالصة (يرفض $011$!)؛ ب يشترط 11 في البداية؛ د لا يضمن «1» متتاليتين في النهاية ($01$ تنتهي بواحدة فقط ومقبولة عنده خطأً). ولإغلاق الدائرة: آلة كشف هذه اللغة هي حرفياً «كاشف 11» من مثال 4 بنكهة مور بثلاث حالات. ✔ الإجابة: ج.
صمّم آلة ميلي بدخل واحد وخرج واحد: $z=1$ إذا وفقط إذا كان مجموع البتات المستقبَلة حتى الآن (بما فيها الحالية) يقبل القسمة على 3 وكان الدخل الحالي 1. اتبع الخطوات: (أ) كم حالة تلزم وماذا تمثل؟ (ب) اكتب جدول الحالات. (ج) بإسناد ثنائي مباشر، استخرج دوال الانتقال والخرج.
💡 تلميح
👁 الحل الكامل خطوة بخطوة
(أ) ثلاث حالات $S_0,S_1,S_2$ = باقي عدد الآحاد mod 3. البداية $S_0$. (قافزان: $\lceil\log_2 3\rceil=2$، مع توليفة رابعة فائضة — don't care مستقبلية!).
(ب) الدخل 0 يجمّد الحالة والخرج 0. الدخل 1 يقدّم الباقي، والخرج 1 فقط عند الانتقال إلى باقٍ صفري (أي من $S_2$ مع دخل 1):
| PS | x=0 → NS,z | x=1 → NS,z |
|---|---|---|
| S0 | S0,0 | S1,0 |
| S1 | S1,0 | S2,0 |
| S2 | S2,0 | S0,1 |
(تحقق حدّي: السلسلة $111$: بعد ثالث «1» المجموع 3 و$z=1$ ✔ — لاحظ أن ميلي تُخرجها في نفس دورة البت الثالث.)
(ج) بإسناد $S_0{=}00, S_1{=}01, S_2{=}10$ ($y_1y_2$) والتوليفة $11$ لامبالاة:
$$Y_1 = x'y_1 + x\,y_2 \qquad Y_2 = x'y_2 + x\,y_1'y_2' \qquad z = x\,y_1$$الاشتقاق: $Y_1=1$ عندما نبقى في $S_2$ ($x'y_1$) أو ندخلها من $S_1$ ($xy_2$)؛ $Y_2=1$ عندما نبقى في $S_1$ أو ندخلها من $S_0$؛ والخرج $z=xy_1$ («في $S_2$ ووصل 1») — واستغللنا $\phi_{11}$ لتبسيط الحدود (مثلاً في $z$: الخلية $x y_1 y_2=111$ لامبالاة فسمحت بالحد $xy_1$ بدل $xy_1y_2'$). سبع بوابات صغيرة وقافزان — آلة كاملة وفق المنهجية السباعية حرفياً.
المزيد عن آلات الحالات: التوقيت الدقيق وحدود القدرة
6.1 أين نقف؟
في المحاضرة السابقة تعلمنا بناء الآلات: مخطط، جدول، إسناد، دوالّ، دارة. محاضرة اليوم تطرح سؤالين أعمق وأقسى: (1) متى تعمل الآلة المبنية فيزيائياً بشكل صحيح — بأي دورة ساعة، وبأي هوامش، وماذا يفعل بها انحراف الساعة؟ (2) وما الذي تستطيع الآلات المنتهية حسابه أصلاً — وأين يقف جدار الاستحالة؟ نصفها هندسة توقيت دقيقة، ونصفها نظرية جميلة ستمنحك في الامتحان أجوبة من سطر واحد على أسئلة تبدو مخيفة.
6.2 لكل لوجيك مساران: الأبطأ Max والأسرع Min
خذ زوج قافزات $a \to CL \to c$. كتلة اللوجيك بينهما ليست «زمناً واحداً» بل مروحة مسارات، ويهمنا طرفاها:
Propagation Delay ($t_{dMax}$): الزمن من آخر تغيّر في المداخل حتى آخر تغيّر في المخارج — من استقرار الدخل إلى استقرار الخرج. يحكمه المسار الأبطأ.
Contamination Delay ($t_{cMin}$): الزمن من أول تغيّر في المداخل حتى أول تغيّر في المخارج — من «تلوّث» الدخل إلى «تلوّث» الخرج. يحكمه المسار الأسرع.
وللقافز نفسه زوجاه: $t_{dC\to Q}$ (أقصى زمن خروج بعد الجبهة) و$t_{cC\to Q}$ (أدنى زمن يبقى فيه الخرج القديم صامداً). أربعة أرقام — وكل التوقيت المتزامن مبني عليها.
6.3 قيد الـSetup: سباق ضد الجبهة القادمة
6.4 قيد الـHold: «غير آمن بأي سرعة»
المعطيات: $t_{dC\to Q}=t_{cC\to Q}=t_s=150ps$، $t_h=250ps$، $t_{dMax}=850ps$، $t_{cMin}=100ps$. سؤالا الشريحة: هل يتحقق قيد الـhold؟ وما أدنى دورة ساعة؟
6.5 انحراف الساعة (Clock Skew): عندما لا تدق الساعة للجميع معاً
افترضنا حتى الآن أن الجبهة تصل لكل القافزات في اللحظة نفسها. في شريحة حقيقية، شبكة توزيع الساعة تُدخل فوارق وصول — انحرافاً مقداره حتى $t_k$. وبما أننا لا نعرف مسبقاً اتجاهه في كل زوج قافزات، تفترض الشرائح الأسوأ في كلا القيدين:
الـhold: $150+100-100 = 150 \lt 250$ — خرق! الهامش الصفري لم يحتمل أول انحراف. وتذكّر: لا سرعة ساعة تنقذنا — الحل الوحيد إبطاء المسار السريع (رفع $t_{cMin}$ بمقدار 100ps إضافية على الأقل).
الدورة: $t_{cy} \ge 1150+100=1250ps$ — التردد الأقصى هبط إلى $800MHz$. انحراف واحد صغير كلّف 8% أداءً وخرقاً وظيفياً كاملاً.
6.6 حدود الآلات المنتهية: ماذا لا تستطيع FSM أن تحسب؟
ننتقل من البيكو-ثواني إلى الأبدية. الآلات التي بنيناها ذاكرتها منتهية ← عدد حالاتها منتهٍ. هل يمكنها تنفيذ أي تحويل مطلوب على الدخل؟ الشرائح تجيب بالنفي القاطع، والبرهان من النوع الذي يستحق أن تفهمه لا أن تحفظه:
المطلوب المستحيل: $z=1$ إذا وفقط إذا تساوى عدد الآحاد وعدد الأصفار المستقبَلة حتى الآن. (مثال الشريحة: $X=1000110111$ يعطي $Z=0100010100$ — تحقق من موضعين بنفسك!)
المبرهنة: آلة منتهية الحالات تحت دخل دوري تنتج خرجاً دورياً — عدا «زمن عبور» ابتدائي منتهٍ.
البرهان: ليكن للآلة $n$ حالة ولدورة الدخل طول $k$. راقب حالة الآلة عند بداية كل دورة دخل: بعد $n{+}1$ دورة على الأكثر تتطابق حالتان من حالات المراقبة. من نقطة التطابق: نفس الحالة + نفس شريحة الدخل (الدورة تتكرر) ← نفس تسلسل الحالات ونفس الخرج ← الخرج دوري. ∎
النتيجة العملية: أي مواصفة تفرض خرجاً غير دوري تحت دخل دوري = غير قابلة للتنفيذ بآلة منتهية. (مقارنة الأطوال سقطت بهذا المعيار: دخل «كله أصفار» دوري بدورة 1، والخرج المطلوب ليس دورياً).
مطلوب: $z=1$ إذا وفقط إذا كان عدد الآحاد حتى الآن مربعاً كاملاً ($1,4,9,16,\dots$). تحت الدخل الدوري «كله آحاد» يكون الخرج المطلوب: $$Z=1\,0\,0\,1\,0\,0\,0\,0\,1\,0\,0\,0\,0\,0\,0\,1\dots$$ المسافات بين النبضات ($2k+1$: أي 3، 5، 7، …) تتسع بلا حد — فلأي مرشح دورةٍ $n$ يوجد شوط أصفار أطول من $n$ رغم أن السلسلة ليست صفراً دائماً ← الخرج غير دوري ← مستحيلة التنفيذ بآلة منتهية. سطران وانتهى النقاش — هذه قوة المبرهنة في الامتحان.
6.7 لكن احذر التعميم المتسرّع: آلة الباقي مود 5
«الآلة لا تعدّ بلا حدود» لا تعني «الآلة لا تفهم الأعداد الكبيرة»! إليك المثال المضاد الشهير (شريحتا 21-22): عددٌ ثنائي يصل تسلسلياً، الـmsb أولاً، والمطلوب $z=1$ إذا وفقط إذا كان العدد المستقبَل حتى الآن يقبل القسمة على 5. العدد نفسه ينمو بلا حدود — لكن ما الذي يلزم تذكّره فعلاً؟
ليكن الباقي الحالي $r = x \bmod 5$. وصول بت جديد $b$ يحوّل العدد من $x$ إلى $2x+b$ (إزاحة يسار ثم إضافة). إذن:
$$r_{new} = (2r+b) \bmod 5$$خمس حالات فقط ($r\in\{0,1,2,3,4\}$) مهما تضخم العدد. الانتقالات المشتقة آلياً: من $r{=}0$: البت 0 يبقينا في 0 (والخرج 1 — العدد قابل للقسمة!) والبت 1 ينقل إلى 1؛ من $r{=}1$: إلى 2 أو 3؛ من $r{=}2$: البت 0 إلى 4، والبت 1 إلى 0 بخرج 1؛ من $r{=}3$: إلى 1 أو 2؛ من $r{=}4$: إلى 3 أو 4. وتحذير الشريحة الحرفي: «هذه آلة ميلي…» — الخرج معلّق على الأسهم (يُعلن فور اكتمال البت الحالي).
💡 تحدي الشريحة الختامي: وماذا لو وصل الـlsb أولاً؟ هل ما زالت FSM ممكنة؟
نعم — وهذه من أجمل الأفكار: بقدوم الـlsb أولاً، البت الواصل في الخطوة $i$ وزنه $2^i$. لا نستطيع «إعادة وزن» الماضي، لكن يمكن تتبّع أمرين منتهيين: الباقي المتراكم $r=(\sum b_i 2^i)\bmod 5$، ووزن الخطوة الحالية $w=2^i \bmod 5$. والمفتاح: متوالية $2^i \bmod 5$ دورية: $1,2,4,3,1,2,4,3,\dots$ — أربع قيم فقط! التحديث: $r_{new}=(r+b\cdot w)\bmod 5$ و$w_{new}=(2w)\bmod 5$. آلة الضرب الديكارتي (الباقي × الوزن) فيها $5\times4=20$ حالة — منتهية تماماً ✔. العبرة: السؤال الحاسم ليس «هل الكمية بلا حدود؟» بل «هل يوجد ملخّص منتهٍ كافٍ للمستقبل؟».
6.8 خلاصة
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية خاطئ؟
ج هو الخاطئ: خفض جهد التغذية يبطئ الترانزستورات (تيار شحن أقل) ← كل $t_{pd}$ تكبر ← مسارات أبطأ ← مشاكل setup تزداد لا تقل. (يُخفَّض الجهد لتوفير الطاقة — والثمن دائماً سرعة).
أ صحيح: setup يسكن المسارات البطيئة وhold المسارات السريعة — قيدان مستقلان (رأيناه حرفياً في مثالنا: إصلاح أحدهما لا يمس الآخر). ب صحيح: التبريد يسرّع الترانزستورات ← $t_{pd}$ أصغر ← مشاكل setup أقل. د صحيح: «غير آمن بأي سرعة» — $t_{cy}$ غائب عن قيد الـhold أصلاً. ✔ الإجابة: ج.
نظام متزامن: $t_{dC\to Q}=t_{cC\to Q}=t_s=150ps$، $t_h=250ps$، $t_{dMax}=850ps$، $t_{cMin}=100ps$، بلا انحراف ساعة. اختر الادعاء الصحيح:
hold: $t_{cC\to Q}+t_{cMin}=150+100=250=t_h$ — محقق بلا أي هامش. setup: $t_{cy}\ge150+850+150=1150ps$. الخيار أ يقترح العلاج المستحيل (الساعة لا تصلح hold)؛ والخيار د يقع في الفخ المعاكس تماماً — الـhold مستقل عن الدورة بالتعريف. ✔ الإجابة: ب.
أُضيف للنظام السابق انحراف ساعة $t_k=100ps$ (إشارة مجهولة — اتفاقية الأسوأ). أصبح قيد الـhold مخروقاً: $150+100-100=150 \lt 250$. أي الإجراءات التالية يصلح الخرق؟
الشرط المطلوب: $t_{cC\to Q}+t_{cMin}-t_k \ge t_h$ أي $150+t_{cMin}-100\ge250$ ← $t_{cMin}\ge200ps$ — وهذا بالضبط ما يفعله الخيار ب (تبطئة المسار الأسرع بمخازن مؤقتة، دون المساس بالمسار الحرج للـsetup إن حافظنا على $t_{dMax}$). أ عديم الأثر («غير آمن بأي سرعة»)؛ ج يعالج متغيراً لا يظهر في قيد الـhold أصلاً (ويضر الدورة!)؛ د يعالج قيد setup لا hold — $t_s$ ليس في المعادلة. ✔ الإجابة: ب.
أي من المهام التالية قابلة للتنفيذ بآلة حالات منتهية؟
ج ممكنة بخمس حالات فقط — الملخّص المنتهي الكافي هو الباقي: $r_{new}=(2r+b)\bmod5$. أ سقطت ببرهان $n{+}1$ آحاد ثم $n{+}1$ أصفار؛ ب سقطت بمبرهنة الدورية (خرج غير دوري تحت دخل دوري — فجوات $2k{+}1$ المتسعة)؛ د ليست حتى دالة سببية (تعتمد على المستقبل!) — فخ صياغة لمن يقرأ بسرعة. القاعدة الفاصلة: هل يوجد ملخّص منتهٍ للتاريخ يكفي لتحديد كل سلوك مستقبلي؟ ✔ الإجابة: ج.
صمّم آلة ميلي بدخل تسلسلي (msb أولاً) وخرج واحد: $z=1$ إذا وفقط إذا كان العدد الثنائي المستقبَل حتى الآن يقبل القسمة على 3. (أ) كم حالة تلزم وماذا تمثل؟ (ب) اشتق قاعدة الانتقال واكتب جدول الحالات مع الخرج. (ج) هل تتغير إجابتك الجوهرية لو وصل الـlsb أولاً؟
💡 تلميح
👁 الحل الكامل خطوة بخطوة
(أ) ثلاث حالات $r\in\{0,1,2\}$ = باقي قسمة العدد الحالي على 3. البداية $r=0$ (العدد الفارغ صفر).
(ب) القاعدة: $r_{new}=(2r+b)\bmod3$، والخرج $z=1$ إذا وفقط إذا $r_{new}=0$:
| PS (r) | b=0 → NS,z | b=1 → NS,z |
|---|---|---|
| 0 | 0, 1 | 1, 0 |
| 1 | 2, 0 | 0, 1 |
| 2 | 1, 0 | 2, 0 |
الاشتقاق خانة خانة: من $r{=}1$ مع $b{=}1$: $2\cdot1+1=3\equiv0$ ← خرج 1 ✔ (مثلاً العدد $11_2=3$). من $r{=}2$ مع $b{=}0$: $4\equiv1$؛ ومع $b{=}1$: $5\equiv2$. تحقق نهائي: $110_2=6$: المسار $0\xrightarrow{1}1\xrightarrow{1}0(z{=}1)\xrightarrow{0}0(z{=}1)$ — 3 ثم 6 كلاهما قابل للقسمة ✔.
(ج) لا — تبقى ممكنة، بنفس حيلة مود 5: أوزان $2^i\bmod3$ دورية ($1,2,1,2,\dots$ — بدورة 2 فقط هنا!)، فآلة (باقٍ × وزن) بـ$3\times2=6$ حالات تنجز المهمة: $r_{new}=(r+b\cdot w)\bmod3$، $w_{new}=(2w)\bmod3$. الجوهر ثابت: ملخّص منتهٍ ← FSM ممكنة.
تكافؤ الآلات، الفحص بالمسح (Scan)، وخط الأنابيب (Pipeline)
7.1 لماذا تجتمع هذه الثلاثية في محاضرة واحدة؟
للوهلة الأولى تبدو عناوين اليوم الثلاثة غرباء عن بعضها: نظرية تكافؤ رياضية، وتقنية فحص مصانع، وحيلة تسريع معمارية. لكن انظر أعمق تجدها ثلاث إجابات على ثلاثة مخاوف هندسية تلاحق كل من سلّم تصميماً تتابعياً في نهاية الأسبوع الماضي:
- «هل آلتي أكبر من اللازم؟» — ربما جدول حالاتك يحوي حالات «توائم» تتنكر بأسماء مختلفة وتسلك سلوكاً واحداً. كل حالة فائضة = قافزات ولوجيك وطاقة بلا مقابل. تكافؤ الحالات يعطيك خوارزمية ميكانيكية تعصر الآلة إلى أصغر مكافئ لها — وبرهاناً أنك لا تستطيع أصغر.
- «هل عتادي المُصنَّع سليم؟» — تعلمنا في المحاضرة 4 فحص الدارات التوافقية بجداول الأعطال. لكن قافزات الآلة مدفونة: لا نتحكم بمداخل اللوجيك الداخلي ولا نرى مخارجه. Scan يحوّل كل قافزات الشريحة إلى سجل إزاحة واحد طويل نضخ عبره الفحوص ونسحب النتائج.
- «هل عتادي يعمل بكامل طاقته؟» — دارة توافقية عميقة تنجز نتيجة واحدة كل «عمق» كامل، بينما معظم طبقاتها عاطلة معظم الوقت. Pipeline يشغّل كل الطبقات معاً على حسابات متتالية — نفس العتاد، إنتاجية مضاعفة.
وثلاثتها تقف على أكتاف الأسبوعين الماضيين: التقليص يحتاج جداول الحالات (محاضرة 5)، والمسح يحتاج الـDFF وسجل الإزاحة (محاضرة 4)، والأنبوب يحتاج قواعد التوقيت المتزامن (محاضرة 6). لنبدأ.
7.2 تكافؤ الحالات والآلات: متى تكون حالتان «نفس الحالة»؟
7.2.1 التعريف — ولماذا هو أصعب مما يبدو
خذ آلتي حالات (أو حالتين في نفس الآلة). متى نقول إنهما «متكافئتان»؟ الجواب الحدسي: «إذا سلكتا نفس السلوك». لكن ما هو «السلوك»؟ الحالة الداخلية غير مرئية لمن يقف خارج الصندوق — الخرج وحده مرئي. من هنا التعريف الرسمي:
الحالتان $s_i$ و$s_j$ (في آلة واحدة أو آلتين بنفس أبجدية الدخل/الخرج) متكافئتان، ونكتب $s_i \equiv s_j$، إذا كان لكل سلسلة دخل ممكنة — من أي طول — تطبيقُها ابتداءً من $s_i$ يعطي نفس سلسلة الخرج حرفياً التي يعطيها تطبيقها ابتداءً من $s_j$.
وتكافؤ آلتين: الآلتان $M_1$ و$M_2$ متكافئتان إذا كان لكل حالة في إحداهما حالة مكافئة في الأخرى (وبالخصوص حالتا البداية متكافئتان) — أي أن مراقباً خارجياً لا يستطيع، بأي تجربة دخل/خرج مهما طالت، أن يميّز أيهما داخل الصندوق.
7.2.2 الفكرة المروِّضة: التمييز بخطوات محدودة
نقول إن حالتين قابلتان للتمييز بطول $k$ إذا وُجدت سلسلة دخل بطول $\le k$ تُنتج منهما خرجين مختلفين. وإذا لم توجد — فهما متكافئتان-$k$ (لا تجربة بطول $k$ تفضحهما). التكافؤ-$k$ علاقة تكافؤ أيضاً، فتقسم الحالات إلى قسم (Partition) نسميه $P_k$: صفوف الحالات التي «تتشابه حتى عمق $k$».
وبهذه اللغة، التكافؤ الحقيقي هو «التكافؤ-$\infty$»: $$s_i\equiv s_j \iff s_i \text{ و } s_j \text{ متكافئتان-}k \text{ لكل } k$$ خطتنا: نحسب $P_1, P_2, P_3, \dots$ متتابعةً — وسنكتشف أنها تتجمد بسرعة، ولحظة تجمّدها هي الجواب النهائي.
- تنظيف مسبق: احذف كل حالة لا يمكن الوصول إليها من حالة البداية — لا خوارزمية تلزمك؛ سيرٌ بسيط على المخطط يكفي. (حالة لا تُزار لا تؤثر على أي سلوك — حذفها مجاني).
- $P_1$ — فصل بالخرج: ضع في نفس الصف الحالات التي تعطي نفس الخرج لكل دخل مفرد (عمود الخرج في جدول الحالات متطابق). لماذا؟ سلسلة بطول 1 لا ترى إلا خرج الخطوة الأولى.
- التكرير $P_k \to P_{k+1}$: حالتان تبقيان معاً في $P_{k+1}$ إذا وفقط إذا كانتا معاً في $P_k$ ولكل حرف دخل، تنتقلان إلى حالتين واقعتين في نفس الصف من $P_k$.
- توقف عندما $P_{k+1}=P_k$. الصفوف الناتجة هي صفوف التكافؤ الحقيقي.
الحدس وراء خطوة التكرير — بالخطوة الرضيعة: لكي تتشابه حالتان لعمق $k{+}1$ خطوة، يلزم أمران لا ثالث لهما: أن تتفقا في خرج الخطوة الأولى (مضمون لأنهما معاً منذ $P_1$)، وأن يكون وريثاهما بعد تلك الخطوة قادرين على التشابه للعمق المتبقي $k$ — أي في نفس صف $P_k$. أي دخلٍ يرسل الوريثين إلى صفين مختلفين هو «شاهد» يفضح الزوج بعد $k{+}1$ خطوة على الأكثر.
7.2.3 البراهين الثلاثة — قلب الموضوع النظري
الادعاء: كل صف في $P_{k+1}$ محتوى بالكامل داخل صف من $P_k$ — الانفصال نهائي: من افترقا في عمقٍ ما لا يجتمعان أبداً.
البرهان: افترض أن $s_i, s_j$ منفصلتان في $P_k$، أي توجد سلسلة شاهدة $\sigma$ بطول $\le k$ تنتج منهما خرجين مختلفين. لكن $\sigma$ نفسها سلسلة بطول $\le k+1$ أيضاً! فهي شاهد صالح لفصلهما في $P_{k+1}$. ∎ (بديهيّ حدّ الخجل — لكنه اللبنة التي يقف عليها كل شيء بعده).
الادعاء: إذا لم يتغير القسم في تكريرة واحدة، فلن يتغير في أي تكريرة لاحقة: $P_j=P_k$ لكل $j \gt k$، والقسم المتجمد هو التكافؤ الحقيقي ($\infty$).
البرهان: لاحظ الملاحظة المفتاحية: قاعدة التكرير «ابقيا معاً إذا قادكما كل دخل إلى نفس الصف» لا تقرأ إلا القسم الحالي — لا تاريخه ولا رقمه. فإذا كان دخل التكريرة $P_{k+1}=P_k$ مطابقاً لدخل التكريرة السابقة، كان ناتجها مطابقاً بالضرورة: $P_{k+2}=P_{k+1}$، وهكذا بالاستقراء إلى الأبد. وبما أن التكافؤ-$j$ لكل $j$ يساوي القسم المتجمد، فالتقاطع اللانهائي (= التكافؤ الحقيقي) يساويه أيضاً. ∎
المعنى الفلسفي: اللانهاية المرعبة في التعريف انهارت: يكفي أن تصمد التوأمتان تكريرةً واحدة كاملة دون انفصال، لنعرف أنهما ستصمدان أمام كل سلاسل الكون.
الادعاء: لآلة بـ$n$ حالة، $P_{n-1}$ متجمدة حتماً (وغالباً أبكر بكثير).
البرهان — حجة عدّ خالصة: ما دام التجمد لم يحدث، كل تكريرة تشطر صفاً واحداً على الأقل (مبرهنة 1 تمنع الدمج، وعدم التجمد يعني تغيّراً ما — والتغير الوحيد الممكن هو شطر). أي أن عدد الصفوف يتزايد تزايداً صارماً: $|P_1| \lt |P_2| \lt \dots$ حتى التجمد. لكن عدد الصفوف محاصر: يبدأ من $1$ على الأقل ولا يتجاوز $n$ (صف لكل حالة). سلسلة صاعدة صرامةً بين $1$ و$n$ طولها $\le n-1$ خطوة... وبدقة: منذ $P_1$ (صفّان على الأقل إن وُجد أي اختلاف خرج) حتى القاع $n$ يوجد متسع لـ$n-1$ شطرة على الأكثر. ∎
نتيجتان امتحانيتان ثمينتان: (1) حالتان في آلة بـ$n$ حالة متكافئتان إذا وفقط إذا عجزت كل السلاسل بطول $\le n-1$ عن تمييزهما — «سلسلة التمييز» إن وُجدت فهي قصيرة مضمونة القِصر. (2) عند حل أسئلة التقليص: إن رأيت نفسك تجاوزت $n-1$ تكريرة — أخطأت حساباً في مكان ما، توقف وراجع.
7.2.4 الآلة المقلّصة (Quotient Machine): الحصاد
حالات الآلة الجديدة = صفوف القسم النهائي. الانتقال من صفٍّ بدخل $x$: خذ أي ممثل من الصف، انظر إلى أين ينتقل، والصف الحاوي للهدف هو الحالة التالية. والخرج: خرج أي ممثل.
لماذا هذا التعريف سليم (Well-defined)؟ هنا يدفع التجمد ثمن نفسه: لو اختار زميلك ممثلاً آخر من نفس الصف، فبما أن القسم متجمد، وريثا الممثلَين يقعان حتماً في نفس الصف الهدف، وخرجاهما متطابقان (اتفاق منذ $P_1$) — التعريف لا يعتمد على الممثل. ولو لم يكن القسم متجمداً لانهار هذا البناء من أساسه.
وهي الأصغر إطلاقاً: أي آلة مكافئة يجب أن تفرّق بين حالتين غير متكافئتين (وإلا أخطأت في خرج سلسلة شاهدة ما) — فعدد حالاتها $\ge$ عدد الصفوف. الآلة المقلّصة تحقق هذا الحد بمساواة. إنها «البصمة القانونية» للسلوك: آلتان متكافئتان ⟺ آلتاهما المقلّصتان متطابقتان (حتى إعادة تسمية الحالات) — وهكذا يُفحص تكافؤ الآلات عملياً.
الجدول (مدخل $X$ واحد، والخرج مورِيّ — ثابت لكل حالة):
| PS | X=0 → NS | X=1 → NS | Z |
|---|---|---|---|
| A | B | C | 0 |
| B | A | D | 0 |
| C | E | F | 1 |
| D | E | G | 1 |
| E | E | F | 0 |
| F | F | F | 1 |
| G | E | G | 1 |
7.3 الفحص في المنظومات التتابعية: تقنية المسح Scan
7.3.1 المشكلة: قافزات لا نصل إليها
في المحاضرة 4 فحصنا دارة توافقية بتغذية مداخلها ومراقبة مخارجها — كان لدينا «أيدٍ» على الطرفين. الآلة التتابعية تكسر اليدين معاً: مداخلُ اللوجيك الداخلي تأتي من قافزات لا من أرجل الشريحة (فقدنا التحكم — Controllability)، ومخارجه تموت داخل قافزات أخرى قبل أن نراها (فقدنا الرؤية — Observability). نظرياً يمكن «قيادة» الآلة عبر سلاسل دخل طويلة لكل فحص — عملياً هذا كابوس تركيبي. الحل الهندسي المدهش ببساطته: فكّك المنظومة وقت الفحص — أعِد استخدام القافزات أنفسها كقناة نقل.
7.3.2 البنية: Scanned FF وسلسلة المسح
SCAN CONTROL:
- SC=0 (عمل عادي — NORMAL): البورر يمرر
DATA IN— القافز جزء من الآلة كأن شيئاً لم يكن. - SC=1 (مسح — SCAN): البورر يمرر
SCAN IN— مخرجَ القافز السابق في سلسلة مخصصة.
7.3.3 البروتوكول ومحاسبة الدورات — بالمللّيم
7.3.4 والذاكرات الكبيرة؟ BIST وBISR
ذاكرة بملايين الخلايا لا يمكن تحويلها لسجل إزاحة (الكثافة هي مبرر وجودها أصلاً!). والبديل الساذج — اكتب لكل خلية، اقرأ، قارن، وكرر بمحتويات مختلفة (فالأعطال قد تعتمد على المحتوى والجيران) — بطيء ومكلف على جهاز فحص خارجي بمليون دولار (تذكّر: كل دقيقة فحص ≈ 50 سنتاً).
الحل: افحص نفسك بنفسك — Built-In Self-Test (BIST): نبني بجوار الذاكرة آلة حالات صغيرة (كل عدّتنا من المحاضرة 5!) تولّد محتوى «شبه عشوائي»، تكتبه، تقرأه، وتحكم. واللمسة الذكية: بدل أن تتذكر الآلة ماذا كتبت (يلزمها ذاكرة بحجم الذاكرة!)، تستعمل أكواد كشف الأخطاء: المكتوب يُنتَج بقاعدة توليدية، والمقروء يُفحص ضد القاعدة — الآلة تعرف «هل هذا سليم» دون أن تعرف «ماذا كان». لا جهاز خارجي، والفحص يعمل حتى في الميدان.
وخطوة أبعد — Built-In Self-Repair (BISR): أضِف للذاكرة صفوفاً احتياطية؛ عندما يكتشف الـBIST منطقة معطوبة، يعيد برمجة فك العناوين لتحويلها إلى الاحتياط. الشريحة «تضمّد جراحها» ذاتياً — تقنية شائعة جداً في منتجات الذاكرة، وهي حرفياً الفكرة العظيمة #7 (الاعتمادية عبر التكرار) من المحاضرة الأولى وقد صارت منتجاً.
7.4 خط الأنابيب (Pipeline): الإنتاجية بلا عتاد إضافي (تقريباً)
7.4.1 المقياسان — وافتراق طريقيهما
الكمون (Latency): الزمن من بداية حساب واحد حتى نهايته — تعميم مباشر لـ$t_{pd}$ على منظومات كاملة.
الإنتاجية (Throughput): عدد الحسابات المكتملة في وحدة الزمن.
في الدارة التوافقية الخاضعة للنظام الساكن يتصادف أن $TP = 1/L$ — ممنوع إدخال معطيات جديدة قبل استقرار الحساب الجاري. محاضرة اليوم تفك هذا الارتباط: سنرفع $TP$ أضعافاً بينما $L$ لا يتحسن بل قد يسوء. (ومقاييس أخرى تعيش معهما: هدر، مساحة، اعتمادية — لكل تصميم ميزانه).
7.4.2 مثال محرّك: جمع $N$ أعداد بثلاث فلسفات
- تسلسلي: مجمّع واحد + سجل تراكم: $N$ دورات بطول $t_0$ ← الزمن $N\,t_0$. أرخص عتاد، أبطأ زمن.
- قناتان متوازيتان: نصفا المصفوفة يُجمعان معاً ثم دمج أخير: $\left(\tfrac N2+1\right)t_0$ — ضاعفنا العتاد فقاربنا نصف الزمن.
- شجرة مجمّعات توافقية: $N/2$ مجمّعاً في الطبقة الأولى، ثم $N/4$… عمق الشجرة $\log_2 N$ ← الكمون $\approx\log_2(N)\,t_0$. لثمانية أعداد: $3t_0$ فقط.
انتصر الشجري كموناً. لكن انظر إلى إنتاجيته تحت النظام الساكن: $$TP_{tree}=\frac1{\log_2(N)\,t_0}$$ ولاحظ فضيحة العطالة (شريحة 41): بعد $t_0$ الأولى تُنهي الطبقةُ الأولى عملها وتجلس عاطلة $\log_2(N)-1$ من الزمن — وكذلك كل طبقة بعد لحظتها. عتاد مدفوع الثمن، عاطل معظم الوقت. متى يمكن تشغيله؟ الشريحة تشترط شرطين: حسابات كثيرة متطابقة البنية على معطيات مختلفة، وقدرة على التحكم بإيقاع وصول المعطيات. توفرا؟ إذن…
7.4.3 الفكرة: اقبض على النواتج الوسيطة
المانع الوحيد من إطعام الشجرة معطياتٍ جديدة كل $t_0$ هو أن الدارة توافقية: تغيير المداخل الآن يفسد الحساب الجاري في الطبقات العميقة — «موجة» جديدة تلحق بموجة قديمة وتختلط بها. الحل (شريحة 43): ازرع سجلات بين الطبقات تلتقط النواتج الوسيطة عند كل جبهة ساعة. الآن كل «جيل» معطيات يسكن طبقته محمياً بجدار قافزات — ويمكن إدخال جيل جديد كل دورة:
7.4.4 الخطر الصامت: اختلاط الأجيال — وتعريف K-Pipeline
7.4.5 قاعدتا التصميم الشرعيتان — ولماذا تحفظان المعنى
الدارة: مكوّنان بتأخير 2 و1 يغذيان مجمّعاً بتأخير 1 (بوحدات زمنية، سجلات مثالية). نطارد إنتاجية قصوى وكموناً أدنى:
7.5 خلاصة الثلاثية
🏆 أسئلة بمستوى الامتحان
أي من الادعاءات التالية صحيح؟
أ خاطئ: فحص معزول = $N$ شحن + 1 التقاط + $N$ تفريغ = $2N{+}1$؛ وضمن سلسلة فحوص متراكبة، الكلفة الحدية $N{+}1$ للفحص. لا سيناريو يعطي $2N$ بالضبط.
ب خاطئ ومعكوس: رأينا في اللوحة: الكمون لا يتحسن أبداً بالأنبوب — يبقى (في التوازن المثالي) أو يسوء (سجلات فائضة/مراحل غير متوازنة/أزمنة $t_{pC\to Q}+t_{SU}$ الحقيقية).
ج خاطئ بسبب «دائماً»: شاهدنا مضادّين حرفيين: 1-Pipe وبقيت $TP=1/4$؛ و3-Pipe وبقيت $TP=1/2$ (حد المكوّن الأبطأ). المساحة تزيد فعلاً — لكن الإنتاجية لا ترتفع حتماً.
د صحيح: نفس اللوجيك + سجلات إضافية تتقلب كل دورة + حمل إضافي على شبكة الساعة (أكبر مستهلكي الهدر في الشرائح الحديثة!) ← طاقة أكبر لكل حساب وهدر أكبر إجمالاً. الأنبوب يشتري الإنتاجية بالمساحة والطاقة والكمون. ✔ الإجابة: د.
حدد الادعاء الأصح بخصوص طريقة المسح (Scan) كما تعلمناها:
أ: معكوس تماماً — المسح لا يناسب الذاكرات (كثافتها تمنع تحويلها لسلسلة)؛ الذاكرات تُفحص بـBIST. ب: قلبُ الحقيقة: الهدف الأساسي هو فحص اللوجيك التوافقي المدفون — السجلات مجرد قناة نقل. ج: يناقض البروتوكول: SC=0 تُفعَّل لدورة واحدة بالضبط (الالتقاط) مهما كان طول الفحص — لا «نصف بنص». د: ينفي جوهرة البروتوكول: التفريغ والشحن التالي متراكبان في نفس $N$ الدورات. إذن كلها ساقطة. ✔ الإجابة: هـ — كما في الحل الرسمي: «لا ادعاء يطابق طريقة المسح».
دارة توافقية: مكوّنان بتأخير 2 و1 يغذيان مجمّعاً بتأخير 1 (سجلات مثالية، $L_{comb}=4$). ما أفضل (إنتاجية، كمون) يمكن بلوغهما بأنبوب شرعي لهذه الدارة، مع عدم جواز شطر المكوّنات؟
مبدأ عزل الأبطأ: المكوّن ذو العمق 2 غير قابل للشطر ← أدنى دورة ساعة ممكنة $T_C=2$ ← سقف الإنتاجية $1/2$ (يسقط ج). التوازن الأمثل: مرحلتان بعمق 2 لكل منهما ← $L=2\times2=4$ — كمون الأصل نفسه (يسقط د الذي يوهم أن الأنبوب «يقسم» الكمون — إنه يقسم الدورة لا الكمون!). وأ يتجاهل أن Retiming متوازناً يضاعف الإنتاجية فعلاً. ✔ الإجابة: ب — وهي حرفياً خانة «L=4, TP=1/2» من لوحة الشريحة 54.
معطاة آلة الحالات من البند 7.2.4 أعلاه (الحالات $A\dots G$ بجدولها). أ. هل الآلة Moore أم Mealy؟ ب. اكتب صفوف التكافؤ بعد التقليص الكامل. ج. (مستقل) صمّم آلة Moore بأقل حالات: $Z=0$ ما دام $X=0$؛ عندما يصبح $X=1$ يصبح $Z=1$؛ إذا عاد $X=0$ بعد دورة أو دورتين من $X=1$ يعود $Z=0$؛ وإذا بقي $X=1$ ثلاث دورات متتالية يبقى $Z=1$ للأبد. كم عدد الحالات الأدنى؟
💡 تلميح للبند ب
👁 الحل الكامل خطوة بخطوة
أ. Moore — الخرج متطابق في كل أعمدة الدخل لكل سطر: يتحدد بالحالة وحدها.
ب. السلسلة الكاملة (نُفِّذت تفصيلياً في الأداة التفاعلية أعلاه):
$P_1=(A,B,E)(C,D,F,G)$ ← $F$ تنشطر (تذهب لنفسها بينما البقية إلى $E$): $P_2=(A,B,E)(C,D,G)(F)$ ← $E$ تنشطر عن $(A,B)$ (وريث $X{=}1$ إلى $F$) و$C$ تنشطر عن $(D,G)$ (وريثها إلى $F$): $P_3=(A,B)(E)(C)(D,G)... $ بدقة $P_3=(A,B)(E)(C,D,G)(F)$ ثم $P_4=(A,B)(E)(C)(D,G)(F)$ ← وأخيراً $(A,B)$ ينشطر ($A\to C$ لكن $B\to D$): $P_5=(A)(B)(C)(E)(D,G)(F)=P_6$.
النتيجة: ست صفوف؛ الزوج المتكافئ الوحيد: $\mathbf{D\equiv G}$ — مطابق للحل الرسمي.
ج. 4 حالات: $S_0$ (خرج 0، لا آحاد)؛ $S_1$ (خرج 1، «1» واحدة)؛ $S_2$ (خرج 1، «11»)؛ $S_3$ (خرج 1، قفل أبدي بعد «111»). الانتقالات: من $S_0$: 0→$S_0$، 1→$S_1$؛ من $S_1$: 0→$S_0$، 1→$S_2$؛ من $S_2$: 0→$S_0$، 1→$S_3$؛ و$S_3$ ثابتة. ولا أقل من أربع: المواصفة تفرض التمييز بين ثلاث درجات تقدم (0/1/2 آحاد متتالية) + حالة القفل — أربعة سلوكات مستقبلية مختلفة، وبمنطق هذه المحاضرة بالذات: أي دمج بين اثنتين منها تفضحه سلسلة شاهدة قصيرة.
أ. في جدول حالات من 8 حالات $A\dots H$، لوحظ أن الحالة $H$ لا يصل إليها أي انتقال من أي حالة أخرى. إذا كان بيدنا اختيار حالة البداية — بكم حالة يمكن تصغير الآلة فوراً (قبل أي خوارزمية)؟
ب. (مستقل) نفّذ آلة Mealy تتعرف على «11» مع سماح بالتداخل (للمدخل 111 يخرج 011)، بأقل عناصر ذاكرة وبوابات. صِف الدارة النهائية.
👁 الحل الكامل
أ. حالة واحدة. $H$ غير قابلة للوصول (ما دمنا لا نبدأ منها) — تُشطب قبل أي أقسام، وهذا حرفياً «التنظيف المسبق» — الخطوة صفر من خوارزمية هذه المحاضرة. (في الامتحان الأصلي تلت ذلك سلسلة الأقسام: $P_1=(A\dots E,H)(F)(G)$ ثم $P_2=(A,B,C,H)(D,E)(F)(G)$ — نفس الميكانيكية تماماً).
ب. حالتان («هل كان البت السابق 1؟») ← قافز واحد: $D=x$ (خزّن البت الحالي)، والخرج $z=Q\cdot x$ — DFF واحد + بوابة AND واحدة. لا أصغر من هذا — وقد جرّبتها حيّةً في أداة المحاضرة 5 (مثال 4): إنها «أصغر آلة مفيدة في العالم»، وميلي هنا توفر ثلث حالات مور المكافئة.
الذاكرات واللوجيك التتابعي: Latch، Flip-Flop، وRegister File
8.1 لماذا نحتاج ذاكرة أصلاً؟ ومن يتذكّر ماذا؟
كل ما بنيناه حتى الآن توافقي: الخرج دالة للمداخل الحالية فقط. لكن الحوسبة الحقيقية تحتاج حالة: عدّادات، متغيرات، PC… عالم الذاكرات طيف واسع من المفاضلات (מנעד): سجلات (FF) — الأسرع والأغلى والأصغر سعة؛ SRAM (6 ترانزستورات/بت) — سريعة، للكاش؛ DRAM (ترانزستور+مواسع) — كثيفة ورخيصة وأبطأ وتحتاج إنعاشاً؛ ثم Flash/قرص — الأكبر والأبطأ. القاعدة: كلما كبرت السعة، هبطت السرعة وارتفعت الطاقة لكل وصول.
8.2 من التوافقي إلى التتابعي: الـLatch والـFlip-Flop
D-Latch (شفاف): ما دام $EN=1$ الخرج «يرى» المدخل مباشرة ($Q=D$)؛ عند $EN=0$ يتجمّد آخر ما رأى. حسّاس للمستوى (level-sensitive).
D-Flip-Flop: يلتقط $D$ فقط في جبهة الساعة الصاعدة ويتجاهل كل شيء بعدها. حسّاس للجبهة (edge-triggered)، ويُبنى من Latch سيد + Latch تابع بساعتين متعاكستين (Master–Slave).
خصائص توقيت الـFF نفسها: $t_{pd}(FF)$/$t_{cd}(FF)$ — زمن خروج $Q$ بعد الجبهة (أقصى/أدنى). سنستخدم الأربعة ($t_{setup}, t_{hold}, t_{pd}, t_{cd}$) بلا رحمة في المحاضرة 10.
8.3 سجل الإزاحة (Shift Register)
سلسلة FFs: خرج كلٍّ يدخل للذي بعده؛ في كل جبهة ساعة «تزحف» البتات خانة واحدة. الاستخدامات: تحويل تسلسلي↔تفرعي (أساس UART بالمحاضرة 11!)، خطوط تأخير، وScan (المحاضرة 10).
8.4 الـRegister File של RISC-V
ملف السجلات = 32 سجلاً × 32 بت مع: منفذا قراءة توافقيان (ضع رقم سجل ← تحصل على قيمته فوراً، دون انتظار ساعة) ومنفذ كتابة واحد متزامن (الكتابة تحدث في جبهة الساعة عندما $RegWEn=1$). البناء الداخلي: Decoder $5\to32$ لاختيار سجل الكتابة، وMUX $32\to1$ (اثنان) للقراءة، و$x0$ مثبّت صفراً بالسلك — لا FF له أصلاً. هذا المكوّن هو قلب المعالج القادم.
8.5 Verilog تتابعي — وأخطر فخ في الامتحان: استدلال الـLatch
// FF نظيف: always_ff + جبهة ساعة
always_ff @(posedge clk) begin
if (rst) q <= '0;
else q <= d;
end// توافقي نظيف: قيمة افتراضية أولاً!
always_comb begin
y = '0; // default
case (sel)
2'b00: y = a;
2'b01: y = b;
endcase
endalways_comb: إذا وُجد مسار تنفيذ لا يُسند فيه المخرج قيمة — سيولّد المُركِّب Latch لحفظ القيمة السابقة (واحد لكل بت!). العلاج: قيمة افتراضية في أول البلوك أو فرع else/default شامل.🏆 أسئلة بمستوى الامتحان
module my_module(
input logic [1:0] w, a,
output logic [1:0] z1, z2);
always_comb begin
if (a == 2'b10) z1 = a;
else if (a == 2'b11) z1 = ~a;
end
always_comb begin
z2 = 2'b11;
case (w)
2'b00: z2 = 2'b00;
2'b01: z2 = 2'b01;
2'b11: z2 = 2'b10;
endcase
end
endmodule
كم عنصر ذاكرة (Latch) سينشأ في تركيب (Synthesis) هذا الكود؟
البلوك الأول ($z1$): الإسناد يحدث فقط عندما $a=10$ أو $a=11$؛ في الحالتين $a=00, 01$ لا إسناد إطلاقاً ← يجب حفظ القيمة السابقة ← Latch لكل بت، و$z1$ بعرض 2 بت ← 2 Latch.
البلوك الثاني ($z2$): يبدأ بقيمة افتراضية z2=2'b11 قبل الـcase ← $z2$ معرّف في كل مسار تنفيذ (حتى الحالة 2'b10 غير المذكورة) ← 0 Latch.
المجموع: 2. ✔ الإجابة: ج.
وحدة mymodule#(N) تعدّ من 0 حتى $N-1$ وتُخرج نبضة (pulse=1) لمدة دورة واحدة عندما $count=N-1$. في الوحدة العليا: نسخة بـ$N=3$ تتغذى من clk بتردد 120MHz، وخرجُها p1 يُستخدم كساعة لنسخة ثانية بـ$N=2$، وخرجها p2=out. ما تردد الخرج وما نسبة الـduty cycle؟
النسخة الأولى ($N=3$) تُخرج نبضة كل 3 دورات ساعة، بعرض دورة واحدة ← p1 إشارة دورية بزمن دورة $3T_{clk}$. النسخة الثانية تعمل على جبهات p1 الصاعدة ($N=2$: نبضة كل جبهتين) ← دورة كاملة لـout تستغرق $2\times3=6$ دورات من الساعة الأصلية: $120/6=\mathbf{20MHz}$. أما شكل الموجة: p2 يساوي 1 لمدة «دورة» كاملة من ساعته (أي $3T_{clk}$) و0 لمدة $3T_{clk}$ ← duty cycle $=\mathbf{1/2}$. ✔ الإجابة: أ. (لاحظ الفكرة: تركيب مقسّمي تردد Frequency Dividers).
في سجل إزاحة 4-بت (ابتداءً من 0000)، أدخلنا تسلسل البتات 1,0,1,1 (الأقدم أولاً) مع 4 جبهات ساعة. ما محتوى السجل إذا كان البت الجديد يدخل من اليسار (MSB) والأقدم يُدفع لليمين؟
نتتبع: بعد «1»: 1000؛ بعد «0»: 0100؛ بعد «1»: 1010؛ بعد «1»: 1101. آخر بت دخل يجلس في الـMSB والأقدم زحف نحو اليمين. ✔ الإجابة: أ. (جرّب ذلك في الأداة التفاعلية أعلاه!)
آلات الحالات المنتهية FSM: ميلي، مور، والتقليص
9.1 ما هي آلة الحالات؟
آلة الحالات المنتهية (FSM) هي النموذج الرياضي لكل دارة تتابعية متزامنة: مجموعة حالات منتهية، دالة انتقال تحدد الحالة التالية من (الحالة الحالية، المدخل)، ودالة خرج. عملياً: سجل حالات (FFs) + دارتان توافقيتان (Next-State Logic وOutput Logic) — كل ما تعلمناه حتى الآن مجتمعاً في قالب واحد.
Moore: الخرج دالة للحالة فقط: $z=\lambda(S)$ — الخرج مستقر طوال الدورة، ويتأخر دورة عن المدخل عادة.
Mealy: الخرج دالة للحالة والمدخل معاً: $z=\lambda(S,x)$ — يستجيب فوراً في نفس الدورة، وغالباً يحتاج حالات أقل.
كيف تميّز من جدول الحالات؟ إذا كان الخرج متطابقاً في كل أعمدة المدخلات لكل سطر (حالة) ← Moore. إذا اختلف الخرج داخل نفس السطر حسب المدخل ← Mealy.
9.2 خط الإنتاج الكامل: من المواصفة إلى الدارة
- مواصفة (كلامية أو تعبير منتظم — كل لغة يقبلها FSM هي لغة منتظمة والعكس صحيح).
- مخطط حالات ← جدول حالات (P.S. / N.S. / Z).
- تقليص الحالات (أدناه) — أقل حالات = أقل FFs ولوجيك أصغر.
- ترميز الحالات: ثنائي مضغوط ($\lceil\log_2 k\rceil$ بتات) أو one-hot (FF لكل حالة: لوجيك انتقال أبسط وأسرع مقابل FFs أكثر).
- استخراج المعادلات لكل بت حالة (خرائط كارنو!) وبناء الدارة: FFs + لوجيك.
9.3 تقليص الحالات: خوارزمية أقسام التكافؤ (של מור)
حالتان متكافئتان إذا كان لهما نفس الخرج ولكل مدخل تنتقلان إلى حالتين متكافئتين. عملياً نبني سلسلة أقسام:
$P_0$ = كل الحالات في صف واحد ← $P_1$ = فصل حسب الخرج ← $P_{k+1}$ = فصل زوج حالات إذا قادهما نفس المدخل إلى صفوف مختلفة في $P_k$ ← نتوقف عندما $P_{k+1}=P_k$. كل صف نهائي = حالة واحدة في الآلة المقلَّصة.
9.4 آلة في Verilog: القالب القياسي
typedef enum logic [1:0] {S0, S1, S2, S3} state_t;
state_t ps, ns;
always_ff @(posedge clk) begin // سجل الحالة
if (rst) ps <= S0;
else ps <= ns;
end
always_comb begin // لوجيك الانتقال + الخرج
ns = ps; z = 1'b0; // قيم افتراضية (لا Latches!)
case (ps)
S0: begin z = 0; ns = x ? S1 : S0; end
S1: begin z = 1; ns = x ? S2 : S0; end
S2: begin z = 1; ns = x ? S3 : S0; end
S3: begin z = 1; ns = S3; end // قفل أبدي
endcase
end
(هذا الكود ينفّذ حرفياً آلة السؤال المفتوح من امتحان شتاء 2025-2026 أدناه — أربع حالات.)
9.5 حدود آلات الحالات (מגבלות)
ذاكرة الـFSM منتهية — لا تستطيع «العدّ إلى ما لا نهاية». لذلك لا يمكنها التعرف على لغات مثل $a^n b^n$ (عدد متساوٍ غير محدود) أو أقواس متوازنة بعمق حر: كانت ستحتاج حالة مميزة لكل قيمة عدّ ممكنة، وهي غير منتهية. ما تقبله الـFSM = اللغات المنتظمة فقط (ما يُكتب كتعبير منتظم). هذا سؤال نظري قصير محبوب.
🏆 أسئلة بمستوى الامتحان
أي من اللغات التالية لا يمكن لآلة حالات منتهية التعرف عليها؟
أ، ب، د كلها تحتاج ذاكرة منتهية (آخر 3 بتات؛ عدّاد mod 3؛ بت زوجية) — منتظمة. أما $0^n1^n$ فتتطلب عدّ الأصفار بلا حدّ لمقارنتها بالآحاد — مستحيل بعدد حالات منتهٍ (لو وُجدت آلة بـ$k$ حالة، فبعد $k+1$ أصفار لا بد أن تتكرر حالة، فتخلط بين عددين مختلفين). ✔ الإجابة: ج.
الأنظمة المتزامنة: المسار الحرج، Skew/Jitter، وفحص Scan
10.1 العقد المقدّس للنظام المتزامن
النظام المتزامن = سجلات (FFs) تفصل بينها كتل لوجيك توافقي، والجميع يرقص على ساعة واحدة. في كل دورة: تُطلق السجلات قيمها ← تعبر اللوجيك ← تصل للسجلات التالية قبل الجبهة القادمة. من هذا «العقد» ينبع شرطان لكل مسار $FF_i \to CL \to FF_j$:
10.2 من أين يأتي الـSkew؟ وماذا عن الـJitter؟
- Skew: فرق مكاني ثابت في وصول الساعة بين سجلين (أسلاك أطول، Buffers على شبكة الساعة).
- Jitter: ارتجاج زمني عشوائي في لحظة الجبهة نفسها ($\pm t_{jitter}$ في كل جبهة وباتجاه مستقل لكل FF). في أسوأ حالة للـsetup: جبهة الإرسال تتأخر بـ$t_{jitter}$ وجبهة الاستقبال تتقدّم بـ$t_{jitter}$ ← «نافذة» الدورة تنكمش بـ$2t_{jitter}$: $$T_{min} = t_{pd}(FF)+t_{pd}(CL)+t_{setup} + 2\,t_{jitter}$$
- Clock Gating: تمرير الساعة عبر AND مع إشارة تحكم — يجمّد سجلات كتلة كاملة لتوفير الطاقة ($P\propto f$). ظهر كفكرة محورية في سؤال امتحان حقيقي (أدناه): طالما CTR=0 لا توجد جبهات أصلاً.
10.3 فحص العتاد بطريقة Scan
كيف نفحص لوجيكاً مدفوناً بين سجلات دون منافذ خارجية؟ نضيف لكل FF بورراً صغيراً بإشارة scan_ctrl: في وضع الفحص تتحول كل سجلات الدارة إلى سجل إزاحة واحد طويل (سلسلة). البروتوكول لكل اختبار:
- إدخال (Shift-in): $n$ دورات لإزاحة متجه الاختبار إلى داخل $n$ سجلات.
- التقاط (Capture): دورة واحدة بوضع العمل الطبيعي — اللوجيك التوافقي يحسب وتُلتقط النتائج في السجلات.
- إخراج (Shift-out): $n$ دورات لإزاحة النتائج للخارج — وبنفس الدورات ندخل متجه الاختبار التالي! (تراكب ذكي).
🏆 أسئلة بمستوى الامتحان
سلسلة: $FF1 \to CL1 \to FF2 \to CL2 \to FF3$. أزمنة $T_{pd}$ معطاة كمجالات (بسبب ظروف الدارة): $FF1{:}\,[7,9]$، $FF2{:}\,[12,13]$، $FF3{:}\,[10,11]$، $CL1{:}\,[20,24]$، $CL2{:}\,[18,26]$؛ و $t_{setup}$: 3/4/5ns للسجلات الثلاثة بالترتيب. كل ساعة قد ترتجّ بـ$t_{jitter}=2ns$ باتجاه عشوائي مستقل. (النظام يحقق hold دائماً). ما $T_{min}$ الذي يضمن عملاً سليماً؟
لضمان العمل نفترض الأسوأ: أعلى قيمة في كل مجال $T_{pd}$، والـjitter يقرص النافذة من الجهتين ($+2t_{jitter}$):
مسار 1: $T \ge 9 + 24 + 4 + 2\cdot2 = 41$ns.
مسار 2: $T \ge 13 + 26 + 5 + 2\cdot2 = \mathbf{48}$ns ← هو الحرج.
✔ الإجابة: ب. لاحظ المنهجية: «يضمن» = خذ دائماً الحد الأسوأ من كل مجال، وأضف $2t_{jitter}$ لكل قيد setup.
نظام متزامن: الساعة تمرّ عبر بوابة AND مع إشارة $CTR$ (Clock Gating) ثم تتفرع: مباشرة إلى $FF1$، وعبر Buffer بتأخير $N$ إلى $FF2$. المسارات: $FF1 \xrightarrow{XOR} FF2$ و $FF2 \xrightarrow{NOR\to OR} FF1$. المعطيات (ns): للسجلين $t_{pd}=4, t_{cd}=2, t_{setup}=5, t_{hold}=2$؛ للبوابات: XOR $t_{pd}=3,t_{cd}=2$؛ NOR $2,2$؛ OR $1.5,1$؛ و$T_{clk}=20$. ما أكبر $N$ يُبقي النظام محقّقاً لنظام التوقيت؟
الـBuffer يؤخّر ساعة $FF2$ بـ$N$ ← skew $=+N$ للمسار $FF1\to FF2$ و $-N$ للمسار المعاكس. نفحص القيود الأربعة:
$FF1\to FF2$ setup: $4+3+5 \le 20+N$ ← $N\ge-11$ ✔ دائماً.
$FF1\to FF2$ hold: $t_{cd}(FF1)+t_{cd}(XOR) \ge t_{hold}(FF2)+N$ ← $2+2\ge 2+N$ ← $\mathbf{N\le 2}$.
$FF2\to FF1$ setup: $4+2+1.5+5+N \le 20$ ← $N\le 7.5$.
$FF2\to FF1$ hold: $2+2+1 + N \ge 2$؟ بصيغة الاتجاه: $\ge$ يتحقق لكل $N\ge-3$ ✔.
القيد الأشدّ: $N\le2$ ← $N_{max}=\mathbf{2ns}$. ✔ الإجابة: هـ. 📌 لاحظ: من اكتفى بقيود الـsetup اختار «ج» ووقع في الفخ — hold هو القاتل الصامت مع skew الموجب.
في نظام فيه 7 سجلات FF، كم دورة ساعة يتطلب تنفيذ 5 اختبارات بطريقة Scan؟
$N = k(n+1)+n = 5\cdot(7+1)+7 = 40+7 = \mathbf{47}$. التفصيل: 7 دورات إدخال + 1 التقاط لكل اختبار، مع تراكب الإخراج مع إدخال الاختبار التالي، ثم 7 دورات أخيرة لإخراج نتائج الاختبار الخامس. ✔ الإجابة: ج.
تخطيط اللوجيك (Pipelining) والاتصال التسلسلي UART
11.1 الإنتاجية مقابل زمن الاستجابة
زمن الاستجابة (Latency): الزمن من دخول معطى واحد حتى خروج نتيجته.
الإنتاجية (Throughput): عدد النتائج الخارجة في وحدة الزمن.
دارة توافقية عميقة تنجز عملية كل $t_{pd}$ الكلي. الفكرة العبقرية: نقطعها بسجلات إلى مراحل تعمل بالتوازي على معطيات متتالية — مثل خط تجميع سيارات. زمن الدورة يصبح بطول أبطأ مرحلة فقط:
$$T_{clk} = t_{pd}(FF) + \max_k t_{pd}(\text{stage}_k) + t_{setup}(FF) \qquad TP = \frac{1}{T_{clk}} \qquad Latency = k\cdot T_{clk}$$11.2 الاتصال التسلسلي اللامتزامن: UART
كيف يتحادث جهازان بلا سلك ساعة مشترك؟ يتفقان مسبقاً على معدل الإرسال (Baud Rate) ويستعملان إطاراً بسيطاً:
المستقبِل يراقب الخط؛ عند هبوطه (بداية Start) ينتظر $1.5\,T_{bit}$ ليعيّن منتصف بت البيانات الأول، ثم يعيّن كل $T_{bit}$. لكي ينجح ذلك، ساعته الداخلية يجب أن تكون أسرع من معدل الإرسال (عادة $\times16$) — وإلا لا يستطيع أصلاً «الانتظار نصف بت».
🏆 أسئلة بمستوى الامتحان
دارة توافقية مكوّنة من كتل بتأخيرات (ns): 10، 7، 4، 9 (الأبطأ 10 غير قابلة للشطر). معطى للسجلات: $t_{pd}(FF)=7$، $t_{setup}(FF)=8$. ما أقصى Throughput إذا سُمح بتخطيط الدارة بحرّية؟
بمبدأ عزل الأبطأ: أفضل ما يمكن هو مرحلة تحوي المكوّن ذا 10ns وحده:
$$T_{clk}=t_{pd}(FF)+t_{pd}^{max}(Logic)+t_{setup}(FF)=7+10+8=25\,ns$$ $$TP=\frac{1}{25\cdot10^{-9}}=4\cdot10^{7}\ \text{ops/sec}$$✔ الإجابة: د. لاحظ أن زيادة عدد المراحل بعد هذا الحد لا ترفع الإنتاجية — فقط تزيد الـLatency.
نظام يشبه UART المُدرَّس لكن بإرسال $N$ بتات بيانات بدل 8. تردد ساعة المرسل الداخلية $f_{tx}=12MHz$ ومعدل الخط المطلوب $4MHz$. (يجب استقبال بت التوقف سليماً أيضاً). اختر الادعاء الصحيح بشأن ساعة المستقبل $f_{rx}$ وعينة الـstart:
أ، ب خاطئتان: إذا كانت ساعة المستقبل مساوية لمعدل الخط ($T_{rx}=T_{bit}$) فلا يستطيع أصلاً أخذ العينة الأولى بعد $1.5\,T_{bit}$ — لا توجد لديه «أنصاف دورات»!
ج صحيحة: $f_{rx}=40MHz$ ← $T_{bit}=10\,T_{rx}$ بالضبط (نسبة صحيحة) ← لا انحراف متراكم لا في الإرسال ولا في الاستقبال. حتى لو تأخّر اكتشاف الـstart بشظية ثابتة، فالخطأ لا يكبر مع البتات ← يمكن استقبال أي $N$ بتات سليمة. ✔ الإجابة: ج.
مرسل بساعة داخلية $3ns$ ومستقبل بساعة داخلية $10ns$ يتواصلان بـUART 8-بت. المستقبل يكشف بداية الـSTART فور وصولها. ما أقصى معدل إرسال $\left(\frac{bits}{sec}\right)$ يضمن استقبال 8 بتات البيانات سليمة؟
د تُرفض فوراً: $T_{bit}=3ns < T_{rx}=10ns$ — المستقبل أبطأ من البتات نفسها!
ج تُرفض: $T_{bit}=9ns$: كل عينة تتأخر $1ns$ إضافية (لأن $10=9+1$) ← خطأ متراكم $1.5ns$ ثم يتصاعد؛ الحد المسموح $4.5ns$ يُخترق قبل البت الثامن.
ب تُرفض: $T_{bit}=25ns$: العينات كل $2.5$ دورات لا تُنفَّذ بدقة بساعة $10ns$؛ التحليل يعطي انحرافاً يبلغ $23.5ns$ حتى بت التوقف $> T_{bit}/2=12.5ns$.
أ صحيحة: $T_{bit}=30ns=3\,T_{rx}$ بالضبط ← لا خطأ متراكم، وخطأ العينة الأولى أصغر من نصف البت. ✔ الإجابة: أ.
📌 القاعدة الذهبية: ابحث دائماً عن الخيار الذي يجعل $T_{bit}$ مضاعفاً صحيحاً لدورة ساعة المستقبل.
أوامر الذاكرة، المكدّس، الروتينات، والعودية
12.1 أوامر الذاكرة وأنماط العنونة
الذاكرة في RISC-V مصفوفة بايتات بعناوين 32-بت. نمط العنونة الوحيد للبيانات هو قاعدة + إزاحة:
lw t0, 8(s1) # t0 = Mem[s1 + 8] (تحميل كلمة 4 بايتات)
sw t0, -4(s1) # Mem[s1 - 4] = t0 (تخزين كلمة)
- الإزاحة ثابت 12-بت موقّع $[-2048, 2047]$ — للوصول لعناوين بعيدة نبني العنوان بـlui أولاً.
- الكلمات محاذاة لمضاعفات 4: عناصر مصفوفة int متتالية تبعد 4 بايتات ←
addi s1, s1, 4للتقدم عنصراً واحداً (نمط رأيته في حلقة المحاضرة 2!). - القفزات لها أنماطها: beq/bne بإزاحة نسبية للـPC؛ jal بإزاحة أوسع؛ jalr بقاعدة+إزاحة.
12.2 المكدّس (Stack)
sp. الدفع والسحب دائماً بمضاعفات 4 (كل سجل = 4 بايتات):
# push t0 | # pop t0
addi sp, sp, -4 | lw t0, 0(sp)
sw t0, 0(sp) | addi sp, sp, 412.3 بروتوكول استدعاء الدوال — احفظه كالقانون
- الاستدعاء:
jal ra, func— يحفظ $PC+4$ فيraويقفز. العودة:jr ra. - المعاملات في
a0…a7، وقيمة الإرجاع فيa0(وa1). - مسؤولية الحفظ: سجلات
t*وa*— يحفظها المستدعي (Caller) إن احتاجها بعد الاستدعاء؛ سجلاتs*وsp— يحفظها المستدعى (Callee) إن أراد استخدامها، ويعيدها قبل العودة. - Prologue: أول الدالة — إنزال sp وحفظ ra وس‑سجلات ستُستخدم. Epilogue: آخرها — استرجاع وحذف الإطار ثم
jr ra.
- «main لا تحتاج حفظ ra قبل استدعاء دالة» — خطأ، main نفسها دالة ويجب أن تحفظ ra إن استدعت غيرها.
- «الاستدعاء يتم بـjr ra» — خطأ، الاستدعاء بـjal والعودة بـjr.
- «نحرك sp بمقدار 1 لكل سجل» — خطأ، بمقدار 4 (بايتات).
- «الـCallee يعيد كل السجلات ما عدا a0/a1» — خطأ، سجلات t ليست ملزمة بالاسترجاع إطلاقاً. (لذلك كانت الإجابة الصحيحة في ربيع 2025: «كل الادعاءات خاطئة»).
12.4 العودية: الدالة تستدعي نفسها
العودية تعمل «مجاناً» بفضل المكدّس: كل استدعاء يبني إطاراً جديداً يحفظ فيه ra (وإلا سيدوسه الاستدعاء الداخلي!) والمعاملات التي سيحتاجها بعد العودة. إليك الحل الكامل والمشروح لسؤال الامتحان المفتوح (شتاء 2025-2026):
int climbing_stairs(int n) { // عدد طرق صعود سلّم بـ n درجة
if (n == 1) return 1; // (خطوة أو خطوتين في كل مرة)
if (n == 2) return 2;
return climbing_stairs(n-1) + climbing_stairs(n-2);
}
climbing_stairs:
0x...08: addi t0, x0, 1
0x...0C: beq a0, t0, base_case_n1
0x...10: addi t0, x0, 2
0x...14: beq a0, t0, base_case_n2
0x...18: addi sp, sp, -8 # ┐
0x...1C: sw ra, 4(sp) # │ Prologue: مكان لـ ra و a0
0x...20: sw a0, 0(sp) # ┘
0x...24: addi a0, a0, -1
0x...28: jal ra, climbing_stairs # f(n-1)
0x...2C: add t1, a0, x0 # t1 = f(n-1)
0x...30: lw a0, 0(sp) # استرجاع n الأصلية!
0x...34: addi a0, a0, -2
0x...38: jal ra, climbing_stairs # f(n-2)
0x...3C: add a0, a0, t1 # ★ result = f(n-1)+f(n-2)
0x...40: lw ra, 4(sp) # ┐
0x...44: addi sp, sp, 8 # │ Epilogue
0x...48: jr ra # ┘
base_case_n1: addi a0, x0, 1 ; jr ra
base_case_n2: addi a0, x0, 2 ; jr ra
💡 لماذا حفظنا a0 أيضاً وليس ra فقط؟
🏆 أسئلة بمستوى الامتحان
على الكود أعلاه، مع main تبدأ في 0x00000008 وتستدعي climbing_stairs(5):
أ. أكمل كود main بحيث يحترم بروتوكول الاستدعاء.
ب. كم قيمة مختلفة لـra حُفظت في المكدّس منذ تشغيل main؟ وكم مرة حُفظ ra إجمالاً؟
ج. حدّد أسطر الـPrologue والـEpilogue والسطر الذي يُحسب فيه ناتج الدالة.
👁 الحل الكامل خطوة بخطوة
أ. كود main:
0x08: addi sp, sp, -4
0x0C: sw ra, 0(sp) # حفظ ra الخاص بـ main
0x10: addi a0, x0, 5 # المعامل n=5
0x14: jal ra, climbing_stairs
0x18: lw ra, 0(sp)
0x1C: addi sp, sp, 4
ب. نرسم شجرة الاستدعاءات لـ$f(5)$: $f(5)\to f(4), f(3)$؛ $f(4)\to f(3), f(2)$؛ وكل $f(3)\to f(2), f(1)$. الدالة تحفظ ra فقط عندما $n>2$ (وإلا تخرج من الـbase case قبل الـprologue). العقد التي فيها $n>2$: $f(5), f(4)$ و$f(3)$ مرتين = 4 مرات، زائد الحفظ في main = 5 مرات إجمالاً.
أما القيم المختلفة: (1) ra الأصلي لـmain، (2) 0x18 — عنوان العودة من استدعاء main، (3) 0x…2C — العودة بعد jal الأول (حُفظ مرتين: في $f(4)$ وفي $f(3)$ الابن الأول له... كل دالة تحفظ الـra الذي دخلت به)، (4) 0x…3C — العودة بعد jal الثاني. المجموع: 4 قيم مختلفة، 5 عمليات حفظ. ✔ (مطابق للحل الرسمي).
ج. الـPrologue: الأسطر 0x…18–0x…20 (إنزال sp وحفظ ra وa0). الـEpilogue: 0x…40–0x…48. الناتج يُحسب في 0x…3C (السطر ★): $f(n-1)+f(n-2)$، وفي الـbase cases يُحمَّل 1 أو 2 مباشرة في a0.
وفق بروتوكول استدعاء الدوال كما تعلمناه، اختر الادعاء الصحيح:
أ خاطئ (main دالة عادية)؛ ب خاطئ (jal يستدعي، jr يعيد)؛ ج خاطئ (4 بايتات لكل سجل)؛ د خاطئ (سجلات t حرّة للـcallee ولا يلتزم بإعادتها). ✔ الإجابة: هـ.
دالة func تستخدم السجل s0 داخلها ولا تستدعي أحداً. ما الأسطر التي يجب إضافتها في بدايتها لتحترم البروتوكول (شقّ الـPrologue)؟
s0 سجل callee-saved: من يستخدمه ملزم بحفظه واسترجاعه. لا حاجة لحفظ ra هنا لأن الدالة ورقة (لا تستدعي أحداً فلا أحد سيدوس ra). ✔ الإجابة: أ.
بناء المعالج: RISC-V أحادي الدورة (Single-Cycle)
13.1 الفكرة الكلية
معالج أحادي الدورة = كل أمر يُنفَّذ كاملاً في دورة ساعة واحدة. في كل جبهة ساعة: يُحدَّث PC وتُكتب النتائج، وبين الجبهتين «تتدفق» الإشارات عبر مسار بيانات توافقي ضخم. المكوّنات كلها أصدقاؤنا القدامى من المحاضرات السابقة!
13.2 إشارات التحكم — «مفاتيح» البكر Controller
البكر دارة توافقية تقرأ حقول الأمر (opcode, funct3, funct7) وتضبط المفاتيح:
| الإشارة | وظيفتها | مثال قيم |
|---|---|---|
| PCSel | مصدر PC القادم: PC+4 أم هدف قفزة (ALU) | beq المتحقق/jal ← ALU |
| ImmSel | كيف يُركَّب الـimm من بتات الأمر (I/S/SB/U/UJ) | lw←I ، sw←S |
| RegWEn | هل نكتب إلى rd في نهاية الدورة؟ | sw/beq ← 0، والبقية ← 1 |
| BrUn / BrEq / BrLT | مقارن القفزات (موقّع/غير موقّع، ونتائجه) | beq يفحص BrEq |
| ASel | مدخل ALU الأول: rs1 أم PC | jal/beq/auipc ← PC |
| BSel | مدخل ALU الثاني: rs2 أم imm | R-type←rs2، البقية غالباً imm |
| ALUSel | العملية (add/sub/and/…) | lw/sw/jal ← add دائماً |
| MemRW | قراءة أم كتابة DMEM | sw فقط ← Write |
| WBSel | ماذا يُكتب لـrd: نتيجة ALU / قراءة ذاكرة / PC+4 | lw←Mem، jal←PC+4 |
lw t0, 8(s1): الأمر من نوع I ← ImmSel=I، ونكتب نتيجة لسجل ← RegWEn=1.13.3 زمن الدورة: أسير الأمر الأبطأ
الدورة يجب أن تتسع لأطول مسار لأبطأ أمر — وهو دائماً lw:
وهذه نقطة الضعف القاتلة للتصميم: أمر add السريع يدفع ثمن دورة بحجم lw كاملة. هذا ما سيدفعنا للمعالج متعدد الدورات (المحاضرة 14) ثم المخطّط (15).
13.4 مهارة الامتحان الذهبية: تعديل المعالج لأمر جديد
نمط سؤال يتكرر في كل موعد تقريباً: «أضِف أمراً جديداً — ماذا يتغير؟». منهجية الحل:
- حدّد نوع الأمر (كم سجل مصدر؟ هل يوجد rd؟ هل يوجد imm؟) — يحدد الترميز وImmSel.
- ارسم مسار البيانات المطلوب: هل يكفي الموجود؟ هل نحتاج توسيع MUX (إضافة مدخل) أو ثابت جديد؟
- حدّد ما يتغير في البكر فقط (قيم إشارات) مقابل ما يتطلب عتاداً جديداً (بوررات/أسلاك).
🏆 أسئلة بمستوى الامتحان
نريد إضافة الأمر Movz rd, rs1, rs2 لمعالج Single-Cycle: إذا كان $Reg[rs2]=0$ ينفَّذ $Reg[rd]\leftarrow Reg[rs1]$، وإلا $Reg[rd]\leftarrow 0$. اختر الادعاء الأصح:
النوع: سجلا مصدر + سجل وجهة، بلا imm ← R-Type (يسقط أ، ج).
العتاد: نحتاج: (1) مقارنة $Reg[rs2]$ بصفر — مقارن الـBranch يقارن rs1 بـrs2، فنضيف MUX يُدخل الثابت 0 للمقارن؛ (2) حساب $Reg[rs1]+0$ في الـALU — توسيع MUX الخاص بـB لاختيار 0؛ (3) كتابة 0 لـrd عند فشل الشرط — توسيع WB MUX بمدخل ثابت 0، مع جعل WBSel تتأثر بإشارة BrEq. كلها «بوررات و/أو ثوابت» + منطق بكر — ليست إعادة توصيل فقط. ✔ الإجابة: د.
أ. في معالج Single-Cycle تعطّلت إشارة funct7 فلا تصل إلى ALU-Ctrl. من بين: jal, beq, add, or, sub, lw, sw — أي الأوامر قد لا تعمل سليمة؟
ب. بعد إصلاح العطل، تبيّن أن المُجمِّع يُدخل 2 NOP بعد كل أمر قفزة (سواء قفزت فعلاً أم لا). كم دورة ساعة تستغرق التشغيلة التالية؟
1. addi x4, x0, 7
2. addi x5, x4, 11
3. loop: beq x4, x0, exit
4. add x6, x5, x4
5. addi x4, x4, -1
6. jal x0, loop
7. exit: add a0, x6, x5
8. addi a1, a0, 1
ج. معالج جديد سليم بـ$T=6ns$ مقابل المعالج المعطوب أعلاه بـ$T=3ns$. لبرنامج فيه $\alpha$ نسبة أوامر القفز، متى يستحق شراء الجديد؟
👁 الحل الكامل خطوة بخطوة
أ. funct7 يستخدمه ALU-Ctrl لأوامر R-Type فقط (يميّز add/sub وsrl/sra). إذن المتأثرة: add, or, sub فقط. (lw/sw/beq/jal تحدد عمليتها من opcode/funct3 — الجمع دائماً).
ب. كل قفزة (beq أو jal) تصبح 3 دورات (هي + NOP×2). الحلقة تدور 7 مرات ($x4: 7\to0$):
$$\underbrace{1+1}_{addi\times2} + 7\cdot\underbrace{(3+1+1+3)}_{beq+add+addi+jal} + \underbrace{3}_{beq\ الأخيرة} + \underbrace{1+1}_{exit} = 2+56+3+2 = \mathbf{63}$$
ج. الجديد: $6N$. القديم: كل أمر قفزة يكلف 3 دورات ← $3N(1+2\alpha)$. نطلب $6N < 3N(1+2\alpha)$: $$6 < 3+6\alpha \iff \alpha > \tfrac12$$ يستحق الشراء عندما تزيد نسبة القفزات عن 50%. ✔
في معالج Single-Cycle انقطع سلك $PC+4$ عن بورر الـWB — فتعطّلت jal (لا يمكنها حفظ عنوان العودة). لا يمكن تعديل الأسلاك، لكن يمكن تعريف أمر جديد وتعديل البكر. أ. عرّف أمراً جديداً addpci يُمكّن تنفيذ jal كأمر زائف. ب. نفّذ بواسطته jal بأقل دورات.
💡 تلميح
👁 الحل الكامل
أ. تعريف الأمر:
Instruction: addpci rd, imm
RegFile: Reg[rd] ← PC + imm
PC: PC ← PC + 4
Type: I/U-TYPE
إشارات البكر: PCSel=PC+4، ImmSel حسب النوع، RegWEn=1، ASel=PC، BSel=imm، ALUSel=add، MemRW=Read، WBSel=ALU (المسار السليم!).
ب. تنفيذ jal بأمرين (دورتان — الحد الأدنى):
addpci ra, 8 # ra = PC+8 = عنوان ما بعد الأمرين
jal x0, label # قفزة دون كتابة سجل (x0 يهمل الكتابة)
لماذا 8؟ لأن العودة يجب أن تصل إلى ما بعد زوج الأمرين (الأمر الحالي + jal الذي يليه). واستخدام jal x0 يتفادى مسار WB المقطوع تماماً. ✔
المعالج متعدد الدورات، الميكروكود، والمقاطعات
14.1 لماذا نهجر أحادي الدورة؟
رأينا المشكلة: الدورة بطول lw كاملاً. الحل: نقسم كل أمر إلى خطوات صغيرة، كل خطوة تستغرق دورة ساعة قصيرة، وكل أمر يأخذ عدد الدورات الذي يحتاجه فقط:
| الأمر | المراحل | دورات |
|---|---|---|
| R-type / addi (حساب) | Fetch, Decode, Exec, WB | 4 |
| lw | Fetch, Decode, Exec(عنوان), Mem, WB | 5 |
| sw | Fetch, Decode, Exec(عنوان), Mem | 4 |
| beq / jal / j | Fetch, Decode, Exec | 3 |
البنية تسمح أيضاً بمشاركة العتاد: ذاكرة واحدة (للأوامر والبيانات) وALU واحد يُستخدم في خطوات مختلفة — لأن الخطوات لا تتزاحم زمنياً.
14.2 البكر يصبح آلة حالات — والميكروكود
في أحادي الدورة كان البكر توافقياً؛ الآن للأمر «تاريخ» عبر الدورات ← البكر FSM: حالة لكل خطوة (Fetch ← Decode ← تفرّع حسب opcode ← …). وهنا فكرة أنيقة من التاريخ: بدل تصميم FSM سلكياً، نخزّن إشارات التحكم في ذاكرة ميكروكود:
- كل سطر (Micro-instruction) = قيم كل إشارات التحكم لدورة واحدة + من أين يأتي السطر التالي (Sequencer: التالي / تفرّع حسب opcode / عودة لـFetch).
- الميزة: تعديل سلوك المعالج أو إضافة أمر = تعديل محتوى ذاكرة، لا إعادة تصميم دارة. الثمن: قراءة الذاكرة أبطأ من لوجيك سلكي.
14.3 الاستثناءات والمقاطعات (חריגות ופסיקות)
استثناء (Exception): حدث داخلي متزامن مع أمر معين — أمر غير شرعي، قسمة على صفر، ecall. مقاطعة (Interrupt): حدث خارجي غير متزامن — عتاد يطلب خدمة.
ماذا يفعل المعالج عند الحدث؟ (1) يحفظ عنوان الأمر المتأثر في SEPC ليمكن الرجوع. (2) يسجّل سبب الحدث في SCAUSE لتعرف نظام التشغيل ماذا حدث. (3) يحمّل الـPC عنوان معالج الأحداث الثابت (في المساق: 0x1C090000 — مدخل إضافي في بورر الـPC). المعالجة برمجية، والعودة عبر SEPC.
🏆 أسئلة بمستوى الامتحان
كم دورة ساعة يستغرق الكود التالي على معالج Multi-Cycle كما تعلمناه؟ (سطر end: ليس أمراً)
add s0, x0, t3 # t3 = 3
add s2, x0, t1 # t1 = 1
loop: beq s0, x0, end
sub s0, s0, s2
xor t0, s0, s2
sw t3, 0(x0)
lw t2, 0(x0)
j loop
end:
الحلقة تدور 3 مرات ($s0: 3\to2\to1\to0$)، وفي المرة الرابعة تُنفَّذ beq الناجحة فقط. الدورات: add=4، sub/xor=4، sw=4، lw=5، beq/j=3:
✔ الإجابة: هـ. الفخ: نسيان الـbeq الرابعة (الخروج) أو عدّ lw كـ4.
برنامج فيه أمران قبل حلقة تدور 4 مرات (جسمها: addi، sub، bne — والأمران قبلها addi وlw وlw… بالضبط: قبل الحلقة addi, addi, lw, lw). الخياران: Single-Cycle بـ$T=4ns$ أو Multi-Cycle بـ$T=1ns$. إجمالي الأوامر المنفّذة 16. أيهما أسرع؟
Single-Cycle: 16 أمراً × دورة × 4ns = 64ns.
Multi-Cycle (بـ1ns للدورة): addi×2 قبل الحلقة $=4+4$، lw×2 $=5+5$، والحلقة $4\times(addi\,4 + sub\,4 + bne\,3) = 4\times11=44$. المجموع $8+10+44=\mathbf{62}$ دورة = 62ns.
62 < 64 ← Multi-Cycle أسرع بفارق ضئيل. ✔ الإجابة: ب. لاحظ العبرة العامة: نسبة الترددات هنا 4:1 بينما CPI المتوسط للـMulti حوالي 3.9 — لذلك الفارق صغير جداً؛ لو كان فيه lw أكثر لانقلبت النتيجة.
شركة تصنع معالجات Multi-Cycle مع دعم استثناءات ومقاطعات، وقررت: عند أي استثناء/مقاطعة يُستدعى نظام التشغيل الذي ينهي البرنامج نهائياً — بلا عودة وبلا معالجة إضافية. عن أي مكوّن/مكوّنات يمكن الاستغناء؟
لا عودة للبرنامج ← لا حاجة لعنوان العودة SEPC. المعالجة موحّدة مهما كان السبب ← لا حاجة لـSCAUSE. لكن ما زلنا بحاجة للقفز إلى نظام التشغيل ← مدخل بورر الـPC (0x1C090000) ضروري. ✔ الإجابة: د.
المعالج المخطّط (Pipeline) والتبعيات: قمة المساق
15.1 الفكرة: خط تجميع للأوامر
نقسم تنفيذ الأمر إلى 5 مراحل ونضع سجلات أنابيب بينها — فيعمل المعالج على 5 أوامر متداخلة في اللحظة نفسها:
عدّ الدورات الأساسي: لبرنامج من $N$ أوامر بلا عوائق: $N + 4$ دورات ($N$ دخول + 4 لتفريغ الأنبوب من آخر أمر). كل عائق (stall/flush) يضيف دوراته.
15.2 التبعيات الثلاث (תלויות) — أعداء الأنبوب
1. بنيوية (Structural): موردان يتنازعان نفس العتاد في نفس الدورة. مثال المساق: الكتابة والقراءة من Register File في نفس الدورة — تُحل بكتابة في النصف الأول وقراءة في النصف الثاني (وهذا هو «forwarding داخلي» WB→DEC).
2. بيانات (Data, RAW): أمر يحتاج نتيجة لم تُكتب بعد. الحل الأساسي: Forwarding — تمرير النتيجة فور جهوزها من مخرج EX أو MEM/WB مباشرة إلى مدخل EX دون المرور بالسجلات.
3. تحكم (Control): بعد قفزة، لا نعرف من أين نجلب. في معالج المساق: القرار في EX، والافتراض «القفزة لا تُؤخذ» — إن أُخذت نعمل flush للأمرين اللذين دخلا خطأً ← عقوبة دورتين لكل قفزة مأخوذة.
lw تُنتج قيمتها فقط في نهاية MEM؛ الأمر التالي مباشرة الذي يستهلكها يحتاجها في بداية EX — أبكر مما يمكن تمريره ← stall دورة واحدة إلزامية (تحقنها وحدة Hazard Detection). أمّا إن فصل بينهما أمر آخر — لا stall.البرنامج: lw t1,0(t0) ← add t3,t1,t2 (تبعية load-use!) ← sw t3,4(t0) ← addi t0,t0,8. اضغط لترى دورة دورة:
15.3 وصفة عدّ الدورات في الامتحان (منهجية مضمونة)
- احسب عدد الأوامر المنفَّذة فعلاً $N$ (تتبّع الحلقات! كما فعلنا بالمحاضرة 2).
- ابدأ من $N+4$.
- أضف +1 لكل load-use hazard فعلي (افحص هل يوجد أمر فاصل).
- أضف +2 لكل قفزة مأخوذة (مع «التنبؤ لا تُؤخذ» والقرار في EX). القفزة غير المأخوذة مجانية.
- انتبه للتفاصيل المعدِّلة: هل الـforwarding كامل؟ أين يُتخذ قرار الـbranch؟ هل توجد كتابة/قراءة RF بنفس الدورة؟
🏆 أسئلة بمستوى الامتحان
البرنامج من المحاضرة 2 (lui/addi ثم حلقة من 6 أوامر تدور 14 مرة: beq, lw, srai, sw, addi, srli ثم bne). المعالج: Pipeline بـforwarding كامل (WB→MEM، EX→EX، WB→DEC) + Hazard Detection + تنبؤ «لا تُؤخذ» وflush بدورتين عند الأخذ (القرار في EX). كم دورة ساعة تستغرق التشغيلة كاملة؟
الحلقة تدور 14 مرة (قيم $a0$: من $2^{13}$ إلى $2^0$). في كل دورة حلقة: load-use hazard بين lw t0 وsrai t0 ← +1 stall. وقفزة bne تُؤخذ في 13 مرة الأولى (تنبؤ خاطئ ← +2 flush)، ولا تؤخذ في الأخيرة (beq عندها هي التي تُؤخذ… بحساب الحل الرسمي المُجمَّع):
• أمران قبل الحلقة: 2 دورة (بمنطق «دورة لكل أمر»).
• 13 دورة حلقة أولى: كل واحدة 6 أوامر + 1 (load) + 2 (bne مأخوذة) + ... = 10 دورات لكل منها.
• الدورة الأخيرة (رقم 14): 6 أوامر + 1 (load) + دخول beq… = 8 دورات.
• تفريغ الأنبوب: +4.
✔ الإجابة: د. لاحظ كيف انبنى السؤال طبقات: تتبّع الحلقة (محاضرة 2) + srai/srli + load-use + عقوبة القفزات — سؤال «تجميعة» يختبر المساق كله.
المعالج نفسه (forwarding كامل + hazard detection). الكود:
1. lw t1, 0(t0)
2. lw t2, 4(t0)
3. add t3, t1, t2
4. sw t3, 12(t0)
5. lw t4, 8(t0)
6. add t5, t1, t4
7. sw t5, 16(t0)
اختر الادعاء الصحيح بشأن إعادة ترتيب الكود:
في الكود الأصلي توجد مشكلتا load-use: (2→3): lw t2 ثم add يستعملها فوراً ← stall؛ و(5→6): lw t4 ثم add t5 ← stall. المجموع stallان.
الحركة السحرية: انقل السطر 5 (lw t4,8(t0)) ليصبح بين السطرين 2 و3. الآن: بين lw t2 وadd t3 يفصل أمر ← لا stall؛ وبين lw t4 وadd t5 تفصل أوامر عدة ← لا stall. (النقل شرعي: لا تبعية بين lw t4 وبين add/sw اللتين قفز فوقهما). وفّرنا دورتين. ✔ الإجابة: ب. هذه مهارة «جدولة الكود» — المُجمِّعات الحديثة تفعلها تلقائياً.
برنامج طويل بتوزيعة: 50% R-type، 40% lw، 10% beq. المعالجات الثلاثة بنفس أزمنة المراحل (كل المراحل متساوية التأخير، أهمل سجلات الأنبوب). Pipeline بـforwarding كامل وقرار قفز في EX مع «لا تُؤخذ». رتّب أزمنة التنفيذ:
لتكن كل مرحلة $T=1$:
Single: دورة = 5 مراحل ← لكل أمر 5.
Multi: CPI $=0.5(4)+0.4(5)+0.1(3)=4.3$ ← لكل أمر 4.3.
Pipeline: CPI $\approx 1$ + عقوبات: حتى في أسوأ الحالات (stall لكل lw وflush لكل beq): $1+0.4(1)+0.1(2)=1.6$ — ما زال أصغر بكثير من 4.3.
$T_{pipe} < T_{multi} < T_{single}$ ✔ الإجابة: أ. (القصة الكبيرة للمساق في سطر واحد!)
في معالج Pipeline (forwarding كامل + hazard detection + قرار قفز في EX) حدث عطل: في سجل الأنبوب inst_D البتات $[11:7]$ تُصفَّر لكل أمر.
أ. أي من الأوامر: slt, lui, sw, lw, beq, j ستستمر بالعمل السليم حتماً؟
ب. أُصلح العطل لكنه انتقل إلى inst_F (قبل فك الترميز وقبل توليد imm): أيها يعمل الآن؟
ج. الكود: loop: addi s0,x0,0xdef ; addi s1,x0,6 ; sw s1,12(s0) ; beq s1,x0,end ; bne s0,s0,loop ; end: — مع العطل من (ب): إلى أي عنوان تُكتب أي قيمة؟ وكم دورة يستغرق الكود؟
💡 تلميح
👁 الحل الكامل خطوة بخطوة
أ. في inst_D (بعد أن أُنتج الـimm في مرحلة Decode... وفق بنية المعالج في المساق يُستخرج الـimm من inst في مرحلة EX من inst_D؟ الحل الرسمي): تصفير [11:7] يعني تصفير rd لأوامر R/I/U/UJ ← كل كتابة سجل تتجه لـx0 فتضيع: slt, lui, lw تفشل. أما sw وbeq فالبتات [11:7] عندهما جزء من imm لكن العطل يقع بعد استخراج الـimm ← تعملان سليمتين. وj (=jal x0) أصلاً تكتب لـx0 ← تعمل. الجواب: sw، beq، j.
ب. الآن العطل قبل توليد الـimm ← حتى sw وbeq يفسد جزء من الـimm عندهما. الوحيدة الناجية: j.
ج. بسبب العطل: addi لا يحدّث s0 وs1 (يكتب لـx0) ← يبقيان 0.
• sw: الإزاحة 12=$(1100)_2$ تقع بالضبط في البتات المصفّرة ← تصبح 0 ← الكتابة إلى العنوان 0x0 والقيمة 0.
• beq s1,x0: بما أن $s1=0$ الشرط متحقق ويجب القفز لـend (إزاحة 8=$(1000)_2$ — ضمن البتات المصفّرة!) ← القفزة تحسب $PC+0$ ← الأمر يقفز إلى نفسه إلى الأبد.
• إذن: $N=\infty$ — البرنامج لا ينتهي أبداً. ✔ (مطابق للحل الرسمي: كتابة 0 إلى 0x0 وحلقة أبدية).
🎯 مراجعة نهائية واستراتيجية الامتحان
ما الذي يتكرر فعلاً في الامتحانات؟ (تحليل مواعد 2024–2026)
من تحليل 7 امتحانات كاملة، هذه «الزبائن الدائمون» في الأسئلة الأمريكية: استدلال الـLatch في Verilog، مسافة الكود وأكواد التصحيح، أنظمة العمليات الكاملة/نصف الكاملة، حساب $T_{pd}$ مع فحص المسارات المزيفة، setup/hold مع skew أو jitter، UART والانحراف المتراكم، عدّ دورات Multi-Cycle، وعدّ دورات Pipeline مع hazards. أما الأسئلة المفتوحة الثلاثة فتأتي غالباً واحدة من كل عائلة: (1) أسمبلي/عودية/بروتوكول الاستدعاء، (2) آلات حالات: تقليص + تصميم، (3) معالج: عطل في مسار البيانات/إضافة أمر/تحليل أداء.
الأخطاء القاتلة الشائعة — لا تقع فيها
- تغطية حالات $\phi$ في كارنو «لأنها موجودة» — غطِّ الآحاد فقط.
- نسيان أن skew الموجب يريح setup لكنه يخنق hold — افحص القيود الأربعة دائماً.
- عدّ قفزة غير مأخوذة كعقوبة في Pipeline — العقوبة فقط عند الأخذ (مع تنبؤ «لا تُؤخذ»).
- lw في Multi-Cycle = 5 دورات وليس 4، وbeq/j = 3.
- نسيان تنفيذة beq الأخيرة (الخروج) عند عدّ دورات الحلقات.
- الخلط بين «الحمل الخارج» والفيض في المتمّم لـ2.
- في أسئلة الأعطال: rd هو inst[11:7] — لكن في S/SB هذه البتات imm!
خطة ليلة الامتحان
ساعة واحدة: امسح كل صناديق «التعريف» الزرقاء في هذا الملف. ساعتان: أعد حل كل أسئلة الامتحانات هنا دون فتح الحلول — ما أخطأت فيه، أعد قراءة محاضرته. نصف ساعة: احفظ الأرقام المقدسة (دورات Multi-Cycle، عقوبة الـflush، صيغة scan، الشرطين الذهبيين). ثم نَم جيداً — Metastability في دماغك أخطر من أي skew. 😄
بالتوفيق يا يزن! 🍀 בהצלחה!