searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

FPGA模块调度请求数据的几种方法

2025-09-26 10:17:40
1
0

在FPGA模块开发过程中,有时会出现多个模块向同一个模块发起申请请求,并接收返回结果的情况。例如,模块MEM内部为片上存储器,保存有特定的配置数据。若只有一个模块A进行读取查询,则模块A发出查询请求和查询内容给MEM,MEM接收到读请求和读地址之后,进行查询并把结果返回给模块A即可。若有多个模块向MEM进行读取请求,则必须要进行数据调度,防止将结果返回给错误的模块。

对于FPGA内部请求调度,本文介绍以下三种方法,可以进行使用。

1、使用总线调度器

若发起请求的数据格式遵循总线协议,如AXI4-stream,avalon-stream等格式,则可以直接使用总线调度器进行调度。当前主流标准总线协议(如 Avalon、AMBA 等),大多配套有开源调度器代码,在GitHub、Gitee等开源平台可便捷获取。这些代码经社区长期验证与迭代,可靠性较高,无需开发者从零开发调度逻辑,直接调用即可实现总线请求的高效调度,大幅降低开发难度、缩短项目周期,同时减少自研调度器可能出现的漏洞风险,为总线相关系统开发提供了稳定支撑。

例如,对于axi4-stream格式的数据,可以找到开源的axis demux模块,实现将任意路数的axis多转一,并保持每一路valid和ready的正确性。

/*
     * AXI input
     */
    input  wire [DATA_WIDTH-1:0]            s_axis_tdata,
    input  wire [KEEP_WIDTH-1:0]            s_axis_tkeep,
    input  wire                             s_axis_tvalid,
    output wire                             s_axis_tready,
    input  wire                             s_axis_tlast,
    input  wire [ID_WIDTH-1:0]              s_axis_tid,
    input  wire [S_DEST_WIDTH-1:0]          s_axis_tdest,
    input  wire [USER_WIDTH-1:0]            s_axis_tuser,

    /*
     * AXI outputs
     */
    output wire [M_COUNT*DATA_WIDTH-1:0]    m_axis_tdata,
    output wire [M_COUNT*KEEP_WIDTH-1:0]    m_axis_tkeep,
    output wire [M_COUNT-1:0]               m_axis_tvalid,
    input  wire [M_COUNT-1:0]               m_axis_tready,
    output wire [M_COUNT-1:0]               m_axis_tlast,
    output wire [M_COUNT*ID_WIDTH-1:0]      m_axis_tid,
    output wire [M_COUNT*M_DEST_WIDTH-1:0]  m_axis_tdest,
    output wire [M_COUNT*USER_WIDTH-1:0]    m_axis_tuser,

如果本身发起请求的接口是native接口,不遵守总线协议,也可以自行将接口封装成AXI4-stream等格式,再调用开源模块。这样开发者只需要关注将单个模块的发起请求、请求数据、返回结果封装到axis总线的valid和data信号中,而不需要再考虑多个模块的请求调度。

2.自行采用FIFO进行调度

例如,对于2个模块的查询请求和查询结果,可以采用FIFO将多路输入的缓存暂存住,然后状态机轮询两个FIFO将数据调出,并额外采用一个顺序FIFO进行记录。当查询结果返回后,根据顺序FIFO中记录的顺序返回给对应模块。

使用FIFO调度.drawio.png

图中,紫色部分的线表明两个模块的req和req info信号,分别送入FIFO中,并要在调度出去的时候记录被调用者的ID在order fifo。使用状态机轮询读取两个FIFO并送出。绿色部分的线表明rsp返回,返回逻辑读取order fifo读到当前的返回属于哪一个模块并对应返回。

自行采用FIFO进行调度,实现简单,可以任意增加减少路数,并完全避免对外部代码的使用。但是使用多个FIFO会增加资源占用率,提高模块间数据传输的延迟。

3、采用开源的rr调度模块

目前也存在直接只提供调度功能的rr调度开源模块,例如采用tm_rr_sched模块,调用模块时提供rr client的数量,给出上一个被调度的client的id和当前所有client的请求情况,则模块会给出下一个要调度的client id。

接口 描述
last[N-1:0] 输入,上一个被调度的client id拉高
request[N-1:0] 输入,当前每个client的请求状态
next[N-1:0] 输出,下一个要被调度的client id拉高

使用该开源模块可以方便简捷地得到下一个需要调度的模块ID,但具体将该模块的请求和数据送出去,还需要开发者自己实现。

