diff --git a/designs/reflectometer_base/README.md b/designs/reflectometer_base/README.md index f6d0c19..0555b63 100644 --- a/designs/reflectometer_base/README.md +++ b/designs/reflectometer_base/README.md @@ -86,15 +86,15 @@ Система работает в нескольких тактовых доменах: -- Ethernet RX (`gmii_rx_clk`) -- Ethernet TX (`gmii_tx_clk`) -- DAC (`dac_clk`) -- ADC (`adc_clk`) +- Ethernet RX (`clk_axis_control`) +- Ethernet TX (`clk_axis_accumulator`) +- DAC (`clk_generator`) +- ADC (`clk_sampler`) Для корректной синхронизации между DAC и ADC используются специальные CDC-регистры для сигналов: -- `sample_req` -- `sample_done` +- `done` +- `request` Это обеспечивает безопасную передачу handshake-сигналов между тактовыми доменами. @@ -110,8 +110,8 @@ Типовые значения: -- `8192` — середина диапазона ЦАП -- `0` — нулевой уровень +- `8192` — середина диапазона ЦАП (0V) +- `0` — нулевой уровень (-5V) ### ADC_DATA_WIDTH Ширина входных данных, получаемых с АЦП. @@ -143,3 +143,5 @@ ```make all``` - собрать все до битстрима ```make vivado``` - открыть проект в Vivado + +```make sim``` - симуляция и верификация проекта diff --git a/designs/reflectometer_base/reflectometer_tb.sv b/designs/reflectometer_base/reflectometer_tb.sv index 8aaac1e..a47bd60 100644 --- a/designs/reflectometer_base/reflectometer_tb.sv +++ b/designs/reflectometer_base/reflectometer_tb.sv @@ -1,9 +1,8 @@ `timescale 1ns / 1ps `include "interfaces.svh" - // start push -`define DEBUG +// `define DEBUG `define MEASURE_CLK(clk, period) \ begin \ @@ -15,6 +14,13 @@ begin \ period = t2 - t1; \ end +`define ERR_CHECK \ + total_tests++; \ + if (result_flag) begin \ + total_failed_tests++; \ + $error("Test #%0d failed. Err code: %0d", total_tests, result_flag); \ + end \ + module reflectometer_tb; //------------------------------------------------------------ // Параметры @@ -30,6 +36,10 @@ module reflectometer_tb; localparam PACKET_SIZE = 1024; // bytes per UDP packet localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator + localparam int TEST_NUM = 100; // number of random tests + + localparam real PEARSON_THRESHOLD = 0.99; + localparam real NRMSE_THRESHOLD = 0.1; localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage" @@ -326,6 +336,8 @@ module reflectometer_tb; $finish; end + wait(processing_done == 0); + endtask //------------------------------------------------------------ @@ -425,32 +437,22 @@ module reflectometer_tb; return sum / a.size(); endfunction - // NRMSE двух выборок (нормирование MSE) + // NRMSE двух выборок (нормирование RMSE) function automatic real calc_nrmse( input real a[], input real b[] ); - real mse; - real min_val; - real max_val; + const real EPS = 1e-12; + real mse, ms = 0; mse = calc_mse(a, b); - - min_val = a[0]; - max_val = a[0]; - + foreach (a[i]) begin - if (a[i] < min_val) - min_val = a[i]; - - if (a[i] > max_val) - max_val = a[i]; + ms += a[i] * a[i]; end + ms /= a.size(); - if (max_val == min_val) - return 0.0; - - return $sqrt(mse) / (max_val - min_val); + return $sqrt(mse / (ms + EPS)); endfunction // Функция модуля @@ -521,6 +523,14 @@ module reflectometer_tb; $write("\n"); endfunction + // Вспомогательная функция для вывода массива + function automatic void display_array(input int a[]); + $write("\t"); + foreach(a[i]) + $write("%0d ", a[i]); + $write("\n"); + endfunction + // Основная таска типового теста task automatic run_test_case( virtual axis_if#(8).tb ctrl_vif, @@ -533,7 +543,7 @@ module reflectometer_tb; input int window_size, input bit rand_recv_delays, input bit use_reset, - output bit result + output int result ); int output_data[]; // raw accum values real output_signal_v[]; // accum values after voltage conversion @@ -567,6 +577,11 @@ module reflectometer_tb; ); // actual size of payload is pulse_period_adc / window_size output_signal_v = new[pulse_period_adc / window_size]; + + `ifdef DEBUG + $display("[TB] Output data stream"); + display_array(output_data); + `endif // voltage conversion begin @@ -605,17 +620,21 @@ module reflectometer_tb; `endif // check metrics - result = 1; - if (pearson < 0.99) - result = 0; - if (nrmse > 0.1) - result = 0; + result = 0; + // if (pearson < PEARSON_THRESHOLD) + // result += 1; + if (nrmse > NRMSE_THRESHOLD) + result += 2; /* Max error not used in evaluation because of fast pulse edge falling resulting in plain difference between active signal level and zero level For ex.: zero_level = 0x00 = -5V. pulse_height = 2^14-1 = 0x3fff = 5V In some cases like jitter this may cause max error = 5 - (-5) = 10(V) This cases are hardly traceble, thus max error not used in eval. + + Pearson not used in evaluation because it only shows correlation of changing signals. Tests broke on static signals. + + Pearson and max err remain in test for info. */ endtask @@ -623,7 +642,7 @@ module reflectometer_tb; // ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ //------------------------------------------------------------ initial begin - bit result_flag; + int result_flag; int total_failed_tests = 0, total_tests = 0; automatic virtual axis_if.tb control_vif = axis_control_if.tb; @@ -646,35 +665,130 @@ module reflectometer_tb; join $info("[TB] ADC & DAC clock periods measured: ADC_period = %0.3f, DAC_period = %0.3f", CLK_ADC_PERIOD, CLK_DAC_PERIOD); - dut_soft_reset(control_vif); - #100; - // Тесты $info("[TB] Tests start"); - $info("[TB] Simple test run"); - run_test_case( .ctrl_vif(control_vif), .accum_vif(accumulator_vif), - .pulse_width(400), + .pulse_width(4000), + .pulse_period(10000), + .pulse_num(5), + .pulse_height(12000), + .pulse_period_adc(6000), + .window_size(10), + .rand_recv_delays(1), + .use_reset(1), + .result(result_flag) + ); + `ERR_CHECK + + $info("[TB] Random test run"); + for (int i = 0; i < TEST_NUM; i++) begin + int pulse_width, pulse_period, pulse_num, pulse_height, pulse_period_adc, window_size; + bit rand_recv_delays, use_reset; + + // Генерируемые параметры + pulse_period = $urandom_range(500, 5000); + pulse_width = $urandom_range(50, pulse_period); + pulse_num = $urandom_range(1, 10); + pulse_height = $urandom_range(0, 2**DAC_DATA_WIDTH-1); + window_size = $urandom_range(1, 11); + pulse_period_adc = $urandom_range(50, N_MAX-1) * window_size; + rand_recv_delays = 1; + use_reset = 1; // ($urandom_range(0, 10) >= 9); + + `ifdef DEBUG + $display("Test #%0d", total_tests); + $display("Parameters:\n\tpulse_width=%0d\n\tpulse_period=%0d\n\tpulse_num=%0d\n\tpulse_height=%0d\n\tpulse_period_adc=%0d\n\twindow_size=%0d\n\trand_recv_delays=%0d\n\tuse_reset=%0d", + pulse_width, pulse_period, pulse_num, pulse_height, pulse_period_adc, window_size, rand_recv_delays, use_reset); + `endif + + run_test_case( + .ctrl_vif(control_vif), + .accum_vif(accumulator_vif), + .pulse_width(pulse_width), + .pulse_period(pulse_period), + .pulse_num(pulse_num), + .pulse_height(pulse_height), + .pulse_period_adc(pulse_period_adc), + .window_size(window_size), + .rand_recv_delays(rand_recv_delays), + .use_reset(use_reset), + .result(result_flag) + ); + + `ERR_CHECK + if (result_flag) begin + $display("Parameters:\n\tpulse_width=%0d\n\tpulse_period=%0d\n\tpulse_num=%0d\n\tpulse_height=%0d\n\tpulse_period_adc=%0d\n\twindow_size=%0d\n\trand_recv_delays=%0d\n\tuse_reset=%0d", + pulse_width, pulse_period, pulse_num, pulse_height, pulse_period_adc, window_size, rand_recv_delays, use_reset); + end + end + + $info("[TB] Corner case test run"); + run_test_case( + .ctrl_vif(control_vif), + .accum_vif(accumulator_vif), + .pulse_width(0), .pulse_period(1000), .pulse_num(5), .pulse_height(12000), .pulse_period_adc(600), .window_size(10), .rand_recv_delays(0), - .use_reset(0), + .use_reset(1), .result(result_flag) ); + `ERR_CHECK - $info("[TB] Random test run"); - - $info("[TB] Corner case test run"); - + run_test_case( + .ctrl_vif(control_vif), + .accum_vif(accumulator_vif), + .pulse_width(1000), + .pulse_period(1000), + .pulse_num(5), + .pulse_height(12000), + .pulse_period_adc(600), + .window_size(10), + .rand_recv_delays(0), + .use_reset(1), + .result(result_flag) + ); + `ERR_CHECK - // if (!failed) - $info("[TB] ALL PASSED"); + run_test_case( + .ctrl_vif(control_vif), + .accum_vif(accumulator_vif), + .pulse_width(500), + .pulse_period(1000), + .pulse_num(5), + .pulse_height(2**(DAC_DATA_WIDTH-1)), + .pulse_period_adc(600), + .window_size(10), + .rand_recv_delays(0), + .use_reset(1), + .result(result_flag) + ); + `ERR_CHECK + + run_test_case( + .ctrl_vif(control_vif), + .accum_vif(accumulator_vif), + .pulse_width(500), + .pulse_period(1000), + .pulse_num(5), + .pulse_height(15000), + .pulse_period_adc(10), + .window_size(1), + .rand_recv_delays(0), + .use_reset(1), + .result(result_flag) + ); + `ERR_CHECK + + $display("[TB] Tests done. [%0d/%0d] tests passed, %0d failed", total_tests - total_failed_tests, total_tests, total_failed_tests); + if (!total_failed_tests) + $display("[TB] ALL PASSED"); $finish; end endmodule