diff --git a/designs/reflectometer_base/Makefile b/designs/reflectometer_base/Makefile index f6df81d..e7b027c 100644 --- a/designs/reflectometer_base/Makefile +++ b/designs/reflectometer_base/Makefile @@ -10,16 +10,21 @@ FPGA_PART = xc7a100tfgg484-2 FPGA_TOP = reflectometer_top FPGA_ARCH = artix7 +SIM_TOP = reflectometer_tb RTL_DIR = ../../rtl include ../../scripts/vivado.mk + +INC_FILES += interfaces.svh + +TB_FILES += reflectometer_tb.sv SYN_FILES += reflectometer.sv SYN_FILES += dac_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' \))) 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 += debug.xdc -SIM_TOP = tb_reflectometer program: $(PROJECT).bit diff --git a/designs/reflectometer_base/debug.xdc b/designs/reflectometer_base/debug.xdc index e87e9ac..d408385 100644 --- a/designs/reflectometer_base/debug.xdc +++ b/designs/reflectometer_base/debug.xdc @@ -1,4 +1,9 @@ # Primary clocks 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_tx_clock -period 8.000 [get_ports clk_s_axis] \ No newline at end of file +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 \ No newline at end of file diff --git a/designs/reflectometer_base/interfaces.svh b/designs/reflectometer_base/interfaces.svh new file mode 100644 index 0000000..94b44b1 --- /dev/null +++ b/designs/reflectometer_base/interfaces.svh @@ -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 \ No newline at end of file diff --git a/designs/reflectometer_base/reflectometer.sv b/designs/reflectometer_base/reflectometer.sv index 2a4afb1..1e1bd0a 100644 --- a/designs/reflectometer_base/reflectometer.sv +++ b/designs/reflectometer_base/reflectometer.sv @@ -1,5 +1,7 @@ `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, @@ -16,18 +18,12 @@ module reflectometer_top #( output wire locked, // Accumulator AXI-S bus - input wire clk_m_axis, // GMII PHY RX clock - output wire [7:0] m_axis_tdata, - output wire m_axis_tvalid, - input wire m_axis_tready, - output wire m_axis_tlast, + input wire clk_axis_accumulator, // GMII PHY RX clock + axis_if.master axis_accumulator, // Control AXI-S bus - input wire clk_s_axis, // GMII PHY TX clock - input wire [7:0] s_axis__tdata, - input wire s_axis_tvalid, - input wire s_axis_tlast, - output wire s_axis_tready, + input wire clk_axis_control, // GMII PHY TX clock + axis_if.slave axis_control, // RTL-MAC handshake input wire request_ready, @@ -101,15 +97,15 @@ module reflectometer_top #( control #( .DAC_DATA_WIDTH(DAC_DATA_WIDTH) ) udp_ctrl_inst ( - .eth_clk_in (clk_s_axis), + .eth_clk_in (clk_axis_control), .dac_clk_in (clk_generator), .adc_clk_in (clk_sampler), .rst_n (ctrl_rst_n), - .s_axis_tdata (s_axis__tdata), - .s_axis_tvalid (s_axis_tvalid), - .s_axis_tready (s_axis_tready), - .s_axis_tlast (s_axis_tlast), + .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), @@ -131,9 +127,9 @@ module reflectometer_top #( //------------------------------------------------------------ // DAC -> ADC CDC //------------------------------------------------------------ - logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени - logic [1:0] sync_DA; - wire dac_done_stretched; + (* 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; @@ -163,7 +159,7 @@ module reflectometer_top #( //------------------------------------------------------------ // 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 if (dac_rst) @@ -237,11 +233,11 @@ module reflectometer_top #( .req_ready(request_ready), .send_req(send_request), - .eth_clk_in(clk_m_axis), - .m_axis_tdata(m_axis_tdata), - .m_axis_tvalid(m_axis_tvalid), - .m_axis_tready(m_axis_tready), - .m_axis_tlast(m_axis_tlast), + .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) ); diff --git a/designs/reflectometer_base/tb_reflectometer.sv b/designs/reflectometer_base/reflectometer_tb.sv similarity index 56% rename from designs/reflectometer_base/tb_reflectometer.sv rename to designs/reflectometer_base/reflectometer_tb.sv index 60afcba..abcd758 100644 --- a/designs/reflectometer_base/tb_reflectometer.sv +++ b/designs/reflectometer_base/reflectometer_tb.sv @@ -1,6 +1,8 @@ `timescale 1ns / 1ps -module tb_reflectometer; +`include "interfaces.svh" + +module reflectometer_tb; //------------------------------------------------------------ // Параметры //------------------------------------------------------------ @@ -42,15 +44,15 @@ module tb_reflectometer; // Внутренние сигналы тестбенча //------------------------------------------------------------ // AXI-S интерфейс для управления - logic [7:0] m_axis_control_tdata = 8'b0; - logic m_axis_control_tvalid = 1'b0; - wire m_axis_control_tready; - logic m_axis_control_tlast = 1'b0; + axis_if axis_control_if ( + .clk(clk_eth_phy), + .rst_n(rst_n) + ); // AXI-S интерфейс для данных - wire [7:0] s_axis_accumulator_tdata; - wire s_axis_accumulator_tvalid; - logic s_axis_accumulator_tready = 1'b0; - wire s_axis_accumulator_tlast; + axis_if axis_accumulator_if ( + .clk(clk_eth_phy), + .rst_n(rst_n) + ); // DAC интерфейс wire clk_dac; wire dac_wrt; @@ -94,7 +96,7 @@ module tb_reflectometer; //------------------------------------------------------------ // Config handler //------------------------------------------------------------ - + //------------------------------------------------------------ // DUT //------------------------------------------------------------ @@ -114,19 +116,13 @@ module tb_reflectometer; .locked(mmcm_locked), // Accumulator AXI-S bus - .clk_m_axis(clk_eth_phy), // GMII PHY RX clock - .m_axis_tdata(s_axis_accumulator_tdata), - .m_axis_tvalid(s_axis_accumulator_tvalid), - .m_axis_tready(s_axis_accumulator_tready), - .m_axis_tlast(s_axis_accumulator_tlast), + .clk_axis_accumulator(clk_eth_phy), // GMII PHY RX clock + .axis_accumulator(axis_accumulator_if.master), // Control AXI-S bus - .clk_s_axis(clk_eth_phy), // GMII PHY TX clock - .s_axis__tdata(maxis_control_tdata), - .s_axis_tvalid(maxis_control_tvalid), - .s_axis_tlast(maxis_control_tlast), - .s_axis_tready(maxis_control_tready), - + .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), @@ -154,86 +150,100 @@ module tb_reflectometer; // Таски для тестирования //------------------------------------------------------------ -// task automatic axis_send_byte( -// ref logic clk, -// input logic [7:0] data, -// input logic last, -// ref logic tvalid, -// ref logic [7:0] tdata, -// ref logic tlast, -// input logic tready -// ); -// @(posedge clk); -// tdata <= data; -// tlast <= last; -// tvalid <= 1'b1; + // AXI-S таски + task automatic axis_send_packet( + virtual axis_if.tb vif, + const ref logic [7:0] payload[] + ); + int packet_size = payload.size(); -// // Ждем готовности приемника -// wait(tready === 1'b1); + if (packet_size == 0) begin + $display("[WARNING] -axis_send_packet- Попытка отправить пустой пакет."); + return; + end -// @(posedge clk); -// tvalid <= 1'b0; -// tlast <= 1'b0; -// endtask + 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 активен только на последнем байте -// task automatic dut_soft_reset(); -// axis_send_byte( -// .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 + // Шагаем на следующий фронт клока, чтобы симулятор применил выходы + @(vif.drv_cb); -// task automatic dut_start(); -// axis_send_byte( -// .clk(clk_eth_phy_rx), -// .data(8'b11110000), -// .last(1'b1), -// .tvalid(m_axis_rx_tvalid), -// .tdata(m_axis_rx_tdata), -// .tlast(m_axis_rx_tlast), -// .tready(m_axis_rx_tready) -// ); -// endtask + // Ждем на последующих фронтах, пока tready не станет равен 1. + while (vif.drv_cb.tready !== 1'b1) begin + @(vif.drv_cb); + end + end -// task automatic dut_send_config( -// input logic [127:0] ctrl_config -// ); -// // команда set_data -// axis_send_byte( -// .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; + // Снимаем валидность на следующем дельта-цикле + vif.drv_cb.tvalid <= 1'b0; + vif.drv_cb.tlast <= 1'b0; + vif.drv_cb.tdata <= '0; + endtask -// // get byte -// byte_to_send = ctrl_config[i*8 +: 8]; -// // tlast for last byte -// is_last = (i == 15); + task automatic dut_soft_reset(); + logic [7:0] cmd[] = '{8'b00001111}; + axis_send_packet( + .vif(axis_control_if.tb), + .payload(cmd) + ); + endtask -// axis_send_byte( -// .clk(clk_eth_phy_rx), -// .data(byte_to_send), -// .last(is_last), -// .tvalid(m_axis_rx_tvalid), -// .tdata(m_axis_rx_tdata), -// .tlast(m_axis_rx_tlast), -// .tready(m_axis_rx_tready) -// ); -// end -// 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 + + // Таски сбора и обработки статистики //------------------------------------------------------------ @@ -245,10 +255,17 @@ module tb_reflectometer; // Инициализация rst_n = 1; wait(mmcm_locked === 1'b1); - + #10; - - #100; + 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;