add randomized tests for sync/rst/start longevity

This commit is contained in:
Zer0Nu11
2026-06-09 14:12:55 +03:00
parent 9c74fe91e8
commit 1a3b811e75

View File

@ -1,129 +1,215 @@
`timescale 1ns / 1ps `timescale 1ns / 1ps
module generator_tb; module generator_tb;
// === Параметры ===
localparam DATA_WIDTH = 14;
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
localparam VOLTAGE_ZERO_LEVEL = 2**(DATA_WIDTH-1); // DAC 0V for logic zero
localparam CLK_PERIOD = 8;
parameter string ZERO_LEVEL = "logic"; // "logic" VS "true"
parameter DATA_WIDTH = 14; // === Сигналы ===
parameter ZERO_LEVEL = 0; // Системные сигналы
parameter CLK_PERIOD = 8;
logic clk; logic clk;
logic rst; logic rst;
logic start; logic start;
// Входные сигналы
logic [31:0] pulse_width; logic [31:0] pulse_width; // config reg
logic [31:0] pulse_period; logic [31:0] pulse_period; // config reg
logic [DATA_WIDTH-1:0] pulse_height; logic [DATA_WIDTH-1:0] pulse_height; // config reg
logic [15:0] pulse_num; logic [15:0] pulse_num; // config reg
logic sampler_done; // sampler request for synchronization
wire pulse; // Выходные сигналы
wire [DATA_WIDTH-1:0] dac_out; wire dac_wrt; // DAC wrt singnal
wire sample_done; wire [DATA_WIDTH-1:0] dac_out; // DAC input logic signal
logic sample_req; wire generator_done; // generator request for synchronization
// DUT // DUT
generator #( generate
.DATA_WIDTH(DATA_WIDTH), if (ZERO_LEVEL == "true") begin : gen_dut_true
.ZERO_LEVEL(ZERO_LEVEL) generator #(
) dut ( .DATA_WIDTH(DATA_WIDTH),
.clk_dac(clk), .ZERO_LEVEL(VOLTAGE_ZERO_LEVEL)
.rst(rst), ) dut (
.start(start), .clk_dac(clk),
.pulse_width(pulse_width), .rst(rst),
.pulse_period(pulse_period), .start(start),
.pulse_height(pulse_height), .pulse_width(pulse_width),
.pulse_num(pulse_num), .pulse_period(pulse_period),
.dac_wrt(pulse), .pulse_height(pulse_height),
.dac_out(dac_out), .pulse_num(pulse_num),
.done(sample_done), .dac_wrt(dac_wrt),
.request(sample_req) .dac_out(dac_out),
); .done(generator_done),
.request(sampler_done)
);
initial $display("[TB] Скомпилирован генератор ZERO_LEVEL: TRUE");
end
else if (ZERO_LEVEL == "logic") begin : gen_dut_logic
generator #(
.DATA_WIDTH(DATA_WIDTH),
.ZERO_LEVEL(LOGIC_ZERO_LEVEL)
) dut (
.clk_dac(clk),
.rst(rst),
.start(start),
.pulse_width(pulse_width),
.pulse_period(pulse_period),
.pulse_height(pulse_height),
.pulse_num(pulse_num),
.dac_wrt(dac_wrt),
.dac_out(dac_out),
.done(generator_done),
.request(sampler_done)
);
initial $display("[TB] Скомпилирован генератор ZERO_LEVEL: LOGIC");
end
else begin : gen_dut_error
// защита от дурака
initial begin
$display("[ERROR] Неизвестное значение ZERO_LEVEL: %s", ZERO_LEVEL);
$finish;
end
end
endgenerate
// Clock // Тактовые сигналы
initial begin initial begin
clk = 0; clk = 0;
forever #(CLK_PERIOD/2) clk = ~clk; forever #(CLK_PERIOD/2) clk = ~clk;
end end
initial begin // === Таски для тестипрования ===
$display("\n=== GENERATOR TEST ===\n"); // Таска синхронизации, одно рукопожатие
task automatic synchronize(
input bit sampler_first, // 1 - выставить sampler_done ДО генератора, 0 - ПОСЛЕ
input int delay_before_ack, // Если sampler_first=0: задержка ПОСЛЕ gen_done. Если 1: задержка от НАЧАЛА цикла.
input int ack_duration // сколько тактов удерживать sampler_done после встречи сигналов
);
if (sampler_first) begin
// --- сэмплер готов до генератора ---
repeat(delay_before_ack) @(posedge clk);
sampler_done <= 1;
wait(generator_done == 1);
repeat(ack_duration) @(posedge clk);
sampler_done <= 0;
end
else begin
// --- генератора готов до сэмплер ---
wait(generator_done == 1);
repeat(delay_before_ack) @(posedge clk);
sampler_done <= 1;
repeat(ack_duration) @(posedge clk);
sampler_done <= 0;
end
endtask
// Таска сброса DUT
task automatic reset_dut(
input int rst_duration // сколько тактов держать сброс
);
rst <= 1;
repeat(rst_duration) @(posedge clk);
rst <= 0;
endtask
// Таска запуска DUT
task automatic start_dut(
input int start_duration // сколько тактов держать импульс
);
start <= 1;
repeat(start_duration) @(posedge clk);
start <= 0;
endtask
// Таска конфигурации DUT
task automatic set_config(
input logic [31:0] w, // ширина импульса
input logic [31:0] p, // период импульса
input logic [15:0] n, // количество импульсов
input logic [DATA_WIDTH-1:0] h // высота импульса
);
// Задаем конфигурационные регистры
@(posedge clk);
pulse_width <= w;
pulse_period <= p;
pulse_num <= n;
pulse_height <= h;
endtask
// Таска проверки устойчивости к долгим управляющим импульсам
task automatic check_impulses;
// Локальные переменные для хранения случайных параметров
int rand_start_duration;
int rand_delay;
int rand_ack;
bit rand_first;
$display("[TB] -check_impulses- Проверка устойчивости к долгим управляющим импульсам");
// 1. Установка базовой конфигурации
set_config(
.w(3),
.p(10),
.n(4),
.h(1024)
);
reset_dut(5);
repeat(2) @(posedge clk);
// 3. Генерируем случайную БОЛЬШУЮ длительность для импульса START
// В норме он 1 такт. Сделаем случайным от 5 до 25 тактов.
rand_start_duration = $urandom_range(5, 25);
$display("[TB] Сгенерирован долгий импульс START: %0d тактов", rand_start_duration);
// 4. Параллельный запуск длинного старта и обработки синхронизации
fork
// Поток 1: Удерживаем старт аномально долго
begin
start_dut(rand_start_duration);
end
// Поток 2: Обслуживаем n=4 циклов синхронизации со случайными задержками
begin
repeat(4) begin
// Рандомизируем параметры для каждого из 4-х рукопожатий
rand_first = $urandom; // Случайно: Самплер первый (1) или Генератор первый (0)
rand_delay = $urandom_range(1, 8); // Случайная задержка ожидания (1..8 тактов)
rand_ack = $urandom_range(10, 30); // Аномально долгий удерживаемый импульс sampler_done (10..30 тактов)
synchronize(
.sampler_first(rand_first),
.delay_before_ack(rand_delay),
.ack_duration(rand_ack)
);
end
end
join
// Ожидание завершения переходных процессов
repeat(10) @(posedge clk);
$display("[TB] -check_impulses- Тест на долгие импульсы пройден");
endtask
// --- ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ ---
initial begin
$display("[TB] Старт тестов");
// Инициализация
rst = 1; rst = 1;
start = 0; start = 0;
pulse_width = 0; pulse_width = 0;
pulse_period = 0; pulse_period = 0;
pulse_height = 0; pulse_height = 0;
pulse_num = 0; pulse_num = 0;
sample_req = 0; sampler_done = 0;
repeat(5) @(posedge clk); check_impulses();
rst = 0;
repeat(2) @(posedge clk); $display("[TB] Все тесты выполнены!");
pulse_width = 0; $finish;
pulse_period = 20;
pulse_num = 4;
pulse_height = 1024;
// startup signal
#1;
start = 1;
@(posedge clk);
#1;
start = 0;
repeat(pulse_num) begin
// syncronization
wait(sample_done == 1);
repeat(4) @(posedge clk);
sample_req = 1;
repeat(2) @(posedge clk);
sample_req = 0;
end
wait(sample_done == 1);
// // --- Test 2 ---
// $display("\n--- SECOND RUN ---\n");
// @(posedge clk);
// pulse_width = 2;
// pulse_period = 5;
// pulse_num = 3;
// pulse_height = 14'h155;
// start = 1;
// @(posedge clk);
// start = 0;
// repeat(40) @(posedge clk);
// pulse_width = 3;
// pulse_period = 8;
// pulse_num = 4;
// pulse_height = 14'h3FF;
// start = 1;
// repeat(1) @(posedge clk);
// start = 0;
// repeat(5) @(posedge clk);
// start = 1;
// pulse_height = 14'h155;
// repeat(1) @(posedge clk);
// start = 0;
// repeat(50) @(posedge clk);
// $display("\n=== TEST FINISHED ===");
#100;
$finish;
end end
// // Display
// always @(posedge clk) begin
// $display("t=%0t | pulse=%0b | height=%h",
// $time, pulse, pulse_height_out);
// end
endmodule endmodule