Thứ Sáu, 27 tháng 4, 2018

[System Verilog] Sự khác nhau giữa Verilog và System Verilog

Nguồn tham khảo
1/ IEEE Computer Society and the IEEE Standards Association Corporate Advisory Group, IEEE Standard for SystemVerilog - Unified Hardware Design, Specification, and Verification Language (IEEE Std 1800™-2012), 21 February 2013
2/ http://www.asic-world.com/

1. Tại sao cần phải có System Verilog?

Ngôn ngữ mô tả phần cứng thuần tuý Verilog (Verilog 1995, Verilog 2001, Verilog 2005) vừa có khả năng mô hình các phần cứng khả tổng hợp (synthesizable) lại vừa có khả năng mô hình các cấu trúc hành vi dạng chỉ dùng cho mô phỏng, kiểm tra (verification). Thuật ngữ “phần cứng” được hiểu là “vi mạch” hoặc “các thành phần cụ thể trong 1 vi mạch”.
Tuy nhiên, ngôn ngữ mô tả phần cứng Verilog không có nhiều hỗ trợ mạnh cho kiểm tra thiết kế (verification) và mô hình hoá hệ thống (modeling). System Verilog ra đời là để nâng cao khả năng này. Lưu ý, System Verilog bao hàm toàn bộ Verilog thuần tuý và mở rộng thêm khả năng ứng dụng trong phạm vi mô hình hoá và kiểm tra, mô phỏng.
System Verilog hỗ trợ:
  • Mô tả phần cứng mức cổng (gate level), mức RTL (Register transfer level) và mức hành vi (behavioral)
  • Xây dựng testbench, coverage, assertion, hướng đối tượng và các random có ràng buộc.
  • Các giao tiếp lập trình ứng dụng API (Application Programming Interface) đến các ngôn ngữ lập trình khác.
Ví dụ, System Verilog hỗ trợ “assertion” cho phép xác thực sự hợp lệ của hành vi phần cứng, nghĩa là kiểm tra xem một phần cứng có hoạt động đúng theo trình tự mong muốn hay không. Giả sử, bạn cần kiểm tra chuỗi hành vi “khi tín hiệu x = 1 thì sau 1 đến 8 chu kỳ cung clock thì tín hiệu y = 1” thì assertion sẽ giúp bạn kiểm tra điều này.
System Verilog được chuẩn hoá trong tài liệu có tên “IEEE Standard for SystemVerilog Unified Hardware Design, Specification, and Verification Language” (Có thể tìm và download dễ dàng phiên bản IEEE Std 1800™-2012 bằng công cụ tìm kiếm google). Thông qua tên gọi có thể thấy System Verilog là ngôn ngữ hợp nhất dùng cho thiết kế, chi tiết hoá và kiểm tra phần cứng.

2. Một số nâng cấp cơ bản của System Verilog so với Verilog
Hình 1: Một số nâng cấp của System Verilog so với Verilog
Điểm 1 – Kiểu dữ liệu do người dùng định nghĩa
System Verilog cho phép người dùng có thể tự định nghĩa thêm kiểu dữ liệu. Bằng các sử dụng từ khoá typedef, người dùng có thể định nghĩa thêm các kiểu dữ liệu mới.

typedef enum {NO, YES} boolean;
boolean myvar; // named type

Ví dụ trên định nghĩa kiểu dữ liệu tên boolean và khai báo 1 biến myvar có kiểu dữ liệu là boolean.

Điểm 2 – Sử dụng con trỏ truy xuất bộ nhớ động
System Verilog không hỗ trợ việc sử dụng con trỏ để truy xuất bộ nhớ động linh hoạt như C mà có nhiều giới hạn kèm theo. Nó được gọi là “object handle” hay “safe-pointer”.

class obj_example;
...
endclass
task task1(integer a, obj_example myexample);
   if (myexample == null) myexample = new;
endtask

Trong ví dụ trên, biến myexample là một biến của lớp obj_example. Biến myexample được xem là giữ một “object handle” đến một object của lớp obj_example. Trong ví dụ này, object handle được kiểm tra xem đã được khởi động hay chưa, nếu chưa ( bằng null) thì lệnh new sẽ được sử dụng để tạo ra một đối tượng mới. 

