fix: revert synchronizer changes (false changes) and sampler
This commit is contained in:
@ -1,3 +1,12 @@
|
||||
# Primary clocks
|
||||
create_clock -name eth_clk -period 8.000 [get_ports clk_dac]
|
||||
create_clock -name acc_clk -period 15.385 [get_ports clk_adc]
|
||||
create_clock -name geneartor_clk -period 8.000 [get_ports clk_dac]
|
||||
create_clock -name sampler_clk -period 15.385 [get_ports clk_adc]
|
||||
set_clock_groups -asynchronous -group [get_clocks geneartor_clk] -group [get_clocks sampler_clk]
|
||||
|
||||
# set_false_path -through [get_nets -hierarchical {*dac_signal* *internal_wire_singnal* *adc_singnal*}]
|
||||
# set_false_path -through [get_nets {dac_done dac_done_stretched dac_request adc_done adc_request}]
|
||||
|
||||
set_property DONT_TOUCH true [get_cells -hierarchical -filter {NAME =~ *generator_inst*pulse_height_reg*}]
|
||||
set_property DONT_TOUCH true [get_cells -hierarchical -filter {NAME =~ *generator_inst*dac_out_reg*}]
|
||||
# Применяем к самому проводу сигнала CE, чтобы Vivado не дробила его
|
||||
# set_property DONT_TOUCH true [get_nets -of_objects [get_pins -hierarchical -filter {PIN_NAME =~ *CE} -of_objects [get_cells *pulse_height_reg*]]]
|
||||
@ -6,7 +6,8 @@ module sync_top
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12, // ADC bit-width
|
||||
parameter int unsigned PACK_FACTOR = 1, // number of ADC readings per transaction
|
||||
parameter int unsigned PROCESS_MODE = 0, // representation format of ADC readings (0 - direct code, 1 - 2's completment)
|
||||
parameter int unsigned ZERO_LEVEL = 0
|
||||
parameter int unsigned ZERO_LEVEL = 0,
|
||||
parameter int unsigned USE_DELAY_LINE = 0
|
||||
)
|
||||
(
|
||||
input clk_adc,
|
||||
@ -16,9 +17,9 @@ module sync_top
|
||||
input start,
|
||||
input out_of_range,
|
||||
input [31:0] pulse_width,
|
||||
input [31:0] pulse_period,
|
||||
input [31:0] pulse_period, // DAC counter limit
|
||||
input [DAC_DATA_WIDTH-1:0] pulse_height,
|
||||
input [15:0] pulse_num, // DAC counter limit
|
||||
input [15:0] pulse_num,
|
||||
input [31:0] smp_num, // ADC counter limit
|
||||
output [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata,
|
||||
output m_axis_tvalid
|
||||
@ -29,13 +30,45 @@ module sync_top
|
||||
//------------------------------------------------------------
|
||||
wire dac_done, dac_request, adc_done, adc_request;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_signal;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_singnal;
|
||||
wire [ADC_DATA_WIDTH-1:0] internal_wire_signal;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_signal;
|
||||
|
||||
// 1. Адаптация разрядности и «заземление» лишних бит
|
||||
generate
|
||||
if (ADC_DATA_WIDTH > DAC_DATA_WIDTH) begin : g_pad_zeros
|
||||
assign adc_singnal = { {(ADC_DATA_WIDTH - DAC_DATA_WIDTH){1'b0}}, dac_signal };
|
||||
// АЦП шире ЦАП: добиваем нулями старшие биты
|
||||
assign internal_wire_signal = { {(ADC_DATA_WIDTH - DAC_DATA_WIDTH){1'b0}}, dac_signal };
|
||||
end
|
||||
else if (ADC_DATA_WIDTH < DAC_DATA_WIDTH) begin : g_truncate
|
||||
// ЦАП шире АЦП (например, 14 -> 12): забираем младшие биты
|
||||
assign internal_wire_signal = dac_signal[DAC_DATA_WIDTH-1:DAC_DATA_WIDTH-ADC_DATA_WIDTH];
|
||||
// (* mark_debug = "true" *) wire dummy;
|
||||
// assign dummy = ^dac_signal;
|
||||
end
|
||||
else begin : g_match
|
||||
// Разрядности равны
|
||||
assign internal_wire_signal = dac_signal;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (USE_DELAY_LINE > 0) begin : g_delay_line
|
||||
localparam int DELAY_LENGTH = USE_DELAY_LINE;
|
||||
// Двумерный массив для линии задержки
|
||||
logic [DELAY_LENGTH-1:0][ADC_DATA_WIDTH-1:0] signal_delay_line;
|
||||
|
||||
always_ff @(posedge clk_dac) begin
|
||||
signal_delay_line[0] <= internal_wire_signal;
|
||||
for (int i = 0; i < DELAY_LENGTH-1; i++) begin
|
||||
signal_delay_line[i+1] <= signal_delay_line[i];
|
||||
end
|
||||
end
|
||||
|
||||
// ИСПРАВЛЕНО: читаем из последнего элемента массива
|
||||
assign adc_signal = signal_delay_line[DELAY_LENGTH-1];
|
||||
end
|
||||
else begin : g_truncate
|
||||
assign adc_singnal = dac_signal[ADC_DATA_WIDTH-1:0];
|
||||
else begin : g_no_delay
|
||||
assign adc_signal = internal_wire_signal;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
@ -112,7 +145,7 @@ module sync_top
|
||||
) sampler_inst (
|
||||
.clk_in(clk_adc),
|
||||
.rst(rst_adc),
|
||||
.data_in(adc_singnal),
|
||||
.data_in(adc_signal),
|
||||
.out_of_range(out_of_range),
|
||||
.smp_num(smp_num),
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
|
||||
@ -5,16 +5,21 @@ module tb_top;
|
||||
//------------------------------------------------------------
|
||||
// Параметры
|
||||
//------------------------------------------------------------
|
||||
parameter string ZERO_LEVEL_PARAM = "logic"; // "logic" VS "true"
|
||||
parameter VERBOSE = 1;
|
||||
|
||||
localparam DAC_DATA_WIDTH = 14;
|
||||
localparam ADC_DATA_WIDTH = 12;
|
||||
localparam PACK_FACTOR = 1;
|
||||
localparam PROCESS_MODE = 0;
|
||||
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
|
||||
localparam VOLTAGE_ZERO_LEVEL = 2**(DAC_DATA_WIDTH-1); // DAC 0V for logic zero
|
||||
localparam CLK_DAC_PERIOD = 8;
|
||||
localparam CLK_ADC_PERIOD = 15.385;
|
||||
localparam USE_DELAY_LINE = 0;
|
||||
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
|
||||
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 ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "true"
|
||||
localparam CLOCK_DEVIATION = 3; // Maximum clock deviation of pulse stats
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Тактовые сигналы и сброс
|
||||
@ -49,7 +54,8 @@ module tb_top;
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL)
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.USE_DELAY_LINE(USE_DELAY_LINE)
|
||||
) dut (
|
||||
.clk_adc(clk_adc),
|
||||
.clk_dac(clk_dac),
|
||||
@ -77,12 +83,20 @@ module tb_top;
|
||||
end
|
||||
|
||||
// === Таски для тестирования ===
|
||||
// Функция модуля
|
||||
function automatic real fabs(real val);
|
||||
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 // сколько тактов держать сброс
|
||||
);
|
||||
@(negedge clk_dac);
|
||||
rst_dac <= 1;
|
||||
repeat(rst_duration) @(posedge clk_dac);
|
||||
repeat(rst_duration) @(negedge clk_dac);
|
||||
rst_dac <= 0;
|
||||
endtask
|
||||
|
||||
@ -90,8 +104,9 @@ module tb_top;
|
||||
task automatic reset_dut_adc(
|
||||
input int rst_duration // сколько тактов держать сброс
|
||||
);
|
||||
@(negedge clk_adc);
|
||||
rst_adc <= 1;
|
||||
repeat(rst_duration) @(posedge clk_adc);
|
||||
repeat(rst_duration) @(negedge clk_adc);
|
||||
rst_adc <= 0;
|
||||
endtask
|
||||
|
||||
@ -99,8 +114,9 @@ module tb_top;
|
||||
task automatic start_dut(
|
||||
input int start_duration // сколько тактов держать импульс
|
||||
);
|
||||
@(negedge clk_dac); // to make signal stable
|
||||
dac_start <= 1;
|
||||
repeat(start_duration) @(posedge clk_dac);
|
||||
repeat(start_duration) @(negedge clk_dac);
|
||||
dac_start <= 0;
|
||||
endtask
|
||||
|
||||
@ -113,196 +129,435 @@ module tb_top;
|
||||
input logic [31:0] sn // число сэмплов
|
||||
);
|
||||
// Задаем конфигурационные регистры
|
||||
@(posedge clk_dac);
|
||||
pulse_width <= w;
|
||||
pulse_period <= p;
|
||||
pulse_num <= n;
|
||||
pulse_height <= h;
|
||||
smp_num <= sn;
|
||||
endtask
|
||||
|
||||
// Основная таска проверки DUT
|
||||
task automatic run_test_case(
|
||||
input int pulse_width,
|
||||
input int pulse_period,
|
||||
input int pulse_height,
|
||||
input int pulse_num,
|
||||
input int sample_num,
|
||||
input bit skip_reset,
|
||||
input bit randomize_start_timing,
|
||||
input bit out_of_range_val,
|
||||
input bit randomize_out_of_range
|
||||
);
|
||||
int error_flag = 0;
|
||||
int start_hold_time = 1;
|
||||
realtime sync_start_time, pulse_start_time, pulse_update_val_time;
|
||||
realtime sync_time_stats[$], pulse_width_time_stats[$], pulse_period_time_stats[$], pulse_delay_time_stats[$];
|
||||
realtime avearge_pulse_delay, average_pulse_width, average_pulse_period, average_sync_time;
|
||||
|
||||
// // Таска проверки устойчивости к долгим управляющим импульсам
|
||||
// task automatic check_impulses;
|
||||
// // Локальные переменные для хранения случайных параметров
|
||||
// int rand_start_duration;
|
||||
// int rand_delay;
|
||||
// int rand_ack;
|
||||
// bit rand_first;
|
||||
// int total_impulse_cycles = 0;
|
||||
out_of_range = out_of_range_val;
|
||||
|
||||
// int pulse_w = 11;
|
||||
// int pulse_p = 31;
|
||||
// int pulse_n = 5;
|
||||
// int pulse_h = 1024;
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Starting test case");
|
||||
end
|
||||
|
||||
// $display("[TB] -check_impulses- Check system stability under random latencies");
|
||||
if (randomize_out_of_range)
|
||||
fork
|
||||
begin : randomize_out_of_range_proc
|
||||
forever begin
|
||||
@(posedge clk_adc);
|
||||
out_of_range = $urandom_range(0, 1);
|
||||
end
|
||||
end
|
||||
join_none
|
||||
|
||||
// // Установка конфигурации
|
||||
// set_config(
|
||||
// .w(pulse_w),
|
||||
// .p(pulse_p),
|
||||
// .n(pulse_n),
|
||||
// .h(pulse_h)
|
||||
// );
|
||||
if (!skip_reset)
|
||||
fork
|
||||
reset_dut_adc(1);
|
||||
reset_dut_dac(1);
|
||||
join
|
||||
|
||||
// reset_dut(5);
|
||||
// repeat(2) @(posedge clk);
|
||||
set_config(
|
||||
.w(pulse_width),
|
||||
.p(pulse_period),
|
||||
.n(pulse_num),
|
||||
.h(pulse_height),
|
||||
.sn(sample_num)
|
||||
);
|
||||
@(posedge clk_dac);
|
||||
@(posedge clk_dac);
|
||||
|
||||
// // Старт норме 1 такт. Сделаем случайным от 5 до 25 тактов.
|
||||
// rand_start_duration = $urandom_range(5, 25);
|
||||
// $display("[TB] Long start: %0d clocks", rand_start_duration);
|
||||
if (randomize_start_timing)
|
||||
start_hold_time = $urandom_range(1, 15);
|
||||
fork // warning: check not forever
|
||||
start_dut(start_hold_time);
|
||||
begin
|
||||
@(posedge clk_dac);
|
||||
// старт первой синхронизации
|
||||
sync_start_time = $realtime;
|
||||
end
|
||||
join_none
|
||||
|
||||
// // Фоновый процесс подсчета тактов импульса
|
||||
// fork
|
||||
// begin : counter_proc
|
||||
// forever begin
|
||||
// @(negedge clk); // 180 deg. phase shift for "DAC strobing signal"
|
||||
// if (dac_out == pulse_h) begin
|
||||
// total_impulse_cycles++;
|
||||
// end
|
||||
// end
|
||||
// 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;
|
||||
|
||||
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);
|
||||
// Фактическое начало импульса. Поступление высокого уровня
|
||||
pulse_update_val_time = $realtime;
|
||||
pulse_delay_time_stats.push_back(pulse_update_val_time - pulse_start_time);
|
||||
|
||||
// Проверим что высота импульса совпала с заданной. Т.к. OTR != 0 влияет на выходные данные сэмплера, то не будем проверять такие случаи.
|
||||
@(posedge clk_adc);
|
||||
#1.5; // Ожидание завершения переходных процессов
|
||||
// Будем считать что из-за OTR данные изменились (по условию OTR + MSB), проверка пропускается, т.к. сложно понять точное значение OTR в момент обработки данных от tdata
|
||||
if (m_axis_tdata != (pulse_height >> 2) && (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 >> 2);
|
||||
$finish;
|
||||
end
|
||||
|
||||
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
|
||||
// Конец импульса
|
||||
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(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 (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
|
||||
out_of_range = 0;
|
||||
|
||||
// Проверка по статистике. Подсчет средних значений
|
||||
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 && 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: %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: %d VS %d", sync_time_stats.size(), pulse_num);
|
||||
$finish;
|
||||
end
|
||||
|
||||
avearge_pulse_delay = 0;
|
||||
foreach (pulse_delay_time_stats[i])
|
||||
avearge_pulse_delay += pulse_delay_time_stats[i];
|
||||
avearge_pulse_delay /= pulse_num;
|
||||
|
||||
average_pulse_width = 0;
|
||||
foreach (pulse_width_time_stats[i])
|
||||
average_pulse_width += pulse_width_time_stats[i];
|
||||
average_pulse_width /= pulse_num;
|
||||
|
||||
average_pulse_period = 0;
|
||||
foreach (pulse_period_time_stats[i])
|
||||
average_pulse_period += pulse_period_time_stats[i];
|
||||
average_pulse_period /= pulse_num;
|
||||
|
||||
average_sync_time = 0;
|
||||
foreach (sync_time_stats[i])
|
||||
average_sync_time += sync_time_stats[i];
|
||||
average_sync_time /= pulse_num;
|
||||
|
||||
// // Параллельный запуск длинного старта и обработки синхронизации
|
||||
// fork
|
||||
// // Поток 1: Удерживаем старт аномально долго
|
||||
// begin
|
||||
// start_dut(rand_start_duration);
|
||||
// end
|
||||
// // Поток 2: Обслуживаем n=4 циклов синхронизации со случайными задержками
|
||||
// begin
|
||||
// repeat(pulse_n) begin
|
||||
// // Рандомизируем параметры для каждого из 4-х рукопожатий
|
||||
// rand_first = $urandom; // Случайно: Самплер первый (1) или Генератор первый (0)
|
||||
// rand_delay = $urandom_range(1, 8); // Случайная задержка ожидания (1..8 тактов)
|
||||
// rand_ack = $urandom_range(5, 10); // Аномально долгий удерживаемый импульс sampler_done (10..30 тактов)
|
||||
if (VERBOSE >= 1) begin
|
||||
$display("[TB] -run_test_case- Pulse test stats:\n\tavearge_pulse_delay: %0.3f\n\taverage_pulse_width: %0.3f\n\taverage_pulse_period: %0.3f\n\taverage_sync_time: %0.3f", avearge_pulse_delay, average_pulse_width, average_pulse_period, average_sync_time);
|
||||
end
|
||||
|
||||
// synchronize(
|
||||
// .sampler_first(rand_first),
|
||||
// .delay_before_ack(rand_delay),
|
||||
// .ack_duration(rand_ack)
|
||||
// );
|
||||
// end
|
||||
// end
|
||||
// join
|
||||
// repeat(pulse_p+5) @(posedge clk);
|
||||
// disable counter_proc;
|
||||
// // Ожидание завершения переходных процессов
|
||||
// repeat(10) @(posedge clk);
|
||||
// if (total_impulse_cycles == pulse_w*pulse_n)
|
||||
// $display("[TB] -check_impulses- Pulse generation CORRECT");
|
||||
// else begin
|
||||
// $display("[ERROR] -check_impulses- Pulse generation INCORRECT. Total number of pulses: %d, must be: %d", total_impulse_cycles, pulse_w*pulse_n);
|
||||
// $finish;
|
||||
// end
|
||||
// $display("[TB] -check_impulses- Done");
|
||||
// endtask
|
||||
if (avearge_pulse_delay > CLOCK_DEVIATION * CLK_ADC_PERIOD) begin
|
||||
$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 * (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
|
||||
if (fabs(average_pulse_period - sample_num * CLK_ADC_PERIOD) > CLOCK_DEVIATION * CLK_ADC_PERIOD) begin
|
||||
$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
|
||||
|
||||
// task automatic run_test_case(
|
||||
// input int pulse_w,
|
||||
// input int pulse_p,
|
||||
// input int pulse_n,
|
||||
// input int pulse_h,
|
||||
// input bit skip_reset, // skip reset sequence on demand
|
||||
// input bit count_level // count ticks of amplitude == pulse_h or amplitude != pulse_h
|
||||
// );
|
||||
// int total_impulse_cycles = 0;
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Pass error processing");
|
||||
end
|
||||
|
||||
// if (!skip_reset) begin
|
||||
// reset_dut(1);
|
||||
// @(posedge clk);
|
||||
// end
|
||||
if (error_flag)
|
||||
$finish;
|
||||
|
||||
// set_config(
|
||||
// .w(pulse_w),
|
||||
// .p(pulse_p),
|
||||
// .n(pulse_n),
|
||||
// .h(pulse_h)
|
||||
// );
|
||||
// @(posedge clk);
|
||||
|
||||
// start_dut(1);
|
||||
|
||||
// // Фоновый процесс подсчета тактов импульса
|
||||
// fork
|
||||
// begin : counter_proc
|
||||
// forever begin
|
||||
// @(negedge clk); // 180 deg. phase shift for "DAC strobing signal"
|
||||
// if (count_level) begin
|
||||
// if (dac_out == pulse_h) begin
|
||||
// total_impulse_cycles++;
|
||||
// end
|
||||
// end
|
||||
// else begin
|
||||
// if (dac_out != current_zero_level) begin
|
||||
// total_impulse_cycles++;
|
||||
// end
|
||||
// end
|
||||
// end
|
||||
// end
|
||||
// join_none
|
||||
|
||||
// repeat(pulse_n) begin
|
||||
// synchronize(
|
||||
// .sampler_first(0),
|
||||
// .delay_before_ack(1),
|
||||
// .ack_duration(2)
|
||||
// );
|
||||
// end
|
||||
// repeat(pulse_p+5) @(posedge clk);
|
||||
// disable counter_proc;
|
||||
// repeat(10) @(posedge clk);
|
||||
|
||||
// if (count_level) begin
|
||||
// if (total_impulse_cycles == pulse_w*pulse_n)
|
||||
// $display("[TB] -run_test_case- Pulse generation CORRECT");
|
||||
// else begin
|
||||
// $display("[ERROR] -run_test_case- Pulse generation INCORRECT. Total number of pulses: %d, must be: %d", total_impulse_cycles, pulse_w*pulse_n);
|
||||
// $finish;
|
||||
// end
|
||||
// end
|
||||
// else begin
|
||||
// if (total_impulse_cycles == 0)
|
||||
// $display("[TB] -run_test_case- Pulse generation CORRECT");
|
||||
// else begin
|
||||
// $display("[ERROR] -run_test_case- Pulse generation INCORRECT. Total number of pulses: %d, must be: %d", total_impulse_cycles, 0);
|
||||
// $finish;
|
||||
// end
|
||||
// end
|
||||
// endtask
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Passed checks");
|
||||
end
|
||||
endtask
|
||||
// Таска
|
||||
|
||||
// --- ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ ---
|
||||
initial begin
|
||||
$display("[TB] Tests start");
|
||||
|
||||
// Инициализация
|
||||
dac_start = 0;
|
||||
dac_start = 0;
|
||||
pulse_width = 0;
|
||||
pulse_period = 0;
|
||||
pulse_height = 0;
|
||||
pulse_num = 0;
|
||||
smp_num = 0;
|
||||
out_of_range = 0;
|
||||
fork
|
||||
reset_dut_adc(3);
|
||||
reset_dut_dac(6);
|
||||
join
|
||||
@(posedge clk_dac);
|
||||
@(posedge clk_adc);
|
||||
set_config(
|
||||
.w(50),
|
||||
.p(125),
|
||||
.n(5),
|
||||
.h(1024),
|
||||
.sn(65)
|
||||
rst_adc = 0;
|
||||
rst_dac = 0;
|
||||
|
||||
#100; // init
|
||||
|
||||
$display("[TB] Test 1. Simple test. (1/4)");
|
||||
run_test_case(
|
||||
.pulse_width(50),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**DAC_DATA_WIDTH-1),
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(0),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 1. Simple test. (2/4)");
|
||||
run_test_case(
|
||||
.pulse_width(25),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(ADC_DATA_WIDTH-1)),
|
||||
.pulse_num(10),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 1. Simple test. (3/4)");
|
||||
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)
|
||||
);
|
||||
start_dut(1);
|
||||
|
||||
repeat(1000) @(posedge clk_adc);
|
||||
$display("[TB] Test 1. Simple test. (4/4)");
|
||||
run_test_case(
|
||||
.pulse_width(25),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(DAC_DATA_WIDTH-1)),
|
||||
.pulse_num(10),
|
||||
.sample_num(65),
|
||||
.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");
|
||||
|
||||
$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(2, 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
|
||||
|
||||
endmodule
|
||||
endmodule
|
||||
@ -20,7 +20,7 @@ include ../../scripts/vivado.mk
|
||||
|
||||
INC_FILES += interfaces.svh
|
||||
|
||||
TB_FILES += reflectometer_tb.sv
|
||||
TB_FILES += reflectometer_tb.sv
|
||||
SYN_FILES += reflectometer.sv
|
||||
SYN_FILES += dac_model.sv
|
||||
SYN_FILES += adc_model.sv
|
||||
|
||||
@ -152,8 +152,8 @@ module reflectometer_tb;
|
||||
|
||||
// AXI-S таски
|
||||
task automatic axis_send_packet(
|
||||
virtual axis_if.tb vif,
|
||||
const ref logic [7:0] payload[]
|
||||
virtual axis_if.tb vif,
|
||||
logic [7:0] payload[]
|
||||
);
|
||||
int packet_size = payload.size();
|
||||
|
||||
@ -163,17 +163,18 @@ module reflectometer_tb;
|
||||
end
|
||||
|
||||
foreach (payload[i]) begin
|
||||
vif.drv_cb.tdata <= payload[i];
|
||||
vif.drv_cb.tvalid <= 1'b1;
|
||||
vif.drv_cb.tlast <= (i == packet_size - 1); // tlast активен только на последнем байте
|
||||
$display("%1", payload[i]);
|
||||
// vif.drv_cb.tdata <= payload[i];
|
||||
// vif.drv_cb.tvalid <= 1'b1;
|
||||
// vif.drv_cb.tlast <= (i == packet_size - 1); // tlast активен только на последнем байте
|
||||
|
||||
// Шагаем на следующий фронт клока, чтобы симулятор применил выходы
|
||||
@(vif.drv_cb);
|
||||
// // Шагаем на следующий фронт клока, чтобы симулятор применил выходы
|
||||
// @(vif.drv_cb);
|
||||
|
||||
// Ждем на последующих фронтах, пока tready не станет равен 1.
|
||||
while (vif.drv_cb.tready !== 1'b1) begin
|
||||
@(vif.drv_cb);
|
||||
end
|
||||
// // Ждем на последующих фронтах, пока tready не станет равен 1.
|
||||
// while (vif.drv_cb.tready !== 1'b1) begin
|
||||
// @(vif.drv_cb);
|
||||
// end
|
||||
end
|
||||
|
||||
// Снимаем валидность на следующем дельта-цикле
|
||||
@ -206,7 +207,7 @@ module reflectometer_tb;
|
||||
input logic [31:0] pulse_period_adc
|
||||
);
|
||||
// Выделяем 17 байт: 1 байт команды + 16 байт регистров
|
||||
logic [7:0] full_packet[] = new[17];
|
||||
logic [7:0] full_packet[17];
|
||||
|
||||
// 1. Сначала пишем команду в нулевой байт пакета
|
||||
full_packet[0] = 8'b10001000; // Твоя команда set_data
|
||||
@ -253,11 +254,13 @@ module reflectometer_tb;
|
||||
$display("[TB] Tests start");
|
||||
|
||||
// Инициализация
|
||||
rst_n = 0;
|
||||
#100;
|
||||
rst_n = 1;
|
||||
wait(mmcm_locked === 1'b1);
|
||||
#10;
|
||||
|
||||
// dut_soft_reset();
|
||||
dut_soft_reset();
|
||||
// dut_send_system_config(
|
||||
// .pulse_width(32'd350),
|
||||
// .pulse_period(32'd1250),
|
||||
|
||||
117
designs/reflectometer_base/reflectometer_tb_behav.wcfg
Normal file
117
designs/reflectometer_base/reflectometer_tb_behav.wcfg
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<wave_config>
|
||||
<wave_state>
|
||||
</wave_state>
|
||||
<db_ref_list>
|
||||
<db_ref path="reflectometer_tb_behav.wdb" id="1">
|
||||
<top_modules>
|
||||
<top_module name="glbl" />
|
||||
<top_module name="reflectometer_tb" />
|
||||
</top_modules>
|
||||
</db_ref>
|
||||
</db_ref_list>
|
||||
<zoom_setting>
|
||||
<ZoomStartTime time="0.000 ns"></ZoomStartTime>
|
||||
<ZoomEndTime time="1,506.001 ns"></ZoomEndTime>
|
||||
<Cursor1Time time="1,000.000 ns"></Cursor1Time>
|
||||
</zoom_setting>
|
||||
<column_width_setting>
|
||||
<NameColumnWidth column_width="196"></NameColumnWidth>
|
||||
<ValueColumnWidth column_width="76"></ValueColumnWidth>
|
||||
</column_width_setting>
|
||||
<WVObjectSize size="7" />
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/mmcm_locked">
|
||||
<obj_property name="ElementShortName">mmcm_locked</obj_property>
|
||||
<obj_property name="ObjectShortName">mmcm_locked</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group28">
|
||||
<obj_property name="label">Signal</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/dac_data">
|
||||
<obj_property name="ElementShortName">dac_data[13:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">dac_data[13:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="other" fp_name="/reflectometer_tb/signal_voltage">
|
||||
<obj_property name="ElementShortName">signal_voltage</obj_property>
|
||||
<obj_property name="ObjectShortName">signal_voltage</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/adc_data">
|
||||
<obj_property name="ElementShortName">adc_data[11:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">adc_data[11:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/adc_otr">
|
||||
<obj_property name="ElementShortName">adc_otr</obj_property>
|
||||
<obj_property name="ObjectShortName">adc_otr</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/send_request">
|
||||
<obj_property name="ElementShortName">send_request</obj_property>
|
||||
<obj_property name="ObjectShortName">send_request</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/request_ready">
|
||||
<obj_property name="ElementShortName">request_ready</obj_property>
|
||||
<obj_property name="ObjectShortName">request_ready</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group51">
|
||||
<obj_property name="label">Controller</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<obj_property name="isExpanded"></obj_property>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/clk">
|
||||
<obj_property name="ElementShortName">clk</obj_property>
|
||||
<obj_property name="ObjectShortName">clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/axis_control_if/tdata">
|
||||
<obj_property name="ElementShortName">tdata[7:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">tdata[7:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tvalid">
|
||||
<obj_property name="ElementShortName">tvalid</obj_property>
|
||||
<obj_property name="ObjectShortName">tvalid</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tlast">
|
||||
<obj_property name="ElementShortName">tlast</obj_property>
|
||||
<obj_property name="ObjectShortName">tlast</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tready">
|
||||
<obj_property name="ElementShortName">tready</obj_property>
|
||||
<obj_property name="ObjectShortName">tready</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group52">
|
||||
<obj_property name="label">Accumulator</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<obj_property name="isExpanded"></obj_property>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/clk">
|
||||
<obj_property name="ElementShortName">clk</obj_property>
|
||||
<obj_property name="ObjectShortName">clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/axis_accumulator_if/tdata">
|
||||
<obj_property name="ElementShortName">tdata[7:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">tdata[7:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tvalid">
|
||||
<obj_property name="ElementShortName">tvalid</obj_property>
|
||||
<obj_property name="ObjectShortName">tvalid</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tlast">
|
||||
<obj_property name="ElementShortName">tlast</obj_property>
|
||||
<obj_property name="ObjectShortName">tlast</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tready">
|
||||
<obj_property name="ElementShortName">tready</obj_property>
|
||||
<obj_property name="ObjectShortName">tready</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
</wave_config>
|
||||
Reference in New Issue
Block a user