SemiMatrix / TOPICS / UVM / OVM TESTBENCH
FUNCTIONAL VERIFICATION — INDUSTRY METHODOLOGY

Universal Verification Methodology (UVM)
SystemVerilog OOP, TLM 2.0, Factory Overrides & Coverage-Driven Verification

อ่าน 30 นาที อัปเดต 2026–2028 Standard Functional Verification Signoff

เจาะลึกมาตรฐานการตรวจสอบความถูกต้องของวงจรรวมระดับโลกตามมาตรฐาน 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

💡
Directed Testing vs Constrained-Random Verification (CRV)
ในอดีต วิศวกรจะเขียนการทดสอบแบบระบุเงื่อนไขตรงๆ (Directed Tests) ซึ่งทำได้เพียงตรวจสอบเงื่อนไขที่มนุษย์ "คาดคิดไว้แล้ว" แต่ UVM ปฏิวัติวงการด้วยการนำระเบียบวิธี Constrained-Random Verification (CRV) มาใช้ โดยเปิดให้คอมพิวเตอร์สร้างสัญญาณกระตุ้นแบบสุ่มนับล้านกรณีภายใต้ข้อจำกัดของโพรโทคอล ทำให้สามารถค้นพบจุดบกพร่องที่ซ่อนอยู่ในสภาวะมุมอับ (Corner Cases) ที่มนุษย์คาดไม่ถึงได้อย่างมีประสิทธิภาพ
📍 CAREER ROADMAP CONTEXT
STAGE 03 — FUNCTIONAL VERIFICATION: Verification & Coverage
ตรวจสอบ 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
COMPONENT 01
uvm_driver
ทำหน้าที่รับข้อมูลระดับทรานแซกชัน (Transaction Packet) จาก Sequencer ผ่านพอร์ต TLM แล้วแปลงออกมาเป็นสัญญาณคลื่นจริงระดับพิน (Pin-Level Wiggle) ป้อนเข้าสู่ขั้วอินพุตของวงจร DUT (Design Under Test) ผ่าน Virtual Interface
COMPONENT 02
uvm_monitor
ดักจับสัญญาณระดับพินจาก DUT โดยไม่รบกวนการทำงาน (Passive Sniffing) แปลงสัญญาณบิตกลับมาเป็น Transaction Packet แล้วกระจายส่งออกไปยัง Scoreboard และ Coverage Collector ผ่าน Analysis Port
COMPONENT 03
uvm_agent (Active vs Passive)
ห่อหุ้ม Sequencer, Driver, และ Monitor สำหรับโพรโทคอลหนึ่งๆ เข้าด้วยกัน — หากกำหนดเป็น UVM_ACTIVE จะมีทั้ง Driver และ Sequencer แต่หากเป็น UVM_PASSIVE จะมีเพียง Monitor คอยดักฟังอย่างเดียว
COMPONENT 04
uvm_scoreboard
บรรจุแบบจำลองอุดมคติ (Golden Reference Model / Predictor) เปรียบเทียบผลลัพธ์ที่ได้รับจริงจาก DUT กับผลลัพธ์ที่คาดหวัง เพื่อตรวจจับข้อผิดพลาดเชิงตรรกะแบบเรียลไทม์

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 ดำเนินการทดสอบผ่านลำดับขั้นตอนที่ถูกกำหนดไว้ล่วงหน้าอย่างเคร่งครัด เพื่อให้คอมโพเนนต์ทุกตัวในระบบทำงานสอดประสานกัน:

BUILD PHASES (0-TIME FUNCTION)
การสร้างและผูกเชื่อมต่อโครงสร้าง
1. build_phase: ดำเนินการแบบบนลงล่าง (Top-Down) สร้างอ็อบเจกต์ของคอมโพเนนต์ผ่าน UVM Factory และดึงค่าคอนฟิก
2. connect_phase: ดำเนินการแบบล่างขึ้นบน (Bottom-Up) เชื่อมโยงพอร์ต TLM และ Virtual Interfaces
3. end_of_elaboration & start_of_simulation: ตรวจสอบความสมบูรณ์ก่อนเริ่มเดินเวลา
RUN PHASES (TIME-CONSUMING TASK)
การจำลองพฤติกรรมตามเวลาจริง
run_phase: เป็น task ที่เวลาจำลองเดินจริง ดำเนินการไปพร้อมกันทุกคอมโพเนนต์แบบคู่ขนาน หรือสามารถแบ่งย่อยเป็น 12 Sub-phases (เช่น reset_phase, configure_phase, main_phase, shutdown_phase) ได้
CONTROLLING TESTBENCH LIFETIME VIA OBJECTIONS
$$ \text{Simulation Ends} \iff \sum \text{Active Objections} == 0 $$
เมื่อ Sequence เริ่มต้นส่งข้อมูล จะต้องเรียก 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):

UVM CONFIG DATABASE SCOPING
$$ \text{Top: } \mathbf{uvm\_config\_db\#(virtual\ my\_if)::set}(null, \text{"uvm_test_top.env.agent*"}, \text{"vif"}, my_vif); $$
$$ \text{Agent: } \mathbf{uvm\_config\_db\#(virtual\ my\_if)::get}(this, \text{""}, \text{"vif"}, vif); $$

06 สถาปัตยกรรม Sequence และ Virtual Sequences

ใน UVM การสร้างสัญญาณกระตุ้นถูกแยกขาดออกจาก Driver โดยใช้โครงสร้าง 3 ประสาน:

  1. uvm_sequence_item: โครงสร้างข้อมูลแพ็กเก็ตที่มีการใส่คีย์เวิร์ด rand และระบุข้อกำหนด constraint
  2. uvm_sequencer: ทำหน้าที่เป็นนายสถานีคอยจัดคิวและประสานงานระหว่าง Sequence หลายชุด
  3. uvm_sequence: สคริปต์ขั้นตอนการทำงานที่สร้างและสุ่มข้อมูล sequence_item แล้วส่งต่อไปยัง Sequencer ผ่านคำสั่ง start_item() และ finish_item()
🎯
Virtual Sequences ในการทดสอบระดับชิป SoC
ในระบบ SoC ที่มีอินเทอร์เฟซหลายโพรโทคอลพร้อมกัน (เช่น CPU AXI Master ส่งข้อมูลไปขับ DMA Controller และส่งต่อไปออกพอร์ต PCIe) วิศวกรจะใช้ Virtual Sequencer ซึ่งไม่มี Driver เป็นของตัวเอง แต่ทำหน้าที่ควบคุมการทำงานของ Sub-Sequencer หลายตัวให้ส่งทรานแซกชันประสานเวลากันอย่างสมบูรณ์แบบ

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
// QUICK CONCEPT CHECK
ในเฟสการจำลอง run_phase ของ UVM หากไม่มีคอมโพเนนต์หรือ Sequence ใดเรียกคำสั่ง phase.raise_objection() เลย จะเกิดสิ่งใดขึ้นกับการทดสอบ?