Virtual interface: class truy cập đúng instance, đổi binding có kiểm tra

Khoảng 45 phútMức 2/3Bản nháp: một số khẳng định chưa đối chiếu spec

Sau bài này bạn sẽ

  • Phân biệt interface instance tĩnh và virtual handle trong class
  • Truyền modport view qua constructor và chặn null trước truy cập
  • Kiểm rebind bằng oracle độc lập bên ngoài class

Driver là object, chân tín hiệu thuộc hierarchy

Một driver class cần điều khiển a/b của DUT nhưng class không tạo interface instance bên trong như module top. Top tạo left/right cùng hai DUT, rồi đưa một tham chiếu tới instance có sẵn cho driver. Virtual interface là cầu nối giữa object runtime và tín hiệu trong hierarchy.

Từ virtual ở đây không có nghĩa có một mạch mô phỏng khác hoặc driver tự clone tín hiệu. Nó mô tả biến tham chiếu có thể giữ binding tới một interface instance. Cũng đừng lẫn với virtual method trong OOP: dynamic dispatch của method và việc đổi đích truy cập tín hiệu giải hai vấn đề khác nhau.

Khai báo virtual handle chưa tạo tín hiệu

Property local virtual sum_link.driver vif lưu view driver của một instance sum_link. Khai báo này không tạo a/b/total và không thể thay cho sum_link left() ở top. Constructor của SumDriver tạo object driver; actual left.driver xác định bộ tín hiệu mà object sử dụng.

Vì giữ tham chiếu, nhiều object có thể được truyền cùng một physical interface. Chúng không tự có storage độc lập. Nếu cùng drive a/b, cần thiết kế ownership hoặc arbitration; gọi mỗi object bằng một tên khác không tránh tranh chấp. Main chỉ có một driver object để tập trung kiểm binding.

[1]

Driver giữ một virtual handle; trước rebind tới left, sau rebind tới right. Hai interface instance vẫn tồn tại độc lập.

Constructor nhận đúng view trước khi chạy task

Interface định nghĩa calc cho DUT và driver cho class. Với driver, a/b là output và total là input. Constructor nhận virtual sum_link.driver link, kiểm null rồi gán property vif. Local property giúp code bên ngoài không tùy tiện thay binding, còn method bind_link là nơi đổi đích có kiểm tra.

Top gọi driver=new(left.driver). Đây là truyền một tham chiếu đã có, không phải gọi new để cấp phát interface. Nếu đổi W hoặc modport ở các bên, type của virtual interface phải tương thích. Bài chỉ kiểm một definition 4 bit và view driver; không dùng PASS này để tuyên bố mọi specialization đều gán lẫn nhau được.

Dừng ở cấu hình thiếu, trước khi ghi tín hiệu

Cả constructor và bind_link từ chối null bằng $fatal(1,"null virtual interface"). Guard báo lỗi ở điểm nhận cấu hình thay vì đợi một truy cập member xa hơn. Probe âm gọi new(null) kiểm đúng đường này, giữ message do ví dụ tự viết để không phụ thuộc diagnostic dereference của simulator.

Guard không chữa một handle hợp lệ nhưng trỏ nhầm instance. Left và right đều có type phù hợp nên compiler có thể chấp nhận việc dùng nhầm. Cần oracle kiểm routing ở top, không chỉ kiểm “vif khác null”. Khi làm UVM sau này, kiểm config_db get phải thành công cũng mới là một phần của bài toán kết nối.

Task có chờ thời gian, function chỉ đổi binding

Task drive_and_check ghi a/b qua vif, chờ #1 rồi kiểm tổng với hai argument int nhận từ caller. Task được phép tiêu thụ thời gian; constructor và function bind_link không chờ cạnh hoặc delay. Hai loại method này có trách nhiệm khác nhau.

Argument trong main luôn từ 0 tới 15 nên cast 4 bit giữ nguyên giá trị. Nếu mở API nhận số ngoài miền, phải thêm contract/guard hoặc định nghĩa rõ hành vi cắt bit; không giả định int tùy ý vẫn tương đương chân 4 bit. Main dùng mạch tổ hợp, không claim quy tắc drive/sample cho DUT tuần tự.

Đổi handle không sao chép hoặc xoá tín hiệu cũ

Driver quét 256 cặp vào left rồi gọi bind_link(right.driver) một lần và quét tiếp 256 cặp vào right. Khi xong left, giá trị cuối là a=15,b=15,total=30. Đổi binding chỉ đổi nơi các lần truy cập vif tiếp theo đi tới; nó không tự reset left.

Sau mỗi call vào right, top kiểm left vẫn giữ ba giá trị cuối. Với 256 call, có thêm 256 isolation check. Nếu cần dừng nhiều task đang chạy trước rebind, phải thêm đồng bộ riêng: ví dụ tuần tự ở đây không chứng minh rebind trong khi driver/monitor đồng thời hoạt động là an toàn.

Checker nằm trong class có thể cùng đi nhầm đường

Nếu bind_link quên gán vif, driver tiếp tục ghi left. Phép kiểm bên trong class vẫn đọc left và so với argument nên có thể hoàn toàn đúng dù mục tiêu right chưa được chạm tới. Do đó PASS của self-check bên trong chưa đủ chứng minh routing.

