Program block: hiểu Reactive và giới hạn bằng chứng của simulator
Tiên quyết
Sau bài này bạn sẽ
- Đặt program đúng vai trò testbench trong hierarchy
- Phân biệt quan sát ổn định có delay với kiểm Reactive cùng time slot
- Giữ failure và kết thúc test có điều kiện rõ thay vì suy tool hỗ trợ đầy đủ
Container testbench không thay cho một hợp đồng thời gian
Trong testbench có DUT module, interface và driver class, từ program chỉ một container ngôn ngữ riêng, không phải tên chung của mọi đoạn kiểm thử. Mục đích được mô tả trong training là đặt hoạt động testbench vào nhóm Reactive sau hoạt động design, giúp phân tách những phản ứng tại cùng time slot.
Nhưng một parser chấp nhận cú pháp program chưa chứng minh simulator thực hiện đúng toàn bộ scheduling của nó. Bài này cố ý tách main có quan sát ổn định và probe đòi quan sát đúng Reactive. Nhờ vậy người học biết kết quả nào đã chạy được và phần nào còn giới hạn tool, thay vì thấy nhãn simulated rồi suy mọi ngữ nghĩa đều đã được xác nhận.
Top tạo DUT, program nhận kết nối
Top tạo clock và register q; instance observe nhận clk/q cùng hai cổng kết quả done/checks. Program chứa initial và logic kiểm, không chứa instance DUT của ví dụ. Với kiến trúc lớn hơn, top cũng là nơi tạo physical interface và truyền kết nối cho lớp kiểm thử.
Program không phải class: không new một program instance để đổi đích runtime. Class object có thể được dùng trong test sequence nhưng đó là cơ chế cấp phát khác. Tách hierarchy elaboration và object runtime giúp tránh nhầm program block với một driver class chỉ vì cả hai đều có test code.
Reactive là một phần scheduling, không phải thêm một nanosecond
Trong mô hình SV, code procedural của program được đặt vào nhóm Reactive, khác với module procedural thuộc nhóm Active. Đây là khác biệt về thứ tự xử lý trong cùng time slot; tự chèn #1 làm thời gian tiến lên và không phải cách chứng minh một process đã chạy ở Reactive.
Ngay cả khi simulator hỗ trợ đúng, không nên viết “mọi thứ đã xong vĩnh viễn”: hoạt động ở nhóm reactive có thể tạo sự kiện tiếp và scheduler có các vùng re-entrant. Bài scheduling đi sâu việc lặp trong một time slot. LRM vẫn needs-spec-check; main không dựa vào ordering Reactive để tự nhận PASS.
Main đợi thêm 1 ns và kiểm bốn kết quả ổn định
Clock posedge ở 5,15,25,35 ns. DUT thực hiện q<=q+1 từ giá trị khởi tạo 0. Observe đợi mỗi posedge, sau đó #1 rồi so q với n=1..4. Bốn điểm quan sát là 6,16,26,36 ns; tại đó kết quả mong đợi 1,2,3,4.
Delay này đặt một hợp đồng ổn định đơn giản cho đúng ví dụ register không có delay khác. Nó không biến program thành Reactive nếu tool chưa hỗ trợ, cũng không phải bằng chứng setup/hold. Nếu DUT thêm cập nhật trễ quá 1 ns, cần thiết kế lại điểm kiểm thay vì giữ #1 như thuốc chữa mọi race.
Probe cùng cạnh không đạt thì phải giữ failure
Probe bỏ khoảng chờ bổ sung: program đợi posedge rồi yêu cầu q=1 ngay ở cạnh đầu. Với mô hình Reactive sau NBA của DUT, q phải là 1. Trên Verilator 5.050 hiện tại, probe parse được nhưng dừng bởi program Reactive must see design NBA q=1 tại 5 ns.
Đây là failure khả năng tool trong cấu hình đang chạy, không phải lý do đổi quy tắc bài thành “program luôn đọc q cũ”. Không bỏ oracle hoặc thêm delay vào chính probe để gọi nó đã đạt. Main có delay vẫn là main scope hẹp hơn; chuyển sang simulator khác phải chạy lại cả hai trước khi nâng claim.
Done và watchdog phải gắn với phép kiểm thực sự
Observe chỉ set done sau bốn check đúng. Top đợi done, rồi kiểm lại checks=4, q=4 và time 36 ns trước khi in summary và gọi $finish. Một watchdog ở 50 ns dừng nếu luồng kiểm không tới điểm hoàn tất.
Nguồn training mô tả completion ngầm của các initial trong program và $exit. Main chủ động dùng top-level done/$finish nên không claim cơ chế tự kết thúc ấy đã được kiểm. Không coi một simulator thoát tự nhiên là PASS nếu chưa có đủ output và số check mong đợi; pipeline vẫn yêu cầu cả exit 0 lẫn expected output.
Không xem program là điều kiện bắt buộc của mọi testbench
Một môi trường dùng module + interface + clocking block có thể định nghĩa timing rõ mà không bọc toàn bộ vào program. Việc chọn container cần phù hợp simulator, methodology và cách testbench giao tiếp với DUT, không chỉ theo một ví dụ ngắn trên mạng.
Trong program, không dùng always như một clock generator của DUT; main để always ở top module và sequence hữu hạn trong initial của observe. Không tạo thêm một writer q trong program để làm checker thấy giá trị mong đợi. Khi gặp khác biệt tool, giữ case tối giản và diagnostic thật để tách lỗi testbench khỏi giới hạn hỗ trợ.
Bốn sample ổn định và một probe Reactive riêng
Expected trước chạy: PROGRAM CHECK stable_samples=4 q=4 time_ns=36. Main parsed/simulated đạt, nhưng nhãn này chỉ xác nhận source có điểm quan sát#1 đã kiểm; failure Reactive không được gộp thành PASS của ngữ nghĩa đầy đủ.
Mutant DUT tăng q thêm 2 thay vì 1 bị program stable count oracle bắt. Probe Reactive giữ nguyên assertion như trên. Scope không gồm automatic program exit, mọi region SV hay UVM phase.
Tự kiểm tra
Đọc nhãn kiểm chứng cùng scope và phản ví dụ
Trước khi dùng program để tránh race, xác định đúng code nào nằm trong container ấy, ordering nào bạn cần và tool nào đã kiểm ordering đó. Một main ổn định cho kết quả hữu ích nhưng không thay cho probe cùng time slot. Giữ failure độc lập là cách biết cần kiểm lại phần nào khi đổi simulator.
Nguồn và mức độ đối chiếu
- SystemVerilog Program Block — bản chụp resources.zip, What Is the Need for a Program Block?; Syntax; Examples; Why always Blocks Aren't Allowed in a Program Block. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thí nghiệm nguyên bản ex.b4.program, Source, self-checks, verification.json và timing/argument probes. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Clocking, program, stratified scheduling and simulation I/O — chưa đối chiếu LRM. Chưa đối chiếu với văn bản nguồn (chưa mở).