upd: reflectometer on axis bus iface + TB

This commit is contained in:
2026-07-10 18:46:48 +03:00
parent 0ba25a3541
commit 11a9e97691
5 changed files with 199 additions and 124 deletions

View File

@ -10,16 +10,21 @@
FPGA_PART = xc7a100tfgg484-2 FPGA_PART = xc7a100tfgg484-2
FPGA_TOP = reflectometer_top FPGA_TOP = reflectometer_top
FPGA_ARCH = artix7 FPGA_ARCH = artix7
SIM_TOP = reflectometer_tb
RTL_DIR = ../../rtl RTL_DIR = ../../rtl
include ../../scripts/vivado.mk include ../../scripts/vivado.mk
INC_FILES += interfaces.svh
TB_FILES += reflectometer_tb.sv
SYN_FILES += reflectometer.sv SYN_FILES += reflectometer.sv
SYN_FILES += dac_model.sv SYN_FILES += dac_model.sv
SYN_FILES += adc_model.sv SYN_FILES += adc_model.sv
SYN_FILES += tb_reflectometer.sv SYN_FILES += reflectometer_tb.sv
SYN_FILES += $(sort $(shell find ../../rtl -type f \( -name '*.v' -o -name '*.sv' \))) SYN_FILES += $(sort $(shell find ../../rtl -type f \( -name '*.v' -o -name '*.sv' \)))
XCI_FILES = $(sort $(shell find ../../rtl/ethernet-udp/src -type f -name '*.xci')) XCI_FILES = $(sort $(shell find ../../rtl/ethernet-udp/src -type f -name '*.xci'))
@ -28,7 +33,6 @@ XCI_FILES += $(sort $(shell find ip/ -type f -name '*.xci'))
XDC_FILES += ../../constraints/ax7102.xdc XDC_FILES += ../../constraints/ax7102.xdc
XDC_FILES += debug.xdc XDC_FILES += debug.xdc
SIM_TOP = tb_reflectometer
program: $(PROJECT).bit program: $(PROJECT).bit

View File

@ -1,4 +1,9 @@
# Primary clocks # Primary clocks
create_clock -name ref_clock -period 5.000 [get_ports clk_in] create_clock -name ref_clock -period 5.000 [get_ports clk_in]
create_clock -name phy_rx_clock -period 8.000 [get_ports clk_m_axis] create_clock -name phy_rx_clock -period 8.000 [get_ports clk_m_axis]
create_clock -name phy_tx_clock -period 8.000 [get_ports clk_s_axis] create_clock -name phy_tx_clock -period 8.000 [get_ports clk_s_axis]
set clk_125_name [get_clocks -of_objects [get_pins generator_inst/clk_dac_125]]
set clk_65_name [get_clocks -of_objects [get_pins accumulator_top_dut/clk_adc_65]]
set_clock_groups -asynchronous -group $clk_125_name -group $clk_65_name

View File

