ثوابت بلمسة
parameter هو ثابت - يختار المترجم قيمته ويُضمّنها في التصميم قبل بدء المحاكاة. اللمسة هي أن من يأخذ نسخة من module يمكنه تغيير القيمة. ملف المصدر نفسه لـ module يمكن أن يُنتج دارات بأحجام مختلفة بحسب كيف يضبطها المستدعون.
هكذا تبني IP قابل لإعادة الاستخدام. module FIFO بـ parameters WIDTH وDEPTH يستطيع خدمة كل فريق في شركة. عدّاد بـ parameter WIDTH هو نفس المصدر سواء يعدّ إلى 16 أم 4 مليارات.
إعلان parameter أساسي
ثلاث قطع جديدة من الصياغة:
- كتلة parameter:
#( parameter WIDTH = 8 )بين اسم module وقائمة المنافذ. القيمة الافتراضية8هي ما يستخدمه module عندما لا يتجاوز أحد. - موقع الاستخدام:
output reg [WIDTH-1:0] count. parameter هو فقط ثابت - نُدخله في نطاق البتات. نفس مصدر module يُنتج خرجًا 8 بت أو 16 بت بحسبWIDTH. - صياغة التجاوز:
counter #(.WIDTH(16)) dut16(...)عند الـ instantiation. تذهب كتلة#(...)قبل اسم النسخة، بعد اسم module. أي parameters لا تذكرها تحتفظ بقيمها الافتراضية.
localparam: ثوابت داخلية
ثمة ثوابت لا تريد للمستدعين تجاوزها. ترميز الحالات هو الحالة الكلاسيكية:
localparam يجعل IDLE وRUNNING وDONE متاحة داخل module لكنها غير قابلة للتجاوز من الـ instantiation. هذا الاختيار الصحيح - تغيير ما تعنيه IDLE من قيمة حالة من خارج module مرعب.
استخدم parameter لأشياء يجب أن يضبطها المستدعون (عروض، أعماق، خيارات سلوك) وlocalparam لكل ما عداها. نمط شائع هو اشتقاق localparams من parameters:
parameter WIDTH = 32;
localparam WIDTH_M1 = WIDTH - 1; // مُحسَب مرة؛ غير قابل للتجاوز
عروض بـ parameters في الممارسة
أكثر استخدامات parameters شيوعًا هو جعل عروض buses مرنة. إليك جامع يعمل بأي عرض:
ملف مصدر واحد، نسختان، عرضان مختلفان، بلا نسخ ولصق. هذا هو العائد الكامل لـ parameters.
parameters متعددة، تجاوز بالاسم
لـ modules أكبر سيكون لديك غالبًا عدة parameters. تجاوزها بالاسم بأي ترتيب:
module fifo #(
parameter WIDTH = 8,
parameter DEPTH = 16,
parameter AFULL = DEPTH - 2
)(
input wire clk,
input wire reset,
// ... ports ...
);
// ...
endmodule
// At the call site:
fifo #(.WIDTH(32), .DEPTH(1024)) cmd_queue (.clk(clk), .reset(reset), ...);
لست مضطرًا لتجاوز كل parameter؛ ما لم تُذكر يحتفظ بافتراضاته. افتراضي AFULL في المثال محسوب من DEPTH، وهذا يعني إن تجاوزت DEPTH، يتبعها AFULL تلقائيًا - بالضبط نوع التبعية الذي يتعامل معها localparam أيضًا إن لم ترد أن يستطيع المستدعون تجاوز AFULL باستقلال.
أخطاء شائعة
نسيان # في التجاوز. counter (.WIDTH(16)) dut(...) يبدو كتجاوز لكن Verilog يقرأ (.WIDTH(16)) كوصلة منفذ. تحتاج counter #(.WIDTH(16)) dut(...).
استخدام parameters حيث ليست ثابتة بما يكفي. parameters تُحلّ في وقت elaboration، قبل وجود أي إشارات. لا يمكنك ضبط parameter على إشارة وقت تشغيل - إن اعتمدت القيمة على ما يفعله دخل في وقت المحاكاة، فهي ليست parameter، بل منطق.
خلط parameter وlocalparam في قائمة المنافذ. فقط parameter يذهب في كتلة #(...) في الأعلى. localparam يعيش داخل الجسم. سيخبرك المترجم إن بدّلت.
ماذا بعد
تستطيع الآن صنع modules حجمها يُضبط في وقت الترجمة. المستندان التاليان يغطّيان قواعد كتابة الثوابت الحرفية (8'h1F، 4'b1010، 32'd100) وقيم x وz التي تظهر عندما تكون الإشارات غير مَقُودة أو متنازَع عليها. بعد ذلك ننتقل إلى العوامل - كل شيء يمكنك فعله بـ vectors وparameters التي رأيتها الآن.
الأسئلة الشائعة
ما هو parameter في Verilog؟
parameter هو ثابت وقت الترجمة مُعلن داخل module. يمكن استخدامه حيثما يُسمح بثابت - عروض buses، أعماق ذواكر، ترميز حالات، قيم افتراضية. الأهم أن كل نسخة من module يمكن أن تتجاوز parameter، فيُنتج ملف المصدر نفسه، مثلًا، عدّاد 8 بت في مكان وعدّاد 32 بت في آخر.
ما الفرق بين parameter وlocalparam في Verilog؟
قيم parameter يمكن تجاوزها من خارج module عند أخذ نسخة. قيم localparam لا يمكن - فهي ثوابت داخلية فقط. استخدم localparam لترميز الحالات والثوابت المُشتقة التي لا يريد مؤلف module للمستدعين العبث بها.
كيف تتجاوز parameter في Verilog؟
عند أخذ نسخة من module، أضف كتلة تجاوز parameter قبل اسم النسخة: counter #(.WIDTH(16)) my_inst (.clk(clk), .count(count));. صياغة .WIDTH(16) تضبط ذلك parameter المحدد؛ أي parameters لا تذكرها تحتفظ بقيمها الافتراضية. التجاوزات المتعددة تفصل بينها فواصل داخل #(...).
ما هو parameterized module؟
module يكشف عن إعلان parameter واحد أو أكثر يمكن للمستدعين تجاوزه. FIFO ذي parameters قد يحوي WIDTH وDEPTH فيُنتج نفس المصدر FIFO بـ 32 بت × 16 عمق في مكان وFIFO بـ 8 بت × 1024 عمق في آخر. هكذا تُكتب مكتبات كتل IP القابلة لإعادة الاستخدام.