1. Giới thiệu
Verilog là một trong hai ngôn ngữ mô tả phần cứng thông dụng và sử dụng phổ biến trong công nghiệp hiện nay, ngôn ngữ kia là VHDL, tên viết tắt của VHSIC (Very High Speed Integrated Circuits) Hardware Description Language. Tuy có nhiều sự so sánh hơn thua giữa Verilog và VHDL nhưng theo quan điểm của cá nhân tôi các bạn sử dụng thành thạo ngôn ngữ nào phục vụ trực tiếp và tốt nhất cho công việc, sở thích và đam mê của bạn thì nó là tuyệt vời nhất. Từ nền tảng đó, bạn có thể dễ dàng mở rộng thêm đến các ngôn ngữ khác khi cần thiết. "Một nghề cho chín còn hơn chín nghề" là câu nói rất đáng để suy ngẫm đối với người làm kỹ thuật.
Chọn ngôn ngữ nào để bắt đầu học? đó luôn là câu hỏi đau đầu cho những người mới bắt đầu. Tôi xin để link một bài viết hay nguyên văn ở đây để các bạn nào phân vân có thể tìm thấy cấu trả lời của mình.
http://www.bitweenie.com/listings/verilog-vs-vhdl/
và một vài ý kiến của người có kinh nghiệm lâu năm:
http://www.eetimes.com/author.asp?doc_id=1283049
Quay lại vấn đề chính, Verilog HDL khả tổng hợp (Verilog for Synthesis, Synthesizable Verilog) là một phần (tập con) của ngôn ngữ Verilog và System Verilog.
Hình 1. Mối liên quan giữa các phiên bản ngôn ngữ mô tả phần cứng |
Hình 1 minh họa rõ mối liên quan giữa các phiên bản ngôn ngữ, trong đó Verilog-1995 được bao hàm trong Verilog-2001, Verilog-2001 được bao hàm trong Verilog-2005 và System Verilog bao hàm các phiên bản Verilog nói chung.
Verilog, gọi tắt cho Verilog 1995/2001/2005, đã gồm 2 phần là:
- Phần ngôn ngữ tổng hợp được, hay gọi là khả tổng hợp (Synthesis)
- Phần ngôn ngữ dành cho mô phỏng (Verification)
Tuy nhiên, Verilog bị giới hạn nhiều về mô tả mô hình hệ thống và mô hình mô phỏng nên System Verilog ra đời đem lại sự nâng cấp mạnh mẽ cho Verilog không chỉ trên phương diện mô phỏng mà còn trên phương diện mô tả phần cứng tổng hợp được. Điều này làm cho các kỹ sư thiết kế phần cứng cần phân biệt rõ giữa thành phần khả tổng hợp và thành phần chỉ có thể dùng để mô tả mô hình mô phỏng.
2. Khả tổng hợp là gì?
Verilog khả tổng hợp là khả năng của RTL (Register Transfer Level) code viết bằng Verilog được phần mềm tổng hợp (synthesis tool) hiểu và biên dịch thành "phần cứng" (netlist) hoạt động chính xác theo những hành vi, chức năng mà RTL code thể hiện. "Phần cứng" ở đây là các thành phần logic như cổng OR, AND, XOR, Flip-Flop, MUX, AOI, ... gọi chung là các cell chuẩn (standard cell) được tập hợp trong một thư viện chung gọi là thư viện tổng hợp (synthesis library) hay thư viện công nghệ (technology library) hay thư viện cell chuẩn (Standard cell library).
Hình 2. Tổng hợp RTL code |
Các phần mềm mô phỏng (verification) như VCS (Synopsys), Questasim (Mentor), ModelSim (Mentor), Incisive (Cadence) ... có thể hiểu toàn bộ các thành phần quy định trong chuẩn ngôn ngữ Verilog, System Verilog quy định nhưng phần mềm tổng hợp chỉ hiểu và biên dịch được một phần ngôn ngữ nhất định và phần ngôn ngữ đó được gọi là phần có thể tổng hợp được.
3. Ví dụ về sự khác nhau giữa Verilog khả tổng hợp và Verilog mô phỏng
Ví dụ, bạn có thể mô tả một thanh ghi như sau:
module veriloghdl_1 (clk, data_in, data_out);
//
//Interface
//
input clk;
input [3:0] data_in;
output reg [3:0] data_out;
initial begin
data_out[3:0] = 4'b0000;
end
always @ (posedge clk) begin
data_out[3:0] <= data_in[3:0];
end
endmodule
Với đoạn code trên, bạn mong muốn thanh ghi data_out[3:0] được khởi động giá trị ban đầu là 0. Với các phần mềm mô phỏng, bạn có thể thấy được kết quả mong muốn đúng như đoạn code trên mô tả. Hình dưới đây cho thấy data_out[3:0] sẽ bằng 4'b0000 ngay từ thời điểm bắt đầu mô phỏng cho đến cạnh lên thứ nhất của xung clock clk.
Hình 2. Mô phỏng đoạn code của module veriloghdl_1 |
Ở đây tôi dùng phần mềm ModelSim và testbench có nội dung đơn giản như sau để chạy mô phỏng:
module tb;
//
//Interface
//
reg clk;
reg [3:0] data_in;
wire [3:0] data_out;
veriloghdl_ex dut (clk, data_in, data_out);
initial begin
data_in = 4'b1010;
clk = 0;
forever #10 clk = !clk;
end
endmodule
Mục đích của testbench trên là cấp giá trị data_in[3:0] và cấp xung clock clk có chu kỳ là 20 đơn vị thời gian mặc định của trình mô phỏng.
Tuy nhiên, nếu đoạn code của module veriloghdl_1 được tổng hợp thành netlist thì phần cứng được tạo thành chỉ là thanh ghi 4 bit không có giá trị khởi tạo ban đầu là 4'b0000 vì initial là thành phần không thể tổng hợp được. Giá trị thực tế của thanh ghi data_out[3:0], tính từ khi được cấp nguồn (hoặc bắt đầu mô phỏng) đến cạnh lên thứ nhất của xung clock clk, là một giá trị không xác định. Giá trị không xác định ở đây không phải là giá trị lơ lửng không rõ mức logic mà phần cứng thực tế có thể mang giá trị logic 0 hoặc 1. Hình sau sẽ cho thấy sự khác biệt.
Hình 3. Mô phỏng module veriloghdl_1 ở mức cổng (gate level) ứng với phần cứng thực tế |
Trước cạnh lên thứ nhất của xung clock clk, giá trị thanh ghi là không xác định nhưng được lái về một giá trị nào đó, ví dụ như 4'b0000 như hình minh họa. Sau cạnh lên của xung clock clk, giá trị thanh ghi data_out[3:0] sẽ lấy giá trị data_in[3:0]. Vì đây là mô phỏng mức cổng nên các bạn sẽ thấy data_out[3:0] phải mất một khoảng thời gian trễ sau cạnh xung clock trươc khi đạt giá trị ổn định.
Xin lưu ý với các bạn, hình 3 là hình tôi mô phỏng trên phần cứng FPGA để minh họa nên kết quả mô phỏng sẽ hơi khác so với khi bạn tổng hợp trên thư viện công nghệ vi mạch. Cụ thể, đoạn thời gian từ khi bắt đầu mô phỏng đến cạnh lên thứ nhất của xung clock sẽ được thể hiện hoàn toàn bằng màu đỏ, biểu thị giá trị không xác định.
Vậy để viết một thanh ghi phần cứng có thể khởi động giá trị ban đầu thì làm sao? Câu trả lời là mô tả thêm tín hiệu reset kèm giá trị khởi tạo. Ví dụ như đoạn RTL code sau dùng reset mức thấp và bất đồng bộ:
module veriloghdl_2 (clk, rst_n, data_in, data_out);
//
//Interface
//
input clk;
input rst_n;
input [3:0] data_in;
output reg [3:0] data_out;
always @ (posedge clk, negedge rst_n) begin
if (~rst_n)
data_out[3:0] <= 4'd0;
else
data_out[3:0] <= data_in[3:0];
end
endmodule
Đoạn testbench dùng để mô phỏng code trên như sau (thêm đoạn lái tín hiệu reset rst_n)
module tb;
//
//Interface
//
reg clk;
reg rst_n;
reg [3:0] data_in;
wire [3:0] data_out;
veriloghdl_ex dut (clk, rst_n, data_in, data_out);
initial begin
data_in = 4'b1010;
clk = 0;
forever #10 clk = !clk;
end
initial begin
rst_n = 0;
#20
rst_n = 1;
end
endmodule
Hình 4. Mô phỏng module veriloghdl_2 ở mức cổng (gate level) ứng với phần cứng thực tế |
Kết quả khi rst_n = 0, thanh ghi được reset về giá trị 4'd0 và giữ giá trị này đến khi rst_n=1 và gặp cạnh lên xung clock mới cập nhật ngõ vào data_in[3:0].
Ví dụ trên đây là là một phần nhỏ trong sự khác biệt giữ mô tả RTL code khả tổng hợp và code chỉ dùng cho mô phỏng. Những thành phần Verilog nào là khả tổng hợp sẽ được giới thiệu đến các bạn trong các bài viết khác.
0 bình luận:
Đăng nhận xét