@ -0,0 +1,53 @@
`ifndef AXIS_INTERFACE_SVH
`define AXIS_INTERFACE_SVH
interface axis_if #(
parameter int DATA_WIDTH = 8
)(
input logic clk,
input logic rst_n
);
// Сигналы шины AXI-Stream
logic [DATA_WIDTH-1:0] tdata;
logic tvalid;
logic tlast;
logic tready;
//------------------------------------------------------------
// Clocking block для Testbench (Driver/Monitor)
// Защищает от Race Conditions в симуляции
//------------------------------------------------------------
clocking drv_cb @(posedge clk);
default input #1step output #100ps;
output tdata, tvalid, tlast;
input tready;
endclocking
clocking mon_cb @(posedge clk);
default input #1step;
input tdata, tvalid, tlast, tready;
endclocking
//------------------------------------------------------------
// Modports для автоматического подключения одной строчкой
//------------------------------------------------------------
modport master (
output tdata, tvalid, tlast,
input tready
);
modport slave (
input tdata, tvalid, tlast,
output tready
);
// Modport для тестбенча (чтобы работать через функции)
modport tb (
clocking drv_cb,
clocking mon_cb
);
endinterface
`endif // AXIS_INTERFACE_SVH

View File

@ -1,5 +1,7 @@
`timescale 1 ns / 1 ns `timescale 1 ns / 1 ns
`include "interfaces.svh"
module reflectometer_top #( module reflectometer_top #(
parameter int unsigned DAC_DATA_WIDTH = 14, parameter int unsigned DAC_DATA_WIDTH = 14,
parameter int unsigned ADC_DATA_WIDTH = 12, parameter int unsigned ADC_DATA_WIDTH = 12,
@ -16,18 +18,12 @@ module reflectometer_top #(
output wire locked, output wire locked,
// Accumulator AXI-S bus // Accumulator AXI-S bus
input wire clk_m_axis, // GMII PHY RX clock input wire clk_axis_accumulator, // GMII PHY RX clock
output wire [7:0] m_axis_tdata, axis_if.master axis_accumulator,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
// Control AXI-S bus // Control AXI-S bus
input wire clk_s_axis, // GMII PHY TX clock input wire clk_axis_control, // GMII PHY TX clock
input wire [7:0] s_axis__tdata, axis_if.slave axis_control,
input wire s_axis_tvalid,
input wire s_axis_tlast,
output wire s_axis_tready,
// RTL-MAC handshake // RTL-MAC handshake
input wire request_ready, input wire request_ready,
@ -101,15 +97,15 @@ module reflectometer_top #(
control #( control #(
.DAC_DATA_WIDTH(DAC_DATA_WIDTH) .DAC_DATA_WIDTH(DAC_DATA_WIDTH)
) udp_ctrl_inst ( ) udp_ctrl_inst (
.eth_clk_in (clk_s_axis), .eth_clk_in (clk_axis_control),
.dac_clk_in (clk_generator), .dac_clk_in (clk_generator),
.adc_clk_in (clk_sampler), .adc_clk_in (clk_sampler),
.rst_n (ctrl_rst_n), .rst_n (ctrl_rst_n),
.s_axis_tdata (s_axis__tdata), .s_axis_tdata (axis_control.tdata),
.s_axis_tvalid (s_axis_tvalid), .s_axis_tvalid (axis_control.tvalid),
.s_axis_tready (s_axis_tready), .s_axis_tready (axis_control.tready),
.s_axis_tlast (s_axis_tlast), .s_axis_tlast (axis_control.tlast),
.finish (finish), .finish (finish),
@ -131,9 +127,9 @@ module reflectometer_top #(
//------------------------------------------------------------ //------------------------------------------------------------
// DAC -> ADC CDC // DAC -> ADC CDC
//------------------------------------------------------------ //------------------------------------------------------------
logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени (* ASYNC_REG = "TRUE" *) logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени
logic [1:0] sync_DA; (* ASYNC_REG = "TRUE" *) logic [1:0] sync_DA;
wire dac_done_stretched; wire dac_done_stretched;
wire generator_done, generator_request; wire generator_done, generator_request;
wire sampler_done, sampler_request; wire sampler_done, sampler_request;
@ -163,7 +159,7 @@ module reflectometer_top #(
//------------------------------------------------------------ //------------------------------------------------------------
// ADC -> DAC CDC // ADC -> DAC CDC
//------------------------------------------------------------ //------------------------------------------------------------
logic [1:0] sync_AD; (* ASYNC_REG = "TRUE" *) logic [1:0] sync_AD;
always_ff @(posedge clk_generator or posedge dac_rst) begin always_ff @(posedge clk_generator or posedge dac_rst) begin
if (dac_rst) if (dac_rst)
@ -237,11 +233,11 @@ module reflectometer_top #(
.req_ready(request_ready), .req_ready(request_ready),
.send_req(send_request), .send_req(send_request),
.eth_clk_in(clk_m_axis), .eth_clk_in(clk_axis_accumulator),
.m_axis_tdata(m_axis_tdata), .m_axis_tdata(axis_accumulator.tdata),
.m_axis_tvalid(m_axis_tvalid), .m_axis_tvalid(axis_accumulator.tvalid),
.m_axis_tready(m_axis_tready), .m_axis_tready(axis_accumulator.tready),
.m_axis_tlast(m_axis_tlast), .m_axis_tlast(axis_accumulator.tlast),
.finish(finish) .finish(finish)
); );