0条评论
0 / 1000
cuixinyu
8文章数
0粉丝数
cuixinyu
8 文章 | 0 粉丝
原创

FPGA模块调度请求数据的几种方法

2025-09-26 10:17:40
1
0

在FPGA模块开发过程中,有时会出现多个模块向同一个模块发起申请请求,并接收返回结果的情况。例如,模块MEM内部为片上存储器,保存有特定的配置数据。若只有一个模块A进行读取查询,则模块A发出查询请求和查询内容给MEM,MEM接收到读请求和读地址之后,进行查询并把结果返回给模块A即可。若有多个模块向MEM进行读取请求,则必须要进行数据调度,防止将结果返回给错误的模块。

对于FPGA内部请求调度,本文介绍以下三种方法,可以进行使用。

1、使用总线调度器

若发起请求的数据格式遵循总线协议,如AXI4-stream,avalon-stream等格式,则可以直接使用总线调度器进行调度。当前主流标准总线协议(如 Avalon、AMBA 等),大多配套有开源调度器代码,在GitHub、Gitee等开源平台可便捷获取。这些代码经社区长期验证与迭代,可靠性较高,无需开发者从零开发调度逻辑,直接调用即可实现总线请求的高效调度,大幅降低开发难度、缩短项目周期,同时减少自研调度器可能出现的漏洞风险,为总线相关系统开发提供了稳定支撑。

例如,对于axi4-stream格式的数据,可以找到开源的axis demux模块,实现将任意路数的axis多转一,并保持每一路valid和ready的正确性。

/*
     * AXI input
     */
    input  wire [DATA_WIDTH-1:0]            s_axis_tdata,
    input  wire [KEEP_WIDTH-1:0]            s_axis_tkeep,
    input  wire                             s_axis_tvalid,
    output wire                             s_axis_tready,
    input  wire                             s_axis_tlast,
    input  wire [ID_WIDTH-1:0]              s_axis_tid,
    input  wire [S_DEST_WIDTH-1:0]          s_axis_tdest,
    input  wire [USER_WIDTH-1:0]            s_axis_tuser,

    /*
     * AXI outputs
     */
    output wire [M_COUNT*DATA_WIDTH-1:0]    m_axis_tdata,
    output wire [M_COUNT*KEEP_WIDTH-1:0]    m_axis_tkeep,
    output wire [M_COUNT-1:0]               m_axis_tvalid,
    input  wire [M_COUNT-1:0]               m_axis_tready,
    output wire [M_COUNT-1:0]               m_axis_tlast,
    output wire [M_COUNT*ID_WIDTH-1:0]      m_axis_tid,
    output wire [M_COUNT*M_DEST_WIDTH-1:0]  m_axis_tdest,
    output wire [M_COUNT*USER_WIDTH-1:0]    m_axis_tuser,

如果本身发起请求的接口是native接口,不遵守总线协议,也可以自行将接口封装成AXI4-stream等格式,再调用开源模块。这样开发者只需要关注将单个模块的发起请求、请求数据、返回结果封装到axis总线的valid和data信号中,而不需要再考虑多个模块的请求调度。

2.自行采用FIFO进行调度

例如,对于2个模块的查询请求和查询结果,可以采用FIFO将多路输入的缓存暂存住,然后状态机轮询两个FIFO将数据调出,并额外采用一个顺序FIFO进行记录。当查询结果返回后,根据顺序FIFO中记录的顺序返回给对应模块。

使用FIFO调度.drawio.png

图中,紫色部分的线表明两个模块的req和req info信号,分别送入FIFO中,并要在调度出去的时候记录被调用者的ID在order fifo。使用状态机轮询读取两个FIFO并送出。绿色部分的线表明rsp返回,返回逻辑读取order fifo读到当前的返回属于哪一个模块并对应返回。

自行采用FIFO进行调度,实现简单,可以任意增加减少路数,并完全避免对外部代码的使用。但是使用多个FIFO会增加资源占用率,提高模块间数据传输的延迟。

3、采用开源的rr调度模块

目前也存在直接只提供调度功能的rr调度开源模块,例如采用tm_rr_sched模块,调用模块时提供rr client的数量,给出上一个被调度的client的id和当前所有client的请求情况,则模块会给出下一个要调度的client id。

接口 描述
last[N-1:0] 输入,上一个被调度的client id拉高
request[N-1:0] 输入,当前每个client的请求状态
next[N-1:0] 输出,下一个要被调度的client id拉高

使用该开源模块可以方便简捷地得到下一个需要调度的模块ID,但具体将该模块的请求和数据送出去,还需要开发者自己实现。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0