Constructor: tạo object ở trạng thái dùng được, không chỉ gọi new

Khoảng 45 phútMức 1/3Bản nháp: một số khẳng định chưa đối chiếu spec

Sau bài này bạn sẽ

  • Phân biệt implicit constructor với khởi tạo theo contract riêng
  • Đọc default và named arguments tại call site
  • Kiểm field shadowing, width và storage riêng giữa các object

Object tồn tại chưa chắc đã đúng contract

Một frame có length và array payload. Nếu hai thành phần không khớp nhau, monitor có thể truy cập sai hoặc checker có thể bỏ sót byte. Constructor là nơi thiết lập invariant ban đầu; sau đó code vẫn phải bảo vệ invariant nếu các field được phép sửa.

Implicit constructor vẫn có khởi tạo theo type

Class Plain trong ví dụ không viết function new. Sau new, field bit 8 có giá trị 0 và string rỗng. Đó là hai type cụ thể đã kiểm trên flow này; không suy mọi numeric type đều khởi tạo 0, đặc biệt không dùng simulator 2-state để kết luận về mặc định X của type 4-state.

[1]

Function new không ghi return type

Frame định nghĩa function new(int length=2, bit[7:0] seed=8'h20). Nó gán length, cấp phát payload rồi điền các byte. Constructor không được biến thành một task chờ giao dịch; test kiểm toàn bộ construction xong ở time 0. Constructor chaining và typed constructors để dành bài inheritance, chưa có claim ở đây.

Call bỏ argument dùng default tại định nghĩa

defaults = new() dùng length 2 và seed 32. Hai byte lần lượt 32 và 33, tổng 65. Default có ý nghĩa API: đổi nó sẽ đổi các call bỏ argument. Đừng chỉ test một call truyền đủ tham số rồi cho rằng default đã được kiểm.

Named arguments làm rõ ý nghĩa nhưng không đổi type

named = new(.seed(8'hfe), .length(3)) đổi thứ tự tên trong call nhưng vẫn gắn đúng formal. Payload có ba byte 254/255/0 vì từng element 8 bit giữ giá trị modulo 256. Tổng 509 được tính từ các byte đã lưu, không phải tổng 254+255+256.

This phân biệt field với argument trùng tên

Constructor dùng this.length = length: bên trái là field, bên phải là formal. Nếu viết length = length, bạn có thể chỉ gán argument cho chính nó và field vẫn giữ giá trị khai báo 99. Đây là lỗi shadowing; không chữa bằng đổi expected length thành 99.

Kiểm cả size, nội dung và object độc lập

TB kiểm field length, payload.size và từng byte cho cả hai object. Sau đó đổi byte đầu của named thành 1 và xác nhận defaults vẫn 32. Việc mỗi constructor thực hiện new array tạo storage riêng trong example này; không suy mọi field kiểu handle đều tự deep-copy.

Hai call và một mutation sau construction

Expected tính trước chạy: Plain bit 0/string rỗng; defaults length 2/sum 65; named length 3/sum 509; sau sửa named thì defaults[0] vẫn 32; $time0. Có assert cho mỗi invariant thay vì chỉ in chuỗi PASS.

Constructor: tạo object ở trạng thái dùng được, không chỉ gọi new

Expected tính trước chạy: Plain bit 0/string rỗng; defaults length 2/sum 65; named length 3/sum 509; sau sửa named thì defaults[0] vẫn 32; $time0. Có assert cho mỗi invariant thay vì chỉ in chuỗi PASS.

tb.sv testbench
`timescale 1ns/1psclass Plain;  bit[7:0] data;  string label;endclassclass Frame;  int length=99;  bit[7:0] payload[];  function new(int length=2,bit[7:0] seed=8'h20);    this.length=length;    payload=new[length];    foreach(payload[i])payload[i]=8'(int'(seed)+i);  endfunction  function int sum();    int result=0;    foreach(payload[i])result+=int'(payload[i]);    return result;  endfunctionendclassmodule tb_constructor;  Plain implicit_object;  Frame defaults,named;  initial begin    implicit_object=new();defaults=new();named=new(.seed(8'hfe),.length(3));    if(implicit_object.data!=0||implicit_object.label!="")$fatal(1,"implicit constructor type defaults");    if(defaults.length!=2||defaults.payload.size()!=2||defaults.sum()!=65||defaults.payload[0]!=32||defaults.payload[1]!=33)      $fatal(1,"default constructor arguments");    if(named.length!=3||named.payload.size()!=3||named.sum()!=509||named.payload[0]!=254||named.payload[1]!=255||named.payload[2]!=0)      $fatal(1,"named constructor arguments and byte wrap");    named.payload[0]=1;    if(defaults.payload[0]!=32||$time!=0)$fatal(1,"construction independence or time");    $display("CTOR CHECK implicit_bit=0 implicit_string_empty=1 default_length=2 default_sum=65 named_length=3 named_sum=509 after_mutation_default=32 at=0");    $finish;  endendmodule

Đã kiểm chứng thế nào

  • Phân tích và elaborate theo LRM (pyslang 12.1.0)
  • Mô phỏng, exit 0 và output khớp kỳ vọng tính tay (Verilator 5.050, 2-state)

Output phải khớp: CTOR CHECK implicit_bit=0 implicit_string_empty=1 default_length=2 default_sum=65 named_length=3 named_sum=509 after_mutation_default=32 at=0

Chỉ source và self-check đã nêu, Verilator 2-state; không claim X/Z, synthesis, garbage-collection timing hoặc đầy đủ mọi class feature.

Các kiểm tra chạy lúc xây dựng nội dung (2026-11-06), không chạy trong trình duyệt. Kỳ vọng được tính tay trước khi chạy.

[2]

Tự kiểm tra

Tự kiểm tra: constructor

  1. Named constructor tạo payload byte 254/255/0. Tổng đã lưu là bao nhiêu?
  2. Nếu đổi this.length=length thành length=length, field giữ giá trị khai báo nào?
  3. Defaults=new() trong main có size và tổng nào?
  4. Main kiểm thời gian ngay sau construction bằng bao nhiêu?
  5. Sau sửa named.payload[0]=1, defaults.payload[0] bằng bao nhiêu?

Đặt invariant cạnh constructor và test caller

Review constructor cùng các call dùng default/named arguments. Kiểm giá trị sau width conversion và array size, rồi sửa một object để phát hiện storage chia sẻ ngoài ý muốn. Không lấy new thành công làm bằng chứng dữ liệu đầu vào nào cũng hợp lệ; ví dụ chưa có API xử lý length âm hay quá lớn.

Nguồn và mức độ đối chiếu

  1. SystemVerilog Class Constructor — bản chụp resources.zip, Nguồn đào tạo đã đọc theo section. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. Thí nghiệm nguyên bản ex.b5.constructor, Bằng chứng thực nghiệm. Trích dẫn; nguồn đã đọc toàn văn.
  3. IEEE 1800-2023 SystemVerilog LRM, Class handles, construction, static and const properties. Chưa đối chiếu với văn bản nguồn (chưa mở).
  4. Thí nghiệm nguyên bản ex.b5.constructor, Source, self-checks, verification.json và mutation/capability probes. Trích dẫn; nguồn đã đọc toàn văn.
  5. SystemVerilog Class Constructor — bản chụp resources.zip, Explicitly Defining a Constructor; The Implicit Constructor. Trích dẫn; nguồn đã đọc các mục liên quan.
  6. this keywords in classes — bản chụp resources.zip, Example without this keyword; Example with this keyword; Example for this keyword with static method. Trích dẫn; nguồn đã đọc các mục liên quan.