From 71b825ef2c80bc09975654f2f70279503ef2236c Mon Sep 17 00:00:00 2001 From: Zer0Nu11 Date: Thu, 16 Jul 2026 19:33:51 +0300 Subject: [PATCH] upd: fix axi-stream interface definition; successful TB DUT launch --- designs/reflectometer_base/interfaces.svh | 117 ++++++++++++--- .../reflectometer_base/reflectometer_tb.sv | 133 +++++------------- 2 files changed, 136 insertions(+), 114 deletions(-) diff --git a/designs/reflectometer_base/interfaces.svh b/designs/reflectometer_base/interfaces.svh index 94b44b1..8f0c4aa 100644 --- a/designs/reflectometer_base/interfaces.svh +++ b/designs/reflectometer_base/interfaces.svh @@ -14,40 +14,117 @@ interface axis_if #( logic tlast; logic tready; - //------------------------------------------------------------ - // Clocking block для Testbench (Driver/Monitor) - // Защищает от Race Conditions в симуляции - //------------------------------------------------------------ + initial begin // Default values + tdata = 'x; + tvalid = 1'b0; + tlast = 1'b0; + tready = 1'b0; + end + + // Master Clocking Block (для отправки данных из TB) clocking drv_cb @(posedge clk); default input #1step output #100ps; output tdata, tvalid, tlast; input tready; endclocking + // Slave Clocking Block (для приема данных в TB с генерацией tready) + clocking slv_cb @(posedge clk); + default input #1step output #100ps; + input tdata, tvalid, tlast; + output tready; + endclocking + + // Passive Monitor Clocking Block 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 master (output tdata, tvalid, tlast, input tready); + modport slave (input tdata, tvalid, tlast, output tready); + + // Модпорт для тестбенча с тасками modport tb ( clocking drv_cb, - clocking mon_cb + clocking slv_cb, + clocking mon_cb, + import master_send, + import slave_recv, + import monitor_recv ); + // Отправка пакета (Тестбенч выступает как Master) + task automatic master_send(input logic [DATA_WIDTH-1:0] payload[]); + if (payload.size() == 0) return; + + @(drv_cb); + + for (int i = 0; i < payload.size(); i++) begin + drv_cb.tdata <= payload[i]; + drv_cb.tvalid <= 1'b1; + drv_cb.tlast <= (i == payload.size() - 1); + + forever begin // Ждем подтверждение от слейва пока не получим + @(drv_cb); + if (drv_cb.tready === 1'b1) begin + break; + end + end + end + // Сбрасываем сигналы после отправки пакета + drv_cb.tvalid <= 1'b0; + drv_cb.tlast <= 1'b0; + drv_cb.tdata <= 'x; + endtask + + // Прием пакета (Тестбенч выступает как Slave и управляет tready). Не применять если есть реальный Slave (его tready опустится насильно) + task automatic slave_recv(output logic [DATA_WIDTH-1:0] payload[]); + logic [DATA_WIDTH-1:0] local_queue[$]; // Внутри таски очередь использовать можно + + slv_cb.tready <= 1'b1; // Показываем, что готовы принимать + + forever begin + @(slv_cb); + if (slv_cb.tvalid === 1'b1) begin + local_queue.push_back(slv_cb.tdata); + if (slv_cb.tlast === 1'b1) begin + break; // Пакет закончился + end + end + end + + slv_cb.tready <= 1'b0; // Снимаем готовность + + // Перекладываем из очереди в динамический массив + payload = new[local_queue.size()](local_queue); + endtask + + // Прием пакета (Тестбенч выступает как пассивный наблюдатель без tready) + task automatic monitor_recv(output logic [DATA_WIDTH-1:0] payload[]); + logic [DATA_WIDTH-1:0] local_queue[$]; // Внутри таски очередь использовать можно + + forever begin + if (mon_cb.tready === 1'b1) begin + break; // Дождались слейва + end + @(slv_cb); + end + + forever begin + @(mon_cb); + if (mon_cb.tvalid === 1'b1) begin + local_queue.push_back(mon_cb.tdata); + if (mon_cb.tlast === 1'b1) begin + break; // Пакет закончился + end + end + end + + // Перекладываем из очереди в динамический массив + payload = new[local_queue.size()](local_queue); + endtask + endinterface -`endif // AXIS_INTERFACE_SVH \ No newline at end of file +`endif // AXIS_INTERFACE_SVH` \ No newline at end of file diff --git a/designs/reflectometer_base/reflectometer_tb.sv b/designs/reflectometer_base/reflectometer_tb.sv index e6b3820..f4484c2 100644 --- a/designs/reflectometer_base/reflectometer_tb.sv +++ b/designs/reflectometer_base/reflectometer_tb.sv @@ -149,99 +149,37 @@ module reflectometer_tb; //------------------------------------------------------------ // Таски для тестирования //------------------------------------------------------------ - - // 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; + 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_soft_reset(); - logic [7:0] cmd[] = '{8'b00001111}; - axis_send_packet( - .vif(axis_control_if.tb), - .payload(cmd) - ); + 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_start(); - logic [7:0] cmd[] = '{8'b11110000}; - axis_send_packet( - .vif(axis_control_if.tb), - .payload(cmd) - ); - 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, + input logic [13:0] pulse_height, // achtung! p_height strictly must have 14 bits of width 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) - ); + // Создаем временный фиксированный массив и упаковываем всё одной строкой + 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 // Таски сбора и обработки статистики @@ -251,24 +189,31 @@ module reflectometer_tb; // ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ //------------------------------------------------------------ initial begin + 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); #10; + $display("[TB] MMCM locked"); - 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(); + dut_soft_reset(control_vif); + #100; + dut_send_system_config( + .vif(control_vif), + .pulse_width(32'd350), + .pulse_period(32'd1250), + .pulse_num(16'd10), + .pulse_height(14'd14000), // 0V + .pulse_period_adc(32'd650) + ); + #100; + dut_start(control_vif); $display("[TB] ALL PASSED"); $finish;