Điểm 3 – Hỗ trợ kiểu enum
System Verilog hỗ trợ kiểu dữ liệu enum. Đây là kiểu dữ liệu đặc biệt, mỗi phần tử trong enum phải được gán 1 giá trị riêng biệt. Nếu vi phạm sẽ báo lỗi khi tổng hợp hoặc biên dịch. Nhờ đặc điểm này, sử dụng kiểu enum cho mô tả máy trạng thái FSM sẽ giúp phát hiện ra lỗi “gán giá trị trạng thái trùng nhau” sớm hơn so với việc sử dụng khai báo parameter.

Khai báo trạng thái dùng parameter:

parameter IDLE = 2'b00;
parameter D0 = 2'b01;
parameter D1 = 2'b11;
parameter D2 = 2'b11;

reg [1:0] state;

Khai báo trạng thái dùng enum:
enum bit [1:0] {IDLE=2'b00, D0=2'b01, D1=2'b11, D2=2'b11} state;

Trong ví dụ trên, hai trạng thái D1 và D2 bị khai báo trùng giá trị. Nếu dùng kiểu khai báo parameter, trình biên dịch sẽ không báo lỗi cú pháp, lỗi này chỉ được phát hiện khi bạn chạy mô phỏng và kết quả không như mong muốn. Nếu dùng kiểu khai báo enum, lỗi cú pháp sẽ báo ngay khi biên dịch. Ví dụ, tôi dùng Questa Sim, lỗi như sau sẽ xuất hiện.
Hình 2: Báo lỗi khi khai báo sai trong kiểu enum
Điểm 4 – Loại dữ liệu struct/union
Một structure là một tập hợp các kiểu dữ liệu. Nó có thể được sử dụng như một thể thống nhất hoặc sử dụng từng loại dữ liệu riêng bên trong structure.

struct { bit [7:0] opcode; bit [23:0] addr; }IR; // anonymous structure defines variable IR
IR.opcode = 1; // set field in IR.

Ví dụ trên khai báo một structure định nghĩa biến IR và gán giá trị 1 cho vùng opcode trong biến IR.

Một union cũng được khai báo như một tập hợp các kiểu dữ liệu như một structure nhưng tại một thời điểm, chỉ có một loại dữ liệu trong union được phép sử dụng.

Điểm 5 – Hỗ trợ mảng liên kết
Mảng liên kết (associative array) được sử dụng để thu thập và lưu trữ các dữ liệu có số lượng không biết trước và không gian dữ liệu rải rác. Một số ví dụ về mảng liên kết:

integer i_array[*]; // associative array of integer (unspecified index)
bit [20:0] array_b[string]; // associative array of 21-bit vector, indexed by string
event ev_array[myClass]; // associative array of event indexed by class myClass

Điểm 6 - Hỗ trợ cấu trúc có thể bao gồm cả dữ liệu và chương trình con (subroutine, method), có tính kế thừa

System verilog hỗ trợ một thành phần rất mạnh là class. Một class là kiểu bao gồm cả dữ liệu (data) và các chương trình con (subroutine) dùng để xử lý các dữ liệu của class. Dữ liệu của class còn được gọi là thuộc tính class (class property). Các chương trình con còn gọi là các method, chúng là các function hoặc task. Với khả năng này, chúng ta có thể dùng class mô hình hoá một giao thức bất kỳ.

class Packet ;
//data or class properties
bit [3:0] command;
bit [40:0] address;
bit [4:0] master_id;
integer time_requested;
integer time_issued;
integer status;
typedef enum { ERR_OVERFLOW= 10, ERR_UNDERFLOW = 1123} PCKT_TYPE;
const integer buffer_size = 100;
const integer header_size;

// initialization
function new();
  command = 4'd0;
  address = 41'b0;
  master_id = 5'bx;
  header_size = 10;
endfunction

// methods
// public access entry points
task clean();
    command = 0; address = 0; master_id = 5'bx;
endtask

task issue_request( int delay );
// send request to bus
endtask

function integer current_status();
  current_status = status;
endfunction

endclass

Sử dụng class

Packet p = new; //Khai báo một biến p của class Packet và khởi tạo biến bằng new
int var1;
p.command = INIT; //Gán giá trị cho dữ liệu (thuộc tính) của class
p.address = $random; //Gán giá trị cho dữ liệu (thuộc tính) của class
packet_time = p.time_requested; //Lấy giá trị từ dữ liệu của class
var1 = p.buffer_size; //Lấy giá trị từ dữ liệu của class

