Đọc Verilog từ token đến bốn trạng thái 0/1/X/Z

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

Tiên quyết

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

  • Đọc literal có độ rộng và phân biệt identifier hoa/thường
  • Giải thích X và Z bằng mô hình mô phỏng số, không gán chúng cho điện áp cụ thể
  • Dự đoán bitwise logic, equality và điều kiện khi có X
  • Dùng case inequality trong self-check để không bỏ sót kết quả unknown

Đọc đúng ký hiệu trước khi suy luận mạch

HDL mô tả phần cứng nhưng trước hết vẫn là một ngôn ngữ có cú pháp. Nhầm độ rộng literal hoặc tên biến có thể khiến bạn debug một mạch khác với mạch mình tưởng đã viết. Bài bắt đầu từ chương trình nhỏ, in kết quả và tự dừng khi kết quả sai.

Ta dùng SystemVerilog, file .sv, Icarus Verilog 11.0 với chế độ -g2012. Simulator này giữ bốn trạng thái trong những phép toán của ví dụ. Verilator của pipeline vẫn dùng cho các bài khác; không lấy kết quả 2-state của nó làm bằng chứng về X/Z.

Các nhận xét dưới đây được minh hoạ bằng chương trình đã chạy; quy tắc đầy đủ về token, literal và expression còn cần [1]. Bài giữ draft.

Token, identifier và thời gian

Trong logic ready = 1'b1;, logic là từ khóa, ready là identifier, = là phép khởi tạo ở khai báo và 1'b1 là literal. Dấu ; kết thúc khai báo. Khoảng trắng giúp người đọc nhưng không được tùy ý chèn vào giữa các ký tự cấu thành một token.

TB có cả ready=1 và Ready=0. Hai tên khác nhau và hai giá trị cùng tồn tại; không phải lần gán sau đổi giá trị tên trước. Với tên dài, việc chỉ khác một chữ hoa dễ làm review bỏ sót, nên thực hành tốt là chọn tên khác rõ ý nghĩa.

Comment // ... tới hết dòng và /* ... */ là phần giải thích, không phải assertion. Dòng “expected 1” trong comment không kiểm được bất kỳ điều gì; TB phải dùng phép so sánh và $fatal thật.

timeunit 1ns và timeprecision 1ps trong module TB làm bước #1 ở bài này là 1 ns, không phải một chu kỳ clock. Ví dụ không có clock. Những directive bắt đầu bằng dấu backtick như `timescale thuộc lớp xử lý source; đừng nhầm với dấu nháy đơn trong literal.

Một byte viết theo ba cơ số

8'b1010_0101, 8'ha5, 8'o245 và 8'd165 cùng biểu diễn byte nhị phân 10100101. Tính tay: 128+32+4+1=165; hai nhóm nibble là a và 5. Dấu _ trong literal nhị phân chỉ giúp đọc nhóm bit.

Trong các literal này, số 8 là độ rộng, chữ b/h/o/d chọn cơ số. Cùng giá trị toán học không có nghĩa literal không ghi độ rộng sẽ có mọi hành vi giống nhau trong biểu thức. Trước khi cộng/dịch, cần đọc tiếp bài width/signedness; không dùng một quy tắc đoán chung cho mọi literal unsized.

