diff --git a/designs/adc_dac_synchoronizer/tb_sync_top.sv b/designs/adc_dac_synchoronizer/tb_sync_top.sv index a722e7e..b029cd1 100644 --- a/designs/adc_dac_synchoronizer/tb_sync_top.sv +++ b/designs/adc_dac_synchoronizer/tb_sync_top.sv @@ -3,7 +3,7 @@ module tb_top; //------------------------------------------------------------ - // Параметры + // ��������� //------------------------------------------------------------ parameter string ZERO_LEVEL_PARAM = "logic"; // "logic" VS "true" parameter VERBOSE = 1; @@ -22,14 +22,14 @@ module tb_top; localparam CLOCK_DEVIATION = 3; // Maximum clock deviation of pulse stats //------------------------------------------------------------ - // Тактовые сигналы и сброс + // �������� ������� � ����� //------------------------------------------------------------ logic clk_dac; logic rst_dac; logic clk_adc; logic rst_adc; //------------------------------------------------------------ - // Управление и конфиг + // ���������� � ������ //------------------------------------------------------------ logic dac_start; logic [31:0] pulse_width; @@ -38,11 +38,11 @@ module tb_top; logic [15:0] pulse_num; logic [31:0] smp_num; //------------------------------------------------------------ - // Входы + // ����� //------------------------------------------------------------ reg out_of_range; //------------------------------------------------------------ - // Выходы + // ������ //------------------------------------------------------------ wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata; wire m_axis_tvalid; @@ -72,7 +72,7 @@ module tb_top; .out_of_range(out_of_range) ); - // Тактовые сигналы + // �������� ������� initial begin clk_adc = 0; forever #(CLK_ADC_PERIOD/2) clk_adc = ~clk_adc; @@ -82,17 +82,17 @@ module tb_top; forever #(CLK_DAC_PERIOD/2) clk_dac = ~clk_dac; end - // === Таски для тестирования === - // Функция модуля + // === ����� ��� ������������ === + // ������� ������ function automatic real fabs(real val); return (val < 0.0) ? -val : val; endfunction `define MIN(x, y) (((x) < (y)) ? (x) : (y)) - // Таска сброса DAC DUT + // ����� ������ DAC DUT task automatic reset_dut_dac( - input int rst_duration // сколько тактов держать сброс + input int rst_duration // ������� ������ ������� ����� ); @(negedge clk_dac); rst_dac <= 1; @@ -100,9 +100,9 @@ module tb_top; rst_dac <= 0; endtask - // Таска сброса ADC DUT + // ����� ������ ADC DUT task automatic reset_dut_adc( - input int rst_duration // сколько тактов держать сброс + input int rst_duration // ������� ������ ������� ����� ); @(negedge clk_adc); rst_adc <= 1; @@ -110,9 +110,9 @@ module tb_top; rst_adc <= 0; endtask - // Таска запуска DUT + // ����� ������� DUT task automatic start_dut( - input int start_duration // сколько тактов держать импульс + input int start_duration // ������� ������ ������� ������� ); @(negedge clk_dac); // to make signal stable dac_start <= 1; @@ -120,15 +120,15 @@ module tb_top; dac_start <= 0; endtask - // Таска конфигурации DUT + // ����� ������������ DUT task automatic set_config( - input logic [31:0] w, // ширина импульса - input logic [31:0] p, // период импульса - input logic [15:0] n, // количество импульсов - input logic [DAC_DATA_WIDTH-1:0] h, // высота импульса - input logic [31:0] sn // число сэмплов + input logic [31:0] w, // ������ �������� + input logic [31:0] p, // ������ �������� + input logic [15:0] n, // ���������� ��������� + input logic [DAC_DATA_WIDTH-1:0] h, // ������ �������� + input logic [31:0] sn // ����� ������� ); - // Задаем конфигурационные регистры + // ������ ���������������� �������� pulse_width <= w; pulse_period <= p; pulse_num <= n; @@ -136,7 +136,7 @@ module tb_top; smp_num <= sn; endtask - // Основная таска проверки DUT + // �������� ����� �������� DUT task automatic run_test_case( input int pulse_width, input int pulse_period, @@ -192,7 +192,7 @@ module tb_top; start_dut(start_hold_time); begin @(posedge clk_dac); - // старт первой синхронизации + // ����� ������ ������������� sync_start_time = $realtime; end join_none @@ -209,27 +209,28 @@ module tb_top; 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 влияет на выходные данные сэмплера, то не будем проверять такие случаи. + // �������� ��� ������ �������� ������� � ��������. �.�. 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 + #1.5; // �������� ���������� ���������� ��������� + // todo fix + // ����� ������� ��� ��-�� 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 @@ -240,14 +241,14 @@ module tb_top; 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 @@ -256,7 +257,7 @@ module tb_top; $display("[TB] -run_test_case- Stop pulse generation"); end - fork // Проверка с таймаутом на лишние циклы + fork // �������� � ��������� �� ������ ����� @(posedge m_axis_tvalid); repeat(30) @(posedge clk_adc); join_any @@ -277,12 +278,13 @@ module tb_top; 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 + // �������� �� ����������. ������� ������� �������� + // todo randomize_out_of_range || out_of_range_val + if (pulse_delay_time_stats.size() != pulse_num && pulse_height != ZERO_LEVEL && pulse_width != 0 && !(randomize_out_of_range || out_of_range_val)) 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 + if (pulse_width_time_stats.size() != pulse_num && pulse_height != ZERO_LEVEL && pulse_width != 0 && !(randomize_out_of_range || out_of_range_val)) 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 @@ -323,7 +325,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 * (pulse_height != ZERO_LEVEL)) > CLOCK_DEVIATION * CLK_ADC_PERIOD && sample_num * CLK_ADC_PERIOD >= pulse_width * CLK_DAC_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 && !(randomize_out_of_range || out_of_range_val)) 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 @@ -343,13 +345,13 @@ module tb_top; $display("[TB] -run_test_case- Passed checks"); end endtask - // Таска + // ����� - // --- ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ --- + // --- �������� ������� ����??�����??� --- initial begin $display("[TB] Tests start"); - // Инициализация + // ??������������ dac_start = 0; pulse_width = 0; pulse_period = 0; @@ -475,12 +477,12 @@ module tb_top; .randomize_out_of_range(0) ); - // Ожидание окончания работы генератора. Т.к. конец работы определяется по tvalid сэмплера, а он завершается сильно раньше. Чтобы не пропустить start следующей таски, ждем + // �������� ��������� ������ ����������. �.�. ����� ������ ������������ �� 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 + // �������� � ������ �������, �.�. run_test_case ����������� ���� pulse num ������. �������� ����� ������������ �� ���������� �������. �� �� ������ ���� ��� sample num = 0 set_config( .w(10), .p(125), @@ -502,14 +504,26 @@ module tb_top; disable wait_sampler_active_proc; repeat(30) @(posedge clk_adc); - // Данный тест должен приводить к тому, что сэмплер будет давать крайние значения вместо заданного pulse height из-за OTR=1 - // TODO известно что при таких настройках OTR = 1 постоянно. Легко предсказать уровень - // Дописать авто тест + // ������ ���� ������ ��������� � ����, ��� ������� ����� ������ ������� �������� ������ ��������� 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_height(10), // goes to 0x0.. + .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. Edge cases. OTR == 1. (7-2/7)"); + run_test_case( + .pulse_width(10), + .pulse_period(125), + .pulse_height(14'b11010000000000), // goes to 0xff.. .pulse_num(5), .sample_num(65), .skip_reset(1), @@ -524,15 +538,15 @@ module tb_top; 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 случайным + // ���������� ��������� + 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 = 0; // Out Of Range ��������� �������� + r_otr_rand = 0; // ������� OTR ��������� if (VERBOSE >= 1) $display("[TB] --- Test #%0d (Config: W=%0d, P=%0d, N=%0d, H=%0d, SN=%0d, SkipReset=%0b) ---", @@ -550,7 +564,7 @@ module tb_top; .randomize_out_of_range(r_otr_rand) ); - wait(dut.generator_inst.enable == 0); // Проверка на завершение работы + wait(dut.generator_inst.enable == 0); // �������� �� ���������� ������ #50; end $display("[TB] Test 3 complete"); diff --git a/rtl/sampler/src/sampler.sv b/rtl/sampler/src/sampler.sv index ccc36b7..19fc901 100644 --- a/rtl/sampler/src/sampler.sv +++ b/rtl/sampler/src/sampler.sv @@ -13,136 +13,78 @@ module sampler input [31:0] smp_num, input request, - output logic [DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata, - output logic m_axis_tvalid, + output logic [DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata, + output logic m_axis_tvalid, output logic done ); logic [DATA_WIDTH-1:0] data_converted; - logic out_of_range_reg; logic [31:0] smp_num_reg, cnt_smp_num; - logic enable; + logic synced; + logic [$clog2(PACK_FACTOR):0] pack_cnt; - generate - if (PROCESS_MODE) begin - - always @(posedge clk_in) begin - if (rst) begin - data_converted <= '0; - out_of_range_reg <= 0; - end - else begin - out_of_range_reg <= out_of_range; - if (data_in == {1'b1, {(DATA_WIDTH-1){1'b0}}}) - data_converted <= data_in; - else - data_converted <= data_in[DATA_WIDTH-1] ?{1'b1, (~data_in[DATA_WIDTH-2:0] + 1'b1)}:data_in; - end - end - end else begin - always @(posedge clk_in) begin - if (rst) begin - data_converted <= '0; - out_of_range_reg <= 0; - end - else begin - out_of_range_reg <= out_of_range; - data_converted <= data_in; - end - end - end - endgenerate - - logic [DATA_WIDTH*PACK_FACTOR-1:0] buffer; - logic buffer_ready; - logic [$clog2(PACK_FACTOR):0] cnt; - - generate - if (PACK_FACTOR == 1) begin - always @(posedge clk_in) begin - if (rst) begin - buffer <= '0; - buffer_ready <= 0; - cnt_smp_num <= '0; - smp_num_reg <= '0; - enable <= 0; - done <= 0; - end - else begin - buffer_ready <= 0; - if (!enable) begin - if (done && request) begin - enable <= 1; - done <= 0; - cnt_smp_num <= 0; - smp_num_reg <= smp_num; - end else begin - done <= 1; - end - end else begin - if (cnt_smp_num != smp_num_reg) begin - cnt_smp_num <= cnt_smp_num +1; - buffer_ready <= 1; - // if (!out_of_range_reg) begin - buffer <= data_converted; - // end - end else begin - cnt_smp_num <= '0; - buffer_ready <= 0; - enable <= 0; - buffer <= '0; - end - end - end - end - end else begin - always @(posedge clk_in) begin - if (rst) begin - buffer <= '0; - cnt <= '0; - buffer_ready <= 0; - cnt_smp_num <= '0; - smp_num_reg <= '0; - enable <= 0; - done <= 0; + always_comb begin + data_converted = '0; + if (PROCESS_MODE) begin + if (out_of_range) begin + if (data_in[DATA_WIDTH-1]==1'b1) data_converted = {1'b1, {(DATA_WIDTH-2){1'b0}}}; + else if (data_in[DATA_WIDTH-1]==1'b0) data_converted = {1'b0, {(DATA_WIDTH-2){1'b1}}}; end else begin - buffer_ready <= 0; - if (!enable) begin - if (done && request) begin - enable <= 1; - done <= 0; - cnt_smp_num <= 0; - smp_num_reg <= smp_num; - end else begin - done <= 1; - end + if (data_in == {1'b1, {(DATA_WIDTH-1){1'b0}}}) + data_converted = data_in; + else + data_converted = data_in[DATA_WIDTH-1] ?{1'b1, (~data_in[DATA_WIDTH-2:0] + 1'b1)}:data_in; + end + end else begin + if (out_of_range) begin + if (data_in[DATA_WIDTH-1]==1'b1) data_converted = '1; + else if (data_in[DATA_WIDTH-1]==1'b0) data_converted = '0; + end else begin + data_converted = data_in; + end + end + end + + + always_ff @(posedge clk_in) begin + if (rst) begin + m_axis_tdata <= '0; + m_axis_tvalid <= 0; + cnt_smp_num <= '0; + smp_num_reg <= '0; + pack_cnt <= '0; + synced <= 0; + done <= 0; + end else begin + m_axis_tvalid <= 0; + if (!synced) begin + if (done && request) begin + synced <= 1; + done <= 0; + cnt_smp_num <= 0; + smp_num_reg <= smp_num; + end else begin + done <= 1; + end + end else begin + if (cnt_smp_num != smp_num_reg) begin + cnt_smp_num <= cnt_smp_num +1; + m_axis_tdata[pack_cnt*DATA_WIDTH +: DATA_WIDTH] <= data_converted; + if (pack_cnt == PACK_FACTOR-1) begin + pack_cnt <= 0; + m_axis_tvalid <= 1; end else begin - if (cnt_smp_num != smp_num_reg) begin - cnt_smp_num <= cnt_smp_num +1; - buffer_ready <= 1; - // 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 - end else begin - cnt_smp_num <= '0; - buffer_ready <= 0; - enable <= 0; - cnt <= 0; - end + pack_cnt <= pack_cnt + 1; end + end else begin + cnt_smp_num <= '0; + pack_cnt <= '0; + synced <= 0; + done <= 1; + m_axis_tdata <= '0; end end end - endgenerate - - assign m_axis_tdata = buffer; - assign m_axis_tvalid = buffer_ready; + end endmodule