277 lines
10 KiB
Systemverilog
277 lines
10 KiB
Systemverilog
`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,
|
||
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
|
||
$display("%1", payload[i]);
|
||
// 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[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 = 0;
|
||
#100;
|
||
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
|