From 1a3b811e757f8fd703f17bcfe04f1c715598f22c Mon Sep 17 00:00:00 2001 From: Zer0Nu11 Date: Tue, 9 Jun 2026 14:12:55 +0300 Subject: [PATCH] add randomized tests for sync/rst/start longevity --- rtl/generator/tests/generator_tb.sv | 290 ++++++++++++++++++---------- 1 file changed, 188 insertions(+), 102 deletions(-) diff --git a/rtl/generator/tests/generator_tb.sv b/rtl/generator/tests/generator_tb.sv index 3512745..c2eaf85 100644 --- a/rtl/generator/tests/generator_tb.sv +++ b/rtl/generator/tests/generator_tb.sv @@ -1,129 +1,215 @@ `timescale 1ns / 1ps 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 rst; logic start; - - logic [31:0] pulse_width; - logic [31:0] pulse_period; - logic [DATA_WIDTH-1:0] pulse_height; - logic [15:0] pulse_num; - - wire pulse; - wire [DATA_WIDTH-1:0] dac_out; - wire sample_done; - logic sample_req; + // Входные сигналы + logic [31:0] pulse_width; // config reg + logic [31:0] pulse_period; // config reg + logic [DATA_WIDTH-1:0] pulse_height; // config reg + logic [15:0] pulse_num; // config reg + logic sampler_done; // sampler request for synchronization + // Выходные сигналы + wire dac_wrt; // DAC wrt singnal + wire [DATA_WIDTH-1:0] dac_out; // DAC input logic signal + wire generator_done; // generator request for synchronization // DUT - generator #( - .DATA_WIDTH(DATA_WIDTH), - .ZERO_LEVEL(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(pulse), - .dac_out(dac_out), - .done(sample_done), - .request(sample_req) - ); + generate + if (ZERO_LEVEL == "true") begin : gen_dut_true + generator #( + .DATA_WIDTH(DATA_WIDTH), + .ZERO_LEVEL(VOLTAGE_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: 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 clk = 0; forever #(CLK_PERIOD/2) clk = ~clk; 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; start = 0; - pulse_width = 0; pulse_period = 0; pulse_height = 0; pulse_num = 0; - sample_req = 0; + sampler_done = 0; - repeat(5) @(posedge clk); - rst = 0; + check_impulses(); - repeat(2) @(posedge clk); - pulse_width = 0; - 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; + $display("[TB] Все тесты выполнены!"); + $finish; end - // // Display - // always @(posedge clk) begin - // $display("t=%0t | pulse=%0b | height=%h", - // $time, pulse, pulse_height_out); - // end - endmodule \ No newline at end of file