目次
1. บทนำ
parameter ใน Verilog คืออะไร?
Verilog เป็นหนึ่งในภาษาบรรยายฮาร์ดแวร์ (HDL: Hardware Description Language) ที่ใช้สำหรับการออกแบบวงจรดิจิทัล ภายในนั้น parameter (พารามิเตอร์) เป็นฟีเจอร์สำคัญที่ช่วยเพิ่มความยืดหยุ่นและการนำกลับมาใช้ซ้ำของการออกแบบ parameter เป็นการกำหนดค่าคงที่ (constant) โดยมีชื่อกำกับ ซึ่งมีประโยชน์อย่างมากเมื่อคุณต้องการใช้โมดูลเดียวกันซ้ำภายใต้การตั้งค่าที่ต่างกัน หรือเพื่อให้โค้ดอ่านและดูแลได้ง่ายขึ้น โดยปกติแล้วแทนที่จะระบุค่าแบบตายตัว (เช่น ความกว้างของบิต ขนาดบัส หรือการตั้งค่า timing) เราสามารถกำหนดเป็น parameter เพื่อให้ปรับเปลี่ยนค่าได้ง่ายภายหลังทำไม parameter จึงสำคัญ?
การใช้ parameter ในการออกแบบด้วย Verilog มีข้อดีดังนี้:- เพิ่มความสามารถในการนำกลับมาใช้ซ้ำ โมดูลที่สร้างขึ้นครั้งเดียวสามารถนำไปใช้ซ้ำได้หลายงาน ทำให้การพัฒนาโครงการขนาดใหญ่มีประสิทธิภาพมากขึ้น
- เพิ่มความสะดวกในการบำรุงรักษา ค่าคงที่จะถูกจัดการในที่เดียว หากมีการเปลี่ยนแปลงก็เพียงแก้ไข
parameterที่เกี่ยวข้อง - ทำให้โค้ดอ่านง่ายขึ้น ช่วยกำจัด “magic number” และทำให้ผู้อ่านเข้าใจได้ทันทีว่าค่าใดมีความหมายว่าอะไร
parameter DATA_WIDTH = 8; และตามด้วย [DATA_WIDTH-1:0] จะสื่อความหมายของการออกแบบได้ชัดเจนกว่าสิ่งที่จะได้จากบทความนี้
บทความนี้จะอธิบายการใช้parameter ใน Verilog ตั้งแต่พื้นฐานไปจนถึงการประยุกต์ โดยเหมาะสำหรับ:- ผู้เริ่มต้นที่กำลังเรียนรู้ Verilog
- ผู้ที่ต้องการออกแบบโมดูลให้มีความยืดหยุ่นมากขึ้น
- ผู้ออกแบบที่ต้องการให้โค้ดอ่านง่ายและดูแลรักษาง่าย
parameter พื้นฐาน วิธีการนำไปใช้ในโมดูลจริง รวมถึงข้อควรระวังที่ควรทราบ2. โครงสร้างพื้นฐานของ parameter
วิธีประกาศ parameter
ใน Verilog, parameter ใช้สำหรับกำหนดค่าคงที่ที่ใช้ภายในโมดูล โครงสร้างพื้นฐานมีดังนี้:parameter ชื่อพารามิเตอร์ = ค่า;ตัวอย่างเช่น หากต้องการกำหนดความกว้างข้อมูลเป็น 8 บิต:parameter DATA_WIDTH = 8;parameter ที่ประกาศไว้สามารถใช้งานได้เหมือนตัวแปรภายในโมดูล อย่างไรก็ตาม parameter เป็นค่าคงที่ที่ถูกกำหนดตอนออกแบบ ไม่สามารถเปลี่ยนแปลงได้ในระหว่างการทำงานจริงการกำหนด parameter หลายค่าในครั้งเดียว
ถ้าโมดูลมีหลายพารามิเตอร์ สามารถกำหนดในบรรทัดเดียวโดยใช้เครื่องหมายคอมมา:parameter WIDTH = 8, DEPTH = 256;หรือเพื่อให้อ่านง่ายขึ้น อาจเขียนแยกบรรทัด:parameter WIDTH = 8;
parameter DEPTH = 256;การกำหนดความกว้างบิต (bit-width)
โดยค่าเริ่มต้นparameter จะเป็นจำนวนเต็มแบบไม่เซ็น (unsigned) ขนาด 32 บิต แต่สามารถระบุความกว้างได้ชัดเจน เช่น:parameter [7:0] INIT_VALUE = 8'hFF;วิธีนี้ทำให้ INIT_VALUE ถูกกำหนดอย่างชัดเจนว่าเป็นค่าขนาด 8 บิต ซึ่งสำคัญเมื่อมีการออกแบบที่เกี่ยวข้องกับการดำเนินการทางบิตขอบเขต (scope) และการเขียนทับ (override) ของ parameter
parameter เป็นค่าคงที่ที่ใช้ได้เฉพาะภายในโมดูล ไม่สามารถเข้าถึงโดยตรงจากภายนอกได้ อย่างไรก็ตาม ขณะอินสแตนซ์โมดูลสามารถเขียนทับ (override) ค่าพารามิเตอร์จากโมดูลระดับบนได้ (รายละเอียดจะกล่าวในภายหลัง) นอกจากนี้ Verilog ยังมี localparam ซึ่งคล้ายกัน แต่ไม่สามารถเขียนทับจากภายนอกได้3. การทำโมดูลให้เป็นแบบปรับได้ด้วย parameter
parameter เพื่อเพิ่มความยืดหยุ่นของโมดูล
parameter ช่วยให้โมดูลมีความยืดหยุ่นและสามารถนำโมดูลเดียวกันไปใช้ในเงื่อนไขที่ต่างกัน ได้อย่างมีประสิทธิภาพ โดยการกำหนดค่าต่าง ๆ (เช่น ความกว้างบิต ขนาดอาร์เรย์ รอบสัญญาณนาฬิกา) เป็น parameter จะทำให้การออกแบบหนึ่งสามารถใช้ได้หลายวัตถุประสงค์ตัวอย่าง: โมดูลตัวบวกที่ปรับได้ด้วยพารามิเตอร์
ด้านล่างคือตัวอย่างโมดูลตัวบวก (adder) ที่สามารถกำหนดความกว้างบิตได้ด้วยparameter:module adder #(parameter WIDTH = 8)(
input [WIDTH-1:0] a,
input [WIDTH-1:0] b,
output [WIDTH-1:0] sum
);
assign sum = a + b;
endmoduleโมดูลนี้มีค่าเริ่มต้นเป็นตัวบวกขนาด 8 บิต แต่เมื่อทำการอินสแตนซ์สามารถเปลี่ยนค่า WIDTH ได้ เพื่อใช้เป็นตัวบวกความกว้างบิตอื่นวิธีเขียนทับพารามิเตอร์จากโมดูลระดับบน
1. การใช้โครงสร้าง #()
ขณะอินสแตนซ์โมดูล สามารถใช้ #() เพื่อกำหนดค่าใหม่ให้พารามิเตอร์ จากโมดูลระดับบน:adder #(.WIDTH(16)) adder_inst (
.a(a_input),
.b(b_input),
.sum(sum_output)
);โค้ดนี้จะทำให้ตัวบวกทำงานเป็นแบบ 16 บิต2. การใช้ defparam (ไม่แนะนำ)
อีกวิธีหนึ่งคือใช้คำสั่ง defparam:defparam adder_inst.WIDTH = 16;อย่างไรก็ตาม defparam มักทำให้โค้ดกระจัดกระจายและยากต่อการบำรุงรักษา ดังนั้นในแนวทางการออกแบบสมัยใหม่ถือว่าไม่แนะนำ จึงควรใช้วิธี #() เพื่อความชัดเจนการเขียนทับโมดูลที่มีหลายพารามิเตอร์
ถ้าโมดูลมีหลายพารามิเตอร์ ก็สามารถกำหนดค่าผ่าน#() โดยใช้เครื่องหมายคอมมาคั่น:module fifo #(parameter DATA_WIDTH = 8, DEPTH = 64)(/* ports */);
// การอินสแตนซ์ในโมดูลระดับบน
fifo #(
.DATA_WIDTH(16),
.DEPTH(128)
) fifo_inst (
/* การเชื่อมต่อ */
);วิธีนี้ช่วยให้โมดูลมีการนำกลับมาใช้ซ้ำสูงและปรับการตั้งค่าได้ยืดหยุ่น4. ตัวอย่างการประยุกต์ใช้ parameter
parameter ไม่ได้จำกัดเพียงแค่การแทนค่าคงที่เท่านั้น แต่ยังสามารถนำไปประยุกต์ใช้ได้หลากหลายในการออกแบบ Verilog ส่วนนี้จะแสดงตัวอย่างจริงเพื่อให้เข้าใจวิธีการใช้ parameter ในระดับที่สูงขึ้นการปรับเปลี่ยนความกว้างบิตและขนาดบัส
ในการออกแบบวงจรดิจิทัล การปรับความกว้างบิตได้อย่างยืดหยุ่น เป็นสิ่งที่มีประโยชน์มาก โดยเฉพาะใน datapath หรือ bus design ที่มักมีการเปลี่ยนข้อกำหนดภายหลังmodule register #(parameter WIDTH = 8)(
input wire clk,
input wire [WIDTH-1:0] d,
output reg [WIDTH-1:0] q
);
always @(posedge clk)
q <= d;
endmoduleตัวอย่างนี้ใช้ WIDTH เพื่อปรับขนาดบิตได้อิสระ เช่น 8 บิต, 16 บิต หรือ 32 บิตการจัดการค่าการออกแบบจากจุดเดียวเพื่อความอ่านง่ายและดูแลรักษา
แม้จะมีการใช้ค่าคงที่ร่วมกันหลายโมดูลหรือหลายไฟล์ การใช้parameter ทำให้กำหนดและแก้ไขได้ในที่เดียว ตัวอย่าง:parameter CLK_DIV = 100;จากนั้นสามารถใช้ในวงจรแบ่งสัญญาณนาฬิกา (clock divider), ตัวจับเวลา (timer) หรือเคาน์เตอร์ (counter) ได้พร้อมกัน:always @(posedge clk)
if (counter == CLK_DIV)
clk_out <= ~clk_out;สิ่งนี้ช่วยกำจัด “magic number” และทำให้เจตนาของโค้ดชัดเจนการใช้ร่วมกับ generate เพื่อควบคุมโครงสร้างที่ซ้ำกัน
parameter สามารถใช้ร่วมกับ generate เพื่อสร้างโครงสร้างซ้ำได้ยืดหยุ่น ตัวอย่างเช่น การสร้าง shift register N ขั้น:module shift_reg #(parameter STAGES = 4)(
input wire clk,
input wire in,
output wire out
);
reg [STAGES-1:0] shift;
always @(posedge clk)
shift <= {shift[STAGES-2:0], in};
assign out = shift[STAGES-1];
endmoduleเพียงเปลี่ยนค่า STAGES ก็สามารถสร้าง shift register ได้หลายขนาดตามต้องการ ซึ่งทำให้การออกแบบฮาร์ดแวร์ยืดหยุ่นและประหยัดทรัพยากรการใช้งานใน Testbench
ใน testbench ก็สามารถใช้parameter เพื่อกำหนดเงื่อนไขการทดสอบจากจุดเดียว และเปลี่ยนการตั้งค่าทั้งหมดได้รวดเร็ว:module testbench;
parameter DATA_WIDTH = 16;
reg [DATA_WIDTH-1:0] a, b;
wire [DATA_WIDTH-1:0] result;
adder #(.WIDTH(DATA_WIDTH)) dut (
.a(a),
.b(b),
.sum(result)
);
// กระบวนการทดสอบ...
endmoduleเพียงเปลี่ยนค่าพารามิเตอร์ใน testbench ก็สามารถทดสอบโมดูลเดียวกันกับหลายความกว้างบิตได้สะดวก5. ข้อควรระวังในการใช้ parameter
แม้ว่า parameter จะเป็นฟีเจอร์ที่มีประโยชน์มาก แต่หากใช้งานไม่ถูกต้องอาจก่อให้เกิดพฤติกรรมที่ไม่คาดคิด หรือข้อผิดพลาดในการออกแบบ ได้ ส่วนนี้จะอธิบายจุดที่ควรระวังอย่าลืมระบุความกว้างบิตให้ชัดเจน
ใน Verilog,parameter จะถูกตีความเป็นจำนวนเต็มไม่เซ็น (unsigned) ขนาด 32 บิต โดยค่าเริ่มต้น แม้จะไม่มีปัญหาเมื่อใช้กับค่าธรรมดา แต่เมื่อมีการคำนวณทางบิตหรือการเลือกบิต (slice) ควรระบุความกว้างบิตชัดเจน:parameter [7:0] INIT_VAL = 8'hFF; // กำหนดให้เป็นค่า 8 บิตอย่างชัดเจนสิ่งนี้ช่วยให้โค้ดทำงานตามที่ตั้งใจ ป้องกันคำเตือนระหว่างการจำลองและหลีกเลี่ยงบั๊กขณะสังเคราะห์เข้าใจความแตกต่างระหว่าง parameter และ localparam
ใน Verilog มี localparam ซึ่งคล้ายกับ parameter แต่ไม่สามารถแก้ไขค่าจากภายนอกโมดูลได้| ชนิด | เขียนทับจากโมดูลระดับบนได้หรือไม่ | การใช้งาน |
|---|---|---|
parameter | ได้ | ค่าที่ต้องการให้กำหนดจากภายนอกโมดูล |
localparam | ไม่ได้ | ค่าคงที่ที่ใช้เฉพาะภายในโมดูล |
module example #(parameter WIDTH = 8) ();
localparam HALF_WIDTH = WIDTH / 2;
endmoduleในกรณีนี้ localparam เหมาะสำหรับค่าช่วยคำนวณที่ไม่ควรถูกแก้ไขจากภายนอกการนิยามซ้ำและปัญหาเกี่ยวกับลำดับชั้น (hierarchy)
เมื่อโมดูลซับซ้อนขึ้น อาจสับสนได้ว่าค่าparameter ใดถูกใช้จริง โดยเฉพาะหากมีหลายอินสแตนซ์ที่ใช้ชื่อเดียวกันแต่กำหนดค่าต่างกัน ซึ่งอาจก่อให้เกิดพฤติกรรมที่ไม่คาดคิด แนวทางแก้ไข:- ตั้งชื่อนิพจน์ให้ชัดเจน เช่น
FIFO_DEPTH,ALU_WIDTH - เขียนโค้ดโดยคำนึงถึงขอบเขตของโมดูลแต่ละระดับ
ข้อจำกัดของเครื่องมือสังเคราะห์ (synthesis tools)
เครื่องมือสังเคราะห์และซิมูเลชันบางตัวอาจมีข้อจำกัดหรือพฤติกรรมต่างกันในการจัดการparameter เช่น:- การคำนวณที่เกี่ยวข้องกับ
parameterแบบกำหนดบิต อาจทำงานต่างกันไปขึ้นกับเครื่องมือ - การตีความ signed/unsigned อาจแตกต่างกัน
- บางกรณีไม่รองรับ
defparamเพราะเป็นโครงสร้างที่ล้าสมัย
6. FAQ: คำถามที่พบบ่อยและคำตอบ
ส่วนนี้จะอธิบายคำถามที่มักเกิดขึ้นเกี่ยวกับparameter ใน Verilog ตั้งแต่ระดับผู้เริ่มต้นจนถึงระดับกลาง โดยอ้างอิงจากปัญหาที่มักพบในสถานการณ์จริงQ1. ความแตกต่างระหว่าง parameter และ localparam คืออะไร?
A1. parameter เป็นค่าคงที่ที่สามารถแก้ไขได้จากโมดูลภายนอก ในขณะที่ localparam เป็นค่าคงที่ที่ใช้ได้เฉพาะภายในโมดูล และไม่สามารถเขียนทับได้parameter: มีความยืดหยุ่น แต่ต้องระวังการถูกเขียนทับโดยไม่ตั้งใจlocalparam: เหมาะกับค่าที่ต้องการให้คงที่และไม่แก้ไขจากภายนอก
- หากต้องการนำโมดูลไปใช้ซ้ำ → ใช้
parameter - หากต้องการค่าคงที่ที่ไม่ควรถูกแก้ไข → ใช้
localparam
Q2. ถ้าไม่ระบุความกว้างบิตของ parameter จะเป็นอย่างไร?
A2. ใน Verilog, parameter ที่ไม่ได้ระบุความกว้างบิตจะถูกตีความเป็นจำนวนเต็มไม่เซ็น (unsigned) 32 บิต โดยอัตโนมัติparameter WIDTH = 8; // จริง ๆ แล้วมีขนาด 32 บิตหากไม่ได้ระบุความกว้างบิตอย่างชัดเจน อาจเกิดปัญหาในการขยายบิต (sign extension) หรือผลลัพธ์ไม่ตรงตามที่คาดไว้ โดยเฉพาะเมื่อมีการคำนวณหรือเลือกบิต (slice)
ดังนั้นควรระบุความกว้างบิต เช่น:parameter [7:0] WIDTH = 8;Q3. parameter ต้องเป็นค่าคงที่เสมอหรือไม่?
A3. ใช่, parameter ต้องเป็นค่าคงที่ในขั้นตอนออกแบบ ไม่สามารถกำหนดค่าจากตัวแปรหรือสัญญาณที่เปลี่ยนแปลงได้ ตัวอย่างโค้ดที่ผิด:input [7:0] a;
parameter WIDTH = a; // ❌ Errorตัวอย่างที่ถูกต้อง:parameter WIDTH = 8; // ✅ ค่าคงที่Q4. ถ้าเปลี่ยนค่าของ parameter จะส่งผลอย่างไรกับ FPGA?
A4. เมื่อเปลี่ยนค่า parameter จะส่งผลโดยตรงกับโครงสร้างวงจรที่สังเคราะห์ เช่น หากเปลี่ยนความกว้างบิตของตัวบวก (adder) วงจรก็จะใหญ่ขึ้นหรือลดลง ส่งผลต่อการใช้ทรัพยากรและความหน่วง (delay) ของวงจร นี่คือข้อดีที่ทำให้ Verilog มีความยืดหยุ่น แต่หากไม่ตรวจสอบอย่างละเอียด อาจได้โครงสร้างวงจรที่ไม่ตรงกับความคาดหวังQ5. สามารถใช้การคำนวณทางคณิตศาสตร์หรือทางตรรกะกับ parameter ได้หรือไม่?
A5. ได้, parameter ถูกประเมินค่าเป็นค่าคงที่ในขั้นตอนออกแบบ ดังนั้นสามารถใช้การคำนวณทางคณิตศาสตร์ (เช่น +, -, *) และตรรกะ (AND, OR, NOT) ได้parameter WIDTH = 8;
parameter HALF_WIDTH = WIDTH / 2;แต่ควรระวังขนาดบิตและ signed/unsigned เพื่อป้องกันผลลัพธ์ที่ไม่ตั้งใจ โดยควรระบุความกว้างบิตให้ชัดเจนหลังการคำนวณ7. สรุป
parameter ใน Verilog เป็นองค์ประกอบสำคัญที่ช่วยให้งานออกแบบฮาร์ดแวร์มีความยืดหยุ่นและสามารถนำกลับมาใช้ซ้ำได้สูง บทความนี้ได้อธิบายตั้งแต่โครงสร้างพื้นฐานไปจนถึงการประยุกต์ใช้งานจริงสรุปประเด็นสำคัญ
parameterคือฟังก์ชันการกำหนดค่าคงที่ภายในโมดูล ที่ช่วยเพิ่มความทั่วไปและความสะดวกในการดูแลรักษา- สามารถเปลี่ยนค่าพารามิเตอร์จากโมดูลภายนอกด้วยโครงสร้าง
#() - การใช้ร่วมกับ
generateทำให้ควบคุมโครงสร้างซ้ำและการเลือกเงื่อนไข ได้อย่างยืดหยุ่น - ควรระวังเรื่องการกำหนดความกว้างบิต, ความแตกต่างกับ
localparamและพฤติกรรมที่ขึ้นอยู่กับเครื่องมือสังเคราะห์ - FAQ ได้ครอบคลุมข้อเข้าใจผิดที่พบบ่อยและปัญหาที่ควรหลีกเลี่ยง
ข้อคิดส่งท้าย
ความสามารถในการใช้parameter อย่างมีประสิทธิภาพในการออกแบบโมดูล Verilog นั้นมีผลโดยตรงต่อคุณภาพและความสามารถในการขยายของโค้ด สำหรับผู้เริ่มต้น ควรเริ่มจากการเข้าใจวิธีใช้พื้นฐาน และค่อย ๆ ขยายไปสู่การประยุกต์ในงานที่ซับซ้อนขึ้น เพื่อสร้างการออกแบบที่มีความชาญฉลาดและบำรุงรักษาง่าย เมื่อโครงการมีความซับซ้อนมากขึ้น การนำ parameter มาใช้จะช่วยให้คุณสามารถเปลี่ยนการตั้งค่าและนำโมดูลเดิมกลับมาใช้ใหม่ ได้อย่างมีประสิทธิภาพ แทนที่จะต้องสร้างใหม่ทั้งหมด 

