Always_comb, always_ff và always_latch: nói rõ phần cứng định mô tả

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

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

  • Phân biệt cập nhật tổ hợp, giữ theo level và lấy mẫu theo edge
  • Kiểm reset đồng bộ trước và sau clock thay vì suy từ tên rst_n
  • Tách intent keyword, quy tắc ngôn ngữ và mức enforcement của tool

Một input đổi, ba output không cần đổi giống nhau

Cùng a/b đi vào mux, một FF và một latch. Khi đổi a lúc không có cạnh clock và gate đóng, y tổ hợp có thể đổi ngay, q phải giữ theo FF, held phải giữ theo latch. Keyword giúp đọc ý định, còn waveform/checker phải chứng minh contract cụ thể ấy.

Always_comb cho mô tả tổ hợp đầy đủ

Ví dụ gán y theo sel ở mọi đường, không có trạng thái cần giữ. Không viết event list bằng tay. Bỏ một nhánh assignment không tự được keyword sửa thành một hàm đúng; tool có thể báo mismatch intent hoặc latch tùy flow. Ngôn ngữ còn có quy tắc về time-zero evaluation, function sensitivity và writer, nhưng bài chỉ claim các stimulus/check đã chạy. [1]

Always_ff vẫn cần event control đúng

Q dùng always_ff @(posedge clk) và NBA. Reset active-low nằm trong thân, nên đồng bộ: kéo rst_n0 giữa hai cạnh chưa làm q đổi ngay. Thêm negedge reset vào event control sẽ đổi contract thành async. Dùng NBA cho state là guideline tránh race ở đây; không nói keyword bắt buộc mọi assignment phải là NBA trong mọi ngữ cảnh.

Always_latch cho phép đường giữ có chủ ý

Held nhận a khi gate 1 và giữ khi gate 0. Không có reset latch trong ví dụ, nên ban đầu heldX. Đây là storage level-sensitive đã yêu cầu, khác thiếu else ngoài ý muốn trong always_comb. Không thêm default 0 nếu mục tiêu thật là giữ giá trị. [2]

Reset đồng bộ phải được kiểm trước cạnh

TB đặt rst_n0 nhưng chưa phát cạnh, q vẫnX trong Icarus; sau tick đầu q 0. Cuối testcase, q đange, kéo rst_n0 và kiểm nó vẫn e trước tick reset rồi mới về 0. Như vậy một mutant đổi sang async reset không thể pass chỉ nhờ cùng giá trị cuối.

Kiểm sau NBA và đổi stimulus ngoài cạnh

Task tick phát cạnh rồi đợi 1 ns mới so q. Các thay đổi control/data được thực hiện khi clk 0, nên không tạo race driver/checker với FF ở cùng Active event. Phân biệt ý định RTL với vị trí sample trong TB; cùng keyword đúng nhưng TB sample sớm vẫn có thể kết luận sai.

Keyword không thay review ownership và reset

Mỗi output ở đây có một procedural owner rõ. Không suy từ một lượt lint sạch rằng mọi tool đều từ chối tất cả kiểu multiple writers hoặc sensitivity/function corner case. Các rule chính thức còn needs-spec-check; điều đã kiểm là hành vi mux/latch/FF và cell count của chính source này.

Năm tick và ba cách giữ dữ liệu

Expected tính trước: reset/capture 5/capture 9/capturee/reset, tổng 5 tick; y cuối e, held giữ 5, q cuối 0 và q ban đầuX.

Thí nghiệm always-x

Tính trước:5tick(reset/capture 5/capture 9/capturee/reset), comb cập nhật ngoài cạnh, latch giữ 5; trước cạnh reset qX, cuốiq 0/ye/held 5.

