การใช้คำสั่ง wait ใน Verilog: คู่มือพื้นฐานถึงการประยุกต์สำหรับการออกแบบวงจรและ FPGA

目次

1. บทนำ

Verilog เป็นภาษาบรรยายฮาร์ดแวร์ (Hardware Description Language) ที่ถูกใช้งานอย่างกว้างขวางในการออกแบบวงจรดิจิทัลและการพัฒนา FPGA โดยคำสั่ง wait ถือเป็นโครงสร้างที่สำคัญ ซึ่งใช้ในการหยุดการทำงานชั่วคราวจนกว่าจะมีเงื่อนไขบางอย่างเป็นจริง มีประโยชน์ต่อการควบคุมการจำลอง (simulation control) และการเขียน testbench อย่างยืดหยุ่น

คำสั่ง wait ใน Verilog แม้จะมีรูปแบบการเขียนที่เรียบง่าย แต่ก็มีพลังในการควบคุมสูง โดยมักใช้ในกรณีที่ต้องรอสัญญาณเปลี่ยนแปลงหรือเกิดเหตุการณ์เฉพาะ อย่างไรก็ตาม หากใช้ไม่ถูกต้องก็อาจทำให้เกิดการทำงานผิดพลาดได้ ดังนั้น การเข้าใจและใช้งาน wait อย่างถูกวิธีจึงมีความสำคัญต่อคุณภาพของการออกแบบและประสิทธิภาพในการตรวจสอบ (verification)

บทความนี้จะอธิบายคำสั่ง wait ใน Verilog ตั้งแต่โครงสร้างพื้นฐาน วิธีการใช้งานจริง ตัวอย่างการประยุกต์ใน testbench รวมถึงแนวทางป้องกันปัญหาที่พบบ่อย อธิบายอย่างละเอียดเพื่อให้ทั้งผู้เริ่มต้นและวิศวกรที่ทำงานกับการออกแบบและการตรวจสอบเข้าใจได้ง่ายและนำไปใช้ได้จริง

การใช้คำสั่ง wait อย่างคล่องแคล่ว จะช่วยเพิ่มประสิทธิภาพการจำลองวงจรได้อย่างมาก ผ่านบทความนี้ คุณจะได้เข้าใจแก่นแท้และการประยุกต์ใช้ของ wait อย่างแท้จริง

2. โครงสร้างพื้นฐานและหลักการทำงานของ wait

ใน Verilog คำสั่ง wait ถูกใช้เมื่อเราต้องการ “หยุดการทำงานจนกว่าเงื่อนไขจะเป็นจริง” ซึ่งเป็นหนึ่งในโครงสร้างควบคุม (control statement) ที่สำคัญ รูปแบบพื้นฐานคือดังนี้:

wait (เงื่อนไข);

ในโครงสร้างนี้ โค้ดหลัง wait จะยังไม่ทำงานจนกว่า เงื่อนไข จะเป็นจริง (true) เมื่อเงื่อนไขสำเร็จ โปรแกรมจึงจะทำงานต่อไป

2.1 วิธีใช้งานพื้นฐาน

คำสั่ง wait มักถูกใช้ภายใน always block หรือ initial block ยกตัวอย่างเช่น หากต้องการหยุดจนกว่า signal ready จะมีค่าเท่ากับ 1 สามารถเขียนได้ดังนี้:

wait (ready == 1'b1);

ในกรณีนี้ การทำงานจะหยุดที่ wait จนกว่า ready จะมีค่าเป็น 1 จากนั้นจึงดำเนินการต่อไป เงื่อนไขสามารถใช้ตัวดำเนินการทางตรรกะและการรวมสัญญาณหลายตัวได้

2.2 ความแตกต่างจากคำสั่งควบคุมอื่น

ใน Verilog มีโครงสร้างควบคุมหลายชนิด เช่น if, while และ forever แต่ wait มีพฤติกรรมเฉพาะ:

  • if จะตรวจสอบเงื่อนไขเพียงครั้งเดียวและทำงานเฉพาะเมื่อเงื่อนไขเป็นจริง
  • while จะทำงานซ้ำตราบใดที่เงื่อนไขยังเป็นจริง
  • wait จะ รอจนกว่าเงื่อนไขจะเป็นจริง และเมื่อสำเร็จ จะทำงานต่อทันทีเพียงครั้งเดียว

2.3 สถานการณ์ที่มักใช้

คำสั่ง wait ถูกใช้เมื่อ ต้องรอสถานะสัญญาณหรือเหตุการณ์เฉพาะ เช่น รอการเปลี่ยนแปลงของ input signal รอการ reset เสร็จสิ้น หรือรอเงื่อนไขใน testbench เพื่อควบคุมเวลาในการจำลอง

3. สถานการณ์ที่ใช้ได้และใช้ไม่ได้ของ wait

แม้ว่า wait จะเป็นโครงสร้างที่สะดวกและทรงพลังใน Verilog แต่ไม่ได้สามารถใช้ได้ทุกที่ มีบางสถานการณ์ที่เหมาะสมและบางสถานการณ์ที่ควรหลีกเลี่ยง

3.1 สถานการณ์ที่เหมาะสมกับการใช้ wait

คำสั่ง wait มักถูกใช้ใน บล็อกสำหรับการจำลองหรือการเริ่มต้น ตัวอย่างเช่น:

  • initial block
  • ใช้รอเงื่อนไขในช่วงเริ่มการจำลอง เช่น การรอเหตุการณ์หนึ่งก่อนจะทำการเริ่มต้น
  • always block
  • ใช้เพื่อรอสัญญาณเปลี่ยนแปลงและควบคุมการทำงานแบบลำดับขั้น

ตัวอย่าง:

initial begin
  wait (reset_n == 1'b1);  // รอจน reset ถูกปลด
  // โค้ดสำหรับการเริ่มต้น
end
always begin
  wait (data_valid);       // รอจนกว่าสัญญาณ data_valid มีค่าเป็นจริง
  // การประมวลผลข้อมูล
end

3.2 สถานการณ์ที่ไม่ควรใช้ wait

มีบางกรณีที่ไม่สามารถใช้หรือควรหลีกเลี่ยง:

  • นอกกระบวนการ (procedural block) เช่น ใช้ตรงใน module หรือ assign statement → ไม่สามารถทำได้
  • การออกแบบที่ต้องการสังเคราะห์เป็นฮาร์ดแวร์ (RTL synthesis)
    คำสั่ง wait ใช้สำหรับการจำลอง (simulation) เท่านั้น โดยทั่วไปไม่รองรับในเครื่องมือสังเคราะห์ FPGA/ASIC

3.3 ความแตกต่างกับ VHDL

VHDL ก็มีคำสั่ง wait เช่นกัน แต่มีความยืดหยุ่นมากกว่า เช่น wait until หรือ wait for ซึ่งสามารถควบคุมทั้งเวลาและเงื่อนไขได้ ในขณะที่ Verilog จำกัดเพียง wait (เงื่อนไข) สำหรับตรวจสอบสถานะสัญญาณ

4. ตัวอย่างการใช้งานที่พบบ่อย

คำสั่ง wait ถูกนำไปใช้ในหลายสถานการณ์เพื่อควบคุมการจำลอง ที่นี่จะแสดงรูปแบบทั่วไปและโค้ดตัวอย่าง

4.1 รอขอบสัญญาณ (Clock edge) หรือการเปลี่ยนแปลงของสัญญาณ

เช่น รอจน reset ถูกปลด หรือรอจนสัญญาณ valid เป็นจริง

initial begin
  // รอจน reset ถูกปลด
  wait (reset_n == 1'b1);
  // โค้ดสำหรับเริ่มต้น
end
always begin
  // รอจนกว่าสัญญาณ data_valid เป็นจริง
  wait (data_valid == 1'b1);
  // การประมวลผลข้อมูล
end

4.2 รอหลายเงื่อนไขพร้อมกัน

สามารถใช้ตัวดำเนินการทางตรรกะ เช่น AND/OR เพื่อรวมหลายเงื่อนไข

wait ((ready == 1'b1) && (start == 1'b1));

รูปแบบนี้ช่วยให้ควบคุมเวลาได้ซับซ้อนมากขึ้น

4.3 รอการเกิดเหตุการณ์ (Event)

เช่น ต้องการให้การทำงานเกิดขึ้นเมื่อสัญญาณบางตัวเปลี่ยนค่า อย่างไรก็ตาม การตรวจจับการเปลี่ยนแปลงมักใช้ร่วมกับ @ หรือ always

wait (enable == 1'b1);

4.4 รอตรวจสอบสถานะหรือ flag

ใน testbench มักใช้รอสถานะของโมดูลหรือ flag ว่าการทำงานเสร็จสิ้นหรือไม่

wait (send_done == 1'b1);

4.5 ตัวอย่างการใช้งานจริง

  • รอจำนวนรอบนาฬิกาที่กำหนด → สามารถใช้ counter ร่วมกับ event control
integer i;
for (i = 0; i < 10; i = i + 1) begin
  @(posedge clk);  // รอขอบขาขึ้นของ clock 10 ครั้ง
end

*ตัวอย่างนี้ใช้ร่วมกับ event control ไม่ใช่ wait เพียงอย่างเดียว

5. การประยุกต์ใช้ wait ใน Testbench

ในการสร้าง testbench ด้วย Verilog คำสั่ง wait เป็นเครื่องมือที่ทรงพลังในการควบคุมลำดับการทำงาน เพราะอุปกรณ์มักต้องรอการป้อนข้อมูลหรือเหตุการณ์บางอย่าง ดังนั้น wait จึงมีบทบาทสำคัญ

5.1 รอจนกว่าจะปลด reset

โดยทั่วไป testbench จะเริ่มจากการ reset และต้องรอจน reset ถูกปลดก่อนเริ่มการตรวจสอบ

initial begin
  // รอจน reset ถูกปลด
  wait (reset_n == 1'b1);
  // เริ่มการตรวจสอบหลัง reset
end

5.2 รอการเปลี่ยนแปลงของสัญญาณ

testbench มักรอจนกว่าสัญญาณ flag หรือ data_valid มีค่าเป็นจริง เพื่อให้การป้อนข้อมูลเกิดขึ้นตรงจังหวะ

wait (data_valid == 1'b1);
// ตรวจสอบ output data
wait (busy == 1'b0);

5.3 ใช้ในโปรโตคอลการสื่อสาร

ในการสื่อสารแบบ serial หรือ handshake signal คำสั่ง wait ทำให้สามารถรอเหตุการณ์ต่อเนื่องได้อย่างง่าย เช่น การรอจน tx_done มีค่าเป็นจริง

wait (tx_done == 1'b1);

5.4 ข้อควรระวังในการใช้ wait ใน testbench

ต้องระวัง กรณีที่เงื่อนไขไม่เป็นจริงตลอดไป เพราะจะทำให้การจำลองหยุดอยู่ตรงนั้น วิธีป้องกันคือใช้ timeout หรือแสดงข้อความแจ้งเตือน

initial begin
  integer timeout;
  timeout = 0;
  while (reset_n != 1'b1 && timeout < 1000) begin
    #1; // รอเวลา 1 หน่วย
    timeout = timeout + 1;
  end
  if (timeout == 1000)
    $display("Error: reset_n ไม่ถูกปลด");
end

6. ข้อผิดพลาดและการแก้ไขที่พบบ่อย

แม้ wait จะสะดวก แต่ถ้าใช้ไม่ถูกต้องอาจทำให้เกิดปัญหาได้ ต่อไปนี้คือปัญหาที่พบบ่อยและแนวทางแก้ไข

6.1 การรอแบบไม่สิ้นสุด

ปัญหาที่พบบ่อยคือ เงื่อนไขไม่เคยเป็นจริง ทำให้การจำลองหยุดอยู่ตลอด สาเหตุอาจเป็นเพราะ initial ไม่ครบถ้วนหรือสัญญาณไม่เปลี่ยน

แนวทางแก้:

  • ตรวจสอบว่าสัญญาณที่รอมีการเปลี่ยนแปลงจริง
  • กำหนดค่าเริ่มต้นและรูปแบบการเปลี่ยนแปลงของสัญญาณชัดเจน
  • เพิ่ม timeout เพื่อป้องกันการหยุดถาวร
integer timeout;
timeout = 0;
while (flag != 1'b1 && timeout < 1000) begin
  #1;
  timeout = timeout + 1;
end
if (timeout == 1000)
  $display("Error: flag ไม่เปลี่ยนเป็น 1");

6.2 การเขียนเงื่อนไขผิดพลาด

หากเขียน expression ผิด เช่น วงเล็บหรือเครื่องหมายตรรกะไม่ถูก จะทำให้ผลลัพธ์ไม่ตรงตามที่คาด

แนวทางแก้:

  • ตรวจสอบวงเล็บและตัวดำเนินการทางตรรกะ
  • ใช้ $display เพื่อตรวจสอบค่าของตัวแปร

6.3 ปัญหา race condition

เมื่อ wait ถูกใช้ร่วมกับ event control (@) หรือ always อาจทำให้ลำดับการทำงานไม่ตรงที่ตั้งใจ เนื่องจากเวลาของการเปลี่ยนแปลงสัญญาณ

แนวทางแก้:

  • ออกแบบให้ชัดเจนว่ารอสัญญาณใด (posedge / negedge)
  • พิจารณาใช้ @ หรือ #delay ร่วมกัน

6.4 เคล็ดลับสำหรับการดีบัก

  • ใช้ $display
    แสดงค่าและเวลา ก่อนและหลัง wait เพื่อตรวจสอบว่าโค้ดหยุดตรงไหน
  • ตรวจสอบการออกจาก wait
    แสดง log เมื่อ wait สำเร็จ
  • เริ่มจากกรณีง่าย
    ทดสอบด้วยสัญญาณง่าย ๆ ก่อนที่จะใช้เงื่อนไขซับซ้อน

การรู้วิธีดีบักช่วยให้การจำลองมีประสิทธิภาพและลดเวลาที่เสียไปกับการหาสาเหตุ

7. เทคนิคการเพิ่มประสิทธิภาพการจำลอง

ในการจำลองด้วย Verilog การใช้ wait อย่างมีประสิทธิภาพร่วมกับโครงสร้างควบคุมอื่นช่วยให้การตรวจสอบรวดเร็วและแม่นยำยิ่งขึ้น

7.1 การเลือกใช้ wait และ #delay

ทั้ง wait และ #delay ใช้เพื่อ “รอ” แต่มีความแตกต่าง:

  • wait: รอจนกว่าเงื่อนไขเป็นจริง เช่น wait (ready == 1'b1);
  • #delay: รอเวลาที่กำหนด เช่น #10; // รอเวลา 10 หน่วย

เคล็ดลับ: ใช้ wait เมื่อรอ event หรือสัญญาณ และใช้ #delay เมื่อรอเวลาแบบตายตัว จะช่วยลดการคำนวณที่ไม่จำเป็นและทำให้การจำลองเร็วขึ้น

7.2 ตัวอย่างการเพิ่มความเร็ว

  • หลีกเลี่ยงลูปที่ไม่จำเป็น เช่น ลูปที่รอเงื่อนไขที่ไม่มีวันเป็นจริง
  • ใช้ flag สถานะ เพื่อควบคุมการทำงานแทนการรอซ้ำซ้อน
wait (done_flag == 1'b1);

7.3 ใช้ finish_flag และ timeout

เพื่อป้องกันการหยุดที่ไม่มีที่สิ้นสุด สามารถกำหนด flag หรือ timeout ได้

wait (finish_flag == 1'b1);
$finish;

7.4 การใช้ event-driven ร่วมกัน

wait สามารถใช้ร่วมกับ @ หรือ fork/join เพื่อสร้างสถานการณ์ที่ซับซ้อน

fork
  wait (signal_a == 1'b1);
  wait (signal_b == 1'b1);
join

ด้วยวิธีนี้สามารถตรวจสอบหลายเงื่อนไขพร้อมกันและลดข้อผิดพลาดจากการพลาดเหตุการณ์

8. การเปรียบเทียบกับ SystemVerilog และภาษาอื่น

แม้ว่า wait ใน Verilog จะเรียบง่าย แต่ใน SystemVerilog และ VHDL มีความสามารถที่ขยายเพิ่มเติม

8.1 การขยายใน SystemVerilog

  • wait fork/join: รอจนกว่า process แบบขนานทั้งหมดจะเสร็จสิ้น
  • wait order: รอหลายเงื่อนไขตามลำดับที่กำหนด (ขึ้นอยู่กับเครื่องมือรองรับ)
  • การใช้ event และ semaphore: รอการซิงโครไนซ์ระหว่าง process ได้ยืดหยุ่นยิ่งขึ้น

8.2 ความแตกต่างระหว่าง Verilog และ VHDL

  • VHDL: มีรูปแบบ wait หลายแบบ เช่น wait until, wait for
    ตัวอย่าง: wait until clk = '1'; wait for 100 ns;
  • Verilog: มีเพียง wait (เงื่อนไข); สำหรับรอสัญญาณ ส่วนการรอเวลาใช้ #delay หรือ @(posedge clk)

สรุป: VHDL มี wait ที่หลากหลาย แต่ Verilog ใช้การผสมผสานระหว่าง wait, delay และ event control

8.3 การเปรียบเทียบกับโครงสร้างควบคุมอื่น

ใน Verilog มี if, while, forever, และ event control (@) ร่วมด้วย
wait เหมาะสำหรับ “รอจนเงื่อนไขเป็นจริง” ส่วน if/while/forever ใช้ควบคุมลูปและการตรวจสอบในรูปแบบอื่น

9. การทำความเข้าใจ wait ด้วยแผนภาพและ waveform

การเข้าใจการทำงานของ wait จะง่ายขึ้นเมื่ออธิบายด้วย timing chart หรือ waveform ตัวอย่าง

9.1 ภาพรวมการทำงานพื้นฐานของ wait

ตัวอย่าง: รอจนสัญญาณ reset_n มีค่า 1

initial begin
  wait (reset_n == 1'b1);
  // ทำงานต่อหลังจาก reset ถูกปลด
end

Timing Chart (ตัวอย่าง)

Time    | 0 | 10 | 20 | 30 | 40 | ...
reset_n   0    0    1    1    1
   <---wait---> |--→ ทำงานต่อ

9.2 การตรวจจับสัญญาณเปลี่ยนแปลง

เช่น รอจน data_valid เป็นจริง

always begin
  wait (data_valid == 1'b1);
  // ประมวลผลข้อมูล
end

Waveform

Time        | 0 | 10 | 20 | 30 | 40 | ...
data_valid    0    0    0    1    0
              <---wait---> | ทำงานต่อ

9.3 การรอหลายเงื่อนไข

wait ((ready == 1'b1) && (start == 1'b1));

Timing

Time   | ... | 40 | 50 | 60 | ...
ready        0    1    1    1
start        0    0    1    1
 <---wait---> | เริ่มทำงาน (เมื่อทั้งคู่ = 1)

9.4 การควบคุมสถานะใน testbench

การรวมหลาย event และ state transition สามารถใช้ wait เพื่อควบคุมลำดับ ทำให้การตรวจสอบ waveform ง่ายและชัดเจนขึ้น

10. คำถามที่พบบ่อย (FAQ)

Q1. wait ต่างจาก #delay อย่างไร?
A. wait จะรอจนเงื่อนไขเป็นจริง ส่วน #delay จะรอเวลาที่กำหนด

Q2. ใช้ wait ใน always block ได้ไหม?
A. ได้ สามารถใช้รอเงื่อนไขใน always block ได้ แต่ต้องจำไว้ว่ามีไว้เพื่อ simulation ไม่ใช่ synthesis

Q3. wait สามารถสังเคราะห์เป็นฮาร์ดแวร์ได้หรือไม่?
A. ไม่ได้ โดยทั่วไปเครื่องมือสังเคราะห์ไม่รองรับ wait

Q4. ถ้า wait ไม่ทำงานหรือไม่หลุดออกมา เกิดจากอะไร?
A. ส่วนใหญ่เกิดจากสัญญาณไม่เปลี่ยนตามที่ตั้งไว้ ควรตรวจสอบ waveform และเพิ่ม timeout

Q5. wait ใน VHDL ต่างจาก Verilog อย่างไร?
A. VHDL มีหลายรูปแบบ เช่น wait until, wait for แต่ Verilog มีเพียง wait (เงื่อนไข)

Q6. ต่างจาก event control (@) อย่างไร?
A. @(posedge clk) จะตอบสนองเมื่อเกิดขอบสัญญาณ ส่วน wait(clk == 1) จะรอจนค่าเป็นจริง

Q7. ถ้าการจำลองหยุดแบบไม่สิ้นสุด?
A. มักเกิดจากเงื่อนไขไม่เคยเป็นจริง ต้องตรวจสอบค่าเริ่มต้นของสัญญาณ หรือเพิ่ม timeout

Q8. ใช้หลายสัญญาณใน wait ได้ไหม?
A. ได้ ใช้ && (AND) หรือ || (OR) เพื่อรวมหลายเงื่อนไข เช่น
wait((ready == 1'b1) && (start == 1'b1));

11. สรุปและบทความที่เกี่ยวข้อง

ในบทความนี้เราได้อธิบายคำสั่ง wait ของ Verilog ตั้งแต่พื้นฐานจนถึงการประยุกต์ใช้งานจริง มาทบทวนประเด็นสำคัญอีกครั้ง

11.1 สรุปประเด็นสำคัญ

  • wait เป็นโครงสร้างสำคัญของ Verilog
    ใช้เพื่อหยุดการทำงานจนกว่าเงื่อนไขจะเป็นจริง เหมาะสำหรับ testbench และการควบคุม simulation
  • โครงสร้างพื้นฐานคือ wait (เงื่อนไข);
    สามารถใช้ expression และรวมหลายเงื่อนไขได้
  • การใช้งานหลัก: การรอ reset ถูกปลด, การรอสัญญาณเปลี่ยน, การรอการสื่อสารหรือการโอนถ่ายข้อมูลเสร็จ
  • wait เป็นโครงสร้างสำหรับ simulation เท่านั้น
    ไม่ควรใช้ในโค้ดที่ต้องการสังเคราะห์เป็น FPGA/ASIC
  • ควรระวังปัญหา infinite wait
    เพิ่ม timeout และใช้เทคนิค debug เช่น $display เพื่อหาสาเหตุ
  • รู้จักการเปรียบเทียบกับภาษาอื่น เช่น SystemVerilog และ VHDL เพื่อเลือกใช้ได้เหมาะกับงาน

การเข้าใจและใช้ wait อย่างถูกต้องจะช่วยเพิ่มคุณภาพของการออกแบบและทำให้การตรวจสอบ (verification) มีประสิทธิภาพมากขึ้น

จบบทความ “การอธิบาย Verilog wait อย่างละเอียด”
หวังว่าบทความนี้จะช่วยให้คุณนำไปใช้จริงได้ และเป็นก้าวต่อไปในการพัฒนาทักษะด้านการออกแบบและการตรวจสอบวงจรดิจิทัล