Một đặc tính rất hữu dụng của class là tính kế thừa (Inheritance). Một class mới có thể được tạo ra bằng cách mở rộng thêm từ một class khác. Khi làm như vậy, class mới sẽ kế thừa toàn bộ đặc điểm của class cũ, đồng thời, nó có thêm các đặc điểm (data hoặc method) mới mà ta sẽ thêm vào. Đặc tính này cho phép khả năng tái sử dụng (reuse) cao. Bạn có thể không cần viết lại hoàn toàn từ đầu một class mới.

class A ;
  integer j = 5;
  task print();
  begin
    $display("j is %0d",j);
  end
  endtask
endclass

class B extends A;
integer i = 1;
// Override the parent class print
task print();
  begin
    $display("i is %0d",i);
    $display("j is %0d",j);
  end
endtask
endclass

Trong ví dụ trên, class B được mở rộng từ class A bằng từ khoá extends. Do tính kế thừa, class B sẽ có j = 5 (data) và print (method) từ class A. Tuy nhiên, ở class B, method print được định nghĩa lại nên method print của class A sẽ bị ghi đè và class B sẽ có method print mới. Giả sử, ta có đoạn code sử dụng class B như sau:

initial begin
B b1; //Khai báo biến b1 từ class B
b1 = new; //Khởi tạo b1
b1.print(); //Gọi method print của class B
end

Kết quả là:
Giả sử bạn dùng class để mô hình hoá một giao thức, ví dụ như giao thức bus APB, AXI, … Thực tế các giao thức này không ngừng được nâng cấp để có thể sử dụng linh động hơn, tốc độ cao hơn, hiệu suất tốt hơn, … nên phiên bản sau sẽ tương thích phiên bản trước và thêm các đặc tính, quy định mới. Khi đó mô hình hoá dùng system verilog của bạn có thể được nâng cấp theo bằng cách kế thừa lại các class cũ và mở rộng thêm tính năng mới mà không cần xây dựng lại từ đầu.

Điểm 7 - Hỗ trợ các cấu trúc khác (program, clocking, interface)

(Program) Một module là một clock cơ bản giúp mô tả một thiết kế phần cứng dễ dàng. Thiết kế phần cứng ở đây là các mô hình mạch logic. Đối với testbench, mục tiêu chính là làm sao để môi trường kiểm tra có thể khởi tạo và đồng bộ chính xác, tránh chạy đua giữa thiết kế và testbench, tự động tạo kích thích đầu vào (input stimuli). Program ra đời để đáp ứng yêu cầu này. Một program được khai báo bằng cặp từ khoá program/endprogram. Một program phục vụ các mục tiêu cơ bản sau:

  • Tách biệt rõ giữa testbench và DUT
  • Đảm bảo không có điều kiện chạy đua giữa testbench và thiết kế
  • Cung cấp điểm truy cập thực thi testbench
  • Tạo một phạm vi đóng gói các dữ liệu chương trình
  • Tạo ngữ cảnh quy định thời gian biểu cho vùng Reactive để tránh chạy đua
  • Không cho phép dùng khối always
  • Mỗi chương trình có thể gọi task hệ thống $exit để thoát và dừng mô phỏng ngay lập tức cho dù đang có các sự kiện khác xảy ra.
  • Có các port như module (input, output, inout) và có thể instance như module để kết nối với DUT
(clocking) Các kết nối của các module, interface chỉ đặc tả tín hiệu và đường kết nối (net) mà không thể hiện được các ràng buộc về timing, các yêu cầu đồng bộ hay đặc tính của clock. Vì vậy, System verilog thêm khối clocking được khai báo bằng cặp từ khoá clocking/endclocking để cho phép mô tả điều này. Một khối clocking sẽ xác định các tín hiệu clock, bắt lại các yêu cầu về timing, đồng bộ của khối được mô hình hoá. Khối clocking sẽ tập hợp các tín hiệu được đồng bộ đến 1 clock cụ thể và mô tả timing của các tín hiệu này một cách rõ ràng. Khối clocking hỗ trợ lấy mẫu ngõ vào, các sự kiện đồng bộ và lái đồng bộ.

clocking ram @(posedge clk);
  input #3 dout;
  output #2 din,addr,ce,we;
endclocking

