Clocking block và skew: đọc mẫu nào, lái tín hiệu lúc nào?
Sau bài này bạn sẽ
- Phân biệt sampled clockvar và tín hiệu raw sau NBA
- Tính thời điểm drive từ output skew có đơn vị rõ
- Đọc bằng chứng #1step và #0 theo đúng phạm vi đã chạy
Cùng một cạnh, hai câu hỏi về giá trị
Một register lấy req ở posedge và cập nhật q bằng nonblocking assignment. Checker hỏi “q trước cạnh là bao nhiêu?” khác với “q sau NBA của cạnh này là bao nhiêu?”. Cả hai câu hỏi đều hữu ích, nhưng trộn câu trả lời sẽ làm một DUT đúng trông như chậm một chu kỳ hoặc làm scoreboard đi trước thiết kế.
Clocking block đặt tên cho một hợp đồng drive/sample quanh một clock event. Nó không đổi latency của DUT. Trước khi chọn skew, hãy viết checker muốn quan sát đầu vào của cạnh, đầu ra sau cập nhật, hay transaction của chu kỳ trước. Chọn mốc theo ý nghĩa kiểm thử, không theo giá trị tình cờ thấy trong một log.
Input của clocking block là phía testbench đọc
Trong interface timed_link, cb khai báo input q và output req. DUT phát q nên testbench đọc q; testbench phát req nên DUT đọc req. Hướng này nhìn từ người dùng clocking block, không sao chép tên input/output từ cổng DUT.
link.cb.q là clocking input đã lấy mẫu theo skew. link.q là tín hiệu raw tại thời điểm process đang đọc. Hai expression có thể khác nhau mà cả hai đều đúng. Main cố ý quan sát cả hai ở các mốc khác nhau để người học nhìn được sự khác biệt thay vì xem cb chỉ là tên dài hơn của interface.
Input #1step giữ giá trị ngay trước clock event
Main viết tường minh default input #1step output #2ns. Input #1step lấy mẫu ngay trước time slot của clock event, tương ứng giá trị vào Preponed; step gắn với độ chính xác thời gian mô phỏng, không phải một chu kỳ clock hoặc mặc định một nanosecond.
Ở cạnh 15 ns, q trước cạnh vẫn bằng 0, trong khi req đã bằng 1 từ 7 ns. Do đó cb.q đọc 0 còn q raw sau NBA bằng 1. Trong ví dụ register này, sampled q trông như kết quả của chu kỳ trước; không khái quát rằng mọi input #1step đều tạo thêm một register hoặc luôn trễ đúng một clock so với mọi tín hiệu khác.
Output #2ns đổi req sau cạnh hai nanosecond
Testbench đợi @(link.cb) rồi gán link.cb.req <= next_req. Với output skew 2 ns, req mới xuất hiện ở 7,17,27,37 ns sau các cạnh 5,15,25,35 ns. DUT tại cạnh 5 ns vẫn lấy req cũ bằng 0; req được drive ở 7 ns có thể được lấy ở 15 ns.
Skew không phải delay vật lý do simulator đo được. Chọn 2 ns chỉ làm hợp đồng của ví dụ rõ ràng khi period 10 ns; nó không chứng minh setup/hold hoặc thay constraints của STA. Ghi #2ns thay vì số trần giúp không vô tình đổi ý nghĩa khi timeunit của scope thay đổi.
Theo bốn cạnh bằng hai state của mô hình
Hai biến model_req và model_q ghi state trước cạnh. Sau mỗi lượt, model_q nhận req cũ và model_req nhận giá trị vừa drive. Oracle không đọc output DUT để cập nhật state dự kiến.
| Cạnh ns | req trước cạnh | cb.q với #1step | q sau NBA | req ở cạnh+2 ns |
|---|---|---|---|---|
| 5 | 0 | 0 | 0 | 1 |
| 15 | 1 | 0 | 1 | 0 |
| 25 | 0 | 1 | 0 | 1 |
| 35 | 1 | 0 | 1 | 0 |
Main kiểm cb.q tại event; ở cạnh+1 ns kiểm q đã cập nhật và req vẫn cũ; ở cạnh+3 ns kiểm req đã mới. Bốn check mỗi cạnh cho 16 check, kết thúc 38 ns. Bảng là dự đoán của mô hình, được self-check trong source, không phải waveform VCD được dựng lại.
Đổi input skew phải đổi ý nghĩa oracle
Probe riêng đổi input thành #0 và đối chiếu cb.q với q của cạnh hiện tại sau NBA: các mẫu dự kiến 0,1,0,1. Probe này đã chạy đạt trên tool hiện tại. Nếu chỉ đổi declaration thành #0 nhưng vẫn giữ oracle đòi mẫu #1step, checker phải báo sai; đó là kiểm hợp đồng, không phải yêu cầu hai skew cho cùng giá trị.
Default khi không ghi skew là input#1step/output#0 theo nguồn đào tạo, vẫn cần đối chiếu LRM chính thức. Main dùng explicit skews; PASS của main không tự chứng minh mọi default, inout, cycle delay hay clocking qua virtual handle. Đọc trực tiếp raw signal cũng không tự áp dụng skew của cb.
Clocking block không tự sửa mọi race
Nếu một process khác vẫn ghi trực tiếp req, clocking block không tự thu hồi quyền ghi của process ấy. Nếu scoreboard so sai chu kỳ, lấy mẫu có trật tự vẫn cho một kết luận sai. Cần giữ một writer theo hợp đồng, dùng đúng sampled value và đặt expected ở đúng transaction.
Nguồn training có lời hứa quá rộng “không bao giờ race”; ở đây chỉ claim bốn cạnh và các mốc được oracle kiểm. Một tài liệu khác trong ZIP ghi default input 0 và chỉ một block cho mỗi clock, mâu thuẫn với mô tả training còn lại; không dùng các khái quát đó để thay LRM. Bài vẫn draft/needs-spec-check.
16 check quanh bốn clock event
Expected trước chạy: CLOCKING CHECK edges=4 checks=16 input_skew=1step output_skew_ns=2 time_ns=38. Parse/simulate main đã đạt với Verilator; probe input#0 đúng oracle là bằng chứng riêng. Mutant đổi skew nhưng giữ hợp đồng cũ và mutant output#0 phải bị bắt, không nới checker để chúng xanh.
Tự kiểm tra
Ghi rõ event, sample, drive và chu kỳ expected
Hãy review một clocking block bằng bốn mốc: event nào, input lấy từ trước hay sau cập nhật nào, output đổi khi nào và DUT sẽ nhận ở cạnh nào. Tách sampled clockvar khỏi raw signal. Khi đổi skew, cập nhật mô hình có chủ đích rồi chạy cả main và phản ví dụ; không sửa expected chỉ vì log mới nhìn thuận mắt.
Nguồn và mức độ đối chiếu
- SystemVerilog Clocking Blocks Part 1 — bản chụp resources.zip, What Is a Clocking Block?; Direction Convention: A Common Source of Confusion; Basic Syntax; Declaring a Clocking Block Inside an Interface. Trích dẫn; nguồn đã đọc các mục liên quan.
- SystemVerilog Clocking Blocks Part 2 — bản chụp resources.zip, Skew Syntax; The Special Case: #1step. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thí nghiệm nguyên bản ex.b4.clocking, 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ở).
- SystemVerilog Clocking Block — bản chụp resources.zip, SystemVerilog Clocking Block; Clocking Skew — ghi nhận khái quát không dùng làm rule. Trích dẫn; nguồn đã đọc các mục liên quan.