Callback: thay hành vi bằng object đăng ký và kiểm đúng thứ tự gọi

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

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

  • Kết hợp registration, base handle và virtual dispatch thành callback
  • Đặt chính sách null, thứ tự và dữ liệu truyền giữa các hook
  • Kiểm kết quả lẫn accounting của từng callback

Extension point cần contract về thứ tự và dữ liệu

Driver xử lý một số qua các hook đã đăng ký. Test có thể chọn hook cộng 3 hoặc nhân 2 mà không sửa code Driver.send. Nhưng hai phép không giao hoán; nếu API không định nghĩa thứ tự, cùng cấu hình có thể tạo expected khác nhau.

Callback dùng cơ chế object và virtual method quen thuộc

Hook.apply có implementation mặc định trả input và tăng calls. AddHook và DoubleHook override công thức. Driver giữ queue Hook handles, nên call qua base handle vẫn tới object đăng ký. Callback là pattern thiết kế ở đây, không phải một scheduler region hoặc keyword mới.

[1]

Registration từ chối null theo contract riêng

Driver.add trả 0 cho null và không thêm vào queue; object hợp lệ được push_back, trả 1. Policy này được kiểm. Bài không quy định mọi callback API phải làm vậy, không có deregistration hay chống đăng ký trùng.

Cộng rồi nhân khác với nhân rồi cộng

Forward order đăng ký Add rồi Double, cho 2 x+6. Reverse order đăng ký Double rồi Add, cho 2 x+3. Main dùng bốn hook object riêng để count không trộn giữa hai driver; registration giữ handle, không clone hook.

Kết quả mỗi hook là input của hook tiếp theo

Send khởi result=value rồi cập nhật bằng apply(result) qua từng queue element. Nếu lần nào cũng gọi apply(value), hook sau bỏ qua thay đổi của hook trước. Mutation này bị symptom callback order bắt, dù từng hook riêng lẻ vẫn đúng.

Không đăng ký hook thì giữ input

Driver rỗng send 5 trả 5. Trước registration, main thử add(null) rồi kiểm queue vẫn rỗng. Cách kiểm tách rõ identity path và null policy, không dùng một default hook được ngầm tạo mà không ghi trong test.

Đếm call trên đúng object và đúng vòng kiểm

Với input 0..7, forward sum 104 và reverse sum 80. Mỗi driver gọi hai hook một lần mỗi input, nên từng hook có calls 8. TB gọi send đúng một lần mỗi driver/input rồi dùng biến f/r cho assertions và cộng tổng, tránh tự tăng count khi kiểm output.

Hai thứ tự và bốn callback object

Expected trước chạy: 8 input,forward_sum104,reverse_sum80,calls_each8,empty identity giữ 5 và null bị từ chối. Example không có timing/race/exception/UVM callback registry; không gọi pattern thuần SV này là một UVM implementation đã chạy.

Callback: thay hành vi bằng object đăng ký và kiểm đúng thứ tự gọi

Expected tính trước chạy: CALLBACK CHECK inputs=8 forward_sum=104 reverse_sum=80 calls_each=8 empty_identity=1 null_rejected=1

tb.sv testbench
`timescale 1ns/1psclass Hook;  int calls=0;  virtual function int apply(int value);calls++;return value;endfunctionendclassclass AddHook extends Hook;  virtual function int apply(int value);calls++;return value+3;endfunctionendclassclass DoubleHook extends Hook;  virtual function int apply(int value);calls++;return 2*value;endfunctionendclassclass Driver;  Hook hooks[$];  function bit add(Hook hook);    if(hook==null)return 0;    hooks.push_back(hook);return 1;  endfunction  function int send(int value);    int result=value;    foreach(hooks[i])result=hooks[i].apply(result);    return result;  endfunctionendclassmodule tb_callback;  Driver forward_order,reverse_order;  AddHook add_first,add_second;  DoubleHook double_first,double_second;  int forward_sum=0,reverse_sum=0;  initial begin    forward_order=new();reverse_order=new();    if(forward_order.send(5)!=5||forward_order.add(null)!=0||forward_order.hooks.size()!=0)$fatal(1,"empty/null callback contract");    add_first=new();double_first=new();add_second=new();double_second=new();    if(!forward_order.add(add_first)||!forward_order.add(double_first)||!reverse_order.add(double_second)||!reverse_order.add(add_second))$fatal(1,"callback registration");    for(int n=0;n<8;n++)begin      int f,r;      f=forward_order.send(n);r=reverse_order.send(n);      if(f!=2*n+6||r!=2*n+3)$fatal(1,"callback order n=%0d",n);      forward_sum+=f;reverse_sum+=r;    end    if(forward_sum!=104||reverse_sum!=80||add_first.calls!=8||double_first.calls!=8||add_second.calls!=8||double_second.calls!=8)      $fatal(1,"callback invocation accounting");    $display("CALLBACK CHECK inputs=8 forward_sum=104 reverse_sum=80 calls_each=8 empty_identity=1 null_rejected=1");    $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: CALLBACK CHECK inputs=8 forward_sum=104 reverse_sum=80 calls_each=8 empty_identity=1 null_rejected=1

Verilator 2-state, không claim X/Z hoặc synthesis.

Queue đăng ký theo thứ tự, null bị từ chối, timed behavior/exception/deregistration/duplicate-registration và UVM callback framework chưa kiểm.

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.

[2]

Tự kiểm tra

Tự kiểm tra: callback

  1. Input 5 qua Add→Double và Double→Add lần lượt cho gì?
  2. Tổng output input 0..7 của hai driver là gì?
  3. Add(null) trong Driver rỗng làm gì?
  4. Driver chưa có hook gửi input 5 trả gì?
  5. Mỗi hook object sau tám input có calls bao nhiêu?

Định nghĩa extension point đủ rõ để viết checker

Ghi thời điểm gọi, thứ tự, dữ liệu chuyển tiếp, quyền sửa và policy null/lifetime. Kiểm cả kết quả và số call khi behavior có side effect. Callback linh hoạt chỉ có ích khi caller và người viết hook cùng hiểu contract.

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

  1. SystemVerilog Callback — bản chụp resources.zip, Nguồn đào tạo đã đọc. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. Thí nghiệm nguyên bản ex.b5.callback, Bằng chứng thực nghiệm. Trích dẫn; nguồn đã đọc toàn văn.
  3. IEEE 1800-2023 SystemVerilog LRM, Class handles, inheritance, virtual methods, access and parameterization. Chưa đối chiếu với văn bản nguồn (chưa mở).
  4. Thí nghiệm nguyên bản ex.b5.callback, Source, self-checks, verification.json và mutation/capability probes. Trích dẫn; nguồn đã đọc toàn văn.
  5. SystemVerilog Callback — bản chụp resources.zip, 1. Define the Callback Class; 2. Register the Callback; 3. Implement the Callback; 4. Invoke the Callback; How Is a Callback Different From a Regular Method Call?. Trích dẫn; nguồn đã đọc các mục liên quan.