Latch inference: đường không gán cũng mô tả phần cứng

Khoảng 35 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ẽ

  • Nhận diện yêu cầu giữ giá trị ẩn trong combinational process thiếu đường gán
  • Phân biệt latch nhạy mức với FF có enable
  • Sửa default theo chức năng mong muốn và kiểm lại cả simulation lẫn synthesis

Không viết assignment không có nghĩa output biến mất

Một process tổ hợp chỉ gán q khi en 1. Khi en 0, giá trị q trước đó vẫn được giữ trong mô phỏng. Để thực hiện đúng hành vi giữ ấy, phần cứng cần state; bạn đã mô tả storage dù không viết từ khóa register nào.

Bài đối chiếu chính cấu trúc thiếu đường với bản có default 0. Chúng được drive cùng stimulus để thấy khác biệt và tổng hợp riêng để kiểm loại phần tử giữ state. [1]

Missing path yêu cầu giữ state

missing_path có always @* if(en) q=d. Q 4 bit ban đầu unknown vì chưa được nạp. Khi mở en và d=a, q thành a. Đóng en rồi đổi d thành 5, q vẫn a; không có assignment mới để xóa hoặc thay giá trị đó.

Đây là latch inference, không phải output tự nhiên thành 0 ở branch thiếu. Phải kiểm từng output, vì một process có thể gán đầy đủ cho tín hiệu này nhưng để thiếu cho tín hiệu khác hoặc một phần vector.

Yosys generic synthesis của module tạo 4 positive-level latch. Bằng chứng này xác nhận state được suy ra trong flow đang chạy; không đo propagation delay hoặc tài nguyên của một FPGA cụ thể. [2]

Trong suốt một mức khác chụp một cạnh

Khi en vẫn 1, đổi d từ 5 sang 3 làm latch theo 3 dù không có cạnh clock. Khi en 0, đổi d thànhf không làm q bỏ giá trị 3. Latch nhạy mức; FF với posedge clk chỉ chụp theo event cạnh trong mô hình của nó.

Thiếu else trong clocked process có thể diễn đạt FF giữ giá trị khi disable, không tự tạo latch. Cần đọc event control trước khi kết luận từ hình dạng if. Cũng không phải latch nào cũng là bug: thiết kế có thể chủ ý cần nó, nhưng phải có timing/verification phù hợp. [3]

Default 0 là một thay đổi chức năng cần có yêu cầu

complete_path gán q 0 đầu mỗi evaluation, sau đó nếu en 1 thì ghi d. Khi en 0, output phải 0, bất kể lịch sử. Bản này không giữ state và Yosys không suy latch/FF.

Nếu yêu cầu thực sự là “giữ dữ liệu lúc disable”, default 0 làm sai chức năng dù lint bớt warning. Trước sửa phải xác định output disabled cần giá trị 0, một giá trị khác, hay state có chủ đích. Không chọn default chỉ để bộ kiểm xanh.

Tương tự, gán q=q không phải một default tổ hợp xóa latch: nó vẫn diễn đạt giữ state. Các quy tắc chuẩn đầy đủ còn [4].

Warning đúng vẫn phải được hiểu

Verilator báo LATCH cho missing_path; metadata giữ warning dự kiến, không tắt nó hoặc tuyên bố module này là combinational sạch. Parse đạt chỉ nói cú pháp hợp lệ. Simulation kiểm được hành vi giữ; synth kiểm được latch count. Mỗi check có một vai trò.

TB drive input rõ sau khi các process @* đã chờ event, rồi mới kiểm. Bản thử đầu chỉ dùng declaration initializer khiến cả output comb còn X ở phép đọc đầu, vì chưa có event như TB đã giả định. Sửa stimulus cho transition rõ ràng, giữ nguyên expected và checker; không đổi unknown thành 0 để che vấn đề. [5]

Sáu ca 4-state và 4 latch so với 0

Tính trước chạy: ban đầu heldXXXX/comb 0; mởena →a/a; đóng đổi 5 →a/0; mở →5/5; đổi 3 →3/3; đóng đổiF →3/0. Sáu ca kiểm bằng case inequality để không bỏ qua X/Z bất ngờ.

Thiếu đường gán tạo state giữ giá trị

Đối chiếu missing branch với default tổ hợp: Icarus giữ X ban đầu và giá trị trước, Yosys suy ra 4 latch so với 0.

