From 2fc927d2e7ce6e27927d95888c7649b7b1feb71c Mon Sep 17 00:00:00 2001 From: "babintsev.lv" Date: Tue, 28 Jul 2026 17:22:17 +0300 Subject: [PATCH] upd: accum fix; new reflectometer signals; TB secure data rx --- designs/backup/reflectometer.sv | 252 ++++++++++++ designs/backup/reflectometer_tb.sv | 365 ++++++++++++++++++ designs/reflectometer_base/reflectometer.sv | 21 +- .../reflectometer_base/reflectometer_tb.sv | 154 ++++++-- rtl/accum/src/accum.sv | 1 + 5 files changed, 750 insertions(+), 43 deletions(-) create mode 100644 designs/backup/reflectometer.sv create mode 100644 designs/backup/reflectometer_tb.sv diff --git a/designs/backup/reflectometer.sv b/designs/backup/reflectometer.sv new file mode 100644 index 0000000..4ae5dc4 --- /dev/null +++ b/designs/backup/reflectometer.sv @@ -0,0 +1,252 @@ +`timescale 1 ns / 1 ns + +`include "interfaces.svh" + +module reflectometer_top #( + parameter int unsigned DAC_DATA_WIDTH = 14, + parameter int unsigned ADC_DATA_WIDTH = 12, + parameter int unsigned PACK_FACTOR = 1, + parameter int unsigned PROCESS_MODE = 0, + parameter int unsigned ZERO_LEVEL = 8192, + parameter int unsigned ACCUM_WIDTH = 32, + parameter int unsigned N_MAX = 4096, + parameter int unsigned PACKET_SIZE = 1024 +)( + input wire clk_in, + input wire rst_n, + output wire locked, + + // Accumulator AXI-S bus + input wire clk_axis_accumulator, // GMII PHY RX clock + axis_if.master axis_accumulator, + + // Control AXI-S bus + input wire clk_axis_control, // GMII PHY TX clock + axis_if.slave axis_control, + input wire [31:0] window_size, // New accum & old controller crutch + + // Status signals + output wire workflow_done, + output wire processing_done, + + // RTL-MAC handshake + input wire request_ready, + output wire send_request, + + // DAC + output wire dac_clk_o, + output wire [DAC_DATA_WIDTH-1:0] dac_data, + output wire dac_wrt, + + // ADC + output wire adc_clk_o, + input wire [ADC_DATA_WIDTH-1:0] adc_data, + input wire adc_otr + +); + + // ------------------------------------------------------------------------- + // Generated clocks for controller + // Need to create this IP in Vivado: + // input resetn + // input clk_200 : 200 MHz : Reference clock + // output clk_adc_65 : 65 MHz : ADC RTL clock + // output clk_adc_65_180 : 65 MHz, phase 180 deg. : ADC PHY clock + // output clk_adc_125 : 125 MHz : DAC RTL clock + // output clk_adc_125_180 : 125 MHz, phase 180 deg. : DAC PHY clock + // output locked + // ------------------------------------------------------------------------- + wire clk_sampler, clk_generator, clk_locked; + + clk_wiz_ctrl_inst clk_wiz_inst + ( + // Clock in ports + .clk_200(clk_in), + // Clock out ports + .clk_adc_65(clk_sampler), + .clk_adc_65_180(adc_clk_o), + .clk_dac_125(clk_generator), + .clk_dac_125_180(dac_clk_o), + // Status and control signals + .resetn(rst_n), + .locked(clk_locked) + ); + + assign locked = clk_locked; + + // ------------------------------------------------------------------------- + // Controller reset + // Use both external reset and clk_wiz lock + // ------------------------------------------------------------------------- + wire ctrl_rst_n = rst_n & clk_locked; + + // ------------------------------------------------------------------------- + // Controller + // ------------------------------------------------------------------------- + wire [31:0] dac_pulse_width; + wire [31:0] dac_pulse_period; + wire [DAC_DATA_WIDTH-1:0] dac_pulse_height; + wire [15:0] dac_pulse_num; + + wire [31:0] adc_pulse_period; + wire [15:0] adc_pulse_num; + + wire dac_start; + wire adc_start; + wire dac_rst; + wire adc_rst; + + wire finish; + + control #( + .DAC_DATA_WIDTH(DAC_DATA_WIDTH) + ) udp_ctrl_inst ( + .eth_clk_in (clk_axis_control), + .dac_clk_in (clk_generator), + .adc_clk_in (clk_sampler), + .rst_n (ctrl_rst_n), + + .s_axis_tdata (axis_control.tdata), + .s_axis_tvalid (axis_control.tvalid), + .s_axis_tready (axis_control.tready), + .s_axis_tlast (axis_control.tlast), + + .finish (finish), + + .dac_pulse_width (dac_pulse_width), + .dac_pulse_period (dac_pulse_period), + .dac_pulse_height (dac_pulse_height), + .dac_pulse_num (dac_pulse_num), + + .adc_pulse_period (adc_pulse_period), + .adc_pulse_num (adc_pulse_num), + + .dac_start (dac_start), + .adc_start (adc_start), + + .dac_rst (dac_rst), + .adc_rst (adc_rst) + ); + + //------------------------------------------------------------ + // DAC -> ADC CDC + //------------------------------------------------------------ + (* ASYNC_REG = "TRUE" *) logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени + (* ASYNC_REG = "TRUE" *) logic [1:0] sync_DA; + wire dac_done_stretched; + + wire generator_done, generator_request; + wire sampler_done, sampler_request; + + always_ff @(posedge clk_generator or posedge dac_rst) + begin + if (dac_rst) + stretch <= 0; + else begin + stretch[0] <= generator_done; + stretch[1] <= stretch[0]; + stretch[2] <= stretch[1]; + end + end + assign dac_done_stretched = |stretch; + + always_ff @(posedge clk_sampler or posedge adc_rst) begin + if (adc_rst) + sync_DA <= 0; + else begin + sync_DA[0] <= dac_done_stretched; + sync_DA[1] <= sync_DA[0]; + end + end + assign sampler_request = sync_DA[1]; + + //------------------------------------------------------------ + // ADC -> DAC CDC + //------------------------------------------------------------ + (* ASYNC_REG = "TRUE" *) logic [1:0] sync_AD; + + always_ff @(posedge clk_generator or posedge dac_rst) begin + if (dac_rst) + sync_AD <= 0; + else begin + sync_AD[0] <= sampler_done; + sync_AD[1] <= sync_AD[0]; + end + end + assign generator_request = sync_AD[1]; + + //------------------------------------------------------------ + // Generator (DAC) + //------------------------------------------------------------ + generator #( + .DATA_WIDTH(DAC_DATA_WIDTH), + .ZERO_LEVEL(ZERO_LEVEL) + ) generator_inst ( + .clk_dac(clk_generator), + .rst(dac_rst), + .start(dac_start), + .pulse_width(dac_pulse_width), + .pulse_period(dac_pulse_period), + .pulse_height(dac_pulse_height), + .pulse_num(dac_pulse_num), + .dac_out(dac_data), + .done(generator_done), + .request(generator_request) + ); + assign dac_wrt = dac_clk_o; + + // ------------------------------------------------------------------------- + // Sampler (ADC) + // ------------------------------------------------------------------------- + wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] sampler_m_axis_tdata; + wire sampler_m_axis_tvalid; + + sampler #( + .DATA_WIDTH(ADC_DATA_WIDTH), + .PACK_FACTOR(PACK_FACTOR), + .PROCESS_MODE(PROCESS_MODE) + ) sampler_dut ( + .clk_in(clk_sampler), + .rst(adc_rst), + .data_in(adc_data), + .out_of_range(adc_otr), + .m_axis_tdata(sampler_m_axis_tdata), + .m_axis_tvalid(sampler_m_axis_tvalid), + .smp_num(adc_pulse_period), + .done(sampler_done), + .request(sampler_request) + ); + + // ------------------------------------------------------------------------- + // Accumulator + // ------------------------------------------------------------------------- + assign workflow_done = finish; + + accumulator_top #( + .DATA_WIDTH(ADC_DATA_WIDTH), + .ACCUM_WIDTH(ACCUM_WIDTH), + .N_MAX(N_MAX), + .PACKET_SIZE(PACKET_SIZE) + ) accumulator_top_dut ( + .clk_in(clk_sampler), + .rst(adc_rst), + .s_axis_tdata(sampler_m_axis_tdata), + .s_axis_tvalid(sampler_m_axis_tvalid), + .start(adc_start), + .smp_num(adc_pulse_period), + .seq_num(adc_pulse_num), + .window_size(window_size), + + .req_ready(request_ready), + .send_req(send_request), + .eth_clk_in(clk_axis_accumulator), + .m_axis_tdata(axis_accumulator.tdata), + .m_axis_tvalid(axis_accumulator.tvalid), + .m_axis_tready(axis_accumulator.tready), + .m_axis_tlast(axis_accumulator.tlast), + + .finish(finish), // full reflectometer workflow complete (with transaction) + .accum_done(processing_done) // signal generation, sampling and processing complete + ); + +endmodule diff --git a/designs/backup/reflectometer_tb.sv b/designs/backup/reflectometer_tb.sv new file mode 100644 index 0000000..ef5c96c --- /dev/null +++ b/designs/backup/reflectometer_tb.sv @@ -0,0 +1,365 @@ +`timescale 1ns / 1ps + +`include "interfaces.svh" + +module reflectometer_tb; + //------------------------------------------------------------ + // Параметры + //------------------------------------------------------------ + localparam int unsigned DAC_DATA_WIDTH = 14; + localparam int unsigned ADC_DATA_WIDTH = 12; + 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 PACK_FACTOR = 1; // not used in TB + localparam PROCESS_MODE = 1; // 0 - uint, 1 - int + localparam ACCUM_WIDTH = 32; // accumulator number bit witdth + localparam N_MAX = 4096; // max value of windows to average by experiments + localparam PACKET_SIZE = 1024; // bytes per UDP packet + + localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator + + localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage" + + localparam CLK_ETH_PHY_PERIOD = 8.000; // 125 MHz + localparam CLK_REF_PERIOD = 5.000; // 200 MHz + + //------------------------------------------------------------ + // Глобальные перменные + //------------------------------------------------------------ + int unsigned WINDOW_SIZE = 65; // fixed subwindow size to average by time + + //------------------------------------------------------------ + // Тактовые сигналы и сброс + //------------------------------------------------------------ + logic clk_ref = 1'b0; // 200 MHz + logic clk_eth_phy = 1'b0; // common for RX & TX + logic rst_n = 1'b0; + + //------------------------------------------------------------ + // Управление и конфиг DUT + //------------------------------------------------------------ + logic [31:0] window_size; + // AXI-S интерфейс для управления + axis_if axis_control_if ( + .clk(clk_eth_phy), + .rst_n(rst_n) + ); + + //------------------------------------------------------------ + // Входы DUT + //------------------------------------------------------------ + // ADC интерфейс + wire clk_adc; + wire adc_otr; + wire [ADC_DATA_WIDTH-1:0] adc_data; + + //------------------------------------------------------------ + // Выходы + //------------------------------------------------------------ + // Статусы + wire mmcm_locked; + wire workflow_done; + wire processing_done; + // DAC интерфейс + wire clk_dac; + wire dac_wrt; + wire [DAC_DATA_WIDTH-1:0] dac_data; + // AXI-S интерфейс для данных + axis_if axis_accumulator_if ( + .clk(clk_eth_phy), + .rst_n(rst_n) + ); + //------------------------------------------------------------ + // Внутренние сигналы тестбенча + //------------------------------------------------------------ + // Интерфейс хендшейка с MAC-PHY + wire send_request; + logic request_ready; + // Сигнал между ЦАП и АЦП + real signal_voltage; + + //------------------------------------------------------------ + // Virtual DAC + //------------------------------------------------------------ + virtual_dac_model #( // default voltage range is +/- 5V + .DAC_DATA_WIDTH(DAC_DATA_WIDTH) + // ,.VOLTAGE_GAIN(2) + ) virtual_dac ( + .clk_i(clk_dac), + .wrt_i(dac_wrt), + .data_i(dac_data), + .voltage_o(signal_voltage) + ); + + //------------------------------------------------------------ + // Virtual ADC + //------------------------------------------------------------ + virtual_adc_model #( // default voltage range is +/- 5V + .ADC_DATA_WIDTH(ADC_DATA_WIDTH) + ) virtual_adc ( + .clk_i(clk_adc), + .voltage_i(signal_voltage), + .otr_o(adc_otr), + .data_o(adc_data) + ); + + //------------------------------------------------------------ + // Statistics processing + //------------------------------------------------------------ + + //------------------------------------------------------------ + // Config handler + //------------------------------------------------------------ + + //------------------------------------------------------------ + // DUT + //------------------------------------------------------------ + reflectometer_top #( + .DAC_DATA_WIDTH(DAC_DATA_WIDTH), + .ADC_DATA_WIDTH(ADC_DATA_WIDTH), + .PACK_FACTOR(PACK_FACTOR), + .PROCESS_MODE(PROCESS_MODE), + .ZERO_LEVEL(ZERO_LEVEL), + .ACCUM_WIDTH(ACCUM_WIDTH), + .N_MAX(N_MAX), + .PACKET_SIZE(PACKET_SIZE) + ) DUT ( + .clk_in(clk_ref), + .rst_n(rst_n), + + // Status + .locked(mmcm_locked), + .workflow_done(workflow_done), + .processing_done(processing_done), + + // Accumulator AXI-S bus + .clk_axis_accumulator(clk_eth_phy), // GMII PHY RX clock + .axis_accumulator(axis_accumulator_if.master), + + // Control AXI-S bus + .clk_axis_control(clk_eth_phy), // GMII PHY TX clock + .axis_control(axis_control_if.slave), + .window_size(window_size), // direct signal crutch (old controller) + + // RTL-MAC handshake + .request_ready(request_ready), + .send_request(send_request), + + // DAC + .dac_clk_o(clk_dac), + .dac_data(dac_data), + .dac_wrt(dac_wrt), + + // ADC + .adc_clk_o(clk_adc), + .adc_data(adc_data), + .adc_otr(adc_otr) + ); + assign window_size = WINDOW_SIZE; + + //------------------------------------------------------------ + // Тактовые сигналы + //------------------------------------------------------------ + initial begin + forever #(CLK_REF_PERIOD/2) clk_ref = ~clk_ref; + end + initial begin + forever #(CLK_ETH_PHY_PERIOD/2) clk_eth_phy = ~clk_eth_phy; + end + + //------------------------------------------------------------ + // Таски для тестирования + //------------------------------------------------------------ + // Таски работы с AXI-Stream + task automatic dut_soft_reset(virtual axis_if#(8).tb vif); + logic [7:0] tx_packet[]; + tx_packet = '{8'h0f}; + vif.master_send(tx_packet); + endtask + + task automatic dut_start(virtual axis_if#(8).tb vif); + logic [7:0] tx_packet[]; + tx_packet = '{8'hf0}; + vif.master_send(tx_packet); + endtask + + task automatic dut_send_system_config( + virtual axis_if#(8).tb vif, + input logic [31:0] pulse_width, + input logic [31:0] pulse_period, + input logic [15:0] pulse_num, + input logic [13:0] pulse_height, // achtung! p_height strictly must have 14 bits of width + input logic [31:0] pulse_period_adc + ); + // Создаем временный фиксированный массив и упаковываем всё одной строкой + logic [7:0] tx_packet[]; + + // Ахтунг, 14-битный ЦАП захардкожен + if (DAC_DATA_WIDTH != 14) + $display("[WARNING] -dut_send_system_config- Default pulse height (DAC bitwidth) is equal to 14. Be aware, controller packet structure is coded for 14 bits"); + + tx_packet = '{ + 8'h88, // Команда + pulse_width[7:0], pulse_width[15:8], pulse_width[23:16], pulse_width[31:24], + pulse_period[7:0], pulse_period[15:8], pulse_period[23:16], pulse_period[31:24], + pulse_num[7:0], pulse_num[15:8], pulse_height[7:0], 8'({2'b00, pulse_height[13:8]}), + pulse_period_adc[7:0], pulse_period_adc[15:8], pulse_period_adc[23:16], pulse_period_adc[31:24] + }; + + vif.master_send(tx_packet); + endtask + + // Таски сбора статистики + task automatic dut_read_output( + virtual axis_if#(8).tb vif, + input int sample_num, + input bit randomize_recv_delays, + output int output_data[] + ); + logic [7:0] rx_packet[]; + logic [ACCUM_WIDTH-1:0] data_packet[]; + int packet_num = $ceil(real'(sample_num / WINDOW_SIZE) / real'(PACKET_SIZE)); + int numbers_per_packet = PACKET_SIZE/(ACCUM_WIDTH/8); + int idx = 0, timeout_flag = 0; + int packet_counter = 0; + + if (sample_num % WINDOW_SIZE) begin + $display("[TB] -dut_read_output- Error, sample_num must be multiple of WINDOW_SIZE: %0d %% %0d = %0d", sample_num, WINDOW_SIZE, sample_num % WINDOW_SIZE); + $finish; + end + + data_packet = new[numbers_per_packet]; + output_data = new[numbers_per_packet * packet_num]; + + // count send_request pulses (equal to number of packets) + fork + begin : packet_counter_proc + forever begin + @(posedge clk_eth_phy); + if(send_request === 1) + packet_counter++; + end + end + join_none + + // Wait until reflectometer done sampling and averaging + wait(processing_done == 1); + + // recv loop + for (int i = 0; i < packet_num; i++) begin + if (randomize_recv_delays) + repeat($urandom_range(0, 500)) @(posedge clk_eth_phy); + + timeout_flag = 0; + fork + begin : receive_packet_proc + request_ready = 1; + vif.slave_recv(rx_packet); + request_ready = 0; + end + begin : timeout_proc + repeat(REQUEST_TIMEOUT) @(posedge clk_eth_phy); + timeout_flag = 1; + end + join_any + + disable receive_packet_proc; + disable timeout_proc; + if (timeout_flag) begin + $display("[ERROR] -dut_read_output- Timeout detected when receiving packet"); + $finish; + end + + if (rx_packet.size() != PACKET_SIZE) begin + $display("[ERROR] -dut_read_output- Wrong packet size received: %0d bytes received, %0d bytes expected", rx_packet.size(), PACKET_SIZE); + end + // unpack values + data_packet = {<< byte {rx_packet}}; + data_packet = {<< ACCUM_WIDTH {data_packet}}; + + // copy and convert values + for (int j = 0; j < data_packet.size(); j++) begin + output_data[i * data_packet.size() + j] = int'(data_packet[j]); + end + end + + disable packet_counter_proc; + + if (packet_counter != packet_num) begin + $display("[ERROR] -dut_read_output- Wrong number of packets received: %0d received, %0d expected", packet_counter, packet_num); + $finish; + end + + // Wait until full transaction of data is complete + timeout_flag = 0; + fork + wait(workflow_done == 1); + begin : timeout_proc + repeat(10) @(negedge clk_adc); // sampler clock + timeout_flag = 1; + end + join_any + + disable timeout_proc; + if (timeout_flag) begin + $display("[ERROR] -dut_read_output- Timeout detected when awaiting for finish pulse"); + $finish; + end + + endtask + + // Основная таска типового теста + // todo + + //------------------------------------------------------------ + // ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ + //------------------------------------------------------------ + initial begin + int output_data[]; + + automatic virtual axis_if.tb control_vif = axis_control_if.tb; + automatic virtual axis_if.tb accumulator_vif = axis_accumulator_if.tb; + + $display("[TB] DUT initializaton"); + // Инициализация + request_ready = 0; + rst_n = 0; + #100; + rst_n = 1; + wait(mmcm_locked === 1'b1); + #150; + $display("[TB] MMCM locked"); + + dut_soft_reset(control_vif); + #100; + + // Тесты + $display("[TB] Tests start"); + dut_send_system_config( + .vif(control_vif), + .pulse_width(32'd123), + .pulse_period(32'd5000), + .pulse_num(16'd1), + .pulse_height(14'd15000), // 0V + .pulse_period_adc(32'd2600) + ); + #100; + dut_start(control_vif); + + dut_read_output( + .vif(accumulator_vif), + .sample_num(2600), + .randomize_recv_delays(0), + .output_data(output_data) + ); + + $display("Received %0d numbers", output_data.size()); + for (int i = 0; i < output_data.size(); i++) begin + $write("%0d ", output_data[i]); + end + $display(""); + + $display("[TB] ALL PASSED"); + $finish; + end +endmodule diff --git a/designs/reflectometer_base/reflectometer.sv b/designs/reflectometer_base/reflectometer.sv index 1e1bd0a..4ae5dc4 100644 --- a/designs/reflectometer_base/reflectometer.sv +++ b/designs/reflectometer_base/reflectometer.sv @@ -10,7 +10,6 @@ module reflectometer_top #( parameter int unsigned ZERO_LEVEL = 8192, parameter int unsigned ACCUM_WIDTH = 32, parameter int unsigned N_MAX = 4096, - parameter int unsigned WINDOW_SIZE = 65, parameter int unsigned PACKET_SIZE = 1024 )( input wire clk_in, @@ -18,12 +17,17 @@ module reflectometer_top #( output wire locked, // Accumulator AXI-S bus - input wire clk_axis_accumulator, // GMII PHY RX clock - axis_if.master axis_accumulator, + input wire clk_axis_accumulator, // GMII PHY RX clock + axis_if.master axis_accumulator, // Control AXI-S bus - input wire clk_axis_control, // GMII PHY TX clock - axis_if.slave axis_control, + input wire clk_axis_control, // GMII PHY TX clock + axis_if.slave axis_control, + input wire [31:0] window_size, // New accum & old controller crutch + + // Status signals + output wire workflow_done, + output wire processing_done, // RTL-MAC handshake input wire request_ready, @@ -216,11 +220,12 @@ module reflectometer_top #( // ------------------------------------------------------------------------- // Accumulator // ------------------------------------------------------------------------- + assign workflow_done = finish; + accumulator_top #( .DATA_WIDTH(ADC_DATA_WIDTH), .ACCUM_WIDTH(ACCUM_WIDTH), .N_MAX(N_MAX), - .WINDOW_SIZE(WINDOW_SIZE), .PACKET_SIZE(PACKET_SIZE) ) accumulator_top_dut ( .clk_in(clk_sampler), @@ -230,6 +235,7 @@ module reflectometer_top #( .start(adc_start), .smp_num(adc_pulse_period), .seq_num(adc_pulse_num), + .window_size(window_size), .req_ready(request_ready), .send_req(send_request), @@ -239,7 +245,8 @@ module reflectometer_top #( .m_axis_tready(axis_accumulator.tready), .m_axis_tlast(axis_accumulator.tlast), - .finish(finish) + .finish(finish), // full reflectometer workflow complete (with transaction) + .accum_done(processing_done) // signal generation, sampling and processing complete ); endmodule diff --git a/designs/reflectometer_base/reflectometer_tb.sv b/designs/reflectometer_base/reflectometer_tb.sv index 1ffdfba..1c15b49 100644 --- a/designs/reflectometer_base/reflectometer_tb.sv +++ b/designs/reflectometer_base/reflectometer_tb.sv @@ -14,13 +14,19 @@ module reflectometer_tb; localparam PROCESS_MODE = 1; // 0 - uint, 1 - int localparam ACCUM_WIDTH = 32; // accumulator number bit witdth localparam N_MAX = 4096; // max value of windows to average by experiments - localparam WINDOW_SIZE = 65; // fixed subwindow size to average by time localparam PACKET_SIZE = 1024; // bytes per UDP packet + + localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage" localparam CLK_ETH_PHY_PERIOD = 8.000; // 125 MHz localparam CLK_REF_PERIOD = 5.000; // 200 MHz + + //------------------------------------------------------------ + // Глобальные перменные + //------------------------------------------------------------ + int unsigned WINDOW_SIZE = 65; // fixed subwindow size to average by time //------------------------------------------------------------ // Тактовые сигналы и сброс @@ -28,43 +34,48 @@ module reflectometer_tb; logic clk_ref = 1'b0; // 200 MHz logic clk_eth_phy = 1'b0; // common for RX & TX logic rst_n = 1'b0; - //------------------------------------------------------------ - // Управление и конфиг - //------------------------------------------------------------ //------------------------------------------------------------ - // Входы - //------------------------------------------------------------ - - //------------------------------------------------------------ - // Выходы - //------------------------------------------------------------ - wire mmcm_locked; - //------------------------------------------------------------ - // Внутренние сигналы тестбенча + // Управление и конфиг DUT //------------------------------------------------------------ + logic [31:0] window_size; // AXI-S интерфейс для управления axis_if axis_control_if ( .clk(clk_eth_phy), .rst_n(rst_n) ); + + //------------------------------------------------------------ + // Входы DUT + //------------------------------------------------------------ + // ADC интерфейс + wire clk_adc; + wire adc_otr; + wire [ADC_DATA_WIDTH-1:0] adc_data; + + //------------------------------------------------------------ + // Выходы + //------------------------------------------------------------ + // Статусы + wire mmcm_locked; + wire workflow_done; + wire processing_done; + // DAC интерфейс + wire clk_dac; + wire dac_wrt; + wire [DAC_DATA_WIDTH-1:0] dac_data; // AXI-S интерфейс для данных axis_if axis_accumulator_if ( .clk(clk_eth_phy), .rst_n(rst_n) ); - // DAC интерфейс - wire clk_dac; - wire dac_wrt; - wire [DAC_DATA_WIDTH-1:0] dac_data; - // ADC интерфейс - wire clk_adc; - wire adc_otr; - wire [ADC_DATA_WIDTH-1:0] adc_data; + //------------------------------------------------------------ + // Внутренние сигналы тестбенча + //------------------------------------------------------------ // Интерфейс хендшейка с MAC-PHY wire send_request; logic request_ready; - // Сигналы ЦАП и АЦП + // Сигнал между ЦАП и АЦП real signal_voltage; //------------------------------------------------------------ @@ -79,6 +90,7 @@ module reflectometer_tb; .data_i(dac_data), .voltage_o(signal_voltage) ); + //------------------------------------------------------------ // Virtual ADC //------------------------------------------------------------ @@ -90,8 +102,9 @@ module reflectometer_tb; .otr_o(adc_otr), .data_o(adc_data) ); + //------------------------------------------------------------ - // Statistics monitor + // Statistics processing //------------------------------------------------------------ //------------------------------------------------------------ @@ -109,12 +122,15 @@ module reflectometer_tb; .ZERO_LEVEL(ZERO_LEVEL), .ACCUM_WIDTH(ACCUM_WIDTH), .N_MAX(N_MAX), - .WINDOW_SIZE(WINDOW_SIZE), .PACKET_SIZE(PACKET_SIZE) ) DUT ( .clk_in(clk_ref), .rst_n(rst_n), + + // Status .locked(mmcm_locked), + .workflow_done(workflow_done), + .processing_done(processing_done), // Accumulator AXI-S bus .clk_axis_accumulator(clk_eth_phy), // GMII PHY RX clock @@ -123,6 +139,7 @@ module reflectometer_tb; // Control AXI-S bus .clk_axis_control(clk_eth_phy), // GMII PHY TX clock .axis_control(axis_control_if.slave), + .window_size(window_size), // direct signal crutch (old controller) // RTL-MAC handshake .request_ready(request_ready), @@ -138,6 +155,8 @@ module reflectometer_tb; .adc_data(adc_data), .adc_otr(adc_otr) ); + assign window_size = WINDOW_SIZE; + //------------------------------------------------------------ // Тактовые сигналы //------------------------------------------------------------ @@ -147,6 +166,7 @@ module reflectometer_tb; initial begin forever #(CLK_ETH_PHY_PERIOD/2) clk_eth_phy = ~clk_eth_phy; end + //------------------------------------------------------------ // Таски для тестирования //------------------------------------------------------------ @@ -173,7 +193,11 @@ module reflectometer_tb; ); // Создаем временный фиксированный массив и упаковываем всё одной строкой logic [7:0] tx_packet[]; - + + // Ахтунг, 14-битный ЦАП захардкожен + if (DAC_DATA_WIDTH != 14) + $display("[WARNING] -dut_send_system_config- Default pulse height (DAC bitwidth) is equal to 14. Be aware, controller packet structure is coded for 14 bits"); + tx_packet = '{ 8'h88, // Команда pulse_width[7:0], pulse_width[15:8], pulse_width[23:16], pulse_width[31:24], @@ -185,7 +209,7 @@ module reflectometer_tb; vif.master_send(tx_packet); endtask - // Таски сбора и обработки статистики + // Таски сбора статистики task automatic dut_read_output( virtual axis_if#(8).tb vif, input int sample_num, @@ -196,7 +220,8 @@ module reflectometer_tb; logic [ACCUM_WIDTH-1:0] data_packet[]; int packet_num = $ceil(real'(sample_num / WINDOW_SIZE) / real'(PACKET_SIZE)); int numbers_per_packet = PACKET_SIZE/(ACCUM_WIDTH/8); - int idx = 0; + int idx = 0, timeout_flag = 0; + int packet_counter = 0; if (sample_num % WINDOW_SIZE) begin $display("[TB] -dut_read_output- Error, sample_num must be multiple of WINDOW_SIZE: %0d %% %0d = %0d", sample_num, WINDOW_SIZE, sample_num % WINDOW_SIZE); @@ -205,16 +230,49 @@ module reflectometer_tb; data_packet = new[numbers_per_packet]; output_data = new[numbers_per_packet * packet_num]; - // count send_request posedge todo - // timeout todo + + // count send_request pulses (equal to number of packets) + fork + begin : packet_counter_proc + forever begin + @(posedge clk_eth_phy); + if(send_request === 1) + packet_counter++; + end + end + join_none + + // Wait until reflectometer done sampling and averaging + wait(processing_done == 1); // recv loop for (int i = 0; i < packet_num; i++) begin - // randomize_recv_delays todo - request_ready = 1; - vif.slave_recv(rx_packet); - request_ready = 0; + if (randomize_recv_delays) + repeat($urandom_range(0, 500)) @(posedge clk_eth_phy); + + timeout_flag = 0; + fork : receive_packet_timeout + begin + request_ready = 1; + vif.slave_recv(rx_packet); + request_ready = 0; + end + begin + repeat(REQUEST_TIMEOUT) @(posedge clk_eth_phy); + timeout_flag = 1; + end + join_any + disable receive_packet_timeout; + + if (timeout_flag) begin + $display("[ERROR] -dut_read_output- Timeout detected when receiving packet"); + $finish; + end + + if (rx_packet.size() != PACKET_SIZE) begin + $display("[ERROR] -dut_read_output- Wrong packet size received: %0d bytes received, %0d bytes expected", rx_packet.size(), PACKET_SIZE); + end // unpack values data_packet = {<< byte {rx_packet}}; data_packet = {<< ACCUM_WIDTH {data_packet}}; @@ -225,12 +283,36 @@ module reflectometer_tb; end end - // wait for dut.finish posedge todo - // timeout todo + disable packet_counter_proc; + + if (packet_counter != packet_num) begin + $display("[ERROR] -dut_read_output- Wrong number of packets received: %0d received, %0d expected", packet_counter, packet_num); + $finish; + end + + // Wait until full transaction of data is complete + timeout_flag = 0; + fork : workflow_timeout + begin + wait(workflow_done == 1); + end + begin + repeat(10) @(negedge clk_adc); // sampler clock + timeout_flag = 1; + end + join_any + + disable workflow_timeout; + if (timeout_flag) begin + $display("[ERROR] -dut_read_output- Timeout detected when awaiting for finish pulse"); + $finish; + end - // error handling todo endtask + // Основная таска типового теста + // todo + //------------------------------------------------------------ // ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ //------------------------------------------------------------ diff --git a/rtl/accum/src/accum.sv b/rtl/accum/src/accum.sv index 6f171b0..7aeb07c 100644 --- a/rtl/accum/src/accum.sv +++ b/rtl/accum/src/accum.sv @@ -185,6 +185,7 @@ module accumulator if (seq_num_reg <= 16'd1) begin cnt_seq_num <= '0; addrb <= '0; + accum_done <= 1; wr_state <= READOUT_START; end else begin // start further accumulation