Pre/post_randomize và randcase: thứ tự, trạng thái và trọng số

Khoảng 40 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ẽ

  • Theo dõi thứ tự callback và trạng thái thay đổi trong một call thành công
  • Phân biệt randcase chọn nhánh với constraint chọn giá trị
  • Kiểm trọng số0 bằng invariant mà không suy histogram từ một seed

Một call có thể chạy code trước khi trả kết quả

Một object cần chuẩn bị cận trên theo mode, sau đó sinh value và lưu một trường mirror để kiểm. Các công việc ấy có vị trí khác nhau: cận trên phải sẵn sàng trước khi giải constraint; mirror chỉ có nghĩa với giá trị mới sau một lần giải thành công.

Thí nghiệm dùng mode 0 với cận 1 và mode 1 với cận 4. Value là field 3 bit. Mirror bằng value cộng 16, không phải một field rand mới; testbench phải thấy mirror phù hợp ngay khi call thành công trả về.

Pre_randomize chuẩn bị state dùng trong constraint

Pre callback tăng pre_count rồi đặt bound thành 1 hoặc 4. Constraint đọc bound như trạng thái của object để giới hạn value. Nó không tự quyết định khi nào bound được cập nhật; phần procedural trong callback thực hiện việc đó trước.

Một thay đổi trong pre vẫn là code có side effect. Đừng thiết kế test dựa trên giả định randomize là một phép thử không thay đổi bất kỳ state nào khi gặp lỗi. Với tình huống thất bại, cần kiểm rõ return code, callback và các giá trị được dùng tiếp.

[1]

Post_randomize tạo dữ liệu dẫn xuất của mẫu mới

Post callback tăng post_count và đặt mirror bằng value cộng 16. Trong main, mỗi call thành công phải tăng đúng một pre và một post; value phải thuộc miền theo mode, mirror phải khớp oracle của testbench.

Counter giúp bắt trường hợp callback chạy thiếu hoặc chạy lặp, kể cả khi mirror cuối cùng tình cờ vẫn đúng. Bài kiểm callback của class randomization, không phải UVM phase, event scheduling hoặc một process chạy ở một thời điểm mô phỏng khác.

[2]

Bảy pin hợp lệ làm mốc kiểm callback

Mode 0 có hai giá trị hợp lệ 0 và 1; mode 1 có năm giá trị 0 đến 4. Main chỉ thực hiện bảy pin hợp lệ này, kiểm từng giá trị, cận trên, counter và mirror. Sau đó thêm 64 call tự do, luân phiên hai mode.

Expected cho main là 71 call thành công, pre_count bằng 71 và post_count bằng 71. Đây là phép kiểm các call thành công, không phải một tuyên bố về mọi đường thất bại của simulator.

Giữ riêng probe callback khi inline bị từ chối

Nguồn đào tạo mô tả post_randomize sau một lần giải thành công. Probe riêng yêu cầu cả những inline pin ngoài cận, rồi kiểm post_count không tăng khi return 0. Trên Verilator 5.050 đã ghi, assertion đó thất bại; probe vẫn giữ nguyên yêu cầu và báo lỗi thật.

Main thành công không được dùng để che probe thất bại hoặc nâng mức hỗ trợ của tool. Nếu một callback ghi log, cấp phát hoặc cập nhật dữ liệu dẫn xuất, cần xác minh đường thất bại trên simulator đang dùng, và không gửi một mẫu bị từ chối đi kiểm DUT.

Randcase chọn một nhánh procedural

Randcase không giải quan hệ giữa các field trong một class. Nó chọn nhánh procedural theo trọng số không âm rồi thực hiện statement của nhánh đó. Main gọi 64 lần với ba trọng số 0, 1 và 3, đếm riêng từng nhánh.

Nhánh có trọng số 0 phải có số hit bằng 0; hai nhánh còn lại cộng thành 64. Ý nghĩa tỷ lệ trọng số được giải thích bằng mô hình 1/4 và 3/4, nhưng test không yêu cầu số hit hữu hạn phải đúng tỷ lệ đó hoặc giống giữa các simulator.

[3]

Trọng số là một phần cấu hình phải kiểm

Nếu các trọng số đến từ biến cấu hình, hãy kiểm chúng trước khi chọn nhánh. Trường hợp tổng bằng 0 không có một nhánh có xác suất hợp lệ theo phép chia trọng số; nguồn đào tạo mô tả không nhánh nào chạy và có diagnostic runtime.

Main của bài dùng tổng dương bằng 4. Nó không thực thi case tổng 0 hoặc kiểm mức severity trên mọi simulator. Không lấy việc một nhánh ít được chọn trong vài lần chạy làm bằng chứng trọng số sai; hãy tách lỗi cấu hình khỏi biến động lấy mẫu.

71 call và 64 lựa chọn nhánh được tự kiểm

Expected tính trước chạy: bảy pin thành công cộng 64 call tự do; pre và post đều 71. Randcase chạy 64 lần, nhánh trọng số 0 không có hit. Probe inline-failure được báo riêng.

Pre/post_randomize và randcase: thứ tự, trạng thái và trọng số

Expected tính trước chạy: HOOK CHECK accepted=7 sampled=64 pre=71 post=71 randcase=64 zero_hits=0

