You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为特定modport指定专属任务?解决AXI-Stream仿真冲突

问题解决方案:为AXI-Stream Modport绑定专属任务

核心问题分析

当前接口任务全局可见,即使未误调用,也存在潜在的多驱动风险;同时任务与modport的功能对应关系模糊:

  • send是发送任务,需驱动TVALID/TDATA等输出信号,应属于master modport
  • get_packet是接收任务,需驱动TREADY输出信号,应属于slave modport
    原错误Variable '/test_tb/dut_in/TREADY' written by continuous and procedural assignments,本质是DUT对AXIS_S.TREADY的连续赋值,与接口任务中对该信号的过程赋值(若误调用)产生冲突。

解决方案:Modport绑定专属任务

通过在modport中声明任务,从语法层面限制任务可见性,仅允许对应modport类型的接口变量访问专属任务。

1. 修改AXIS接口,绑定任务到对应Modport

`timescale 1ns/1ns

import tb_axis_pkg::*;

interface AXIS #(
    parameter integer           TDATA_WIDTH = 32,
    parameter integer           TUSER_WIDTH = 32
) (
    input logic                 CLK
);

    logic                       TVALID;
    logic                       TREADY;
    logic                       TLAST;
    logic [TDATA_WIDTH-1:0]     TDATA;
    logic [TUSER_WIDTH-1:0]     TUSER;

    // Slave Modport:用于接收数据,仅暴露get_packet任务
    modport slave (
        input                   TVALID,
        output                  TREADY,
        input                   TLAST,
        input                   TDATA,
        input                   TUSER,
        task get_packet
    );

    // Master Modport:用于发送数据,仅暴露send任务
    modport master (
        output                  TVALID,
        input                   TREADY,
        output                  TLAST,
        output                  TDATA,
        output                  TUSER,
        task send
    );

    // 接收任务:仅通过slave modport可见
    task automatic get_packet();
        @ (posedge CLK);
        TREADY <= 1'b1;
        // 补充数据读取逻辑(示例)
        while (!TVALID) @(posedge CLK);
        // 读取TDATA/TUSER/TLAST到buffer的逻辑
        @(posedge CLK);
        TREADY <= 1'b0;
    endtask

    // 发送任务:仅通过master modport可见
    task automatic send(const ref data_buffer_c #(TDATA_WIDTH, TUSER_WIDTH) data_buffer);
        
        for (int i = 0; i < data_buffer.size(); ++i) begin
            @ (posedge CLK);
            TVALID <= 1'b1;
            TDATA <= data_buffer.axis_packet[i].tdata;
            TUSER <= data_buffer.axis_packet[i].tuser;
            TLAST <= (i == data_buffer.size() - 1) ? 1'b1 : 1'b0;

            while (TREADY == 1'b0)  @ (posedge CLK);
        end

        @(posedge CLK);
        TVALID <= 1'b0;
    endtask

endinterface

2. 修改测试平台,使用Modport类型接口变量

`timescale 1ns/1ns

import tb_axis_pkg::*;

module test_tb ();

    localparam int      CLK_PERIOD = 5;
    localparam int      WAIT_AFTER_RESET = 10;
    localparam int      TEST_QTY = 1;
    localparam int      TDATA_WIDTH = 16;
    localparam int      TUSER_WIDTH = 16;

    logic clk = 1'b0;
    logic reset = 1'b1;
    event new_iteration;

    // 声明基础接口实例
    AXIS #(
        .TDATA_WIDTH (TDATA_WIDTH),
        .TUSER_WIDTH (TUSER_WIDTH)
    )                       dut_in_if (clk);

    AXIS #(
        .TDATA_WIDTH (TDATA_WIDTH),
        .TUSER_WIDTH (TUSER_WIDTH)
    )                       dut_out_if (clk);
    
    // 用Modport类型声明接口变量,仅暴露对应任务
    AXIS.master             dut_in = dut_in_if;  // 仅能调用send任务
    AXIS.slave              dut_out = dut_out_if; // 仅能调用get_packet任务
    
    test_module DUT (
        .clk    (clk),
        .reset  (reset),
        .AXIS_S (dut_in_if),
        .AXIS_M (dut_out_if)
    );

    // 时钟生成
    initial begin
        forever begin
            #(CLK_PERIOD);
            clk <= ~clk;
        end
    end

    // 复位逻辑
    initial begin
        reset = 1'b1;
        #(17);
        reset = 1'b0;
        repeat (WAIT_AFTER_RESET) @ (posedge clk);
        repeat (TEST_QTY) begin
            -> new_iteration;
            @ (posedge clk);
        end
    end

    // 发送数据:仅能调用send任务
    initial begin
        data_buffer_c #(TDATA_WIDTH, TUSER_WIDTH)  data_buffer;
        forever begin
            wait (new_iteration.triggered);
            data_buffer = new();
            for (int i = 0; i < 10; ++i) begin
                data_buffer.push_back(i, 0);
            end
            dut_in.send(data_buffer);
        end
    end

    // 接收数据:仅能调用get_packet任务
    initial begin
        forever begin
            wait (new_iteration.triggered);
            dut_out.get_packet();
            @ (posedge clk);
        end
    end

endmodule

效果说明

  • 语法层面限制任务可见性:dut_in(master类型)无法访问get_packet,dut_out(slave类型)无法访问send,彻底避免误调用导致的多驱动冲突。
  • 任务与modport功能对应清晰:master负责发送,slave负责接收,符合AXI-Stream接口规范。

内容的提问来源于stack exchange,提问作者Sergey Voloshchuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:04:53