`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 = 0; // 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 ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "true" localparam CLK_ETH_PHY_PERIOD = 8.000; // 125 MHz localparam CLK_REF_PERIOD = 5.000; // 200 MHz //------------------------------------------------------------ // Тактовые сигналы и сброс //------------------------------------------------------------ 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; //------------------------------------------------------------ // Внутренние сигналы тестбенча //------------------------------------------------------------ // AXI-S интерфейс для управления axis_if axis_control_if ( .clk(clk_eth_phy), .rst_n(rst_n) ); // 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 = 1'b0; wire [ADC_DATA_WIDTH-1:0] adc_data = '0; // Интерфейс хендшейка с MAC-PHY wire send_request; logic request_ready = 1'b0; // Сигналы ЦАП и АЦП real signal_voltage; //------------------------------------------------------------ // Virtual DAC //------------------------------------------------------------ virtual_dac_model #( // default voltage range is +/- 5V .DAC_DATA_WIDTH(DAC_DATA_WIDTH) ) 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 monitor //------------------------------------------------------------ //------------------------------------------------------------ // 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), .WINDOW_SIZE(WINDOW_SIZE), .PACKET_SIZE(PACKET_SIZE) ) DUT ( .clk_in(clk_ref), .rst_n(rst_n), .locked(mmcm_locked), // 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), // 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) ); //------------------------------------------------------------ // Тактовые сигналы //------------------------------------------------------------ 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-S таски task automatic axis_send_packet( virtual axis_if.tb vif, const ref logic [7:0] payload[] ); int packet_size = payload.size(); if (packet_size == 0) begin $display("[WARNING] -axis_send_packet- Попытка отправить пустой пакет."); return; 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 активен только на последнем байте // Шагаем на следующий фронт клока, чтобы симулятор применил выходы @(vif.drv_cb); // Ждем на последующих фронтах, пока tready не станет равен 1. while (vif.drv_cb.tready !== 1'b1) begin @(vif.drv_cb); end end // Снимаем валидность на следующем дельта-цикле vif.drv_cb.tvalid <= 1'b0; vif.drv_cb.tlast <= 1'b0; vif.drv_cb.tdata <= '0; endtask task automatic dut_soft_reset(); logic [7:0] cmd[] = '{8'b00001111}; axis_send_packet( .vif(axis_control_if.tb), .payload(cmd) ); endtask task automatic dut_start(); logic [7:0] cmd[] = '{8'b11110000}; axis_send_packet( .vif(axis_control_if.tb), .payload(cmd) ); endtask task automatic dut_send_system_config( input logic [31:0] pulse_width, input logic [31:0] pulse_period, input logic [15:0] pulse_num, input logic [13:0] pulse_height, input logic [31:0] pulse_period_adc ); // Выделяем 17 байт: 1 байт команды + 16 байт регистров logic [7:0] full_packet[] = new[17]; // 1. Сначала пишем команду в нулевой байт пакета full_packet[0] = 8'b10001000; // Твоя команда set_data // 2. Упаковываем регистр pulse_width [31:0] (байты 1..4) full_packet[1] = pulse_width[7:0]; full_packet[2] = pulse_width[15:8]; full_packet[3] = pulse_width[23:16]; full_packet[4] = pulse_width[31:24]; // 3. Упаковываем регистр pulse_period [63:32] (байты 5..8) full_packet[5] = pulse_period[7:0]; full_packet[6] = pulse_period[15:8]; full_packet[7] = pulse_period[23:16]; full_packet[8] = pulse_period[31:24]; // 4. Упаковываем регистр pulse_num [79:64] (байты 9..10) full_packet[9] = pulse_num[7:0]; full_packet[10] = pulse_num[15:8]; // 5. Упаковываем регистр pulse_height [79+dac_width:80] (байты 11..12) full_packet[11] = pulse_height[7:0]; full_packet[12] = {2'b00, pulse_height[13:8]}; // дополняем до честного байта // 6. Упаковываем регистр pulse_period_adc [127:96] (байты 13..16) full_packet[13] = pulse_period_adc[7:0]; full_packet[14] = pulse_period_adc[15:8]; full_packet[15] = pulse_period_adc[23:16]; full_packet[16] = pulse_period_adc[31:24]; axis_send_packet( .vif(axis_control_if.tb), .payload(full_packet) ); endtask // Таски сбора и обработки статистики //------------------------------------------------------------ // ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ //------------------------------------------------------------ initial begin $display("[TB] Tests start"); // Инициализация rst_n = 1; wait(mmcm_locked === 1'b1); #10; dut_soft_reset(); dut_send_system_config( .pulse_width(32'd350), .pulse_period(32'd1250), .pulse_num(16'd10), .pulse_height(14'd14000), // 0V .pulse_period_adc(32'd650) ); dut_start(); $display("[TB] ALL PASSED"); $finish; end endmodule