fast fix of sampler OTR.
fix debug.xdc
Major add of full automated testing for TB.
This commit is contained in:
Zer0Nu11
2026-06-20 03:07:05 +03:00
parent 4fbecd5e30
commit efcd6ef5d0
3 changed files with 244 additions and 37 deletions

View File

@ -1,3 +1,3 @@
# Primary clocks
create_clock -name eth_clk -period 8.000 [get_ports dac_clk_in]
create_clock -name acc_clk -period 15.385 [get_ports adc_clk_in]
create_clock -name geneartor_clk -period 8.000 [get_ports clk_dac]
create_clock -name sampler_clk -period 15.385 [get_ports clk_adc]

View File

@ -19,7 +19,7 @@ module tb_top;
localparam VOLTAGE_ZERO_LEVEL = 2**(DAC_DATA_WIDTH-1); // DAC 0V for logic zero
localparam ZERO_LEVEL = (ZERO_LEVEL_PARAM == "logic") ? LOGIC_ZERO_LEVEL : VOLTAGE_ZERO_LEVEL;
localparam CLOCK_DEVIATION = 1; // Maximum clock deviation of pulse stats
localparam CLOCK_DEVIATION = 2; // Maximum clock deviation of pulse stats
//------------------------------------------------------------
// Тактовые сигналы и сброс
@ -88,6 +88,8 @@ module tb_top;
return (val < 0.0) ? -val : val;
endfunction
`define MIN(x, y) (((x) < (y)) ? (x) : (y))
// Таска сброса DAC DUT
task automatic reset_dut_dac(
input int rst_duration // сколько тактов держать сброс
@ -151,6 +153,10 @@ module tb_top;
out_of_range = out_of_range_val;
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Starting test case");
end
if (randomize_out_of_range)
fork
begin : randomize_out_of_range_proc
@ -186,60 +192,96 @@ module tb_top;
end
join_none
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Starting pulse generation");
end
for (int i = 0; i < pulse_num; i++) begin
if (VERBOSE >= 3) begin
$display("[TB] -run_test_case- Start sync for pulse #%d", i);
end
@(posedge m_axis_tvalid);
if (VERBOSE >= 3) begin
$display("[TB] -run_test_case- Found valid pulse response data positive front");
end
// Старт цикла. Завершение синхронизации
sync_time_stats.push_back($realtime - sync_start_time);
pulse_start_time = $realtime;
// Начало импульса
if (pulse_height != ZERO_LEVEL) begin
wait(m_axis_tdata != ZERO_LEVEL);
if (m_axis_tdata != pulse_height) begin
$display("[ERROR] -run_test_case- Wrong pulse height: %d. Must be: %d", m_axis_tdata, pulse_height);
$finish;
fork
// Поток будет запущен для ненулевых импульсов и гарантированно завершится как только зафиксирует статистику импульса
// Начало импульса
if (pulse_height != ZERO_LEVEL && pulse_width != 0) begin
if (VERBOSE >= 4) begin
$display("[TB] -run_test_case- Wait until pulse become high");
end
wait(m_axis_tdata != ZERO_LEVEL);
// Проверим что высота импульса совпала с заданной. Т.к. OTR != 0 влияет на выходные данные сэмплера, то не будем проверять такие случаи.
// Будем считать что из-за OTR данные изменились (по условию OTR + MSB), проверка пропускается, т.к. сложно понять точное значение OTR в момент обработки данных от tdata
if (m_axis_tdata != pulse_height && (randomize_out_of_range || out_of_range_val)) begin
$display("[ERROR] -run_test_case- Wrong pulse height: %d. Must be: %d", m_axis_tdata, pulse_height);
$finish;
end
// Фактическое начало импульса. Поступление высокого уровня
pulse_update_val_time = $realtime;
pulse_delay_time_stats.push_back(pulse_update_val_time - pulse_start_time);
if (VERBOSE >= 4) begin
$display("[TB] -run_test_case- Wait until pulse become low");
end
wait(m_axis_tdata == ZERO_LEVEL);
pulse_width_time_stats.push_back($realtime - pulse_update_val_time);
end
// Фактическое начало импульса. Поступление высокого уровня
pulse_update_val_time = $realtime;
pulse_delay_time_stats.push_back(pulse_update_val_time - pulse_start_time);
wait(m_axis_tdata == ZERO_LEVEL);
pulse_width_time_stats.push_back($realtime - pulse_update_val_time);
end
// Конец импульса
// Конец импульса
join_none
@(negedge m_axis_tvalid);
if (VERBOSE >= 3) begin
$display("[TB] -run_test_case- Found valid pulse response data negative front");
end
// Завершение цикла. Старт синхронизации
pulse_period_time_stats.push_back($realtime - pulse_start_time);
sync_start_time = $realtime;
end
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Stop pulse generation");
end
fork // Проверка с таймаутом на лишние циклы
@(posedge m_axis_tvalid);
repeat(20) @(posedge clk_adc);
repeat(30) @(posedge clk_adc);
join_any
if (m_axis_tvalid == 1) begin
$display("[ERROR] -run_test_case- Extra pulse cycle num. More than must be.");
$finish;
end
if (randomize_out_of_range)
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Exit waiting via timeout");
end
if (randomize_out_of_range) begin
disable randomize_out_of_range_proc;
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Stop randomize_out_of_range_proc");
end
end
// Проверка по статистике. Подсчет средних значений
if (pulse_delay_time_stats.size() != pulse_num) begin
$display("[ERROR] -run_test_case- Size of pulse_delay_time_stats samples not equal to pulse_num");
if (pulse_delay_time_stats.size() != pulse_num && pulse_height != ZERO_LEVEL && pulse_width != 0) begin // Detected with pulse level. Skip if pulse level undetectable
$display("[ERROR] -run_test_case- Size of pulse_delay_time_stats samples not equal to pulse_num: %d VS %d", pulse_delay_time_stats.size(), pulse_num);
$finish;
end
if (pulse_width_time_stats.size() != pulse_num) begin
$display("[ERROR] -run_test_case- Size of pulse_width_time_stats samples not equal to pulse_num");
if (pulse_width_time_stats.size() != pulse_num && pulse_height != ZERO_LEVEL && pulse_width != 0) begin // Detected with pulse level. Skip if pulse level undetectable
$display("[ERROR] -run_test_case- Size of pulse_width_time_stats samples not equal to pulse_num: %d VS %d", pulse_width_time_stats.size(), pulse_num);
$finish;
end
if (pulse_period_time_stats.size() != pulse_num) begin
$display("[ERROR] -run_test_case- Size of pulse_period_time_stats samples not equal to pulse_num");
$display("[ERROR] -run_test_case- Size of pulse_period_time_stats samples not equal to pulse_num: %d VS %d", pulse_period_time_stats.size(), pulse_num);
$finish;
end
if (sync_time_stats.size() != pulse_num) begin
$display("[ERROR] -run_test_case- Size of sync_time_stats samples not equal to pulse_num");
$display("[ERROR] -run_test_case- Size of sync_time_stats samples not equal to pulse_num: %d VS %d", sync_time_stats.size(), pulse_num);
$finish;
end
@ -271,7 +313,7 @@ module tb_top;
$display("[ERROR] -run_test_case- avearge_pulse_delay too big: %0.3f", avearge_pulse_delay);
error_flag = 1;
end
if (fabs(average_pulse_width - pulse_width * CLK_DAC_PERIOD) > CLOCK_DEVIATION * CLK_ADC_PERIOD) begin
if (fabs(average_pulse_width - pulse_width * CLK_DAC_PERIOD * (pulse_height != ZERO_LEVEL)) > CLOCK_DEVIATION * CLK_ADC_PERIOD && sample_num * CLK_ADC_PERIOD >= pulse_width * CLK_DAC_PERIOD) begin
$display("[ERROR] -run_test_case- average_pulse_width deviates from choosen pulse_width. Deviation: %0.3f > %0.3f ns", fabs(average_pulse_width - pulse_width * CLK_DAC_PERIOD), CLOCK_DEVIATION * CLK_ADC_PERIOD);
error_flag = 1;
end
@ -279,8 +321,17 @@ module tb_top;
$display("[ERROR] -run_test_case- average_pulse_period deviates from choosen pulse_width. Deviation: %0.3f > %0.3f ns", fabs(average_pulse_period - sample_num * CLK_ADC_PERIOD), CLOCK_DEVIATION * CLK_ADC_PERIOD);
error_flag = 1;
end
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Pass error processing");
end
if (error_flag)
$finish;
if (VERBOSE >= 2) begin
$display("[TB] -run_test_case- Passed checks");
end
endtask
// Таска
@ -299,7 +350,7 @@ module tb_top;
rst_adc = 0;
rst_dac = 0;
$display("[TB] Test 1. Simple test. (1/2)");
$display("[TB] Test 1. Simple test. (1/3)");
run_test_case(
.pulse_width(50),
.pulse_period(125),
@ -307,26 +358,182 @@ module tb_top;
.pulse_num(5),
.sample_num(65),
.skip_reset(0),
.randomize_start_timing(0),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 1. Simple test. (2/2)");
$display("[TB] Test 1. Simple test. (2/3)");
run_test_case(
.pulse_width(25),
.pulse_period(125),
.pulse_height(2**(ADC_DATA_WIDTH-1)),
.pulse_num(10),
.sample_num(65),
.skip_reset(0),
.randomize_start_timing(0),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 1. Simple test. (3/3)");
run_test_case(
.pulse_width(10),
.pulse_period(50),
.pulse_height(ZERO_LEVEL),
.pulse_num(4),
.sample_num(25),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 1 complete");
$display("[TB] Test 2. Edge cases. Pulse width 0%%. (1/7)");
run_test_case(
.pulse_width(0),
.pulse_period(125),
.pulse_height(2**(ADC_DATA_WIDTH-1)),
.pulse_num(5),
.sample_num(65),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 2. Edge cases. Pulse width 100%%. (2/7)");
run_test_case(
.pulse_width(10),
.pulse_period(10),
.pulse_height(2**(ADC_DATA_WIDTH-1)),
.pulse_num(5),
.sample_num(65),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 2. Edge cases. Pulse height == ZERO_LEVEL. (3/7)");
run_test_case(
.pulse_width(10),
.pulse_period(125),
.pulse_height(ZERO_LEVEL),
.pulse_num(5),
.sample_num(65),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 2. Edge cases. Pulse num == 0. (4/7)");
run_test_case(
.pulse_width(10),
.pulse_period(125),
.pulse_height(2**(ADC_DATA_WIDTH-3)),
.pulse_num(0),
.sample_num(65),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
$display("[TB] Test 2. Edge cases. Sample num time << Pulse width time. (5/7)");
run_test_case(
.pulse_width(10),
.pulse_period(125),
.pulse_height(2**(ADC_DATA_WIDTH-1)),
.pulse_num(5),
.sample_num(2),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(0),
.randomize_out_of_range(0)
);
// Ожидание окончания работы генератора. Т.к. конец работы определяется по tvalid сэмплера, а он завершается сильно раньше. Чтобы не пропустить start следующей таски, ждем
wait(dut.generator_inst.enable == 0);
#50;
$display("[TB] Test 2. Edge cases. Sample num == 0. (6/7)");
// Запустим в работу вручную, т.к. run_test_case обязательно ждет pulse num циклов. Детекция цикла производится по активности сэплера. Ее не должно быть при sample num = 0
set_config(
.w(10),
.p(125),
.h(2**(ADC_DATA_WIDTH-1)),
.n(5),
.sn(0)
);
start_dut(3);
fork
begin : wait_sampler_active_proc
@(posedge m_axis_tvalid);
$display("[ERROR] Sampler active with sample num == 0");
$finish;
end
begin
@(negedge dut.generator_inst.enable);
end
join_any
disable wait_sampler_active_proc;
repeat(30) @(posedge clk_adc);
// Данный тест должен приводить к тому, что сэмплер будет давать крайние значения вместо заданного pulse height из-за OTR=1
// TODO известно что при таких настройках OTR = 1 постоянно. Легко предсказать уровень
// Дописать авто тест
$display("[TB] Test 2. Edge cases. OTR == 1. (7/7)");
run_test_case(
.pulse_width(10),
.pulse_period(125),
.pulse_height(10),
.pulse_num(5),
.sample_num(65),
.skip_reset(1),
.randomize_start_timing(1),
.out_of_range_val(1),
.randomize_out_of_range(0)
);
$display("[TB] Test 2 complete");
// $finish; // TODO remove
$display("[TB] Test 3. Random tests");
for (int i = 0; i < 100; i++) begin
int r_w, r_p, r_n, r_h, r_sn;
bit r_skip, r_otr, r_otr_rand;
// Генерируем параметры
r_p = $urandom_range(50, 150); // Период от 5 до 50
r_w = $urandom_range(10, r_p); // Ширина не больше периода
r_n = $urandom_range(1, 10); // Количество импульсов
r_h = $urandom_range(0, 2**(`MIN(ADC_DATA_WIDTH, DAC_DATA_WIDTH))-1); // Высота импульса
r_sn = $urandom_range(1, 40); // Число сэмплов
r_skip = $urandom_range(0, 1); // Случайный сброс (0 - сброс, 1 - пропуск)
r_otr = $urandom_range(0, 1); // Out Of Range стартовое значение
r_otr_rand = $urandom_range(0, 1); // Сделать OTR случайным
if (VERBOSE >= 1)
$display("[TB] --- Test #%0d (Config: W=%0d, P=%0d, N=%0d, H=%0d, SN=%0d, SkipReset=%0b) ---",
i+1, r_w, r_p, r_n, r_h, r_sn, r_skip);
run_test_case(
.pulse_width(r_w),
.pulse_period(r_p),
.pulse_height(r_h),
.pulse_num(r_n),
.sample_num(r_sn),
.skip_reset(r_skip),
.randomize_start_timing(0),
.out_of_range_val(r_otr),
.randomize_out_of_range(r_otr_rand)
);
wait(dut.generator_inst.enable == 0); // Проверка на завершение работы
#50;
end
$display("[TB] Test 3 complete");
$display("[TB] ALL PASSED");
$display("[TB] Maximum clock deviation of stats %0.2f", CLOCK_DEVIATION);
$finish;
end

View File

@ -83,9 +83,9 @@ module sampler
if (cnt_smp_num != smp_num_reg) begin
cnt_smp_num <= cnt_smp_num +1;
buffer_ready <= 1;
if (!out_of_range_reg) begin
// if (!out_of_range_reg) begin
buffer <= data_converted;
end
// end
end else begin
cnt_smp_num <= '0;
buffer_ready <= 0;
@ -120,16 +120,16 @@ module sampler
if (cnt_smp_num != smp_num_reg) begin
cnt_smp_num <= cnt_smp_num +1;
buffer_ready <= 1;
if (!out_of_range_reg) begin
// if (!out_of_range_reg) begin
buffer <= {buffer[DATA_WIDTH*(PACK_FACTOR-1)-1:0], data_converted};
if (cnt == PACK_FACTOR-1) begin
cnt <= 0;
buffer <= {buffer[DATA_WIDTH*(PACK_FACTOR-1)-1:0], data_converted};
end
else begin
cnt <= cnt + 1;
end
end
else begin
cnt <= cnt + 1;
end
// end
end else begin
cnt_smp_num <= '0;
buffer_ready <= 0;