目次
1. บทนำ
อะไรคือ parameter
ใน Verilog?
Verilog เป็นหนึ่งในภาษาบรรยายฮาร์ดแวร์ (HDL) ที่ใช้สำหรับการออกแบบวงจรดิจิทัล ภายในนั้น parameter
(พารามิเตอร์) เป็นฟีเจอร์สำคัญที่ช่วยเพิ่มความยืดหยุ่นและการนำกลับมาใช้ซ้ำของการออกแบบได้อย่างมาก parameter
คือฟังก์ชันที่ให้คุณกำหนดค่าคงที่พร้อมชื่อ เพื่อให้ง่ายต่อการนำโมดูลเดียวกันมาใช้ซ้ำภายใต้การตั้งค่าที่แตกต่างกัน หรือเพื่อเพิ่มความชัดเจนในการอ่านโค้ด โดยปกติแล้วแทนที่จะระบุค่าคงที่ลงไปตรง ๆ (เช่น ความกว้างบิต ขนาดบัส หรือค่าการตั้งเวลา) การกำหนดเป็น parameter
จะช่วยสร้างโครงสร้างโค้ดที่ปรับเปลี่ยนได้ง่ายภายหลังทำไม parameter
ถึงมีความสำคัญ?
การใช้ parameter
ในการออกแบบ Verilog มีข้อดีดังนี้:- เพิ่มการนำกลับมาใช้ซ้ำ โมดูลที่สร้างไว้ครั้งเดียวสามารถนำไปใช้ซ้ำได้หลายรูปแบบ ทำให้การพัฒนาโครงการขนาดใหญ่มีประสิทธิภาพมากขึ้น
- เพิ่มความสะดวกในการดูแลรักษา ค่าคงที่ถูกจัดการจากจุดเดียว เมื่อมีการเปลี่ยนแปลงก็เพียงแก้ไข
parameter
ที่เกี่ยวข้อง - เพิ่มความชัดเจนในการอ่านโค้ด การหลีกเลี่ยงการใช้ “Magic number” ช่วยให้เข้าใจได้ง่ายขึ้นว่าแต่ละค่าหมายถึงอะไร ทำให้นักพัฒนาคนอื่นอ่านโค้ดได้สะดวก
parameter DATA_WIDTH = 8;
แล้วใช้ [DATA_WIDTH-1:0]
ซึ่งจะช่วยสื่อความหมายของการออกแบบได้ดีกว่าสิ่งที่จะได้จากบทความนี้
บทความนี้จะอธิบายparameter
ใน Verilog ตั้งแต่พื้นฐานไปจนถึงการประยุกต์ใช้อย่างเป็นระบบ เหมาะสำหรับ:- ผู้เริ่มต้นที่กำลังเรียนรู้ Verilog
- ผู้ที่ต้องการออกแบบโมดูลที่มีความยืดหยุ่นมากขึ้น
- นักออกแบบที่ต้องการเพิ่มความสามารถในการดูแลและความชัดเจนของโค้ด
parameter
เบื้องต้น วิธีนำไปประยุกต์ใช้กับการออกแบบโมดูล และจุดที่ควรระวัง2. โครงสร้างพื้นฐานของ parameter
วิธีประกาศ parameter
parameter
ใน Verilog ใช้สำหรับกำหนดค่าคงที่ที่จะใช้ภายในโมดูล โครงสร้างพื้นฐานมีดังนี้:parameter ชื่อพารามิเตอร์ = ค่า;
ตัวอย่าง หากต้องการกำหนดความกว้างข้อมูลเป็น 8 บิต:parameter DATA_WIDTH = 8;
เมื่อประกาศแล้ว parameter
สามารถถูกเรียกใช้เหมือนตัวแปรภายในโมดูล แต่ต้องจำไว้ว่า parameter
เป็นค่าคงที่ที่ถูกกำหนดในขั้นตอนออกแบบ ไม่สามารถเปลี่ยนแปลงได้ในขณะรันการกำหนด parameter
หลายค่าในครั้งเดียว
สำหรับโมดูลที่มีหลายพารามิเตอร์ สามารถกำหนดได้ในบรรทัดเดียวโดยใช้เครื่องหมายจุลภาคคั่นparameter WIDTH = 8, DEPTH = 256;
เพื่อความอ่านง่าย มักเขียนแยกเป็นหลายบรรทัดดังนี้:parameter WIDTH = 8;
parameter DEPTH = 256;
วิธีระบุความกว้างบิต
โดยค่าเริ่มต้นparameter
จะเป็นจำนวนเต็ม 32 บิตแบบไม่มีเครื่องหมาย แต่สามารถกำหนดความกว้างบิตได้ชัดเจนหากต้องการparameter [7:0] INIT_VALUE = 8'hFF;
วิธีนี้ช่วยให้แน่ชัดว่า INIT_VALUE
ถูกตีความเป็นค่า 8 บิต ซึ่งมีความสำคัญอย่างยิ่งเมื่อใช้กับการออกแบบที่เกี่ยวข้องกับการดำเนินการทางบิตขอบเขต (Scope) และการกำหนดซ้ำของ parameter
parameter
เป็นค่าคงที่ที่มีผลเฉพาะภายในโมดูล หมายความว่าไม่สามารถเข้าถึงได้โดยตรงจากภายนอก แต่เมื่อมีการสร้างอินสแตนซ์ของโมดูล สามารถเขียนทับ (override) ค่าได้จากโมดูลระดับบน รายละเอียดเพิ่มเติมจะอธิบายในภายหลัง นอกจากนี้ Verilog ยังมี localparam
ซึ่งคล้ายกับ parameter
แต่ไม่สามารถถูกเขียนทับจากภายนอกได้
3. การทำให้โมดูลมีความยืดหยุ่นด้วย parameter
เพิ่มความยืดหยุ่นของโมดูลด้วย parameter
parameter
ช่วยให้โมดูลถูกนำไปใช้ซ้ำในเงื่อนไขที่ต่างกันได้ โดยการกำหนดค่าต่าง ๆ เช่น ความกว้างบิต ขนาดอาร์เรย์ หรือรอบนาฬิกาเป็น parameter
จะทำให้สามารถใช้การออกแบบเดียวกันได้กับหลายกรณีตัวอย่าง: โมดูลตัวบวกที่กำหนดค่าพารามิเตอร์ได้
ด้านล่างคือตัวอย่างโมดูลตัวบวกที่กำหนดความกว้างบิตผ่าน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. การใช้โครงสร้าง #()
เมื่อสร้างอินสแตนซ์โมดูล สามารถกำหนดค่า parameter
ได้โดยใช้ #()
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 ส่วนนี้จะแสดงตัวอย่างการใช้งานจริงที่ช่วยให้เข้าใจการประยุกต์ได้ดียิ่งขึ้นการเปลี่ยนแปลงความกว้างบิตและขนาดบัส
ในการออกแบบวงจรดิจิทัล การปรับเปลี่ยนความกว้างบิตได้อย่างยืดหยุ่น เป็นสิ่งสำคัญมาก โดยเฉพาะใน Data path หรือ Bus ที่มักมีการเปลี่ยนแปลงความต้องการภายหลัง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
เพื่อสร้างโครงสร้างซ้ำที่ยืดหยุ่น เช่น การสร้าง register หลายชุด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
parameter
ยังสามารถใช้ใน testbench เพื่อจัดการเงื่อนไขการทดสอบจากจุดเดียว และสลับการตั้งค่าได้ง่าย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
ด้วยวิธีนี้ สามารถเปลี่ยนพารามิเตอร์ครั้งเดียวแล้วทดสอบหลายกรณีของบิตวิดท์ได้ง่าย5. ข้อควรระวังในการใช้ parameter
แม้ว่า parameter
จะเป็นฟีเจอร์ที่สะดวกมาก แต่หากใช้งานไม่ถูกต้อง อาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด หรือข้อผิดพลาดในการออกแบบ ได้ ส่วนนี้จะอธิบายประเด็นสำคัญที่ควรระวังอย่าละเลยการกำหนดความกว้างบิตอย่างชัดเจน
โดยปกติparameter
ใน Verilog จะถูกตีความเป็นจำนวนเต็มแบบไม่มีเครื่องหมายขนาด 32 บิต หากเป็นค่าธรรมดาอาจไม่เกิดปัญหา แต่ถ้าใช้กับการดำเนินการทางบิตหรือการเลือกบิต (slice) จำเป็นต้องกำหนดความกว้างบิตให้ชัดเจนparameter [7:0] INIT_VAL = 8'hFF; // กำหนดให้เป็นค่า 8 บิตโดยตรง
การกำหนดแบบนี้จะช่วยหลีกเลี่ยงพฤติกรรมที่ไม่ต้องการ และป้องกันคำเตือนในการจำลอง (simulation) หรือบั๊กในการสังเคราะห์ (synthesis)ความแตกต่างระหว่าง parameter
และ localparam
ใน Verilog มีคีย์เวิร์ดอีกตัวคือ localparam
ซึ่งคล้าย parameter
แต่ไม่สามารถถูกเขียนทับจากโมดูลภายนอก ได้ชนิด | เขียนทับจากโมดูลภายนอกได้หรือไม่ | การใช้งาน |
---|---|---|
parameter | ได้ | ค่าที่ต้องการให้กำหนดจากภายนอก |
localparam | ไม่ได้ | ค่าคงที่ภายในที่ไม่ควรถูกเปลี่ยน |
module example #(parameter WIDTH = 8) ();
localparam HALF_WIDTH = WIDTH / 2;
endmodule
localparam
เหมาะสำหรับการนิยามค่าช่วย (auxiliary) ภายในโมดูล ที่ไม่ควรถูกแก้จากภายนอกการกำหนดซ้ำและปัญหาจากลำดับชั้นของ parameter
เมื่อโมดูลซับซ้อนขึ้น อาจมีหลายชั้นของลำดับ (hierarchy) ซึ่งทำให้เกิดความสับสนว่าค่า parameter
ไหนถูกนำมาใช้ โดยเฉพาะเมื่อใช้ชื่อเดียวกันในหลายอินสแตนซ์ อาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด- ตั้งชื่อให้ชัดเจน (เช่น
FIFO_DEPTH
,ALU_WIDTH
) - เขียนโค้ดโดยคำนึงถึงขอบเขต (scope) ของแต่ละโมดูล
ข้อจำกัดจากเครื่องมือสังเคราะห์
เครื่องมือสังเคราะห์ (synthesis tools) หรือซิมูเลเตอร์บางตัวมีข้อจำกัดเฉพาะ เกี่ยวกับการตีความparameter
เช่น:- การคำนวณกับ
parameter
ที่มีความกว้างบิตอาจแสดงผลต่างกันระหว่างเครื่องมือ - ความแตกต่างระหว่างค่ามีเครื่องหมาย/ไม่มีเครื่องหมาย
- บางเครื่องมือไม่สนับสนุน
defparam
หรือถือว่าเป็นโครงสร้างที่เลิกใช้แล้ว
6. FAQ: คำถามที่พบบ่อยและคำตอบ
ในหัวข้อนี้ เราจะตอบคำถามที่ผู้เริ่มต้นจนถึงระดับกลางมักสงสัยเกี่ยวกับparameter
ใน Verilog โดยนำเสนอในรูปแบบ Q&A ที่ใช้ได้จริงในงานออกแบบและการเรียนรู้Q1. ความแตกต่างระหว่าง parameter
และ localparam
คืออะไร?
A1. parameter
คือค่าคงที่ที่สามารถเขียนทับจากโมดูลภายนอกได้ ขณะที่ localparam
คือค่าคงที่ที่ใช้ได้เฉพาะภายในโมดูล และไม่สามารถแก้ไขจากภายนอกได้parameter
: มีความยืดหยุ่น แต่ต้องระวังการถูกเขียนทับโดยไม่ตั้งใจlocalparam
: เหมาะสำหรับค่าภายในที่ไม่ควรถูกเปลี่ยน เช่น ค่าคงที่ช่วยในการคำนวณ
- ต้องการให้โมดูลนำกลับมาใช้ซ้ำได้หลายแบบ → ใช้
parameter
- ต้องการค่าคงที่ภายในที่ไม่เปลี่ยนแปลง → ใช้
localparam
Q2. ถ้าไม่กำหนดความกว้างบิตของ parameter
จะเกิดอะไรขึ้น?
A2. หากไม่ระบุ parameter
ใน Verilog จะถูกตีความเป็นจำนวนเต็ม 32 บิตแบบไม่มีเครื่องหมาย โดยอัตโนมัติparameter WIDTH = 8; // จริง ๆ แล้วเป็นค่า 32 บิต
หากใช้ในการคำนวณหรือเลือกบิต อาจเกิดพฤติกรรมที่ไม่คาดคิด ดังนั้นควรกำหนดความกว้างบิตอย่างชัดเจนเสมอ:parameter [7:0] WIDTH = 8;
Q3. parameter
ต้องเป็นค่าคงที่เสมอหรือไม่?
A3. ใช่ parameter
ต้องเป็นค่าคงที่ ที่ถูกกำหนดในขั้นตอนออกแบบ ไม่สามารถใช้ตัวแปรหรือสัญญาณที่เปลี่ยนแปลงระหว่างการทำงานได้ ตัวอย่างที่ไม่ถูกต้อง (NG):input [7:0] a;
parameter WIDTH = a; // ผิด
ตัวอย่างที่ถูกต้อง (OK):parameter WIDTH = 8;
Q4. ถ้าเปลี่ยนค่าของ parameter
จะส่งผลต่อ FPGA อย่างไร?
A4. การเปลี่ยนค่า parameter
จะเปลี่ยนผลลัพธ์ของการสังเคราะห์วงจรโดยตรง เช่น ถ้าเปลี่ยนความกว้างบิตของตัวบวก วงจรที่สร้างขึ้นจะมีขนาดต่างกัน ทำให้จำนวน resource ที่ใช้และค่า delay เปลี่ยนไปด้วย นี่คือจุดแข็งของ Verilog แต่หากไม่ตรวจสอบการทำงานอย่างรอบคอบ อาจทำให้วงจรที่ได้ไม่เป็นไปตามที่คาดหวังQ5. สามารถใช้การคำนวณหรือการดำเนินการลอจิกกับ parameter
ได้หรือไม่?
A5. สามารถทำได้ parameter
จะถูกประเมินค่าเป็นค่าคงที่ในขั้นตอนออกแบบ ดังนั้นจึงสามารถใช้การบวก ลบ คูณ หาร รวมถึง AND, OR, NOT ได้parameter WIDTH = 8;
parameter HALF_WIDTH = WIDTH / 2;
แต่ควรระวังเรื่องความกว้างบิตและสัญลักษณ์บวก/ลบ เพื่อป้องกันผลลัพธ์ที่ไม่คาดคิด การกำหนดบิตวิดท์อย่างชัดเจนหลังการคำนวณเป็นสิ่งที่แนะนำ7. บทสรุป
parameter
ใน Verilog เป็นองค์ประกอบที่สำคัญอย่างยิ่งในการสร้างการออกแบบฮาร์ดแวร์ที่ยืดหยุ่นและนำกลับมาใช้ซ้ำได้ บทความนี้ได้อธิบายตั้งแต่โครงสร้างพื้นฐานไปจนถึงการประยุกต์ใช้อย่างเป็นระบบสรุปเนื้อหาบทความ
parameter
ใช้กำหนดค่าคงที่ภายในโมดูล ช่วยเพิ่มความยืดหยุ่นและความสะดวกในการดูแลรักษา- สามารถเขียนทับจากโมดูลภายนอกได้ด้วยโครงสร้าง
#()
ทำให้เปลี่ยนค่าพารามิเตอร์แบบไดนามิก ได้ - เมื่อนำมาใช้ร่วมกับ
generate
จะช่วยให้ควบคุมโครงสร้างซ้ำและการเลือกเงื่อนไข ได้อย่างยืดหยุ่น - ในการใช้งาน ต้องกำหนดความกว้างบิตอย่างชัดเจน และเข้าใจความแตกต่างระหว่าง
parameter
กับlocalparam
รวมถึงข้อจำกัดของเครื่องมือสังเคราะห์ - FAQ ได้ครอบคลุมข้อสงสัยที่พบบ่อยและหลุมพรางในการออกแบบ
ข้อคิดส่งท้าย
ในการออกแบบโมดูล Verilog ความสามารถในการใช้parameter
อย่างมีประสิทธิภาพจะส่งผลโดยตรงต่อความสามารถในการขยายและคุณภาพของโค้ด สำหรับผู้เริ่มต้น ควรฝึกใช้กับตัวอย่างพื้นฐานก่อน แล้วค่อย ๆ ขยายไปสู่การประยุกต์ในงานจริง จะช่วยให้ได้การออกแบบที่ชาญฉลาดและง่ายต่อการบำรุงรักษา เมื่อการออกแบบมีความซับซ้อนมากขึ้น parameter
จะช่วยให้สามารถปรับแต่งการตั้งค่าแทนที่จะต้องเขียนโค้ดใหม่ทั้งหมด ซึ่งเป็นแนวทางการพัฒนาที่มีประสิทธิภาพและคุ้มค่ามากกว่า