TB khẳng định cả giá trị lẫn $bits(8'ha5)==8. Kết quả byte=a5 bits=8 vì vậy không chỉ là dòng $display viết tay.

X là chưa biết, Z là không drive

Mô hình bốn trạng thái có 0, 1, X và Z. X diễn tả giá trị chưa biết trong mô hình số; Z diễn tả trạng thái trở kháng cao của một driver/net trong các ngữ cảnh tương ứng.

Trong TB, biến uninitialized chưa được gán nên quan sát là X; net floating_net không có driver nên quan sát là Z. TB đợi #1, kiểm bằng !== rồi mới in uninit=x floating=z. Đây là quan sát thực từ Icarus, không phải sơ đồ minh hoạ vẽ tay. [2]

Không suy ra X là một mức điện áp thứ ba hoặc Z bảo đảm chân chip an toàn. Metastability, leakage, nguồn điện và mức điện áp cần mô hình/phép đo khác. Dùng X để tìm lỗi khởi tạo trong simulation cũng không tự chứng minh reset vật lý đúng.

Không phải cứ có X là kết quả X

Tính một bit trước: 0 & X bằng 0, vì dù X thay bằng 0 hay 1, phép AND vẫn ra 0. Ngược lại 0 | X và 0 ^ X đều chưa xác định nên ra X trong ví dụ. Với 1 | X, bit 1 đã quyết định output là 1.

TB duyệt đủ 16 cặp đầu vào từ tập 0/1/X/Z. Oracle dùng chỉ số trạng thái: AND có 0 thì ra 0; cả hai là 1 thì ra 1; còn lại ra X. OR làm tương tự với bit 1 quyết định. XOR chỉ có kết quả 0/1 khi cả hai đầu vào đều 0/1.

Trong các phép bitwise đã kiểm, Z không phải một bit 0 hoặc 1 có thể cộng tùy ý. Mạch tri-state và cách nhiều driver resolve lên net được học ở bài net/variable.

Equality và điều kiện có X

Trong ví dụ, 1'bx == 1'bx cho X. Để kiểm bit pattern có đúng X hay không, TB dùng case equality/inequality === và !==, cho kết quả xác định ở các phép so sánh đã viết. Ví dụ 1'bx === 1'b0 cho 0. Không dùng if (actual != expected) rồi giả định nó luôn phát hiện actual là X: điều kiện unknown có thể không đi vào nhánh báo lỗi.

Một khác biệt đáng thử:

merged = condition ? 4'b1010 : 4'b1001;
if (condition) if_result = 4'b1010;
else           if_result = 4'b1001;

Khi condition=X, toán tử ?: của ví dụ giữ các bit bằng nhau giữa hai nhánh và gộp bit khác thành X: 10xx. Cấu trúc if đi nhánh else nên if_result=1001. Không thay thế hai cách viết rồi khẳng định tương đương cả khi unknown.

Hello world có tự kiểm tra 16 cặp

Trước khi chạy, dự đoán bốn dòng: byte a5 rộng 8 bit; hai identifier có giá trị 1/0 riêng; net thả nổi Z và biến chưa gán X; cuối cùng điều kiện X tạo 10xx so với 1001.

Literal và bốn trạng thái bằng Icarus

Kiểm literal, identifier phân biệt hoa thường và 16 cặp 0/1/X/Z bằng simulator 4-state.

tb_lexical.sv testbench
module tb_lexical;  timeunit 1ns;  timeprecision 1ps;  logic uninitialized;  wire floating_net;  logic ready = 1'b1, Ready = 1'b0;  logic a, b, expected_and, expected_or, expected_xor, expected_eq;  logic condition = 1'bx;  logic [3:0] merged, if_result;  int cases_checked = 0;  function automatic logic state(input int index);    case (index)      0: state = 1'b0;      1: state = 1'b1;      2: state = 1'bx;      3: state = 1'bz;      default: $fatal(1, "bad state index");    endcase  endfunction  initial begin    #1;    if (uninitialized !== 1'bx || floating_net !== 1'bz ||        ready !== 1'b1 || Ready !== 1'b0 ||        8'b1010_0101 !== 8'ha5 || 8'o245 !== 8'd165 || $bits(8'ha5) != 8)      $fatal(1, "lexical or initial state mismatch");    $display("LEXICAL RESULT byte=%0h bits=%0d ready=%b Ready=%b uninit=%b floating=%b",             8'b1010_0101, $bits(8'ha5), ready, Ready, uninitialized, floating_net);    for (int i = 0; i < 4; i++) begin      for (int j = 0; j < 4; j++) begin        a = state(i); b = state(j);        expected_and = (i == 0 || j == 0) ? 1'b0 :                       (i == 1 && j == 1) ? 1'b1 : 1'bx;        expected_or = (i == 1 || j == 1) ? 1'b1 :                      (i == 0 && j == 0) ? 1'b0 : 1'bx;        expected_xor = (i < 2 && j < 2) ? 1'(i ^ j) : 1'bx;        expected_eq = (i < 2 && j < 2) ? 1'(i == j) : 1'bx;        if ((a & b) !== expected_and || (a | b) !== expected_or ||            (a ^ b) !== expected_xor || (a == b) !== expected_eq ||            (a === b) !== (i == j))          $fatal(1, "four state mismatch i=%0d j=%0d", i, j);        cases_checked++;        if (i == 0 && j == 2)          $display("TRUTH RESULT and=%b or=%b xor=%b", a & b, a | b, a ^ b);      end    end    merged = condition ? 4'b1010 : 4'b1001;    if (condition) if_result = 4'b1010; else if_result = 4'b1001;    if (merged !== 4'b10xx || if_result !== 4'b1001 || cases_checked != 16)      $fatal(1, "unknown condition mismatch");    $display("EQ RESULT logical=%b case=%b merge=%b if_else=%b",             1'bx == 1'bx, 1'bx === 1'b0, merged, if_result);    $display("LEXICAL CASES checked=%0d", cases_checked);    $finish;  endendmodule

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

  • Phân tích và elaborate theo LRM (pyslang 12.1.0)
  • Mô phỏng, exit 0 và output khớp kỳ vọng tính tay (Icarus Verilog 11.0, 4-state)

