كتلة إجرائية لقطة واحدة
initial begin ... end شقيق always. الفرق: initial تعمل مرة واحدة بالضبط، بدءًا من الزمن 0، ثم تنتهي. لا قائمة حساسية ولا تكرار.
توجد لسبب واحد: إعداد testbench. ضبط القيم الأولية، إطلاق التحفيز، فتح ملفات السجل، استدعاء $finish بعد وقت محاكاة ثابت - كل الأشياء التي تريد حدوثها مرة عند بداية تشغيل، بترتيب معروف.
اخطُ ما يفعله المحاكي:
- الزمن يتقدم إلى 0.
- كتلة
initialتبدأ.$displayالأولى تطبع. dataيُضبط على8'hA5.#10يُقدّم الزمن المُحاكَى بـ 10 وحدات.$displayالثانية تطبع.$finishتنهي المحاكاة.
الكتلة عملت مرة. لا مرور ثانٍ.
الهيكل المعتاد لـ testbench
كل testbench ستكتبه تقريبًا يستخدم كتلة initial كهذه:
انظر إلى الشكل - إنه قالب testbench الذي ستلجأ إليه في كل مرة:
- افتح ملف VCD (
$dumpfile،$dumpvars) - مُغطّى في Dumpfile وVCD. - اضبط القيم الأولية واحتفظ بـ reset لبضع دورات.
- قُد التحفيز عبر سلسلة من التغييرات متفرقة بـ
#delays. $finishلإنهاء المحاكاة بنظافة.
هذا كل شيء. كل اختبار Verilog ستراه، بما في ذلك تلك في أمثلة الشركات، يتبع هذا النمط.
عدة كتل initial متوازية
عدة كتل initial في نفس module كلها تبدأ عند الزمن 0 في وقت واحد. كل واحدة تعمل جملها في شريحتها الزمنية الخاصة:
يبدأ المحاكي كلتا الكتلتين عند الزمن 0. $display الأولى للكتلة B تعمل فورًا. الكتلة A تنتظر 5 وحدات قبل الطباعة. الكتلة B تطبع مرة أخرى عند الزمن 2. طباعة A الثانية تُطلق عند الزمن 15. $finish للكتلة B يقتل المحاكاة عند الزمن 22.
تقسيم الإعداد، توليد الساعة، والتحفيز إلى كتل initial منفصلة أسلوب شائع - كل كتلة قصيرة وتفعل شيئًا واحدًا.
التهيئة المضمّنة في الإعلانات
شكل مدمج شائع: هيّئ reg مباشرة عند وقت الإعلان. معظم المحاكيات تعامله كـ initial:
reg clk = 0;
reg reset = 1;
reg [7:0] count = 0;
هذا يكافئ:
reg clk;
reg reset;
reg [7:0] count;
initial begin
clk = 0;
reset = 1;
count = 0;
end
الشكل المدمج هو ما ستراه في testbenches - يضع القيمة الأولية بجوار الإعلان حيث يسهل مسحه بصريًا.
initial للمحاكاة فقط
أدوات التركيب تتجاهل كتل initial. العتاد الحقيقي ليس له "لحظة صفر" تعمل فيها شيفرة الإعداد - له power-on، وإشارات reset، والإعداد الذي يأتي من تلك الأحداث. إن احتجت register أن يبدأ في حالة معروفة في عتاد حقيقي، فقده بإشارة reset داخل always @(posedge clk):
always @(posedge clk) begin
if (reset) state <= IDLE;
else state <= next_state;
end
فرع if (reset) ذاك هو المكافئ القابل للتركيب لـ initial state = IDLE. Reset هو الجواب على "كيف أُهيّئ register في عتاد حقيقي؟"
بعض تدفقات FPGA تقبل initial مقيدة لقيم reset للـ registers (أدوات Xilinx، مثلًا)، لكن هذا امتداد خاص بالشركة. لا تعتمد عليه في شيفرة محمولة.
أشياء ستراها داخل initial
بعض الأنماط الشائعة بعد هيكل testbench القياسي:
إنهاء بتأخير زمني
initial begin
#1000 $finish; // safety net: kill the sim after 1000 time units
end
initial منفصلة مهمتها الوحيدة وضع حد أعلى صلب على المحاكاة. حتى إن انغلقت كتلة التحفيز الرئيسية بانتظار إشارة لا تأتي، تُطلق هذه الكتلة وتنهي التشغيل.
إعداد الموجة
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test); // dump everything under the `test` scope
end
هذان السطران يخبران المحاكي بكتابة ملف VCD يحوي كل إشارة في نطاق test. بدونهما، لا تحصل على موجة.
صورة ذاكرة أولية
reg [7:0] memory [0:255];
initial begin
$readmemh("image.hex", memory);
end
$readmemh يُحمّل ملفًا بتنسيق hex إلى array. يُستخدم في testbenches لـ CPU لتحميل ذاكرة التعليمات مسبقًا. للمحاكاة فقط.
أخطاء شائعة
استخدام initial لمنطق قابل للتركيب. لن يُركَّب. استخدم إشارات reset بدلًا من ذلك.
نسيان $finish. بدونه يعمل المحاكي حتى يوقفه شيء آخر (حد زمن افتراضي، مقاطعة يدوية، إلخ). لاختبار سريع لا بأس؛ لسكربت regression، استخدم $finish دائمًا.
نسيان #delay بين إسنادات التحفيز. إن كتبت a = 0; b = 1; بلا delay، كلاهما يحدث في نفس وقت المحاكاة وقد يراهما DUT في وقت واحد بدلًا من كأحداث منفصلة. أدخل #1 أو أكثر بين أحداث التحفيز المتميزة.
محاولة قيادة wire من initial. نفس قاعدة always: فقط reg هدف شرعي.
ماذا بعد
شاهدت نكهتي الكتلة الإجرائية. المستند التالي يغطي أكثر موضوع مربك للمبتدئين في Verilog: Blocking مقابل Non-blocking Assignment. معرفة متى تستخدم = ومتى <= هي الفرق بين flip-flop عامل وفوضى race condition.
الأسئلة الشائعة
ما هي كتلة initial في Verilog؟
initial begin ... end كتلة إجرائية تعمل مرة واحدة بالضبط عند بداية المحاكاة، عند الزمن 0. إنها المكان القياسي لإعداد حالة testbench: تهيئة الإشارات، فتح ملفات السجلات، استدعاء $dumpfile/$dumpvars، قيادة التحفيز، وإنهاء المحاكاة بـ $finish. عدة كتل initial يمكن أن تتعايش في module؛ كلها تبدأ عند الزمن 0 بالتوازي.
ما الفرق بين initial وalways في Verilog؟
initial تعمل مرة عند الزمن 0 ثم تنتهي. always تعيد التشغيل إلى الأبد - لها قائمة حساسية وتستيقظ كلما تغيّرت الإشارات المُدرجة. initial تُستخدم تقريبًا حصرًا في testbenches. always هي حصان العمل لكل من testbenches وRTL القابل للتركيب.
هل كتلة initial قابلة للتركيب؟
ليس في Verilog العادي. أدوات التركيب تتجاهل كتل initial لأن العتاد الحقيقي ليس له لحظة 'صفر زمن' تعمل فيها شيفرة الإعداد. بعض سلاسل أدوات FPGA تقبل شكلًا مقيدًا لضبط قيم reset لـ registers، لكن الحالة العامة هي للمحاكاة فقط. أبقِ كتل initial في testbenches؛ استخدم إشارات reset لتهيئة المنطق القابل للتركيب.
هل يمكن وجود كتل initial متعددة في Verilog module؟
نعم. كل كتلة initial تبدأ عند الزمن 0 وتعمل حتى الاكتمال باستقلال. تقسيم الإعداد إلى كتل متعددة نمط testbench شائع - كتلة لتوليد الساعة، وكتلة للتحفيز، وكتلة لتفريغ الموجة. يعملن بالتوازي من الزمن 0؛ يُداخل المحاكي جملهنّ مع تقدم الزمن.