Ví dụ trên đây thiết lập input skew là 3 cho tín hiệu dout và output skew là 2 cho tín hiệu din, addr, ce và we. Input skew là khoảng thời gian trước cạnh lên clock clk mà tại đó dout sẽ được lấy mẫu. Output skew là khoảng thời gian sau cạnh lên clock clk mà tại đó ngõ ra thực sự được lái giá trị mới.
Hình 3: Input skew và output skew theo cạnh lên clock
(Interface) Các block thường được kết nối và giao tiếp thông qua rất nhiều port. Mỗi lần kết nối các instance, việc khai báo và kết nối các port mất thời gian và khó kiểm soát khi số lượng port lớn. Một interface sẽ giúp gom nhiều port lại và được đại diện bởi 1 tên chung để sử dụng. 

interface simple_bus; // Define the interface 
  logic req, gnt; 
  logic [7:0] addr, data; 
  logic [1:0] mode; 
  logic start, rdy; 
endinterface: simple_bus 

module memMod(simple_bus a, // Access the simple_bus interface 
  input logic clk); 
  logic avail; 

  // When memMod is instantiated in module top, a.req is the req 
  // signal in the sb_intf instance of the 'simple_bus' interface 

  always @(posedge clk) a.gnt <= a.req & avail; 
endmodule 

module cpuMod(simple_bus b, input logic clk); 
... 
endmodule 

module top; 
  logic clk = 0; 
  simple_bus sb_intf(); // Instantiate the interface 
  memMod mem(sb_intf, clk); // Connect the interface to the module instance 
  cpuMod cpu(.b(sb_intf), .clk(clk)); // Either by position or by name 
endmodule 

Trong ví dụ trên, một interface tên simple_bus chứa một nhóm port dùng chung bởi 2 module memMod và cpuMod. Interface này có thể được sử dụng để khai báo port cho module như “simple_bus a” cho memMod và “simple_bus b” cho cpuMod. Hoặc dùng để kết nối các module như “simple_bus sb_intf()” trong module top.

Điểm 8 – Hỗ trợ thêm các cấu trúc lặp và các từ khoá điều khiển
Với phần này, các bạn tham khảo một số ví dụ sau là sẽ hiểu.

(do-while) – Lặp đến khi điều kiện a < 5 vẫn thoả

int a = 0;
initial begin
do begin
$display ("Current value of a = %g\n", a);
a ++;
end while (a < 5);
#5 $display ("done");
end
kết quả
# Current value of a = 0
# Current value of a = 1
# Current value of a = 2
# Current value of a = 3
# Current value of a = 4
# done
(foreach) – Quét toàn bộ phần tử của mảng b
int b [5] = '{1,3,5,7,9};
initial begin
foreach (b[i]) begin
$display ("Value of b is %g",i);
end
#5 $display ("done");
end
kết quả
# Value of b is 0
# Value of b is 1
# Value of b is 2
# Value of b is 3
# Value of b is 4
# done
(break) – Thoát khỏi vòng lặp
int c = 0;
initial begin
do begin
$display ("Current value of c = %g\n", c);
c ++;
if (c == 3) begin
break; //out of do-while loop
end
end while (c < 5);
#5 $display ("done");
end
Kết quả
# Current value of c = 0
# Current value of c = 1
# Current value of c = 2
# done
(continue) – nhảy đến lần lặp tiếp theo và không thực hiện bất cứ biểu thức nào khác phía sau
int d = 0;
initial begin
do begin
$display ("Current value of d = %g\n", d);
d ++;
if (d >= 3) begin
continue; //go to the next interation
end
$display ("at the end of interation\n");
end while (d < 5);
#5 $display ("done");
end
kết quả
# Current value of d = 0
# at the end of interation
#
# Current value of d = 1
# at the end of interation
#
# Current value of d = 2
# Current value of d = 3
# Current value of d = 4
# done

Điểm 9 – Hỗ trợ một số toán tử mới 

Các bạn có thể tìm thêm trong tài liệu chuẩn. 


Điểm 10 – Tạo giá trị ngẫu nhiên có ràng buộc 