missing_path.sv RTL
`timescale 1ns/1ps// Deliberately incomplete: this is storage, not a combinational zero default.module missing_path(input wire en, input wire [3:0] d, output reg [3:0] q);  always @* if(en) q=d;endmodule
complete_path.sv RTL
`timescale 1ns/1psmodule complete_path(input wire en, input wire [3:0] d, output reg [3:0] q);  always @* begin    q=0;    if(en) q=d;  endendmodule
tb_latch.sv testbench
`timescale 1ns/1psmodule tb_latch;  reg en;  reg [3:0] d;  wire [3:0] held,comb;  integer checks=0;  missing_path storage(en,d,held);  complete_path fixed_comb(en,d,comb);  task automatic check_values(input reg [3:0] want_held,want_comb);    if(held !== want_held || comb !== want_comb) $fatal(1,"latch mismatch at=%0t held=%h comb=%h",$time,held,comb);    checks=checks+1;  endtask  initial begin    #0; en=0; d=0; // Register @* waiters before the explicit input transition.    #1; check_values(4'bxxxx,0);    en=1;d=4'ha; #1; check_values(4'ha,4'ha);    en=0;d=5; #1; check_values(4'ha,0);    $display("LATCH HOLD first=%h comb=%h",held,comb);    en=1; #1; check_values(5,5);    d=3; #1; check_values(3,3);    en=0;d=4'hf; #1; check_values(3,0);    if(checks!=6) $fatal(1,"missing latch cases");    $display("LATCH CHECK cases=%0d second_hold=%h comb=%h",checks,held,comb);    $finish;  endendmodule

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

  • Phân tích và elaborate theo LRM (pyslang 12.1.0)
  • Lint -Wall (Verilator 5.050)
  • Mô phỏng, exit 0 và output khớp kỳ vọng tính tay (Icarus Verilog 11.0, 4-state)
  • Tổng hợp, số cell khớp kỳ vọng (Yosys 0.70)

Output phải khớp: LATCH HOLD first=a comb=0LATCH CHECK cases=6 second_hold=3 comb=0

Kỳ vọng sau tổng hợp: missing_path: $_DLATCH_P_ = 4missing_path: $_*DFF* = 0complete_path: $_*DLATCH* = 0complete_path: $_*DFF* = 0

Kỳ vọng trước chạy: ban đầu heldXXXX/comb 0, mởena ->a/a; đóng đổi 5 ->a/0; mở ->5/5; đổi 3 ->3/3; đóng đổiF ->3/0.6 check.

LATCH là warning dự kiến của example cố ý lỗi; không tắt diagnostic hoặc claim latch luôn sai thiết kế.

Default 0 thực hiện yêu cầu output 0 khi disabled; không thêm default máy móc nếu thiết kế thực sự cần giữ state.

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.

Synthesis expected là 4 latch/0 FF ở missing_path,0 latch/0 FF ở complete_path. TB đã chạy Icarus 4-state và lint giữ đúng warning LATCH. Không gọi ví dụ này là STA hoặc bằng chứng mọi latch đều phải loại bỏ. [6]

Tự kiểm tra

Tự kiểm tra: latch-inference

  1. Missing_path đã nạp a, en 0 rồi d5. Held/comb của bài là gì?
  2. En vẫn 1, đổi d từ 5 sang 3 mà không có clock. Held của latch làm gì?
  3. Yosys generic của missing_path4 bit và complete_path có số latch nào?
  4. Yêu cầu thật cần giữ state khi disabled. Thêm default 0 để hết warning có đúng không?
  5. Thiếu else trong always@(posedge clk) nếu en 0 có tự tạo latch không?

Kiểm mọi output ở mọi đường đi

Vẽ yêu cầu output khi các điều kiện đều false; nếu câu trả lời phụ thuộc lịch sử, hãy nhận diện state đó một cách chủ ý. Khi sửa, kiểm lại giá trị và cấu trúc phần cứng, không chỉ đếm warning.

Bài giữ draft/LRM needs-spec-check; những gì đã được xác nhận là sáu ca và các cell check của đúng hai module trong flow hiện tại.

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

  1. D Latch — bản chụp trong resources.zip, Latch và điều kiện giữ. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. Thí nghiệm nguyên bản ex.a8.latch-inference, Cell check. Trích dẫn; nguồn đã đọc toàn văn.
  3. D Latch — bản chụp trong resources.zip, What is a D Latch?. Trích dẫn; nguồn đã đọc các mục liên quan.
  4. 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ở).
  5. Thí nghiệm nguyên bản ex.a8.latch-inference, Source và check thực. Trích dẫn; nguồn đã đọc toàn văn.
  6. Thí nghiệm nguyên bản ex.a8.latch-inference, Bằng chứng nguyên bản. Trích dẫn; nguồn đã đọc toàn văn.
  7. IEEE 1800-2023 SystemVerilog LRM, RTL assignments and simulation semantics: latch-inference. Chưa đối chiếu với văn bản nguồn (chưa mở).
  8. Thí nghiệm nguyên bản ex.a8.latch-inference, Source, assertions, metadata và verification.json. Trích dẫn; nguồn đã đọc toàn văn.
  9. IEEE 1800-2023 SystemVerilog LRM, Procedural assignments; level-sensitive processes; initialization and event sensitivity. Chưa đối chiếu với văn bản nguồn (chưa mở).
  10. D Latch — bản chụp trong resources.zip, What is a D Latch?; Syntax. Trích dẫn; nguồn đã đọc các mục liên quan.
  11. Thí nghiệm nguyên bản ex.a8.latch-inference, missing_path.sv, complete_path.sv, tb_latch.sv và verification.json. Trích dẫn; nguồn đã đọc toàn văn.