Class và struct: copy giá trị không tự clone object nằm trong field

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

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

  • So sánh assignment/equality của packed struct với class handle
  • Theo dõi field kiểu handle trong unpacked struct
  • Chọn cấu trúc theo identity, ownership và nhu cầu biểu diễn

Value type và reference type giải quyết nhu cầu khác nhau

Header bitfield cần layout cố định và copy giá trị. Transaction testbench có thể cần identity, method hoặc ownership. Chọn struct/class theo contract của dữ liệu thay vì vì cả hai đều gom được nhiều field.

Packed struct scalar copy tách giá trị hai biến

Scalar_t có field bit 8. First.value 7, second=first làm hai giá trị bằng nhau; sửa second.value 9 không đổi first 7. Equality tại đây so packed value; main không mở rộng sang mọi unpacked member type hoặc X/Z equality.

[1]

Hai class object cùng dữ liệu vẫn có identity khác

A và B được new riêng với value 7, còn alias_handle=a. Main kiểm a!=b dù field bằng nhau và a==alias_handle. Sửa qua alias làm a đổi nhưng B giữ 7; method compare nội dung nếu cần phải được thiết kế riêng.

Unpacked struct có thể chứa field là class handle

Record_t chứa int tag và Payload handle. Copy record_b=record_a sao chép hai field, gồm giá trị của handle; nó không tự tạo Payload mới. Hai record tag có storage riêng nhưng payload có thể vẫn là một object dùng chung.

Theo dõi hai loại cập nhật sau assignment

Sau copy record, đổi record_b.tag thành 2 không đổi record_a.tag 1. Sửa record_b.payload.value=11 làm a.value và payload đọc qua record_a cùng thành 11. B object khác vẫn 7. Đây là phản ví dụ cho lời khẳng định mọi struct assignment đều deep-copy toàn bộ object graph.

Dùng layout rõ cho RTL, ownership rõ cho testbench

Packed struct hữu ích khi cần bit layout cố định như bài B1. Class thường dùng cho object có behavior và identity trong testbench. Main chỉ parse/sim; không từ ví dụ này kết luận synthesis support cho mọi struct/class trên mọi công cụ.

Tạo object con mới sẽ đổi semantics của value copy

Mutation thay record assignment bằng clone Payload mới bị symptom value copy must not promise recursive object clone bắt. Đây là kiểm semantics cụ thể của assignment, không nói clone luôn sai; clone đúng hay sai phụ thuộc contract caller cần.

Kiểm scalar copy, identity và nested alias

Expected trước chạy: struct 7/9,class 11/7,handle equality giữa A/B false,record tags 1/2,nested value 11. Main kiểm raw field và handle, không serialize rồi coi hai object cùng identity hoặc giả định mọi unpacked struct synthesizable.

Class và struct: copy giá trị không tự clone object nằm trong field

Expected tính trước chạy: VALUE CHECK struct_values=7/9 class_values=11/7 handles_equal=0 record_tags=1/2 shared_nested=11

tb.sv testbench
`timescale 1ns/1psclass Payload;  int value;  function new(int value);this.value=value;endfunctionendclasstypedef struct packed {bit[7:0] value;} scalar_t;typedef struct {int tag;Payload payload;} record_t;module tb_value;  scalar_t first,second;  record_t record_a,record_b;  Payload a,b,alias_handle;  initial begin    first.value=7;second=first;    if(first!=second)$fatal(1,"packed struct equality compares value");    second.value=9;    a=new(7);b=new(7);alias_handle=a;    if(a==b||a!=alias_handle||a.value!=b.value)$fatal(1,"class identity versus field value");    alias_handle.value=9;    record_a.tag=1;record_a.payload=a;record_b=record_a;    record_b.tag=2;record_b.payload.value=11;    if(first.value!=7||second.value!=9||a.value!=11||b.value!=7||record_a.tag!=1||record_b.tag!=2||record_a.payload!=record_b.payload)      $fatal(1,"value copy must not promise recursive object clone");    $display("VALUE CHECK struct_values=7/9 class_values=11/7 handles_equal=0 record_tags=1/2 shared_nested=11");    $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: VALUE CHECK struct_values=7/9 class_values=11/7 handles_equal=0 record_tags=1/2 shared_nested=11

Verilator 2-state, không claim X/Z hoặc synthesis.

Packed scalar và unpacked struct có một class-handle field; không claim mọi nested value type/equality/XZ hoặc deep clone.

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: class-vs-struct

  1. Sau record_b.payload.value=11, record_a.payload.value bằng bao nhiêu?
  2. Sau record_b.tag=2, tags của record_a và record_b là gì?
  3. A/B được new riêng nhưng cùng field value 7. A==B thế nào?
  4. First packed scalar 7, second=first rồi second.value=9. First là gì?
  5. Vì sao không nói mọi struct assignment là deep copy?

Tách value copy khỏi ownership của dữ liệu được tham chiếu

Với mỗi field, hỏi nó chứa giá trị trực tiếp hay handle. Một struct có value semantics vẫn có thể truyền alias thông qua field handle. Review nested fields trước khi gọi một assignment là snapshot độc lập.

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

  1. SystemVerilog Class vs Struct — bản chụp resources.zip, Nguồn đào tạo đã đọc. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. Thí nghiệm nguyên bản ex.b5.class-vs-struct, 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, inheritance, virtual methods, access and parameterization. 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.class-vs-struct, Source, self-checks, verification.json và mutation/capability probes. Trích dẫn; nguồn đã đọc toàn văn.
  5. SystemVerilog Class vs Struct — bản chụp resources.zip, Assignment: Copy vs Share; Equality: Comparing Values vs Comparing Identity; Methods, Constructors, and Inheritance. Trích dẫn; nguồn đã đọc các mục liên quan.