Output phải khớp: LEXICAL RESULT byte=a5 bits=8 ready=1 Ready=0 uninit=x floating=zTRUTH RESULT and=0 or=x xor=xEQ RESULT logical=x case=0 merge=10xx if_else=1001LEXICAL CASES checked=16

Icarus 11.0 chạy SystemVerilog subset của ví dụ; không xác minh mọi literal/identifier hoặc toàn bộ LRM.

X/Z là trạng thái trong mô hình số, không phải phép đo metastability, điện áp hoặc timing silicon.

Ví dụ TB không synthesizable; không claim lint, synthesis hoặc trace extraction.

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.

TB kiểm literal, tên, trạng thái ban đầu, AND/OR/XOR, hai phép equality và điều kiện. Chỉ sau các assertion mới in tổng kết LEXICAL CASES checked=16. Icarus kết thúc exit 0 và output phải khớp kỳ vọng thì pipeline mới cấp simulated. Parse toàn bộ bằng pyslang cũng đạt. [3]

Lỗi nhỏ ở ký hiệu, hậu quả lớn ở debug

  • Nhìn Ready như ready: kiểm tên đúng scope và đúng hoa/thường.
  • Đọc hằng hex mà quên độ rộng: ghi số bit và miền giá trị trước khi tính.
  • Coi Z là giá trị dữ liệu bình thường: xác định ai đang drive net.
  • Coi == là phép so bit pattern X/Z tuyệt đối: chọn phép so sánh theo mục tiêu TB, không sửa RTL chỉ để che unknown.
  • Cho rằng if và ?: luôn xử lý X như nhau: ví dụ đã chạy cho hai kết quả khác nhau.
  • Gọi mọi X là bug silicon: trước hết đây là thông tin của mô hình mô phỏng số.

Tự kiểm tra

Tự kiểm tra: lexical

  1. 8'b1010_0101 trong ví dụ rộng bao nhiêu bit và bằng bao nhiêu thập phân?
  2. Trong ví dụ 4-state, 0 & X cho gì?
  3. 1'bx === 1'b0 trong TB cho gì?
  4. condition=X; condition ? 1010 : 1001 trong ví dụ cho bit pattern nào?
  5. ready=1 và Ready=0 trong TB mô tả gì?

Đọc một dòng HDL có kiểm chứng

Đọc tên, độ rộng, cơ số và loại phép toán. Tính tay một trường hợp nhị phân và một trường hợp có X/Z nếu chủ đề cần. Dùng simulator giữ đúng các trạng thái đó, kiểm kết quả bằng assertion và xem exit status.

Bài đã chạy đúng chương trình và các cặp đã nêu; chưa xác minh toàn bộ quy tắc literal, escaped identifier, string, scheduling hoặc điện áp thực. Nhãn bằng chứng và nhãn đối chiếu đặc tả là hai thông tin riêng.

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

  1. IEEE 1800-2023 SystemVerilog LRM, đối chiếu LRM. Chưa đối chiếu với văn bản nguồn (chưa mở).
  2. Thử nghiệm A6.lexical: source và verification.json, Output khởi tạo. Trích dẫn; nguồn đã đọc toàn văn.
  3. Thử nghiệm A6.lexical: source và verification.json, Bằng chứng chạy. Trích dẫn; nguồn đã đọc toàn văn.
  4. IEEE 1800-2023 SystemVerilog LRM, Lexical conventions, four-state values, equality and conditional operator. Chưa đối chiếu với văn bản nguồn (chưa mở).
  5. Thử nghiệm A6.lexical: source và verification.json, Ví dụ đã chạy: source và verification.json. Trích dẫn; nguồn đã đọc toàn văn.
  6. IEEE 1800-2023 SystemVerilog LRM, Lexical conventions; four-state values; equality and conditional expressions. Chưa đối chiếu với văn bản nguồn (chưa mở).
  7. Thử nghiệm A6.lexical: source và verification.json, tb_lexical.sv và verification.json. Trích dẫn; nguồn đã đọc toàn văn.