Verilog cho phép tạo giá trị ngẫu nhiên nhưng không thể ràng buộc thêm các điều kiện cho quá trình tạo giá trị ngẫu nhiên. System verilog cho phép điều này giúp tạo ra các giá trị “ngẫu nhiên trong phạm vi mong muốn” bằng từ khoá constraint. 
class orgBus;
  rand bit[3:0] addr;
  rand bit[7:0] data;
  constraint word_align {addr[1:0] == 2'b00;}
endclass
orgBus mybus = new;
initial begin
  repeat (10) begin
  if ( mybus.randomize() == 1 )
    $display ("addr = %h data = %h\n", mybus.addr, mybus.data);
  else
    $display ("Randomization failed.\n");
  end
end 
Ví dụ trên đây sử dụng hàm randomize để tác động lên các biến có khai báo rand. addr và data sẽ được gán giá trị ngẫu nhiên sau mỗi lần lặp. Tuy nhiên, hai bit cuối của addr được ràng buộc luôn là 2’b00, nghĩa là addr sẽ chỉ có các giá trị 0, 4, 8, c. Kết quả mô phỏng: 
# addr = c data = bc
# addr = 8 data = 53
# addr = c data = 48
# addr = 0 data = b2
# addr = 0 data = ff
# addr = 4 data = 75
# addr = 4 data = 9a
# addr = 8 data = 34
# addr = 0 data = b6
# addr = 0 data = ec
Điểm 11 – Kiểm tra hành vi hệ thống (assertion)
Khi cần kiểm tra hoặc xác thực một hành vi mà hệ thống hoặc thiết kế phải đáp ứng thì assertion là công cụ hữu hiệu.
reg a, a_sync;
reg clk, rst;

always @ (posedge clk) begin
  if (rst) a_sync <= 0;
  else a_sync <= a;
end

//wire rising_a = ~a_sync & a;
wire rising_a = a;

initial forever #5 clk = !clk;
initial begin
  clk = 0;
  rst = 1;
  #20
  rst = 0;
end

initial begin
  a = 0;
  #36
  a = 1;
end

always @ (posedge clk) begin
  test_a: assert property (rising_a |-> ##1 ~rising_a) else $display ("[%t]error", $time);
end
Ví dụ trên dùng để kiểm tra hành vi của tín hiệu rising_a. Nó là ngõ ra của mạch phát hiện cạnh lên nên rising_a chi được phép tích cực mức “1” trong 1 chu kỳ, nghĩa là sau khi bằng “1” thì chu kỳ clock tiếp theo nó phải bằng 0. Ví dụ dùng một assertion tên test_a để kiểm tra hành vi này, assertion này có ý nghĩa nếu rising_a bằng “1” và sau một chu kỳ rising_a bằng “0” thì hành vi là đúng. Nếu sai lỗi sẽ được hiển thị. Tác giá cố ý gán sai hành vi của mạch là “wire rising_a = a;” (hành vi đúng chính là dòng comment ngay trên dòng này, kết quả là: 
# [ 55]error
# [ 65]error
# [ 75]error
# [ 85]error
# [ 95]error
tương ứng với waveform:
Hình 4: Waveform thể hiện kết quả sai của ví dụ asertion, các vị trí cursor ở 55ns, 65ns, 75ns, 85ns và 95ns là các vị trí asertion báo lỗi vì không phát hiện rising_a bằng "0"

1 bình luận:

  1. Ngoc Tuyen Computer specializes in buying and selling all kinds of old computer trees - the new computer tree set in Hanoi and the provinces of Bac region, with long experience in the industry. Is an established center in the field of commerce and information technology services - technology - electronics, laptop repair, exchange and distribution of computer components, monitors, laptops

    http://www.abstractfonts.com/members/1137812
    https://forums.animeuknews.net/members/ngoctuyenhn101.7073/
    https://www.bgfalconmedia.com/users/profile/ngoctuyenhn101/
    https://forums.animeuknews.net/members/ngoctuyenhn101.7073/
    https://myanimelist.net/profile/111ngoctuyen

    Để được tư vấn và hỗ trợ vui lòng kiên hệ với chúng tôi qua địa chỉ sau.
    Mọi Thông Tin Liên Hệ
    Địa chỉ: Số 131 Vũ Tông Phan, Khương Trung, Thanh Xuân, Hà Nội
    Inbox - Chat trực tiếp : https://m.me/maytinhngoctuyen
    Hotline: 097 123 7999 - 0939 72 5555 ZALO: 097 123 7999
    Facebook: https://www.facebook.com/maytinhngoctuyen/

    Trả lờiXóa