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