215 lines
8.4 KiB
Systemverilog
215 lines
8.4 KiB
Systemverilog
`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"
|
||
|
||
// === Сигналы ===
|
||
// Системные сигналы
|
||
logic clk;
|
||
logic rst;
|
||
logic start;
|
||
// Входные сигналы
|
||
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
|
||
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
|
||
|
||
// Тактовые сигналы
|
||
initial begin
|
||
clk = 0;
|
||
forever #(CLK_PERIOD/2) clk = ~clk;
|
||
end
|
||
|
||
// === Таски для тестипрования ===
|
||
// Таска синхронизации, одно рукопожатие
|
||
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;
|
||
sampler_done = 0;
|
||
|
||
check_impulses();
|
||
|
||
$display("[TB] Все тесты выполнены!");
|
||
$finish;
|
||
end
|
||
|
||
endmodule |