View File

@ -1,6 +1,8 @@
`timescale 1ns / 1ps `timescale 1ns / 1ps
module tb_reflectometer; `include "interfaces.svh"
module reflectometer_tb;
//------------------------------------------------------------ //------------------------------------------------------------
// Параметры // Параметры
//------------------------------------------------------------ //------------------------------------------------------------
@ -42,15 +44,15 @@ module tb_reflectometer;
// Внутренние сигналы тестбенча // Внутренние сигналы тестбенча
//------------------------------------------------------------ //------------------------------------------------------------
// AXI-S интерфейс для управления // AXI-S интерфейс для управления
logic [7:0] m_axis_control_tdata = 8'b0; axis_if axis_control_if (
logic m_axis_control_tvalid = 1'b0; .clk(clk_eth_phy),
wire m_axis_control_tready; .rst_n(rst_n)
logic m_axis_control_tlast = 1'b0; );
// AXI-S интерфейс для данных // AXI-S интерфейс для данных
wire [7:0] s_axis_accumulator_tdata; axis_if axis_accumulator_if (
wire s_axis_accumulator_tvalid; .clk(clk_eth_phy),
logic s_axis_accumulator_tready = 1'b0; .rst_n(rst_n)
wire s_axis_accumulator_tlast; );
// DAC интерфейс // DAC интерфейс
wire clk_dac; wire clk_dac;
wire dac_wrt; wire dac_wrt;
@ -94,7 +96,7 @@ module tb_reflectometer;
//------------------------------------------------------------ //------------------------------------------------------------
// Config handler // Config handler
//------------------------------------------------------------ //------------------------------------------------------------
//------------------------------------------------------------ //------------------------------------------------------------
// DUT // DUT
//------------------------------------------------------------ //------------------------------------------------------------
@ -114,19 +116,13 @@ module tb_reflectometer;
.locked(mmcm_locked), .locked(mmcm_locked),
// Accumulator AXI-S bus // Accumulator AXI-S bus
.clk_m_axis(clk_eth_phy), // GMII PHY RX clock .clk_axis_accumulator(clk_eth_phy), // GMII PHY RX clock
.m_axis_tdata(s_axis_accumulator_tdata), .axis_accumulator(axis_accumulator_if.master),
.m_axis_tvalid(s_axis_accumulator_tvalid),
.m_axis_tready(s_axis_accumulator_tready),
.m_axis_tlast(s_axis_accumulator_tlast),
// Control AXI-S bus // Control AXI-S bus
.clk_s_axis(clk_eth_phy), // GMII PHY TX clock .clk_axis_control(clk_eth_phy), // GMII PHY TX clock
.s_axis__tdata(maxis_control_tdata), .axis_control(axis_control_if.slave),
.s_axis_tvalid(maxis_control_tvalid),
.s_axis_tlast(maxis_control_tlast),
.s_axis_tready(maxis_control_tready),
// RTL-MAC handshake // RTL-MAC handshake
.request_ready(request_ready), .request_ready(request_ready),
.send_request(send_request), .send_request(send_request),
@ -154,86 +150,100 @@ module tb_reflectometer;
// Таски для тестирования // Таски для тестирования
//------------------------------------------------------------ //------------------------------------------------------------
// task automatic axis_send_byte( // AXI-S таски
// ref logic clk, task automatic axis_send_packet(
// input logic [7:0] data, virtual axis_if.tb vif,
// input logic last, const ref logic [7:0] payload[]
// ref logic tvalid, );
// ref logic [7:0] tdata, int packet_size = payload.size();
// ref logic tlast,
// input logic tready
// );
// @(posedge clk);
// tdata <= data;
// tlast <= last;
// tvalid <= 1'b1;
// // Ждем готовности приемника if (packet_size == 0) begin
// wait(tready === 1'b1); $display("[WARNING] -axis_send_packet- Попытка отправить пустой пакет.");
return;
end
// @(posedge clk); foreach (payload[i]) begin
// tvalid <= 1'b0; vif.drv_cb.tdata <= payload[i];
// tlast <= 1'b0; vif.drv_cb.tvalid <= 1'b1;
// endtask vif.drv_cb.tlast <= (i == packet_size - 1); // tlast активен только на последнем байте
// task automatic dut_soft_reset(); // Шагаем на следующий фронт клока, чтобы симулятор применил выходы
// axis_send_byte( @(vif.drv_cb);
// .clk(clk_eth_phy_rx),
// .data(8'b00001111),
// .last(1'b1),
// .tvalid(m_axis_rx_tvalid),
// .tdata(m_axis_rx_tdata),
// .tlast(m_axis_rx_tlast),
// .tready(m_axis_rx_tready)
// );
// endtask
// task automatic dut_start(); // Ждем на последующих фронтах, пока tready не станет равен 1.
// axis_send_byte( while (vif.drv_cb.tready !== 1'b1) begin
// .clk(clk_eth_phy_rx), @(vif.drv_cb);
// .data(8'b11110000), end
// .last(1'b1), end
// .tvalid(m_axis_rx_tvalid),
// .tdata(m_axis_rx_tdata),
// .tlast(m_axis_rx_tlast),
// .tready(m_axis_rx_tready)
// );
// endtask
// task automatic dut_send_config( // Снимаем валидность на следующем дельта-цикле
// input logic [127:0] ctrl_config vif.drv_cb.tvalid <= 1'b0;
// ); vif.drv_cb.tlast <= 1'b0;
// // команда set_data vif.drv_cb.tdata <= '0;
// axis_send_byte( endtask
// .clk(clk_eth_phy_rx),
// .data(8'b10001000),
// .last(1'b0),
// .tvalid(m_axis_rx_tvalid),
// .tdata(m_axis_rx_tdata),
// .tlast(m_axis_rx_tlast),
// .tready(m_axis_rx_tready)
// );
// // config burst
// for (int i = 0; i < 16; i++) begin
// logic [7:0] byte_to_send;
// logic is_last;
// // get byte task automatic dut_soft_reset();
// byte_to_send = ctrl_config[i*8 +: 8]; logic [7:0] cmd[] = '{8'b00001111};
// // tlast for last byte axis_send_packet(
// is_last = (i == 15); .vif(axis_control_if.tb),
.payload(cmd)
);
endtask
// axis_send_byte( task automatic dut_start();
// .clk(clk_eth_phy_rx), logic [7:0] cmd[] = '{8'b11110000};
// .data(byte_to_send), axis_send_packet(
// .last(is_last), .vif(axis_control_if.tb),
// .tvalid(m_axis_rx_tvalid), .payload(cmd)
// .tdata(m_axis_rx_tdata), );
// .tlast(m_axis_rx_tlast), endtask
// .tready(m_axis_rx_tready)
// ); task automatic dut_send_system_config(
// end input logic [31:0] pulse_width,
// endtask 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
// Таски сбора и обработки статистики
//------------------------------------------------------------ //------------------------------------------------------------
@ -245,10 +255,17 @@ module tb_reflectometer;
// Инициализация // Инициализация
rst_n = 1; rst_n = 1;
wait(mmcm_locked === 1'b1); wait(mmcm_locked === 1'b1);
#10;
dut_soft_reset();
#100; 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"); $display("[TB] ALL PASSED");
$finish; $finish;