tb.sv testbench
`timescale 1ns/1ps// Main only exercises seven legal pins and64successful free calls; failed-inline callback probe retained separately.class HookChoice;  rand bit[2:0] value;  bit mode;  int bound,pre_count=0,post_count=0,mirror;  constraint limit {int'(value)<=bound;}  function void pre_randomize();    pre_count++;bound=mode ? 4:1;  endfunction  function void post_randomize();    post_count++;mirror=int'(value)+16;  endfunctionendclassmodule tb_hooks;  HookChoice item;  int accepted=0,samples=0,zero_hits=0,one_hits=0,three_hits=0;  initial begin    item=new();item.srandom(103);    for(int m=0;m<2;m++)for(int pin=0;pin<8;pin++)begin      int result,before_pre,before_post;bit legal;      item.mode=1'(m);item.value=7;item.mirror=99;      before_pre=item.pre_count;before_post=item.post_count;      legal=(m==0&&pin<=1)||(m==1&&pin<=4);      if(!legal)continue;      result=item.randomize() with {value==local::pin;};      if(result!=int'(legal))$fatal(1,"hook pin oracle");      if(item.pre_count!=before_pre+1||item.bound!=(m?4:1))$fatal(1,"pre callback state");      if(result)begin        if(item.value!=pin||item.post_count!=before_post+1||item.mirror!=pin+16)$fatal(1,"post callback state");accepted++;      end else begin        if(item.post_count!=before_post||item.mirror!=99)$fatal(1,"post callback ran after failure");      end    end    for(int k=0;k<64;k++)begin      item.mode=1'(k%2);      if(!item.randomize())$fatal(1,"hook free call failed");      if(int'(item.value)>(k%2?4:1)||item.mirror!=int'(item.value)+16)$fatal(1,"hook free oracle");samples++;    end    repeat(64)begin      randcase        0:zero_hits++;        1:one_hits++;        3:three_hits++;      endcase    end    if(zero_hits!=0||one_hits+three_hits!=64)$fatal(1,"randcase zero-weight invariant");    if(accepted!=7||samples!=64||item.pre_count!=71||item.post_count!=71)$fatal(1,"hook accounting");    $display("HOOK CHECK accepted=7 sampled=64 pre=71 post=71 randcase=64 zero_hits=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: HOOK CHECK accepted=7 sampled=64 pre=71 post=71 randcase=64 zero_hits=0

Verilator 5.050/2-state, SMT solver; chỉ scope đã kiểm, không thay LRM.

Chỉ 71 call thành công và 64 randcase với trọng số 0/1/3; không kiểm tỷ lệ hữu hạn hoặc total-weight 0. Probe inline-failure/postcallback thất bại, giữ riêng.

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.

[4]

Tự kiểm tra

Tự kiểm tra: hooks

  1. Main có 7 pin hợp lệ rồi 64 call tự do thành công. Pre_count và post_count cuối cùng bằng bao nhiêu?
  2. Sau call thành công, value bằng 4 và post đặt mirror=value+16. Mirror phải bằng gì?
  3. Trong 64 randcase với trọng số 0,1,3, nhánh trọng số 0 phải có bao nhiêu hit?
  4. Một nhánh có trọng số 1 trong tổng 0+1+3. Trong mô hình trọng số, phần của nhánh đó là bao nhiêu?
  5. Những phát biểu nào được bằng chứng của bài hỗ trợ?

    Chọn tất cả đáp án đúng.

Ghi contract cho callback thay vì chỉ nhìn display

Xác định code nào chuẩn bị state, code nào tiêu thụ kết quả và điều kiện cho phép dùng dữ liệu dẫn xuất. Kiểm counter lẫn giá trị, cả khi các phép gán trông đơn giản. Với randcase, kiểm miền nhánh và trọng số 0 trước khi bàn về tỷ lệ thống kê.

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

  1. SystemVerilog pre\_randomize & post\_randomize — bản chụp resources.zip, pre_randomize(): Running Code Before Randomization. Trích dẫn; nguồn đã đọc các mục liên quan.
  2. SystemVerilog pre\_randomize & post\_randomize — bản chụp resources.zip, post_randomize(): Running Code After Randomization. Trích dẫn; nguồn đã đọc các mục liên quan.
  3. SystemVerilog randcase — bản chụp resources.zip, Weighted Random Branch Selection; Zero-Weight Branches Are Skipped. Trích dẫn; nguồn đã đọc các mục liên quan.
  4. Thí nghiệm nguyên bản ex.b6.hooks, Main, mutation và callback capability probe. Trích dẫn; nguồn đã đọc toàn văn.
  5. IEEE 1800-2023 SystemVerilog LRM, Constraint expressions, callbacks, arrays and randomization methods. Chưa đối chiếu với văn bản nguồn (chưa mở).
  6. IEEE 1800-2023 SystemVerilog LRM, Class randomization, array constraints and callbacks — chưa đối chiếu LRM. Chưa đối chiếu với văn bản nguồn (chưa mở).
  7. SystemVerilog pre\_randomize & post\_randomize — bản chụp resources.zip, Calling randomize(); pre_randomize(): Running Code Before Randomization; post_randomize(): Running Code After Randomization. Trích dẫn; nguồn đã đọc các mục liên quan.
  8. SystemVerilog randcase — bản chụp resources.zip, Syntax: randcase; Weighted Random Branch Selection; Zero-Weight Branches Are Skipped; What Happens When All Weights Are Zero. Trích dẫn; nguồn đã đọc các mục liên quan.
  9. Thí nghiệm nguyên bản ex.b6.hooks, Source, self-checks, verification.json, mutation và capability probes. Trích dẫn; nguồn đã đọc toàn văn.