upd: TB done
This commit is contained in:
@@ -86,15 +86,15 @@
|
|||||||
|
|
||||||
Система работает в нескольких тактовых доменах:
|
Система работает в нескольких тактовых доменах:
|
||||||
|
|
||||||
- Ethernet RX (`gmii_rx_clk`)
|
- Ethernet RX (`clk_axis_control`)
|
||||||
- Ethernet TX (`gmii_tx_clk`)
|
- Ethernet TX (`clk_axis_accumulator`)
|
||||||
- DAC (`dac_clk`)
|
- DAC (`clk_generator`)
|
||||||
- ADC (`adc_clk`)
|
- ADC (`clk_sampler`)
|
||||||
|
|
||||||
Для корректной синхронизации между DAC и ADC используются специальные CDC-регистры для сигналов:
|
Для корректной синхронизации между DAC и ADC используются специальные CDC-регистры для сигналов:
|
||||||
|
|
||||||
- `sample_req`
|
- `done`
|
||||||
- `sample_done`
|
- `request`
|
||||||
|
|
||||||
Это обеспечивает безопасную передачу handshake-сигналов между тактовыми доменами.
|
Это обеспечивает безопасную передачу handshake-сигналов между тактовыми доменами.
|
||||||
|
|
||||||
@@ -110,8 +110,8 @@
|
|||||||
|
|
||||||
Типовые значения:
|
Типовые значения:
|
||||||
|
|
||||||
- `8192` — середина диапазона ЦАП
|
- `8192` — середина диапазона ЦАП (0V)
|
||||||
- `0` — нулевой уровень
|
- `0` — нулевой уровень (-5V)
|
||||||
|
|
||||||
### ADC_DATA_WIDTH
|
### ADC_DATA_WIDTH
|
||||||
Ширина входных данных, получаемых с АЦП.
|
Ширина входных данных, получаемых с АЦП.
|
||||||
@@ -143,3 +143,5 @@
|
|||||||
```make all``` - собрать все до битстрима
|
```make all``` - собрать все до битстрима
|
||||||
|
|
||||||
```make vivado``` - открыть проект в Vivado
|
```make vivado``` - открыть проект в Vivado
|
||||||
|
|
||||||
|
```make sim``` - симуляция и верификация проекта
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
`include "interfaces.svh"
|
`include "interfaces.svh"
|
||||||
// start push
|
|
||||||
|
|
||||||
`define DEBUG
|
// `define DEBUG
|
||||||
|
|
||||||
`define MEASURE_CLK(clk, period) \
|
`define MEASURE_CLK(clk, period) \
|
||||||
begin \
|
begin \
|
||||||
@@ -15,6 +14,13 @@ begin \
|
|||||||
period = t2 - t1; \
|
period = t2 - t1; \
|
||||||
end
|
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;
|
module reflectometer_tb;
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
// Параметры
|
// Параметры
|
||||||
@@ -30,6 +36,10 @@ module reflectometer_tb;
|
|||||||
localparam PACKET_SIZE = 1024; // bytes per UDP packet
|
localparam PACKET_SIZE = 1024; // bytes per UDP packet
|
||||||
|
|
||||||
localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator
|
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"
|
localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage"
|
||||||
|
|
||||||
@@ -326,6 +336,8 @@ module reflectometer_tb;
|
|||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
wait(processing_done == 0);
|
||||||
|
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
@@ -425,32 +437,22 @@ module reflectometer_tb;
|
|||||||
return sum / a.size();
|
return sum / a.size();
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
// NRMSE двух выборок (нормирование MSE)
|
// NRMSE двух выборок (нормирование RMSE)
|
||||||
function automatic real calc_nrmse(
|
function automatic real calc_nrmse(
|
||||||
input real a[],
|
input real a[],
|
||||||
input real b[]
|
input real b[]
|
||||||
);
|
);
|
||||||
real mse;
|
const real EPS = 1e-12;
|
||||||
real min_val;
|
real mse, ms = 0;
|
||||||
real max_val;
|
|
||||||
|
|
||||||
mse = calc_mse(a, b);
|
mse = calc_mse(a, b);
|
||||||
|
|
||||||
min_val = a[0];
|
|
||||||
max_val = a[0];
|
|
||||||
|
|
||||||
foreach (a[i]) begin
|
foreach (a[i]) begin
|
||||||
if (a[i] < min_val)
|
ms += a[i] * a[i];
|
||||||
min_val = a[i];
|
|
||||||
|
|
||||||
if (a[i] > max_val)
|
|
||||||
max_val = a[i];
|
|
||||||
end
|
end
|
||||||
|
ms /= a.size();
|
||||||
|
|
||||||
if (max_val == min_val)
|
return $sqrt(mse / (ms + EPS));
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
return $sqrt(mse) / (max_val - min_val);
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
// Функция модуля
|
// Функция модуля
|
||||||
@@ -521,6 +523,14 @@ module reflectometer_tb;
|
|||||||
$write("\n");
|
$write("\n");
|
||||||
endfunction
|
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(
|
task automatic run_test_case(
|
||||||
virtual axis_if#(8).tb ctrl_vif,
|
virtual axis_if#(8).tb ctrl_vif,
|
||||||
@@ -533,7 +543,7 @@ module reflectometer_tb;
|
|||||||
input int window_size,
|
input int window_size,
|
||||||
input bit rand_recv_delays,
|
input bit rand_recv_delays,
|
||||||
input bit use_reset,
|
input bit use_reset,
|
||||||
output bit result
|
output int result
|
||||||
);
|
);
|
||||||
int output_data[]; // raw accum values
|
int output_data[]; // raw accum values
|
||||||
real output_signal_v[]; // accum values after voltage conversion
|
real output_signal_v[]; // accum values after voltage conversion
|
||||||
@@ -568,6 +578,11 @@ module reflectometer_tb;
|
|||||||
// actual size of payload is pulse_period_adc / window_size
|
// actual size of payload is pulse_period_adc / window_size
|
||||||
output_signal_v = new[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
|
// voltage conversion
|
||||||
begin
|
begin
|
||||||
// zero level for partial sum
|
// zero level for partial sum
|
||||||
@@ -605,17 +620,21 @@ module reflectometer_tb;
|
|||||||
`endif
|
`endif
|
||||||
|
|
||||||
// check metrics
|
// 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
|
Max error not used in evaluation because of fast pulse edge falling
|
||||||
resulting in plain difference between active signal level and zero level
|
resulting in plain difference between active signal level and zero level
|
||||||
For ex.: zero_level = 0x00 = -5V. pulse_height = 2^14-1 = 0x3fff = 5V
|
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)
|
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.
|
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
|
endtask
|
||||||
|
|
||||||
@@ -623,7 +642,7 @@ module reflectometer_tb;
|
|||||||
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
|
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
initial begin
|
initial begin
|
||||||
bit result_flag;
|
int result_flag;
|
||||||
int total_failed_tests = 0, total_tests = 0;
|
int total_failed_tests = 0, total_tests = 0;
|
||||||
|
|
||||||
automatic virtual axis_if.tb control_vif = axis_control_if.tb;
|
automatic virtual axis_if.tb control_vif = axis_control_if.tb;
|
||||||
@@ -646,35 +665,130 @@ module reflectometer_tb;
|
|||||||
join
|
join
|
||||||
$info("[TB] ADC & DAC clock periods measured: ADC_period = %0.3f, DAC_period = %0.3f", CLK_ADC_PERIOD, CLK_DAC_PERIOD);
|
$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] Tests start");
|
||||||
|
|
||||||
$info("[TB] Simple test run");
|
$info("[TB] Simple test run");
|
||||||
|
run_test_case(
|
||||||
|
.ctrl_vif(control_vif),
|
||||||
|
.accum_vif(accumulator_vif),
|
||||||
|
.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(
|
run_test_case(
|
||||||
.ctrl_vif(control_vif),
|
.ctrl_vif(control_vif),
|
||||||
.accum_vif(accumulator_vif),
|
.accum_vif(accumulator_vif),
|
||||||
.pulse_width(400),
|
.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_period(1000),
|
||||||
.pulse_num(5),
|
.pulse_num(5),
|
||||||
.pulse_height(12000),
|
.pulse_height(12000),
|
||||||
.pulse_period_adc(600),
|
.pulse_period_adc(600),
|
||||||
.window_size(10),
|
.window_size(10),
|
||||||
.rand_recv_delays(0),
|
.rand_recv_delays(0),
|
||||||
.use_reset(0),
|
.use_reset(1),
|
||||||
.result(result_flag)
|
.result(result_flag)
|
||||||
);
|
);
|
||||||
|
`ERR_CHECK
|
||||||
|
|
||||||
$info("[TB] Random 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
|
||||||
|
|
||||||
$info("[TB] Corner case test run");
|
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
|
||||||
|
|
||||||
// if (!failed)
|
$display("[TB] Tests done. [%0d/%0d] tests passed, %0d failed", total_tests - total_failed_tests, total_tests, total_failed_tests);
|
||||||
$info("[TB] ALL PASSED");
|
if (!total_failed_tests)
|
||||||
|
$display("[TB] ALL PASSED");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
Reference in New Issue
Block a user