Oracle isolation ở top đọc trực tiếp left và bắt thay đổi ngay khi lượt right bắt đầu. Top cũng kiểm right.total cuối bằng 30, số call=512, số bind=1 và thời gian 512 ns. Mutant bỏ assignment trong bind_link bị oracle bên ngoài bắt. Đây là lý do cần kiểm cả dữ liệu lẫn đường đi của dữ liệu, thay vì thêm nhiều phép tính giống nhau vào cùng một class.

512 call, một lần rebind, 256 kiểm tra isolation

Expected trước chạy: VIF CHECK calls=512 bindings=1 isolated=256 right_last=30 time_ns=512. Main đã parse/simulate với Verilator; không dùng clocking block, không claim UVM config_db, null-dereference runtime hoặc độ chính xác four-state.

Virtual interface: class truy cập đúng instance, đổi binding có kiểm tra

Expected tính trước chạy: VIF CHECK calls=512 bindings=1 isolated=256 right_last=30 time_ns=512

tb.sv testbench
`timescale 1ns/1ps// Expected:256checks on each physical interface,1rebind,256checks that the old interface stays held.interface sum_link;  logic[3:0] a,b;  logic[4:0] total;  modport calc(input a,b,output total);  modport driver(output a,b,input total);endinterfacemodule sum_unit(sum_link.calc link);  assign link.total={1'b0,link.a}+{1'b0,link.b};endmoduleclass SumDriver;  local virtual sum_link.driver vif;  int checked_calls=0,bindings=0;  function new(virtual sum_link.driver link);    if(link==null)$fatal(1,"null virtual interface");    vif=link;  endfunction  function void bind_link(virtual sum_link.driver link);    if(link==null)$fatal(1,"null virtual interface");    vif=link;bindings++;  endfunction  task drive_and_check(input int a,b);    vif.a=4'(a);vif.b=4'(b);#1;    if(int'(vif.total)!=a+b)$fatal(1,"virtual interface sum oracle");    checked_calls++;  endtaskendclassmodule tb_vif;  sum_link left();sum_link right();  sum_unit left_unit(left);sum_unit right_unit(right);  SumDriver driver;  int isolated=0;  initial begin    driver=new(left.driver);    for(int a=0;a<16;a++)for(int b=0;b<16;b++)driver.drive_and_check(a,b);    driver.bind_link(right.driver);    for(int a=0;a<16;a++)for(int b=0;b<16;b++)begin      driver.drive_and_check(a,b);      if(left.a!=15||left.b!=15||left.total!=30)$fatal(1,"virtual rebind isolation oracle");      isolated++;    end    if(driver.checked_calls!=512||driver.bindings!=1||isolated!=256||right.total!=30||$time!=512)$fatal(1,"virtual interface accounting");    $display("VIF CHECK calls=512 bindings=1 isolated=256 right_last=30 time_ns=512");$finish;  endendmodule

Đã kiểm chứng thế nào

  • Phân tích và elaborate theo LRM (pyslang 12.1.0)
  • Mô phỏng, exit 0 và output khớp kỳ vọng tính tay (Verilator 5.050, 2-state)

Output phải khớp: VIF CHECK calls=512 bindings=1 isolated=256 right_last=30 time_ns=512

Verilator 5.050/2-state; chỉ source/cấu hình đã chạy. Không claim X/Z, timing vật lý, synthesis, UVM hay mọi parameter specialization.

Oracle nguyên bản theo input vòng lặp; fault probes giữ riêng, không làm yếu checker.

Các kiểm tra chạy lúc xây dựng nội dung (2026-11-06), không chạy trong trình duyệt. Kỳ vọng được tính tay trước khi chạy.

Hai đường âm tách riêng: bỏ đổi binding phải bị checker isolation bắt; đưa null vào constructor phải dừng bởi guard của ví dụ. Không sửa checker để chấp nhận driver còn ghi vào instance cũ.

[2]

Tự kiểm tra

Tự kiểm tra: vif

  1. Nếu bind_link quên gán vif=link, checker nào phát hiện driver vẫn ghi left?
  2. Khai báo virtual sum_link.driver vif trong class tạo ra bao nhiêu interface instance mới?
  3. Sau rebind sang right, giá trị left phải giữ trong main là gì?
  4. Probe new(null) được thiết kế dừng ở đâu?
  5. Main gọi drive_and_check bao nhiêu lần?

Kiểm type, binding và ownership trước giá trị

Vẽ instance do top tạo, object do new tạo và virtual handle nối hai miền ấy. Kiểm null ở cấu hình, kiểm destination bằng quan sát độc lập, rồi kiểm dữ liệu sau thời điểm ổn định phù hợp. Handle đúng type không đủ bảo đảm đúng DUT; self-check đúng giá trị cũng chưa đủ bảo đảm đúng đường kết nối.

Nguồn và mức độ đối chiếu

  1. SystemVerilog Virtual Interface — bản chụp resources.zip, Why Do We Need Virtual Interfaces?; Basic Syntax; A Complete Example; The Most Common Pitfall: An Uninitialized Virtual Interface. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. Thí nghiệm nguyên bản ex.b4.vif, Source, self-checks, verification.json và fault probes. Trích dẫn; nguồn đã đọc toàn văn.
  3. IEEE 1800-2023 SystemVerilog LRM, Interfaces, modports, parameterization and virtual interfaces — chưa đối chiếu LRM. Chưa đối chiếu với văn bản nguồn (chưa mở).