Universal Verification Methodology (UVM)
SystemVerilog OOP, TLM 2.0, Factory Overrides & Coverage-Driven
Verification
เจาะลึกมาตรฐานการตรวจสอบความถูกต้องของวงจรรวมระดับโลกตามมาตรฐาน IEEE 1800.2: การสร้าง Testbench เชิงวัตถุ (SystemVerilog OOP), โครงสร้างคอมโพเนนต์ UVM (Driver, Monitor, Sequencer, Scoreboard), การสื่อสารระดับทรานแซกชันผ่านพอร์ต TLM 2.0, วงจรชีวิตของเฟส (Phasing & Objections), การแทนที่คลาสผ่าน UVM Factory, กลยุทธ์การสุ่มทดสอบภายใต้ข้อจำกัด (Constrained-Random Verification) และการปิดเป้าหมายความครอบคลุม (Coverage Closure)
01 บทบาทและนิยามของ UVM (IEEE 1800.2 Standard)
ในโครงการพัฒนาชิปประมวลผลขนาดใหญ่ (SoC) สถิติระดับโลกชี้ชัดว่า กระบวนการตรวจสอบความถูกต้องเชิงฟังก์ชัน (Functional Verification) กินเวลาและทรัพยากรไปถึง 60%–70% ของวงจรการออกแบบชิปทั้งโครงการ หากมีข้อผิดพลาด (Hardware Bug) หลุดรอดผ่านไปถึงขั้นตอนผลิตเวเฟอร์จริง การแก้ไขหน้ากาก (Mask Respin) จะต้องสูญเสียเงินนับล้านดอลลาร์สหรัฐและทำให้ชิปพลาดช่วงเวลาเปิดตัวสู่ตลาด
UVM (Universal Verification Methodology) คือไลบรารีคลาสมาตรฐานของภาษา SystemVerilog ที่ได้รับการรับรองโดยสมาคม IEEE (IEEE 1800.2) เพื่อสร้างกรอบการทำงานสำหรับการสร้าง Verification Environment ที่มีคุณสมบัติโมดูลาร์ (Modular), สามารถนำกลับมาใช้ซ้ำได้ (Reusable), และรองรับการทำงานในระดับองค์กรข้ามแพลตฟอร์ม EDA ทั้ง Synopsys VCS, Cadence Xcelium, และ Siemens Questa
ตรวจสอบ design ด้วย UVM testbench, coverage-driven verification, constrained-random simulation และ formal verification (property checking)
Tools: Synopsys VCS / Verdi, Cadence Xcelium / SimVision, Siemens Questa, JasperGold
Related: RTL Design Architectures · Coverage-Driven Verification · Formal Verification
Path: Design Verification (DV) Engineer, Verification Lead, VIP Developer
02 ลำดับชั้น UVM Component Hierarchy และบทบาทหน้าที่
ใน UVM คลาสทั้งหมดสืบทอดมาจากคลาสแม่ 2 ตัวหลัก:
-
uvm_object: คลาสสำหรับข้อมูลชั่วคราว (Transient Objects) เช่น ข้อมูลแพ็กเก็ต (Sequence Items), การตั้งค่า (Configuration Objects) ที่ถูกสร้างขึ้น ใช้งาน และถูกทำลายโดย Garbage Collector -
uvm_component: คลาสสำหรับส่วนประกอบเชิงโครงสร้างที่คงที่ (Quasi-Static Structural Components) มีลำดับชั้นความเป็นพ่อ-ลูก (Parent-Child Hierarchy) และมีส่วนร่วมในวงจรชีวิตของ UVM Phases
03 การสื่อสารระดับทรานแซกชัน (Transaction-Level Modeling: TLM 2.0)
การเชื่อมต่อระหว่างคอมโพเนนต์ใน UVM ไม่ใช้การต่อสายสัญญาณแบบ Pin-level แต่ใช้การส่งผ่านข้อมูลระดับคำสั่งผ่าน TLM Ports (Transaction-Level Modeling):
| ชนิดของพอร์ต TLM | ทิศทางและการทำงาน | รูปแบบการเชื่อมต่อ (Binding) |
|---|---|---|
uvm_blocking_put_port #(T)
|
ฝั่งส่งข้อมูล ส่งแพ็กเก็ตไปยังฝั่งรับ และจะหยุดรอ (Block) จนกว่าฝั่งรับจะพร้อมรับข้อมูลสำเร็จ | เชื่อมต่อแบบ 1 ต่อ 1 เข้ากับ uvm_blocking_put_export |
uvm_analysis_port #(T)
|
กระจายข้อมูลแบบ 1 ต่อหลายจุด (1-to-Many Broadcast) แบบ Non-blocking ทันทีที่ Monitor สแกนข้อมูลได้ |
เชื่อมต่อเข้ากับ uvm_analysis_imp ใน Scoreboard และ Coverage
Collector โดยไม่เกิดการติดขัด
|
uvm_tlm_analysis_fifo #(T)
|
คิวบัฟเฟอร์พักข้อมูลแบบไม่จำกัดขนาด ทำหน้าที่แปลงสัญญาณ Broadcast จาก Analysis Port ให้กลายเป็น Blocking Get Interface สำหรับ Scoreboard | ช่วยแยกเธรดการทำงานของ Monitor และ Scoreboard ให้เป็นอิสระต่อกันโดยสมบูรณ์ |
04 ลำดับขั้นของเฟส (Phasing Execution) และกลไก Objections
UVM ดำเนินการทดสอบผ่านลำดับขั้นตอนที่ถูกกำหนดไว้ล่วงหน้าอย่างเคร่งครัด เพื่อให้คอมโพเนนต์ทุกตัวในระบบทำงานสอดประสานกัน:
2. connect_phase: ดำเนินการแบบล่างขึ้นบน (Bottom-Up) เชื่อมโยงพอร์ต TLM และ Virtual Interfaces
3. end_of_elaboration & start_of_simulation: ตรวจสอบความสมบูรณ์ก่อนเริ่มเดินเวลา
task ที่เวลาจำลองเดินจริง
ดำเนินการไปพร้อมกันทุกคอมโพเนนต์แบบคู่ขนาน หรือสามารถแบ่งย่อยเป็น 12 Sub-phases
(เช่น reset_phase, configure_phase,
main_phase, shutdown_phase) ได้
phase.raise_objection(this); เพื่อแจ้งว่ามีภารกิจค้างอยู่
และเมื่อส่งข้อมูลและรอให้ผลลัพธ์ผ่าน Scoreboard เรียบร้อยแล้ว จะต้องเรียก
phase.drop_objection(this); หากไม่มีคอมโพเนนต์ใดยกคัดค้านค้างอยู่ UVM
จะปิดฉากการจำลองและเข้าสู่ check_phase และ
report_phase โดยอัตโนมัติ
05 UVM Factory และฐานข้อมูลคอนฟิก (uvm_config_db)
หนึ่งในพลังที่แข็งแกร่งที่สุดของ UVM คือแนวคิด Polymorphism (การพ้องรูป) ผ่านกลไก UVM Factory ซึ่งเปิดโอกาสให้วิศวกรสามารถสลับเปลี่ยนคลาสย่อย (Derived Class) เข้าแทนที่คลาสแม่ (Base Class) ได้โดยไม่ต้องแก้ไขซอร์สโค้ดเดิมแม้แต่บรรทัดเดียว:
// การลงทะเบียนคลาสเข้าสู่ Factory class my_driver extends uvm_driver #(my_transaction); `uvm_component_utils(my_driver) // ... endclass // ในไฟล์ Test: แทนที่ Driver เดิมด้วย Error-Injection Driver พิเศษ class error_test extends base_test; `uvm_component_utils(error_test) virtual function void build_phase(uvm_phase phase); // สั่งให้ Factory แทนที่ my_driver ด้วย my_error_driver ทุกตำแหน่ง set_type_override_by_type(my_driver::get_type(), my_error_driver::get_type()); super.build_phase(phase); endfunction endclass
นอกจากนี้ การส่งผ่านพารามิเตอร์และการอ้างอิง Virtual Interface จาก Top-level Module
ลงสู่วงจร UVM ดำเนินการผ่าน uvm_config_db#(T):
06 สถาปัตยกรรม Sequence และ Virtual Sequences
ใน UVM การสร้างสัญญาณกระตุ้นถูกแยกขาดออกจาก Driver โดยใช้โครงสร้าง 3 ประสาน:
-
uvm_sequence_item: โครงสร้างข้อมูลแพ็กเก็ตที่มีการใส่คีย์เวิร์ดrandและระบุข้อกำหนดconstraint -
uvm_sequencer: ทำหน้าที่เป็นนายสถานีคอยจัดคิวและประสานงานระหว่าง Sequence หลายชุด -
uvm_sequence: สคริปต์ขั้นตอนการทำงานที่สร้างและสุ่มข้อมูลsequence_itemแล้วส่งต่อไปยัง Sequencer ผ่านคำสั่งstart_item()และfinish_item()
07 Scoreboarding และการปิดเป้าหมายความครอบคลุม (Coverage Closure)
การยืนยันความถูกต้องในแนวทาง Coverage-Driven Verification (CDV) ไม่ได้วัดจากจำนวนวันที่รันการจำลอง แต่วัดจากตัวเลขชี้วัดความครอบคลุม 2 มิติ:
| มิติความครอบคลุม | กลไกการวัดผล | เป้าหมายการลงนามรับรอง (Signoff Goal) |
|---|---|---|
| Code Coverage (รันโดย Simulator อัตโนมัติ) | ตรวจวัดว่าโค้ด RTL ถูกกระตุ้นครบหรือไม่: Line Coverage (ทุกบรรทัด), Branch Coverage (ทุกเงื่อนไข if/else), Toggle Coverage (ทุกบิตสลับ 0↔1), และ FSM State/Transition Coverage | 100% (หากมีส่วนที่แตะไม่ถึง ต้องทำ Formal Verification พิสูจน์ว่าเป็น Dead Code หรือเขียน Waivers ชี้แจง) |
| Functional Coverage (เขียนโดยวิศวกร DV) |
เขียนบล็อก covergroup และกำหนด
coverpoint พร้อมการไขว้ตัวแปร
cross เพื่อวัดว่าฟังก์ชันการทำงานตามสเปกถูกทดสอบครบทุกรูปแบบหรือยัง
|
100% ครบทุกโหมดการทำงานของชิป |
| Assertion Coverage (SVA) | ตรวจวัดความครอบคลุมของ SystemVerilog Assertions ที่เฝ้าระวังการละเมิดกฎของบัส (เช่น กฎ Handshake ของ AXI/PCIe) | 100% ปราศจาก Assertion Failures แม้แต่ครั้งเดียว |
08 ตัวอย่างสถาปัตยกรรมโค้ด UVM ระดับโปรดักชัน (Production Code Pattern)
ตัวอย่างการเขียน UVM Driver ขั้นพื้นฐานที่รับไอเทมจาก Sequencer และแปลงเป็นพัลส์คลื่นบน Virtual Interface อย่างถูกต้องตามหลักมาตรฐาน:
class axi_master_driver extends uvm_driver #(axi_transaction); `uvm_component_utils(axi_master_driver) virtual axi_if vif; // Virtual Interface เชื่อมโยงสู่ DUT function new(string name = "axi_master_driver", uvm_component parent = null); super.new(name, parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); if (!uvm_config_db#(virtual axi_if)::get(this, "", "vif", vif)) `uvm_fatal("NOVIF", {"Virtual interface must be set for: ", get_full_name()}); endfunction virtual task run_phase(uvm_phase phase); forever begin // ดึง Transaction ถัดไปจาก Sequencer seq_item_port.get_next_item(req); drive_transfer(req); seq_item_port.item_done(); end endtask virtual task drive_transfer(axi_transaction tr); @(posedge vif.clk); vif.awaddr <= tr.addr; vif.awvalid <= 1'b1; vif.wdata <= tr.data; vif.wvalid <= 1'b1; wait(vif.awready && vif.wready); @(posedge vif.clk); vif.awvalid <= 1'b0; vif.wvalid <= 1'b0; endtask endclass