Mở đầu: Khi lập trình viên lần đầu mở file Verilog
Bạn vừa hoàn thành Series 10 — hiểu rõ cổng logic, D Flip-Flop, và cách ghép chúng thành mạch tuần tự trên
breadboard hoặc mô phỏng. Giờ bạn mở file .v đầu tiên, thấy cú pháp gần giống C, và theo phản
xạ tự nhiên bắt đầu đọc nó từ trên xuống dưới, tưởng tượng dòng lệnh này chạy xong mới
đến dòng kế tiếp. Vài dòng sau bạn bối rối: tại sao thứ tự viết assign không ảnh hưởng tới
kết quả? Tại sao 2 khối always "không hề gọi lẫn nhau" mà vẫn đồng bộ tăm tắp? Đây chính xác
là điểm rẽ nhánh giữa tư duy phần mềm và tư duy phần cứng — và là lý do
hầu hết lập trình viên viết đúng cú pháp Verilog nhưng tạo ra mạch hoạt động sai hoàn toàn trong
tuần đầu tiên học HDL.
Bài này giải quyết đúng điểm rẽ nhánh đó trước khi bạn viết một dòng SystemVerilog thực chiến nào. Bạn sẽ thấy 4 mức trừu tượng mà một con chip được xây từ đó, vì sao HDL mô tả phần cứng song song chứ không thực thi tuần tự, toàn cảnh quy trình biến 1 file text thành 1 con chip thật (RTL → GDSII), và bức tranh các ngôn ngữ HDL đang được dùng trong công nghiệp. Cuối bài, một sân chơi tương tác sẽ để chính bạn chứng minh điều quan trọng nhất: cùng một mạch, viết 3 kiểu code hoàn toàn khác nhau, vẫn ra đúng 1 phần cứng giống hệt.
1. Bốn mức trừu tượng thiết kế vi mạch
Khi thiết kế một vi mạch, kỹ sư không viết code từng transistor. Thay vào đó, họ làm việc ở các mức trừu tượng khác nhau, từ cơ bản nhất (transistor cứng) đến cao nhất (mô tả hành vi toán học):
| Mức | Tên gọi | Mô tả | Ví dụ |
|---|---|---|---|
| 1 | Transistor | Viết điều kiện dẫn (conductivity) từng transistor NMOS/PMOS. Tính toán độ rộng/dài (W/L ratio) để điều chỉnh dòng. | NMOS with W=2µm, L=100nm |
| 2 | Gate / Cổng Logic | Ghép nối các cổng logic (AND, OR, XOR, FF). Bao gồm thông số dây nối và transistor tuning từ mức trước. | Mux 2-1: y = (s) ? a : b = 1 XOR + 2 AND + 1 OR |
| 3 | RTL | Mô tả sự chuyển tiếp dữ liệu giữa các thanh ghi (registers) qua logic tổ hợp (combinational). Code HDL (Verilog, SystemVerilog, VHDL). | always_ff @(posedge clk) result <= data_in; |
| 4 | Behavioral / Hệ thống | Mô tả hành vi toàn chuỗi (pipeline, state machine, protocol). Tương đương với mô hình toán học cao cấp (SystemC, Chisel). | output = FFT(input) (mô tả chiều cao, không chi tiết) |
Các mức này được gọi là "hierarchical design" — mỗi mức phục vụ một mục đích:
- Transistor: Tối ưu hóa tiêu thụ điện, tốc độ, diện tích ở mức chi tiết nhất (công việc của layout designer).
- Gate: Kiến trúc cơ bản của các module (công việc của digital designer).
- RTL: Thiết kế chính (công việc của RTL designer) — phần bạn sẽ học ở series này.
- Behavioral: Kiểm chứng (verification) và mô hình hoá hệ thống (system modeling).
Nên có: Series C (biểu diễn số, con trỏ & bộ nhớ) — nền tảng đọc hiểu cú pháp gần C của SystemVerilog.
Tài nguyên ngoài: HDLBits, ChipVerify, EDA Playground.
2. HDL khác lập trình thế nào?
Đây là hiểu nhầm số 1 của lập trình viên khi chuyển sang HDL: "Ồ, Verilog là ngôn ngữ lập trình, tôi viết code như C, chạy từ trên xuống dưới". Sai!
int x = 5;
x = x + 10; // Thực thi từng dòng, x lúc này = 15
printf("%d", x);
HDL (Verilog):
assign y = a + b; // Đây KHÔNG phải "câu lệnh" tuần tự
always_comb z = x & y; // Cả hai lệnh chạy ĐỒNG THỜI, không theo thứ tự
Cả assign và always_comb chạy cùng lúc, y và z cập nhật tức
thời khi a, b, hoặc x thay đổi. Nếu bạn viết code như Python, trình tổng hợp (synthesis tool) sẽ tạo ra
phần cứng sai hoàn toàn.
Sự khác biệt cốt lõi:
- Lập trình: "Làm cái này rồi làm cái kia" (tuần tự, serial)
- HDL: "Tất cả cái này chạy cùng lúc, kết nối với nhau" (song song, parallel)
Hãy nghĩ về nó theo cách vật lý hơn là cú pháp: mỗi cổng logic trong 1 con chip là 1 miếng silicon thật,
luôn ở trạng thái "sẵn sàng" — chỉ cần điện áp đầu vào đổi, đầu ra của nó đổi theo gần như tức thời (vài
phần nghìn tỷ giây), bất kể bạn viết dòng assign đó ở trên hay dưới file. Không hề có "con
trỏ chương trình" nào chạy qua từng dòng như CPU thực thi lệnh — toàn bộ mạch tồn tại và hoạt động
cùng một lúc, giống hàng nghìn công tắc đèn được nối dây sẵn, tất cả cùng phản ứng ngay
khi bạn bật nguồn. Đây cũng là lý do một lỗi tư duy tuần tự (vd viết vòng lặp for mong đợi nó
"chạy qua nhiều chu kỳ" bên trong 1 khối tổ hợp) không chỉ cho ra kết quả sai — nó có thể khiến trình tổng
hợp từ chối tổng hợp hoặc tạo ra hàng nghìn cổng logic lặp lại một cách vô nghĩa.
3. Design Flow: RTL → GDSII
Khi bạn viết code RTL, nó không phải là "chương trình chạy trên máy tính". Nó là bản thiết kế mà công cụ EDA (Electronic Design Automation) sẽ chuyển đổi thành sơ đồ mạch thực tế (bản vẽ chip).
Toàn bộ quy trình được gọi là Design Flow:
- RTL Code: Viết Verilog/SystemVerilog/VHDL mô tả phần cứng ở mức RTL.
- Simulation: Dùng simulator (Modelsim, VCS) kiểm chứng logic hoạt động đúng (testbench).
- Synthesis: Tool (Yosys, Design Compiler) chuyển RTL → netlist cổng logic (gate-level netlist).
- Place & Route: Tool (Cadence Innovus, nextpnr) đặt cổng trên die và dây nối tối ưu → layout.
- DRC/LVS: Kiểm tra thiết kế vật lý tuân thủ quy tắc (Design Rule Check, Layout vs Schematic).
- GDS II Generation: Tạo file bản vẽ cuối cùng (GDSII) gửi tới nhà máy (fab) để in chip.
4. Verilog vs SystemVerilog vs VHDL vs Chisel vs HLS
Có nhiều ngôn ngữ HDL khác nhau. Series này chọn SystemVerilog vì sao?
| Ngôn ngữ | Xuất xứ | Đặc điểm | Phổ biến ở |
|---|---|---|---|
| Verilog (1984) | Gateway Design Automation (Cadence mua lại năm 1989) | Đơn giản, giống C, cũ. Ít tính năng verification. | Dự án cũ, FPGA hobbist |
| SystemVerilog (2005) | Accellera, chuẩn hoá IEEE 1800-2017. Superset của Verilog. | Thêm assertion (SVA), testbench hướng đối tượng (OOP), constrained-random. Chuẩn công nghiệp. | ASIC design, verification ✓ |
| VHDL (1987) | VHSIC (Quốc phòng Mỹ) | Dài dòng, ada-like syntax, mạnh verification. Ít phổ biến ở công nghiệp hiện đại. | Aerospace, quốc phòng |
| Chisel (2012) | UC Berkeley | HDL sinh ra từ Scala (JVM). Giảm bớt boilerplate code. | Startup, RISC-V design |
| HLS (High-Level Synthesis) | Catapult, Vivado HLS (Xilinx) | Viết C/C++ → tự sinh Verilog. Nhanh prototype nhưng kết quả tối ưu kém. | Mẫu nhanh, xử lý tín hiệu |
Series này dạy SystemVerilog vì:
- ✅ Chuẩn công nghiệp ASIC/FPGA hiện tại
- ✅ Cú pháp gần C → dễ tiếp cận lập trình viên
- ✅ Mạnh verification (SVA, constrained-random)
- ✅ Mỗi bài sẽ note cú pháp Verilog cũ tương đương → đọc được code legacy
5. Sân chơi tương tác: Mux 2-1 viết 3 kiểu — Tour RTL Playground
Cùng một mạch logic đơn giản (Mux 2-1: chọn a hoặc b tùy theo
tín hiệu chọn s) có thể viết bằng 3 kiểu RTL khác nhau. Đây chính là bằng chứng trực tiếp cho
luận điểm ở Mục 2: code RTL là bản thiết kế phần cứng, không phải chương trình — dù bạn
diễn đạt logic theo cách nào, sau khi
synthesis nó luôn ra
đúng cùng một netlist cổng logic. Bấm nút bên dưới để tự kiểm chứng, đây chính là bản thu
gọn của RTL Playground mà các bài sau sẽ dùng lại.
Bấm nút a/b/s để đổi tín hiệu đầu vào — dây dẫn "mang giá trị
1" sẽ tô sáng màu lime. Đổi kiểu code phía trên (Structural/Dataflow/Behavioral): netlist và kết quả
y luôn giống hệt nhau, dù mã nguồn trông rất khác nhau.
module mux2_1_structural (
input a, b, s,
output y
);
wire not_s, and_a, and_b;
not NOT_GATE (not_s, s);
and AND_A (and_a, a, not_s);
and AND_B (and_b, b, s);
or OR_GATE (y, and_a, and_b);
endmodule
Style: Liệt kê từng cổng AND, OR, NOT như bản thiết kế vật lý — instantiate cổng
nguyên thủy (gate primitive) bằng tên chuẩn Verilog (not, and,
or). Bạn thấy đúng những cổng nào được dùng, nhưng khó bảo trì (đổi logic = viết lại toàn
bộ dây nối).
module mux2_1_dataflow (
input a, b, s,
output y
);
assign y = (a & ~s) | (b & s);
endmodule
Style: Ghi công thức Boolean trực tiếp bằng toán tử bitwise (&
AND, | OR,
~ NOT). Trình synthesis tự phân tích công thức và tạo
cổng — cân bằng giữa rõ ràng và linh hoạt, thường dùng ở phần tổ hợp (combinational).
module mux2_1_behavioral (
input a, b, s,
output reg y
);
always @(a, b, s) begin
if (s == 0)
y = a;
else
y = b;
end
endmodule
Style: Viết như lập trình với if/else, trình synthesis sẽ
"suy ra" đây là multiplexer. Dễ viết, dễ đọc, dễ bảo trì nhất — thường dùng ở phần tuần tự
(sequential), sẽ học kỹ ở Bài 3.
- Structural: Dùng khi bạn biết chính xác cổng nào cần (tối ưu điện năng, diện tích thủ công). Khó bảo trì — thay đổi logic nghĩa là viết lại toàn bộ danh sách cổng.
- Dataflow: Cân bằng giữa rõ ràng và linh hoạt. Thường được dùng ở phần tổ hợp (combinational logic).
- Behavioral: Dễ viết, dễ hiểu, dễ bảo trì. Trình synthesis phải "suy ra" từng cổng — đôi khi sinh dư 1-2 cổng thừa (vd 2 cổng NOT lồng nhau) mà công cụ tối ưu hoá logic (logic optimization) sẽ tự loại bỏ để về đúng netlist tối giản, y hệt 2 kiểu kia. Thường dùng ở phần tuần tự (sequential).
Trong công nghiệp thực tế, phần lớn code RTL hiện đại viết theo dataflow + behavioral — structural chỉ dùng khi cần ghép nối thủ công các module con (instantiate submodule) hoặc chèn trực tiếp một cell thư viện cụ thể (technology cell) cho mục đích tối ưu đặc biệt.
Trắc nghiệm ôn tập
Câu 1
Mức trừu tượng nào mô tả phần cứng bằng cách chuyển tiếp dữ liệu giữa các thanh ghi (registers) qua logic tổ hợp?
Câu 2
Sự khác biệt cốt lõi giữa HDL và ngôn ngữ lập trình tuần tự (như C/Python) là gì?
Câu 3
Mux 2-1 viết bằng 3 kiểu (structural, dataflow, behavioral) — sau khi synthesis, kết quả netlist sẽ như thế nào?
Câu 4
Trong Design Flow RTL → GDSII, bước nào diễn ra NGAY SAU Synthesis?
Tóm lược
Bài này giới thiệu tư duy chuyển đổi từ cổng logic sang RTL:
- ✅ HDL là mô tả phần cứng song song, không phải lập trình tuần tự.
- ✅ Design flow: RTL → Simulation → Synthesis → P&R → GDSII (chúng ta tập trung RTL đến Synthesis).
- ✅ SystemVerilog là chuẩn công nghiệp hiện tại.
- ✅ Cùng một mạch có thể viết 3 kiểu (structural, dataflow, behavioral), synthesis ra netlist giống nhau.
Bài tiếp theo sẽ bắt đầu viết code SystemVerilog tổ hợp (combinational) thực tế trên RTL Playground — một trình mô phỏng tương tác giúp bạn thấy code → netlist → waveform theo thời gian thực.
Tải file code thực hành minh họa bài học
File SystemVerilog tổng hợp cả 3 kiểu Mux 2-1 (structural/dataflow/behavioral) kèm testbench tự kiểm tra cả 3 module cho cùng kết quả trên toàn bộ 8 tổ hợp đầu vào. Chạy được trên Verilator hoặc dán trực tiếp vào EDA Playground (xem hướng dẫn trong comment đầu file):
Tải về mux2_1.sv
Bình luận