upd:
fix axi-stream interface definition; successful TB DUT launch
This commit is contained in:
@ -14,40 +14,117 @@ interface axis_if #(
|
|||||||
logic tlast;
|
logic tlast;
|
||||||
logic tready;
|
logic tready;
|
||||||
|
|
||||||
//------------------------------------------------------------
|
initial begin // Default values
|
||||||
// Clocking block для Testbench (Driver/Monitor)
|
tdata = 'x;
|
||||||
// Защищает от Race Conditions в симуляции
|
tvalid = 1'b0;
|
||||||
//------------------------------------------------------------
|
tlast = 1'b0;
|
||||||
|
tready = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Master Clocking Block (для отправки данных из TB)
|
||||||
clocking drv_cb @(posedge clk);
|
clocking drv_cb @(posedge clk);
|
||||||
default input #1step output #100ps;
|
default input #1step output #100ps;
|
||||||
output tdata, tvalid, tlast;
|
output tdata, tvalid, tlast;
|
||||||
input tready;
|
input tready;
|
||||||
endclocking
|
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);
|
clocking mon_cb @(posedge clk);
|
||||||
default input #1step;
|
default input #1step;
|
||||||
input tdata, tvalid, tlast, tready;
|
input tdata, tvalid, tlast, tready;
|
||||||
endclocking
|
endclocking
|
||||||
|
|
||||||
//------------------------------------------------------------
|
modport master (output tdata, tvalid, tlast, input tready);
|
||||||
// Modports для автоматического подключения одной строчкой
|
modport slave (input tdata, tvalid, tlast, output tready);
|
||||||
//------------------------------------------------------------
|
|
||||||
modport master (
|
|
||||||
output tdata, tvalid, tlast,
|
|
||||||
input tready
|
|
||||||
);
|
|
||||||
|
|
||||||
modport slave (
|
// Модпорт для тестбенча с тасками
|
||||||
input tdata, tvalid, tlast,
|
|
||||||
output tready
|
|
||||||
);
|
|
||||||
|
|
||||||
// Modport для тестбенча (чтобы работать через функции)
|
|
||||||
modport tb (
|
modport tb (
|
||||||
clocking drv_cb,
|
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
|
endinterface
|
||||||
|
|
||||||
`endif // AXIS_INTERFACE_SVH
|
`endif // AXIS_INTERFACE_SVH`
|
||||||
@ -149,99 +149,37 @@ module reflectometer_tb;
|
|||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
// Таски для тестирования
|
// Таски для тестирования
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
task automatic dut_soft_reset(virtual axis_if#(8).tb vif);
|
||||||
// AXI-S таски
|
logic [7:0] tx_packet[];
|
||||||
task automatic axis_send_packet(
|
tx_packet = '{8'h0f};
|
||||||
virtual axis_if.tb vif,
|
vif.master_send(tx_packet);
|
||||||
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
|
endtask
|
||||||
|
|
||||||
task automatic dut_soft_reset();
|
task automatic dut_start(virtual axis_if#(8).tb vif);
|
||||||
logic [7:0] cmd[] = '{8'b00001111};
|
logic [7:0] tx_packet[];
|
||||||
axis_send_packet(
|
tx_packet = '{8'hf0};
|
||||||
.vif(axis_control_if.tb),
|
vif.master_send(tx_packet);
|
||||||
.payload(cmd)
|
|
||||||
);
|
|
||||||
endtask
|
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(
|
task automatic dut_send_system_config(
|
||||||
|
virtual axis_if#(8).tb vif,
|
||||||
input logic [31:0] pulse_width,
|
input logic [31:0] pulse_width,
|
||||||
input logic [31:0] pulse_period,
|
input logic [31:0] pulse_period,
|
||||||
input logic [15:0] pulse_num,
|
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
|
input logic [31:0] pulse_period_adc
|
||||||
);
|
);
|
||||||
// Выделяем 17 байт: 1 байт команды + 16 байт регистров
|
// Создаем временный фиксированный массив и упаковываем всё одной строкой
|
||||||
logic [7:0] full_packet[17];
|
logic [7:0] tx_packet[];
|
||||||
|
|
||||||
// 1. Сначала пишем команду в нулевой байт пакета
|
tx_packet = '{
|
||||||
full_packet[0] = 8'b10001000; // Твоя команда set_data
|
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]
|
||||||
|
};
|
||||||
|
|
||||||
// 2. Упаковываем регистр pulse_width [31:0] (байты 1..4)
|
vif.master_send(tx_packet);
|
||||||
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
|
endtask
|
||||||
|
|
||||||
// Таски сбора и обработки статистики
|
// Таски сбора и обработки статистики
|
||||||
@ -251,6 +189,9 @@ module reflectometer_tb;
|
|||||||
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
|
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
initial begin
|
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");
|
$display("[TB] Tests start");
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
@ -259,16 +200,20 @@ module reflectometer_tb;
|
|||||||
rst_n = 1;
|
rst_n = 1;
|
||||||
wait(mmcm_locked === 1'b1);
|
wait(mmcm_locked === 1'b1);
|
||||||
#10;
|
#10;
|
||||||
|
$display("[TB] MMCM locked");
|
||||||
|
|
||||||
dut_soft_reset();
|
dut_soft_reset(control_vif);
|
||||||
// dut_send_system_config(
|
#100;
|
||||||
// .pulse_width(32'd350),
|
dut_send_system_config(
|
||||||
// .pulse_period(32'd1250),
|
.vif(control_vif),
|
||||||
// .pulse_num(16'd10),
|
.pulse_width(32'd350),
|
||||||
// .pulse_height(14'd14000), // 0V
|
.pulse_period(32'd1250),
|
||||||
// .pulse_period_adc(32'd650)
|
.pulse_num(16'd10),
|
||||||
// );
|
.pulse_height(14'd14000), // 0V
|
||||||
// dut_start();
|
.pulse_period_adc(32'd650)
|
||||||
|
);
|
||||||
|
#100;
|
||||||
|
dut_start(control_vif);
|
||||||
|
|
||||||
$display("[TB] ALL PASSED");
|
$display("[TB] ALL PASSED");
|
||||||
$finish;
|
$finish;
|
||||||
|
|||||||
Reference in New Issue
Block a user