ماذا يعني "الزمن" في Verilog
ليس لـ Verilog مفهوم مدمج للثواني. يُقدّم المحاكي "وحدات زمن" - ticks أعداد صحيحة عشوائية - وتستخدم شيفرتك #N لانتظار N منها. توجيه `timescale هو ما يربط تلك ticks بالزمن الحقيقي.
`timescale 1ns / 1ps
module test;
initial begin
$display("t = %0t", $time); // 0
#5;
$display("t = %0t", $time); // 5 ns
#1.5;
$display("t = %0t", $time); // 6500 ps (or 6.5 ns)
$finish;
end
endmodule
معاملان:
- الوحدة (الرقم الأول): ماذا يعني
#1.1nsيقول tick واحد هو نانوثانية واحدة. - الدقة (الرقم الثاني): كم بدقة تتعقّب المحاكاة الزمن داخل تلك الوحدة.
1psيقول تُقرّب delays الكسرية إلى البيكوثانية.
الدقة لا يمكن أن تكون أخشن من الوحدة (1ps / 1ns غير شرعي). اختيارات شائعة:
1ns / 1ps- المعيار الفعلي. كل شيء بالنانوثانية، دقة sub-nanosecond لأي تأخيرات بوابات.1ps / 1ps- عند نمذجة دارات سريعة جدًا أو عندما يكون كل تأخير sub-nanosecond.1us / 1ns- للمحاكيات البطيئة بمقياس مُضمَّن (أزمنة بايت UART، بروتوكولات بطيئة).
أين تضعه
`timescale هو توجيه مترجم، لا بناء على مستوى module. يذهب على قمة الملف بالضبط، قبل أي module:
`timescale 1ns / 1ps
module foo(...);
// ...
endmodule
نطاقه "من هذه النقطة فصاعدًا في ترتيب الترجمة، حتى `timescale التالي أو نهاية الترجمة". هذا له تضمين دقيق: ملف بلا `timescale صريح يرث ما أعلنه الملف المُترجم سابقًا، الذي يعتمد على ترتيب قراءة المترجم للملفات. تجنّب المفاجأة: ضع `timescale على قمة كل ملف.
محرر المتصفح في هذه المستندات يضبط timescale افتراضيًا لك (عادةً 1ns / 1ps)، ولهذا عملت الأمثلة في المستندات السابقة دون إعلان واحد. في مشروع حقيقي ستكون صريحًا.
#delay في الممارسة
بعد `timescale 1ns / 1ps:
#5 // wait 5 ns
#100 // wait 100 ns
#1.5 // wait 1.5 ns (precision allows it)
#0.001 // wait 1 ps (just barely above precision)
#0 // zero-delay; useful for ordering events at the same time
داخل كتلة initial أو always، #N يحجب التدفق الإجرائي لـ N وحدة زمن. يوقف المحاكي هذه الكتلة مؤقتًا (الكتل المتزامنة الأخرى تستمر) ويستأنف بعد التأخير.
يمكنك إسباق إسناد بتأخير:
#10 a = 1; // wait 10 ns, then assign
data <= #2 new_value; // schedule the non-blocking assignment 2 ns from now
الشكل الأول هو دعامة testbench. الشكل الثاني (non-blocking متأخر) يُستخدم في محاكاة مستوى البوابة لنمذجة تأخير الانتشار.
توليد Clock
النمط الكلاسيكي:
`timescale 1ns / 1ps
module test;
reg clk = 0;
always #5 clk = ~clk;
// ...
endmodule
مع timescale 1ns / 1ps، #5 هو 5 ns. يتقلب clock كل 5 ns، فتعطي فترة 10 ns - clock 100 MHz. لتغيير التردد، غيّر التأخير:
| نصف الفترة | الفترة | التردد |
|---|---|---|
#1 | 2 ns | 500 MHz |
#2.5 | 5 ns | 200 MHz |
#5 | 10 ns | 100 MHz |
#10 | 20 ns | 50 MHz |
#25 | 50 ns | 20 MHz |
#50 | 100 ns | 10 MHz |
إن أردت نصف فترة كسري (#2.5)، تحتاج دقتك لدعمه - دقة 1ps تتعامل مع أي شيء حتى 0.001 ns، فأي تردد معقول جيد.
مزج Timescales عبر الملفات
تصميم حقيقي له ملفات كثيرة، ويمكنها إعلان timescales مختلفة. يستخدم المحاكي timescale كل ملف لتفسير delays في ذلك الملف. إن قال module_a.v `timescale 1ns / 1ps واستخدم #5، فهي 5 ns. إن قال module_b.v `timescale 1us / 1ns واستخدم #5، فهي 5 us.
هذا غير مرئي في الغالب لأن المحاكي يُقدّم محور زمن عالمي بصرف النظر - لكن يعني أن نفس #N في ملفين قد يعني أشياء مختلفة بشكل صارخ. الحل: اختر timescale واحد (المعيار الصناعي هو 1ns / 1ps) وضعه على قمة كل ملف. لا تخلط.
Delays غير قابلة للتركيب
نقطة حاسمة: #delay موجودة فقط للمحاكاة. أداة التركيب تقرأ:
// In synthesizable RTL - WRONG
always @(posedge clk) begin
out <= #2 in;
end
…وإما تتجاهل #2 (معظم الأدوات) أو ترفض البناء (linters أكثر صرامة). توقيت العتاد الحقيقي يُحدَّد بـ clock وبتأخير انتشار البوابات - كلاهما غير مرئي للشيفرة المصدر.
القاعدة: استخدم # فقط في testbenches. RTL القابل للتركيب ليس له # delays. إن وجدت نفسك تريد تأخيرًا في شيفرة قابلة للتركيب، فأنت في الحقيقة تريد عدّادًا يتقلص على clock - هكذا "ينتظر" العتاد الحقيقي.
$time مقابل $realtime
طريقتان لقراءة زمن المحاكاة الحالي:
$timeتُرجع عدد صحيح 64 بت بوحدات وحدة timescale الحالي.$realtimeتُرجعrealبوحدات وحدة timescale الحالي، لكن بدقة كاملة.
لتسجيل testbench، $time تقريبًا دائمًا كافية. ألجأ إلى $realtime فقط عندما تحتاج دقة sub-tick في جمل الطباعة.
نصائح عملية
- أعلن
`timescaleدائمًا على قمة كل ملف.1ns / 1psهو الافتراضي الآمن. - استخدم
#delayفقط في testbenches. عامل غيابه في الشيفرة القابلة للتركيب كقاعدة ثابتة. - طابق فترات clock مع التردد المستهدف. إن كنت تُحاكي تصميم 50 MHz، استخدم فترة clock 20 ns - الفترات غير المتطابقة قد تُخفي أخطاء حساسة للتوقيت.
- للتحفيز المعدود بالدورات، استخدم
@(posedge clk)بدلًا من#. قوي ضد التغييرات في فترة clock.
ماذا بعد
شاهدت الآن كل مستند في هذه الدروس عن Verilog. من أساسيات اللغة (wire مقابل reg، modules، عوامل)، عبر الكتل الإجرائية والتحكم في التدفق، إلى التصميم المتزامن وآلات الحالة، وأخيرًا أدوات testbench التي تُثبت أن كل ذلك يعمل. حان وقت بناء شيء - playground بجوار هذه المستندات هو نفس المحاكي الذي استخدمناه طوال الوقت، جاهز لأي module ترسمه.
الأسئلة الشائعة
ماذا يعني `timescale 1ns / 1ps في Verilog؟
يخبر المحاكي: 'وحدة زمن واحدة في هذا الملف هي نانوثانية واحدة، والأزمنة تُتعقّب بدقة بيكوثانية.' بعد ذلك التوجيه، #5 ينتظر 5 ns، #1.5 ينتظر 1.5 ns (مقرّب إلى البيكوثانية)، و$time يُبلَّغ بالنانوثانية. الرقم الأول هو الوحدة؛ والثاني هو الدقة.
هل أحتاج `timescale في كل ملف Verilog؟
أفضل ممارسة: نعم. نطاق التوجيه ينتهي عند \timescaleالتالي أو نهاية الترجمة، فالملفات بلا توجيه ترث ما أعلنه الملف المُترجم سابقًا. هذا يجعل التوقيت غير حتمي عبر البناءات. ضع`timescale 1ns / 1ps` على قمة كل ملف مصدر - هذا الاصطلاح الأكثر شيوعًا - ولن تحصل على مفاجأة.
ماذا تعني #5 في Verilog؟
#5 يُقدّم زمن المحاكاة بـ 5 وحدات زمن. الوحدة تأتي من توجيه \timescaleالنشط. مع`timescale 1ns / 1ps، #5هو 5 نانوثوانٍ. مع`timescale 1us / 1ns، #5هو 5 ميكروثوانٍ. الرقم يمكن أن يكون كسريًا -#1.5` يعمل إن كانت دقتك أدق من الوحدة.
هل #delay قابل للتركيب في Verilog؟
لا. #delay يؤثر فقط على المحاكاة - أداة التركيب تتجاهله أو ترفضه. توقيت العتاد الحقيقي يأتي من إشارة clock وتأخير انتشار البوابات، لا من جمل #. استخدم # بحرية في testbenches؛ لا تكتبها أبدًا في RTL القابل للتركيب.