Assignment và force/release: bỏ ép chưa chắc trở về giá trị cũ
Tiên quyết
- Module A6: Verilog cấu trúc: Đang tải
- Initial, always và fork: đọc nhiều process cùng chạy: Đang tải
Sau bài này bạn sẽ
- Phân biệt continuous assignment với cập nhật biến trong process
- Dự đoán khác biệt khi release net và variable trong ví dụ
- Đọc legacy assign/deassign mà không đưa tùy tiện vào RTL sản phẩm
- Kiểm driver và event tiếp theo thay vì dùng force để che lỗi
Hai output theo cùng source, nhưng khác nguồn cập nhật
Trong TB, một net được drive liên tục từ source; một biến được process gán khi source thay đổi. Bình thường cả hai đều theo source, nên nhìn waveform 0/1 ban đầu rất dễ tưởng hai cơ chế hoàn toàn giống nhau.
Ta cố ý force cả hai thành 1 trong khi source đã trở về 0. Sau đó release cả hai và quan sát khác biệt. Điểm cần học là đối tượng nào được ép, ai còn drive nó và sự kiện nào làm nó cập nhật tiếp.
Bài tham khảo nhóm assignment trong tài liệu người dùng cung cấp, viết lại giải thích và TB riêng. Tài liệu website là nguồn đào tạo; quy tắc đầy đủ vẫn [1].
Assign ở module và gán trong process
Hai đường trong ví dụ:
assign continuous_net = source;
always @(source) procedural_variable = source;
Dòng đầu đặt một continuous driver lên net. Dòng thứ hai là process: chờ source thay đổi, thực hiện phép gán biến, rồi quay lại chờ. Khi source đổi 1 rồi 0 và TB chờ các cập nhật ổn định, cả hai output đều được kiểm bằng 0.
Đây là hai cơ chế cụ thể, không phải bảng đầy đủ về mọi kiểu LHS hợp lệ trong mọi phiên bản Verilog/SystemVerilog. Chỉ nhìn từ khóa assign mà bỏ qua vị trí ở module hay bên trong process có thể khiến bạn đọc sai dạng assignment. [2]
Chữ reg/logic cũng không tự chứng minh có flip-flop. Ví dụ này chỉ là TB quan sát ngữ nghĩa, không có claim synthesis.
Force đang thắng không có nghĩa driver đã đổi
TB force net và variable bằng hằng 1'b1, sau đó cho source đổi 1 rồi 0. Hai output vẫn là 1, nhưng source thực sự bằng 0. Dòng FORCE RESULT net=1 variable=1 driver=0 phân biệt giá trị bị ép với dữ liệu đang đi tới nó.
Vì vậy nhìn output đang đúng dưới force không chứng minh logic gốc hoạt động đúng. Force có thể hữu ích để cô lập một đường debug hoặc tạo một tình huống kiểm tra có chủ đích; nó không phải cách sửa một phép nối hoặc driver sai trong thiết kế.
Ví dụ chỉ force hằng một bit trên hai đối tượng đã khai báo. Không suy ra hành vi của mọi RHS động, force xuyên port/hierarchy hoặc force từng bit từ kết quả này.
Release net khác release variable
Lúc release, source đang là 0:
- Net có continuous driver đang tồn tại, nên sau ổn định nó trở về giá trị driver hiện tại: 0.
- Biến giữ giá trị đã bị force là 1 cho tới một lần gán procedural tiếp theo trong ví dụ. Release không tự tạo một lần source đổi để đánh thức
always @(source).
Vì vậy output thực là RELEASE RESULT net=0 variable=1. Đừng hiểu release như “hoàn tác về snapshot trước force”: thứ quyết định giá trị là loại đối tượng và các nguồn cập nhật đang có, không phải một ngăn lịch sử tự động.
Sau đó source đổi 1 rồi 0; process có sự kiện mới để chạy, và biến trở về 0. TB kiểm NEXT EVENT RESULT net=0 variable=0. [3]
Assign/deassign bên trong process là dạng legacy
TB còn đọc một dạng procedural continuous assignment:
assign legacy_variable = source;
// ...
deassign legacy_variable;
Các statement này nằm bên trong initial, khác continuous assign ở cấp module. Khi assign đang hoạt động, biến theo source tới 1. Deassign dừng cơ chế đó; khi source đổi về 0, biến vẫn giữ 1 trong ví dụ. Một phép gán procedural mới legacy_variable=0 sau đó mới đổi biến về 0.
Dòng kết quả LEGACY RESULT tracked=1 held=1 next_write=0 là ba giá trị được ghi nhận/kiểm ở ba giai đoạn, không phải ba driver đồng thời.
Ta học dạng này để đọc code cũ. Việc simulator hỗ trợ không phải lý do tự chọn nó cho RTL sản phẩm mới. Hãy dùng coding guideline và kiểm khả năng tổng hợp của flow cụ thể; bài không chạy synthesis cho các thao tác override này.
Kiểm 0/0, ép 1/1 rồi bỏ ép
Kỳ vọng tính trước khi chạy: bình thường 0/0; bị ép 1/1 dù source 0; sau release net 0/variable 1; sau event mới cả hai 0. Dạng legacy theo source 1, giữ 1 sau deassign và nhận 0 khi được ghi lại.
TB dùng các phép so case inequality và $fatal sau từng giai đoạn, không chỉ in các con số rồi tự coi là pass. Đợi một bước thời gian để quan sát ổn định, nên không dùng thứ tự tùy ý giữa process source-change và phép kiểm làm đáp án.
Pyslang parse và Icarus simulation đã đạt; exit 0 và đủ output mới có claim simulated. [4]
Nếu source không đổi sau release thì sao?
Với đúng process always @(source) của ví dụ, biến không có một lịch clock riêng để tự ghi lại. Khi không có source event mới, không thể giả định nó sẽ trở về giá trị driver như net continuous.
Nếu đổi process thành cập nhật theo clock, quan hệ tiếp theo cần phân tích theo clock và loại phép gán. Nếu thêm một writer khác, cần phân tích cả tranh chấp. Bài không dùng một kết quả release để đoán mọi biến trong mọi thiết kế.
Trong debug thực tế, ghi lại đối tượng đã force, thời điểm bỏ force và điều kiện để driver bình thường cập nhật. Sau khi bỏ override, kiểm lại đường chức năng gốc trước khi kết luận bug đã hết.
Đừng sửa triệu chứng bằng một force bị quên
- Dùng force làm output đúng rồi xem đó là bằng chứng DUT đã sửa.
- Quên release, khiến phần kiểm sau không còn tác động tới output.
- Mong mọi variable lập tức nhận lại dữ liệu nguồn sau release.
- Nhầm assign cấp module với assign/deassign trong process.
- Mở rộng kết quả hằng một bit của bài sang mọi force expression/port.
- Gắn nhãn synthesizable vì TB đã parse và chạy được.
Tự kiểm tra
Đọc loại đối tượng và driver trước khi release
Hỏi ba câu: đang ép net hay variable, driver bình thường là gì, và lúc nào có lần cập nhật tiếp theo? Sau đó kiểm output khi đang force, ngay sau release và sau sự kiện cập nhật bình thường.
Bài đã đối chiếu các phần nguồn đào tạo liên quan bằng thí nghiệm riêng, chưa thay cho kiểm toàn bộ quy tắc LRM. Trạng thái vẫn draft/needs-spec-check; không sao chép code/đáp án website vào bài rồi coi là bằng chứng chạy.
Nguồn và mức độ đối chiếu
- IEEE 1800-2023 SystemVerilog LRM, cần đối chiếu LRM. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Verilog Assignments — bản chụp trong resources.zip, Ba nhóm assignment trong nguồn đào tạo. Trích dẫn; nguồn đã đọc các mục liên quan.
- Procedural continuous assignments — bản chụp trong resources.zip, Giải thích net/reg khi release trong nguồn đào tạo. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thử nghiệm nguyên bản ex.a7.assign, Bằng chứng thí nghiệm nguyên bản. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Continuous/procedural assignments; procedural continuous assignment; force/release. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thử nghiệm nguyên bản ex.a7.assign, TB nguyên bản và verification.json đã chạy. Trích dẫn; nguồn đã đọc toàn văn.
- Procedural continuous assignments — bản chụp trong resources.zip, assign and deassign; force and release. Trích dẫn; nguồn đã đọc các mục liên quan.
- Verilog Assignments — bản chụp trong resources.zip, Three Basic Assignment Forms; Procedural Assignment. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thử nghiệm nguyên bản ex.a7.assign, content/code/ex.a7.assign/verification.json và tb_assign.sv. Trích dẫn; nguồn đã đọc toàn văn.