Thursday, April 11, 2019

[Bài 9][ UVM ] Tạo transaction

Transaction có thể được mở rộng (Hay nói đúng hơn transaction là class con) từ “uvm_sequense_item” hoặc “uvm_transaction” class (Tuỳ người dùng quyết định). Các class này đã được định nghĩa trong thư viện uvm.
Nhiệm vụ cơ bản của một transaction đó là mô hình hoá các tín hiệu nào giao tiếp giữa các thành phần trong môi trường uvm hoàn chỉnh.  Transaction chứa các biến để liên lạc giữa các phần tử và các ràng buộc cho các biến đó (Các ràng buộc này được áp dụng cho chỉ các biến input). Để viết được một transaction việc đầu tiên bạn cần làm đó là xác định được các biến input hay output nào cần giao tiếp giữa các phần tử (hoặc giữa DUT và interface).
Trước tiên tôi muốn các bạn tập trung vào việc xác định các dữ liệu nào (Hay nói đúng hơn là các input nào) cần được chuyển tiếp đến DUT. Tôi lấy ví dụ 1 bộ cộng 4 bit bên dưới:

module add_4bit (clk, rst_n, in_1, in_2, sum, c_out);
// Define bit width for inputs
parameter WIDTH = 3;
// Define input/output
input clk;
input rst_n;
input [WIDTH:0] in_1;
input [WIDTH:0] in_2;
output [WIDTH:0] sum;
output c_out; 
…….
endmodule


Ta có 4 inputs và 2 outputs cho module này. 
Tuy nhiên hai tín hiệu clk và rst_n cần được điều khiển và biết trước giá trị. Để dễ dàng quản lí và re-use 2 tín hiệu clk và rst_n sẽ được khai báo trong 1 file khác (Hoặc một thành phần khác). Việc chúng ta cần xác định bây giờ là các tín hiệu nào cần được giao tiếp giữa các phần tử với nhau. Trong ví dụ trên ta có 2 inputs và 2 outputs. Đó là
in_1, in_2: Được khai báo như là các biến random (vì chúng là input) và được tạo các rang buộc để giới hạn các giá trị random đó.
sum, c_out: là các output.

Cách viết một transaction

Để viết và thành thạo được một transaction dưới đây là những yêu cầu bạn cần phải học:
Cách định nghĩa 1 biến random. Cái này khá là đơn giản. Dưới đây là một số ví dụ:

Cấu trúc: rand     Kiểu_dữ_liệu    Tên_biến;

  rand bit [3:0] in_1;
  rand bit [3:0] in_2;
  rand int count;

+ Cách tạo 1 ràng buộc (constraint) cho các biến random. Ta có nhiều cách để tạo một rang buộc. Tôi sẽ liệt kê một số cách như bên dưới:

  constraint con_in_1 {
     in_1 inside {[0:15]};
  } 

 Biến in_1 sẽ thuộc khoảng giá trị từ 0 đến 15.

constraint con_in_1 {
        in_1 inside {[$:3], [8:$]};
 } 

Với rang buộc bên trên biến 0 <= In_1 <= 3 hoặc  8 <= in_1 <= 15.

constraint con_in_2 {
    if (op == READ) in_2 inside {[0:8]};
    else in_2  = 15;
}

 Đây là rang buộc cấu trúc if-else. Biến op là một biến được khai báo trước.

  constraint in_2 {
     in_2 dist { [2:4] :/ 30,  8  :/  10};
  }

 Biến  in_2 sẽ có thể mang các giá trị:
2 : 10% của tổng 40%
3: 10% của tổng 40%
4: 10% của tổng 40%
8: 10% của tổng 40%

  constraint c_operand1 {
     in_2 dist {[2:4] := 30, 8 := 10};
  }

 Biến  in_2 mang các giá trị
2 : 30% của tổng 100%
3: 30% của tổng 100%
4: 30% của tổng 100%
8: 10% của tổng 100%

constraint con_0 {
    in_1 < 14;
    in_1 > 2;
}

 Giá trị biến in_1 nằm trong khoảng (2,14).


Xây dựng cấu trúc 1 transaction

Bây giờ chúng ta bắt tay vào phân tích cấu trúc của một transaction nhé.
Việc đầu tiên bạn cần làm đó là định nghĩa 1 transation bằng cách mở rộng từ một class có sẵn trong thư viện uvm. Bạn chỉ cần biết cấu trúc của thư viện uvm đề biết cách dùng và không cần phải hiểu rõ các nội dung code bên trong.

class add4bit_trans extends uvm_sequence_item;
    ………
endclass

Tiếp theo bạn cần khai báo các biến giao tiếp giữa các thành phần và các ràng buộc cho các biến random.

  bit [3:0] sum;
  bit c_out;
  rand bit [3:0] in_1;
  rand bit [3:0] in_2;
  constraint con_in_1 {
     in_1 inside {[0:15]};
  }
  constraint con_in_2 {
     in_2 inside {[0:15]};
  }

Cuối cùng là các câu lệnh bắt buộc mà bất kì thành phần nào cũng cần có.

  function new (string name = "");
     super.new(name);
  endfunction: new

Hàm này giúp bạn khởi tạo cho class add4bit_trans, Tương tự như hàm new trong mảng. 

  `uvm_object_utils_begin(add4bit_trans)
    `uvm_field_int(c_out, UVM_ALL_ON)
    `uvm_field_int(sum, UVM_ALL_ON)
    `uvm_field_int(in_1, UVM_ALL_ON)
    `uvm_field_int(in_2, UVM_ALL_ON)
  `uvm_object_utils_end

Định nghĩa này giúp bạn thực hiện một số thao tác trên các biến như copy, print, packed, unpacked….

Dưới đây là chương trình hoàn chỉnh cuả một transaction cho bộ cộng 4 bit.
Cấu trúc `ifndef , `define, `endif giúp bạn tránh các lỗi compile các class trùng tên nhau. Nghĩa là nếu tồn tại kha báo của class add4bit_trans ở một file nào đó thì khi compile chương trình sẽ bỏ qua việc compile cho phần định nghĩa này và chỉ nhận phần khai báo nào dược compile trước.

`ifndef _UVM_TRANS_
`define _UVM_TRANS_
class add4bit_trans extends uvm_sequence_item;

  bit [3:0] sum;
  bit c_out;
  rand bit [3:0] in_1;
  rand bit [3:0] in_2;
  constraint con_in_1 {
    in_1 inside {[0:15]};
  }
  constraint con_in_2 {
    in_2 inside {[0:15]};
  }
  function new (string name = "");
     super.new(name);
  endfunction: new
  `uvm_object_utils_begin(add4bit_trans)
    `uvm_field_int(c_out, UVM_ALL_ON)
    `uvm_field_int(sum, UVM_ALL_ON)
    `uvm_field_int(in_1, UVM_ALL_ON)
    `uvm_field_int(in_2, UVM_ALL_ON)
  `uvm_object_utils_end
endclass: add4bit_trans
`endif

No comments:

Post a Comment

Cách tính BW và latency trong 1 hệ thống SoC sử dụng chuẩn giao tiếp AXI protocol

Tác giả:  TrongTran Ngày:  31/12/2019 Nếu bạn nào đang làm về verification cho system performance (ST) thì bài này sẽ bổ ích cho bạn. Ngày ...