Toán tử phân giải phạm vi (scope resolution), ký hiệu là "::", là một trong những toán tử được sử dụng rất nhiều để truy xuất các phần tử trong một class. Bài viết này sẽ giải thích rõ cách sử dụng toán tử này. Mỗi đặc điểm sẽ có ví dụ cụ thể để bạn đọc dễ nắm bắt và kiểm chứng.
Chú ý, việc dịch thành tên tiếng việt "toán tử phân giải phạm vi" là dựa trên cách sử dụng của loại toán tử này. Trong bài viết này, tác giả sẽ dùng cụm từ "scope resolution" hoặc ký hiệu "::" để trình bày.
1) Cú pháp sử dụng toán tử "::"
Toán tử "::" được sử dụng để xác định (truy xuất) một phần tử bên trong một class bằng cách sử dụng tên của class. Nó khác với cách truy xuất thông qua handle của một đối tượng class bằng ký hiệu "." như đã trình bày trong bài 1. Cú pháp sử dụng của toán tử này như sau:
Toán tử scope resolution "::" cho phép các xử lý sau đây:
1) Cú pháp sử dụng toán tử "::"
Toán tử "::" được sử dụng để xác định (truy xuất) một phần tử bên trong một class bằng cách sử dụng tên của class. Nó khác với cách truy xuất thông qua handle của một đối tượng class bằng ký hiệu "." như đã trình bày trong bài 1. Cú pháp sử dụng của toán tử này như sau:
class_type :: { class_type :: } identifierTrong đó:
- class_type chính là tên gốc của class. Nó được gọi là class_type vì một class định nghĩa một loại dữ liệu (data type). Ngoài ra, nó có thể là tên package, tên covergroup, tên coverpoint, tên cross, tên typedef hoặc type parameter nhưng bài viết này chỉ tập trung minh họa cho class.
- identifier là tên biến hoặc tên method.
Toán tử scope resolution "::" cho phép các xử lý sau đây:
- Truy xuất các thành phần (biến và method) static và public bên ngoài định nghĩa class. Chú ý, thành phần này phải có hai điều kiện là khai báo static và không có khai báo local hoặc protected.
- Truy xuất các thành phần public (không có khai báo local hoặc protected) hoặc thành phần được protected của class gốc (base class) ở trong class mở rộng.
- Truy xuất các constraint, các khai báo về loại dữ liệu, các hằng số được định nghĩa bằng tên trong enum của một class ở bên ngoài định nghĩa class hoặc bên trong một class mở rộng.
- Truy xuất các parameter và localparam của một class ở bên ngoài class hoặc bên trong một class mở rộng.
Chúng ta cùng phân tích ví dụ sau đây để kiểm chứng các đặc điểm đã nêu về toán tử "::".
Ví dụ 1 - Toán tử "::" trong việc sử dụng class
Xét đặc điểm thứ nhất, để kiểm chứng đặc điểm này bạn đọc chú ý đến các thành phần sau:
Đoạn code sau đây trong module class_scope_resolution kiểm chứng việc truy xuất biến tĩnh count và method tĩnh count_reset thông qua tên class packet bằng toán tử "::".
Xét đặc điểm thứ hai, để kiểm chứng đặc điểm này bạn đọc chú ý đến các method first_gen trong class mở rộng packet_ext. Trong method này, toán tử "::" được sử dụng để truy xuất đến method public addr_gen và biến protected addr_mask. Trong module class_scope_resolution, đoạn code sau đây dùng để kiểm chứng kết quả:
Xét đặc điểm thứ 3, để kiểm chứng đặc điểm này bạn đọc chú ý đến định nghĩa biến enum state trong class packet. Các hằng số của nó sẽ được truy xuất bởi toán tử "::" trong đoạn code sau:
Xét đặc điểm thứ 4, để kiểm chứng đặc điểm này bạn đọc chú ý đến parameter ADDR_WIDTH, localparam trong class packet và parameter TEST_EXT trong class packet_ext. Đoạn code sau sẽ truy xuất các parameter và localparam đã nêu:
Trên đây là những đặc điểm cơ bản khi sử dụng toán tử "::" truy xuất các thành phần trong class.
Ví dụ 1 - Toán tử "::" trong việc sử dụng class
class packet;Ví dụ trên định nghĩa một class gốc tên packet và một class mở rộng tên packet_ext. Module tên class_scope_resolution dùng để kiểm chứng các đặc điểm đã nêu về toán tử "::".
parameter ADDR_WIDTH = 8; //parameter
localparam TEST = "THIS IS THE BASE CLASS"; //local parameter
typedef enum {IDLE, BUSY, FINISH} state; //enum
static int count; //static variable
bit [ADDR_WIDTH-1:0] addr; //non-static variable
protected bit [ADDR_WIDTH-1:0] addr_mask = {{ADDR_WIDTH-4{1'b1}}, 4'd0}; //protected variable
//
task addr_gen; //non-static method
int i = 1;
while (i) begin addr[ADDR_WIDTH-1:2] = $random(count); //Get the random value
addr[1:0] = 2'b00; //mask 2 LSB bits to 0
if (addr[ADDR_WIDTH-1:2] != 0) begin i = 0;
$display ("[addr_gen] Address is %h", addr);
end count++;
end endtask: addr_gen
//
static task count_reset; //static method
count = 0; //Reset count
endtask: count_reset
//
endclass: packet
//
class packet_ext extends packet;
bit [ADDR_WIDTH-1:0] first_addr;
localparam TEST_EXT = "THIS IS THE EXTENDED CLASS";
//
task first_gen;
packet::addr_gen; //Access to a public method of superclass (baseclass)
packet::addr_mask = {{ADDR_WIDTH-6{1'b1}}, 6'd0}; //Access to a protected property of superclass
first_addr = addr & packet::addr_mask; //mask 6 LSB bits
endtask: first_gen
//
endclass: packet_ext
//
module class_scope_resolution;
packet_ext pkt_ext;
initial begin pkt_ext = new;
//
$display ("1/ Access to static public members");
packet::count = 5; //Access to static public property
$display ("-- count = %d", packet::count);
packet::count_reset; //Access to static public method
$display ("-- count = %d", packet::count);
//
$display ("2/ Access to public or protected members of superclass");
pkt_ext.first_gen;
$display ("-- first_addr = %h",pkt_ext.first_addr);
//
$display ("3/ Access to constraints, type declarations, and enumeration named constants");
$display ("-- state: IDLE=%2d, BUSY=%2d, FINISH=%2d", packet::IDLE, packet::BUSY, packet::FINISH);
//
$display ("4/ Access to parameters and local parameters");
$display ("-- ADDR_WIDTH: %d", packet::ADDR_WIDTH);
$display ("-- TEST: %s", packet::TEST);
$display ("-- TEST: %s", packet_ext::TEST);
$display ("-- TEST_EXT: %s", packet_ext::TEST_EXT);
end//endmodule: class_scope_resolution
Xét đặc điểm thứ nhất, để kiểm chứng đặc điểm này bạn đọc chú ý đến các thành phần sau:
- Trong class packet, biến count được khai báo static và là loại public
- Trong class packet, method count_reset là một method static và là loại public
Đoạn code sau đây trong module class_scope_resolution kiểm chứng việc truy xuất biến tĩnh count và method tĩnh count_reset thông qua tên class packet bằng toán tử "::".
$display ("1/ Access to static public members");Biến count được gọi và gán giá trị 5. count_reset được gọi để reset lại biến count về 0. Kết quả mô phỏng như sau:
packet::count = 5; //Access to static public property
$display ("-- count = %d", packet::count);
packet::count_reset; //Access to static public method
$display ("-- count = %d", packet::count);
Hình 1: Kết quả kiểm chứng đặc điểm 1 |
$display ("2/ Access to public or protected members of superclass");method first_gen được gọi để thực thi. Nó sẽ gọi addr_gen của class gốc để tạo một giá trị cho biến addr. Sau đó, biến addr được che 6 bit cuối lại bởi biến addr_mask. Kết quả mô phỏng như sau:
pkt_ext.first_gen;
$display ("-- first_addr = %h",pkt_ext.first_addr);
Hình 2: Kết quả mô phỏng kiểm chứng đặc điểm 2 |
$display ("3/ Access to constraints, type declarations, and enumeration named constants");Kết quả kiểm chứng như sau:
$display ("-- state: IDLE=%2d, BUSY=%2d, FINISH=%2d", packet::IDLE, packet::BUSY, packet::FINISH);
Hình 3: Kết quả mô phỏng kiểm chứng đặc điểm 3 |
$display ("4/ Access to parameters and local parameters");
$display ("-- ADDR_WIDTH: %d", packet::ADDR_WIDTH);
$display ("-- TEST: %s", packet::TEST);
$display ("-- TEST: %s", packet_ext::TEST);
$display ("-- TEST_EXT: %s", packet_ext::TEST_EXT);
Hình 4: Kết quả mô phỏng kiểm chứng đặc điểm 4 |
0 bình luận:
Đăng nhận xét