tb_always.sv testbench
`timescale 1ns/1psmodule tb_always;  logic clk,rst_n,sel,gate;  logic[3:0] a,b;  wire[3:0] y,q,held;  int ticks=0;  always_kinds dut(.*);  task automatic tick(input logic[3:0] expected_q);    #1 clk=1;    #1;    if(q!==expected_q)$fatal(1,"always_ff q mismatch tick=%0d got=%h expected=%h",ticks,q,expected_q);    ticks++;clk=0;  endtask  initial begin    clk=0;rst_n=0;sel=0;gate=0;a=5;b=10;    #1;    if(y!==10||q!==4'bx||held!==4'bx)$fatal(1,"initial comb or synchronous-reset contract");    tick(0);    rst_n=1;sel=1;gate=1;    #1;if(y!==5||held!==5)$fatal(1,"comb and transparent latch");    tick(5);    gate=0;a=9;    #1;if(y!==9||held!==5||q!==5)$fatal(1,"comb versus held latch and FF");    tick(9);    sel=0;b=14;    #1;if(y!==14||q!==9)$fatal(1,"FF changed without a clock");    tick(14);    rst_n=0;    #1;if(q!==14)$fatal(1,"synchronous reset acted asynchronously");    tick(0);    if(ticks!=5||held!==5||y!==14)$fatal(1,"always final accounting");    $display("ALWAYS CHECK ticks=5 comb=e held=5 reset_q=0 initial_q_unknown=1");    $finish;  endendmodule
always_kinds.sv RTL
`timescale 1ns/1psmodule always_kinds(input logic clk,rst_n,sel,gate,input logic[3:0] a,b, output logic[3:0] y,q,held);  always_comb y=sel?a:b;  always_ff @(posedge clk)    if(!rst_n)q<=0;else q<=y;  always_latch if(gate)held=a;endmodule

Đã 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: ALWAYS CHECK ticks=5 comb=e held=5 reset_q=0 initial_q_unknown=1

Kỳ vọng sau tổng hợp: always_kinds: $_*DFF* = 4always_kinds: $_*DLATCH* = 4

Chỉ mux/FF/reset đồng bộ/latch và generic 4 FF 4 latch trong source. Không claim mọi tool enforce đầy đủ intent/writer/function-sensitivity rule, power-up silicon, STA hoặc PPA.

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.

Parse/lint/Icarus/Yosys đạt; generic 4 FF và 4 latch, không phải PPA/STA hoặc bảo đảm reset silicon. [3]

Tự kiểm tra

Tự kiểm tra: always-x

  1. Q đang e, rst_n hạ giữa hai cạnh trong example: trước cạnh kế q thế nào?
  2. Gate 0, a đổi 5→9: held và y khi sel 1 cho gì?
  3. Generic cells của example cho FF/latch bao nhiêu bit?
  4. Trước tick reset đầu tiên, q trong Icarus là gì?
  5. Keyword always_comb làm gì với nhánh thiếu assignment?

Chốt thời điểm nào output được phép đổi

Dùng keyword để diễn đạt intent, event control để diễn đạt clock/reset, assignment coverage để diễn đạt storage. Sau đó kiểm cả thời điểm output phải đổi lẫn thời điểm nó phải giữ. Bài vẫn draft/LRM needs-spec-check.

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

  1. SystemVerilog always\_comb, always\_ff — bản chụp resources.zip, Intent và syntax. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. SystemVerilog always\_comb, always\_ff — bản chụp resources.zip, Latch intent. Trích dẫn; nguồn đã đọc các mục liên quan.
  3. Thí nghiệm nguyên bản ex.b3.always-x, Bằng chứng. Trích dẫn; nguồn đã đọc toàn văn.
  4. IEEE 1800-2023 SystemVerilog LRM, always-x procedural semantics. 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.b3.always-x, Source, self-checks, metadata, verification.json và mutation probes. Trích dẫn; nguồn đã đọc toàn văn.
  6. SystemVerilog always\_comb, always\_ff — bản chụp resources.zip, Syntax; always_comb; always_latch; always_ff. Trích dẫn; nguồn đã đọc các mục liên quan.