58 / 63 · Khái niệm
Kế hoạch kiểm chứng FIFO, bộ nhớ và scoreboard độc lập
Viết queue scoreboard độc lập với con trỏ triển khai, kết nối điều kiện biên, reset, valid và đọc chưa khởi tạo với kế hoạch kiểm chứng.
Bài học miễn phí. Đăng ký để lưu tiến độ học tập.
Tạo đáp án bằng cách khác với DUT
Bộ kiểm tra so sánh giá trị dự kiến theo hợp đồng với DUT. Nếu sao chép rptr, wptr bên trong FIFOFIFO Hàng đợi lấy ra dữ liệu được đưa vào trước. Quy tắc đầy, rỗng và cho phép đọc/ghi đồng thời là một phần của hợp đồng hoạt động. Tìm hiểu thêm để tính đáp án, cùng một lỗi con trỏ có thể bị tái tạo ở cả hai phía. ScoreboardScoreboard Trạng thái tham chiếu trong môi trường kiểm chứng, dùng để đối chiếu dữ liệu dự kiến với đầu ra thực tế theo thứ tự. Nó được tính độc lập, không sao chép nguyên trạng nội bộ của triển khai. độc lập dùng queue SystemVerilog để chỉ lưu thứ tự logic. Khi push được nhận thì thêm cuối; khi pop được nhận thì lấy đầu.
Kế hoạch kiểm chứng cần ghi các tổ hợp chéo giữa trạng thái và yêu cầu. Với từng trạng thái empty/trung gian/full, kiểm tra không có yêu cầu, chỉ push, chỉ pop và yêu cầu đồng thời. Bổ sung quay vòng con trỏ nhiều lần, pop liên tiếp và reset khi vẫn còn dữ liệu. Ghi nhận đã quan sát từng trường hợp hay chưa; lưu seed ngẫu nhiên và đầu vào gây lỗi để tái hiện.
Việc chấp nhận dự kiến được tính từ kích thước cũ của queue, không dùng full hay occupancy của DUT.
Lấy head cũ ra trước rồi mới nối dữ liệu mới vào để bảo toàn head cũ khi yêu cầu đồng thời lúc full. Chỉ so sánh dout khi dự kiến.
Testbench đầy đủ
Biên dịch testbench này cùng fifo4 của bài trước. Mã kiểm chứng dùng độ trễ và queue. Đầu vào đổi tại cạnh xuống; kết quả cập nhật nonblockingNonblocking Phép gán <= trong RTL tuần tự. Đánh giá vế phải rồi lên lịch cập nhật, cho các thanh ghi cùng cạnh tính từ trạng thái cũ. Tìm hiểu thêm của DUT được so sánh 1ps sau cạnh lên.
module tb_fifo4;
timeunit 1ns;
timeprecision 1ps;
typedef logic [7:0] word_t;
logic clk=0, rst=1, push=0, pop=0;
word_t din=0, dout;
logic dout_valid, full, empty;
logic [2:0] occupancy;
word_t model[$], expected;
bit expect_pop, expect_push;
fifo4 dut (.*);
always #5ns clk = ~clk;
always @(posedge clk) begin
if (rst) begin
model.delete();
expect_pop = 0;
end else begin
expect_pop = pop && (model.size() != 0);
expect_push = push && ((model.size() < 4) || expect_pop);
if (expect_pop) expected = model.pop_front();
if (expect_push) model.push_back(din);
end
#1ps;
assert (dout_valid === expect_pop)
else $fatal(1, "valid mismatch");
if (expect_pop)
assert (dout === expected)
else $fatal(1, "data mismatch");
assert (int'(occupancy) === model.size())
else $fatal(1, "count mismatch");
assert (empty === (model.size() == 0))
else $fatal(1, "empty mismatch");
assert (full === (model.size() == 4))
else $fatal(1, "full mismatch");
end
task automatic step(input bit r, p, o, input word_t d);
@(negedge clk);
rst=r; push=p; pop=o; din=d;
endtask
initial begin
step(0,0,1,0);
step(0,1,1,8'hA0);
for (int i=1; i<4; i++)
step(0,1,0,word_t'(160+i));
step(0,1,0,8'hEE);
step(0,1,1,8'hB0);
repeat (5) step(0,0,1,0);
repeat (3) begin
for (int i=0; i<4; i++) step(0,1,0,word_t'(i));
repeat (4) step(0,0,1,0);
end
step(0,1,0,8'h5A);
step(1,1,1,8'hFF);
step(0,0,1,0);
repeat (100)
step(0,bit'($urandom_range(1,0)),bit'($urandom_range(1,0)),
word_t'($urandom));
repeat (4) step(0,0,1,0);
@(negedge clk);
$display("PASS");
$finish;
end
endmoduleCạnh lên đầu có rst=1 nên làm rỗng cả DUT và mô hình. === so sánh nghiêm ngặt cả X. Khi valid=0, không so sánh dout chưa khởi tạo, nhưng valid tự nó bằng X vẫn gây thất bại. Bốn pop cuối kiểm tra toàn bộ dữ liệu còn lại. PASS là thông báo khi thực sự chạy kiểm thử và vượt mọi assertion; việc đưa mã ở đây không có nghĩa mã đó đã được chạy.
Trước khi thêm dữ liệu ghi B0, tách head cũ A0 làm đầu ra dự kiến. Quá trình này so sánh thứ tự logic của dữ liệu thay vì con trỏ hay ô lưu vật lý.
- Queue trước cạnh: [A0, A1, A2, A3]
- Giá trị pop dự kiến: Giữ head cũ A0
- Áp dụng push: [A1, A2, A3, B0]
- So sánh phản hồi: Khi valid=1, dout=A0
Kiểm tra scoreboard bằng ví dụ biên
Khi queue là [A0,A1,A2,A3] và chỉ có push, kích thước đã bằng 4 nên EE bị bỏ. Với yêu cầu đồng thời tiếp theo, trước hết lưu expected=A0 rồi nối B0 vào cuối để được [A1,A2,A3,B0]. Nếu DUT xuất ngay B0 mới, assertion dữ liệu sẽ thất bại. Ngược lại, khi empty và có cả hai yêu cầu, expect_pop=0, expect_push=1 nên lưu một phần tử mà không so sánh đầu ra. Trong reset, bỏ qua hai yêu cầu, làm rỗng queue và kiểm tra valid=0.
Kiểm chứng bộ nhớ dùng cùng nguyên tắc. Duy trì mảng tham chiếu theo địa chỉ và bảng initialized; với read-first, lấy giá trị đọc dự kiến trước khi cập nhật phép ghi tham chiếu. Với bypass của tập thanh ghiThanh ghi Mạch lưu trạng thái nhiều bit. Thanh ghi đồng bộ trong khóa học lưu đầu vào đã quy định tại cạnh clock. Tìm hiểu thêm, chọn wr_data khi xung đột rồi mới áp dụng ghi vào mảng tham chiếu. Phải ghi rõ tiền đề kiểm thử là cấm đọc địa chỉ chưa khởi tạo hay chấp nhận phản hồi chưa xác định; không tự đặt 0 làm đáp án. Bộ nhớ truy cập theo địa chỉ cần bộ kiểm tra riêng.
Hãy lần lượt chèn các lỗi như xuất giá trị mới khi full và pop đồng thời, tăng số phần tử khi nhận cả hai thao tác, hoặc bật valid cho pop lúc empty; kiểm tra tương ứng phải thất bại. Cách rà soát này và coverage theo từng điều kiện biên giúp tìm thiếu sót trong chính kiểm thử. Việc bố trí tài nguyên RAM và timing cần được xác minh riêng bằng tổng hợp và kiểm tra timing.
Tự thử
Một scoreboard sai đưa yêu cầu push vào queue trước, rồi dùng kích thước đã cập nhật để quyết định cho phép pop. Khi empty mà push và pop đồng thời, nó phán đoán sai thế nào? Khi full và có cả hai yêu cầu, phải lưu dữ liệu dự kiến lúc nào? Hãy đánh giá cả quy tắc luôn kiểm tra dout=0 sau reset.
Đọc giải thích
Mô hình sai cho rằng có thể pop ngay phần tử mới khi empty và có cả hai yêu cầu, nên tạo expect_pop=1. Theo hợp đồng, chấp nhận được quyết định từ kích thước ngay trước cạnh: chỉ nhận push và valid đầu ra phải bằng 0. Khi full, trước hết lưu head cũ của queue vào expected và lấy nó ra, rồi thêm dữ liệu mới vào cuối. Reset không đưa dout về 0, nên chỉ kiểm tra valid=0 cùng queue và occupancy rỗng. So sánh dữ liệu khi expect_pop=1, đồng thời phải so sánh riêng valid của DUT để không bỏ sót lỗi luôn xuất valid=0.