add randomized tests for sync/rst/start longevity
This commit is contained in:
@ -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
|
||||
Reference in New Issue
Block a user