منطق ثنائي الحالات مقابل رباعي الحالات
في البرمجيات، البت هي 0 أو 1. في Verilog، يمكن أن تكون البت إحدى أربع قيم:
0- السلك مَقُود إلى الأسفل.1- السلك مَقُود إلى الأعلى.x- قيمة السلك مجهولة. لا يستطيع المحاكي تحديدها.z- السلك في معاوقة عالية. لا شيء يقوده.
نموذج الحالات الأربع موجود لأن العتاد لديه نفس المشكلة. سلك حقيقي يمكن ربطه إلى الأسفل، أو الأعلى، أو غير معرَّف (مَقُود بمصدرين يتصارعان)، أو طائف (بلا قائد على الإطلاق). على المحاكي نمذجة الأربع جميعًا ليكون مفيدًا.
كيف تظهر x
شغّل هذا وانظر إلى الخرج:
a مُعلن لكن لم يُكتب إليه أبدًا، فيبقى عند x. جمع x + 5 يُنتج x - أي حساب مع مجهول يُنتج مجهولًا. الخرج يقرأ ما يساوي aaaa من x's.
مصادر شائعة لـ x في تصاميمك:
regمُعلن لكن لم يُعَد ضبطه أبدًا (معظم Verilog القابل للتركيب يستخدم reset صريحًا لمسحها).- جملة
caseبلاdefault، تُضرب بقيمة دخل لم تطابق أي حالة. wireفقد قائده الوحيد بعد إعادة هيكلة.- سلسلة
if/elseحيث لا يُسند فرع إشارة يُسندها الآخر (يحبسxإن لم يُغطَّ). - القراءة وراء نهاية vector أو array.
انتشار X: قطعة صغيرة من x تُفسد كل شيء
الشيء القاسي بشأن x هو انتشارها. بت x واحدة في معامل تحوّل النتيجة كلها إلى x:
لاحظ أن 0 & x هي 0 (AND مع 0 دائمًا 0) و1 | x هي 1 (OR مع 1 دائمًا 1). المحاكي متشائم بت بت لكنه يحترم الهويات. الحساب والمقارنة ليسا كذلك.
لهذا يمكن لـ register غير مُهيَّأ واحد أن يجعل bus خرج كامل يصبح xxxx. تتبّع للخلف من أي x وستجد المصدر.
كيف تظهر z
z هي قيمة سلك لا يقوده أحد:
نمطان في تلك الشيفرة:
floatingمُعلن فقط ولم يُقد أبدًا. يأخذ افتراضيًاz.data_outهو tri-state متعمَّد. عندما يكونenableمنخفضًا، يحرر الخرج صراحةً إلىz. هكذا "يتركه" قائد bus حتى يستطيع قائد آخر تولّيه.
على المنطق الداخلي، z تقريبًا دائمًا خاطئة. على pin ثنائي الاتجاه أو bus مشترك، z صحيحة تمامًا.
المقارنة بـ == مقابل ===
عامل المساواة العادي == يُرجع x عندما يكون لأي معامل بت x أو z:
=== (وشريكتها !==) تُجري مقارنة صارمة بت بت بما في ذلك x وz. استخدمها كلما احتجت اختبار x/z في testbench. === غير قابل للتركيب، لكن داخل كتلة initial في testbench لا يهم.
دالة النظام $isunknown(expr) هي أنظف طريقة لتسأل "هل لهذا التعبير أي بتات x أو z؟" - تُرجع 1 إن نعم، 0 إن لا.
استخدام x كـ don't-care متعمَّد
نمط مثير للجدل لكنه شرعي: 'x في حالة default لآلة حالة تخبر أداة التركيب "هذه الحالة غير قابلة للوصول، حسّن بحرية":
case (state)
IDLE: next_state = go ? RUNNING : IDLE;
RUNNING: next_state = done ? IDLE : RUNNING;
default: next_state = 'x; // unreachable
endcase
يمكن لأداة التركيب استخدام x لدمج الحالات وتقليل عدد البوابات. في المحاكاة، إن كان منطقك خاطئًا والحالة الافتراضية تُصل فعلًا، فسترى x تنتشر من next_state ويصبح الخطأ ظاهرًا فورًا.
استخدم هذا فقط عندما تكون قد فكرت في ما إذا كانت الحالة الافتراضية غير قابلة للوصول حقًا. إن لم تفعل، اضبط الافتراضي على حالة آمنة بدلًا من ذلك.
وصفة تنقيح شائعة
تحدّق في waveform مليء بـ x. الوصفة:
- اعثر على أبكر
x. سِر بـ waveform للخلف في الزمن. أبكر إشارة تصبحxهي الأقرب للمصدر. - اعثر على قائدها. افتح المصدر. ما الذي يُسند هذه الإشارة؟
assign؟ كتلةalways؟ - افحص مدخلات القائد. إن كان للقائد أي
xفي الطرف الأيمن، فالانتشار يفعل ما يفترض - الخطأ في الأعلى. - إن كان للقائد مدخلات نظيفة لكنه يُنتج
x، فالقائد ناقص.caseمفقود default، أوifمفقودelse، أو register مفقود reset.
معظم أخطاء عاصفة x تتلخص في واحد من: reset مفقود، أو default مفقود، أو sub-module غير موصول.
ماذا بعد
لديك الآن قصة أنواع البيانات الكاملة: wire/reg، vectors، parameters، الأرقام الحرفية، ونموذج المنطق رباعي الحالات. الفصل التالي يبدأ في استخدام كل ذلك لبناء تعابير - عوامل من كل نكهة، بما في ذلك العوامل على مستوى البتات التي لن تكون منطقية في البرمجيات.
الأسئلة الشائعة
ماذا تعني x في Verilog؟
x هي القيمة المجهولة. إشارة قيمتها x يمكن أن تكون إما 0 أو 1 - لا يستطيع المحاكي تحديدها. تظهر عندما لا تُقاد إشارة، أو عند تنازع قائدين، أو عند قراءة register قبل reset، أو في أي مكان قد يستمر فيه السلوك غير المعرَّف بهدوء. عامل x كإشارة على bug؛ فهي تقريبًا لا تعني أبدًا ما تريده.
ماذا تعني z في Verilog؟
z هي قيمة المعاوقة العالية - السلك ليس مَقُودًا أبدًا. إنها الحالة الشرعية لمخارج tri-state (باصات البيانات، الـ pins ثنائية الاتجاه)، لكن على الإشارات الداخلية تكون z عادةً خطأً يعني 'لا شيء موصول هنا'. أدوات التركيب ترفض معظم أنماط z خارج تفعيلات خرج tri-state الصريحة.
لماذا خرج Verilog لديّ xxxx؟
تقريبًا دائمًا لأن إشارة لا تُقاد بأي شيء، أو لأن عملية نقلت x من إشارة أخرى. سِر للوراء: أي إشارة تساوي x، ما الذي يقودها، هل القائد نشط؟ المذنبون الشائعون هم حالات default مفقودة في جمل case، وregisters غير مُعاد ضبطها، وwires فقدت قائدها بعد إعادة هيكلة.
كيف تتحقق من x أو z في Verilog؟
استخدم عامل === الذي يقارن بالبت بالضبط بما في ذلك x وz. a === 1'bx صحيح عندما يكون a فعلًا x. == العادي يُرجع x عندما يكون لأي معامل بت x، مما يعني أن a == 1'bx لا يكون أبدًا الجواب الذي تريده. يوجد أيضًا $isunknown(a)، وهو boolean مرتب.
هل يمكن إسناد x كافتراضي في Verilog؟
نعم، وهي تقنية متعمَّدة في جمل case: default: out = 'x; يخبر أداة التركيب 'أعدك أن هذه الحالة لا تحدث أبدًا، حسّن بحرية'. التكلفة هي أنه إن حدثت في المحاكاة، تنتشر x فترى الخطأ. استخدمها عندما تكون قد أثبتّ بالفعل أن الافتراضي غير قابل للوصول، لا كطريقة لتجنب كتابة الحالة.