Files
reflectometer_fpga_project/designs/reflectometer_base/reflectometer_tb.sv
T

244 lines
8.8 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 = VOLTAGE_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;
wire [ADC_DATA_WIDTH-1:0] adc_data;
// Интерфейс хендшейка с 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
//------------------------------------------------------------
// Таски для тестирования
//------------------------------------------------------------
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[];
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
// Таски сбора и обработки статистики
//------------------------------------------------------------
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
//------------------------------------------------------------
initial begin
logic [7:0] rx_packet[];
automatic virtual axis_if.tb control_vif = axis_control_if.tb;
automatic virtual axis_if.tb accumulator_vif = axis_accumulator_if.tb;
$display("[TB] Tests start");
// Инициализация
rst_n = 0;
#100;
rst_n = 1;
wait(mmcm_locked === 1'b1);
#150;
$display("[TB] MMCM locked");
dut_soft_reset(control_vif);
#100;
dut_send_system_config(
.vif(control_vif),
.pulse_width(32'd12345),
.pulse_period(32'd50000),
.pulse_num(16'd10),
.pulse_height(14'd16000), // 0V
.pulse_period_adc(32'd26000)
);
#100;
dut_start(control_vif);
#1000;
request_ready = 1'b1;
accumulator_vif.slave_recv(rx_packet);
$display("receive %0d bytes", rx_packet.size());
for (int i = 0; i < rx_packet.size(); i+=4) begin
$write("%0d ", {rx_packet[i], rx_packet[i+1], rx_packet[i+2], rx_packet[i+3]});
end
$display("");
#1000;
request_ready = 1'b1;
accumulator_vif.slave_recv(rx_packet);
$display("receive %0d bytes", rx_packet.size());
for (int i = 0; i < rx_packet.size(); i+=4) begin
$write("%0d ", {rx_packet[i], rx_packet[i+1], rx_packet[i+2], rx_packet[i+3]});
end
$display("");
// wait();
// #100000;
// #93000;
// rst_n = 0;
#10000
$display("[TB] ALL PASSED");
$finish;
end
endmodule