对于NVDLA,输入图像和处理结果存储在外部DRAM中,但外部DRAM带宽和延迟通常不足以让NVDLA充分利用其MAC阵列。因此,NVDLA给片内SRAM配置了第二个存储器接口。
为了利用片内SRAM,NVDLA需要在外部DRAM和SRAM之间移动数据。Bridge DMA就是为了完全满足这个目的而提出的。有两条独立的路径,一条是将数据从外部DRAM复制到内部SRAM,另一条是将数据从内部SRAM复制到外部DRAM。两个方向不能同时工作。BDMA还可以将数据从外部DRAM移动到外部DRAM,或者从内部SRAM移动到内部SRAM。
桥接DMA有两个DMA接口,一个连接到外部DRAM,另一个连接到内部SRAM。这两个接口都支持读写请求。两个接口的数据宽度均为512位,最大突发长度为4。
为了在一个cube中移动所有数据,BDMA支持行重复,可以在行之间进行地址跳转来读取多行,反映一个surface。而且,BDMA将支持多一层重复,多行读取可以重复,这反映了多个surface和一个cube。
如图,BDMA有3个接口,CSB总线接口接到的Master是控制CPU,MCIF接口接到的是外部DRAM,SRAMIF接口接到的是内部SRAM。
MCIF
MCIF用于仲裁来自几个内部子模块的请求,并转换为AXI协议以连接到外部DRAM。
MCIF支持读取和写入通道,但一些NVDLA子模块只具有读取要求,所以子模块和MCIF之间的接口支持读取、写入或读写这三种情况。上图中的CDMA0和CDMA1需要只读,其他5个需要读写。
SRAMIF
SRAMIF模块用于将几个内部子模块连接到片内SRAM。它类似于MCIF,但总线延迟会更低。
SRAMIF支持读取和写入通道,但一些NVDLA子模块仅具有读取要求,因此DMA引擎和SRAMIF之间的接口支持读取、写入或读写。CMDA0~1将只需要读通道,而其他5个将同时需要读和写。
Module
我们来看下,BDMA的module代码,可以看到,module的接口分为三类,分别与三个接口对应,除此之外还有一些时钟和中断接口,具体代码后续再做进一步分析。
module NV_NVDLA_bdma (
bdma2cvif_rd_req_ready //|< i
,bdma2cvif_wr_req_ready //|< i
,bdma2mcif_rd_req_ready //|< i
,bdma2mcif_wr_req_ready //|< i
,csb2bdma_req_pd //|< i
,csb2bdma_req_pvld //|< i
,cvif2bdma_rd_rsp_pd //|< i
,cvif2bdma_rd_rsp_valid //|< i
,cvif2bdma_wr_rsp_complete //|< i
,dla_clk_ovr_on_sync //|< i
,global_clk_ovr_on_sync //|< i
,mcif2bdma_rd_rsp_pd //|< i
,mcif2bdma_rd_rsp_valid //|< i
,mcif2bdma_wr_rsp_complete //|< i
,nvdla_core_clk //|< i
,nvdla_core_rstn //|< i
,pwrbus_ram_pd //|< i
,tmc2slcg_disable_clock_gating //|< i
,bdma2csb_resp_pd //|> o
,bdma2csb_resp_valid //|> o
,bdma2cvif_rd_cdt_lat_fifo_pop //|> o
,bdma2cvif_rd_req_pd //|> o
,bdma2cvif_rd_req_valid //|> o
,bdma2cvif_wr_req_pd //|> o
,bdma2cvif_wr_req_valid //|> o
,bdma2glb_done_intr_pd //|> o
,bdma2mcif_rd_cdt_lat_fifo_pop //|> o
,bdma2mcif_rd_req_pd //|> o
,bdma2mcif_rd_req_valid //|> o
,bdma2mcif_wr_req_pd //|> o
,bdma2mcif_wr_req_valid //|> o
,csb2bdma_req_prdy //|> o
,cvif2bdma_rd_rsp_ready //|> o
,mcif2bdma_rd_rsp_ready //|> o
);
//
// NV_NVDLA_bdma_ports.v
//
input nvdla_core_clk; /* bdma2csb_resp, bdma2cvif_rd_cdt, bdma2cvif_rd_req, bdma2cvif_wr_req, bdma2glb_done_intr, bdma2mcif_rd_cdt, bdma2mcif_rd_req, bdma2mcif_wr_req, csb2bdma_req, cvif2bdma_rd_rsp, cvif2bdma_wr_rsp, mcif2bdma_rd_rsp, mcif2bdma_wr_rsp */
input nvdla_core_rstn; /* bdma2csb_resp, bdma2cvif_rd_cdt, bdma2cvif_rd_req, bdma2cvif_wr_req, bdma2glb_done_intr, bdma2mcif_rd_cdt, bdma2mcif_rd_req, bdma2mcif_wr_req, csb2bdma_req, cvif2bdma_rd_rsp, cvif2bdma_wr_rsp, mcif2bdma_rd_rsp, mcif2bdma_wr_rsp */
output bdma2csb_resp_valid; /* data valid */
output [33:0] bdma2csb_resp_pd; /* pkt_id_width=1 pkt_widths=33,33 */
output bdma2cvif_rd_cdt_lat_fifo_pop;
output bdma2cvif_rd_req_valid; /* data valid */
input bdma2cvif_rd_req_ready; /* data return handshake */
output [78:0] bdma2cvif_rd_req_pd;
output bdma2cvif_wr_req_valid; /* data valid */
input bdma2cvif_wr_req_ready; /* data return handshake */
output [514:0] bdma2cvif_wr_req_pd; /* pkt_id_width=1 pkt_widths=78,514 */
output [1:0] bdma2glb_done_intr_pd;
output bdma2mcif_rd_cdt_lat_fifo_pop;
output bdma2mcif_rd_req_valid; /* data valid */
input bdma2mcif_rd_req_ready; /* data return handshake */
output [78:0] bdma2mcif_rd_req_pd;
output bdma2mcif_wr_req_valid; /* data valid */
input bdma2mcif_wr_req_ready; /* data return handshake */
output [514:0] bdma2mcif_wr_req_pd; /* pkt_id_width=1 pkt_widths=78,514 */
input csb2bdma_req_pvld; /* data valid */
output csb2bdma_req_prdy; /* data return handshake */
input [62:0] csb2bdma_req_pd;
input cvif2bdma_rd_rsp_valid; /* data valid */
output cvif2bdma_rd_rsp_ready; /* data return handshake */
input [513:0] cvif2bdma_rd_rsp_pd;
input cvif2bdma_wr_rsp_complete;
input mcif2bdma_rd_rsp_valid; /* data valid */
output mcif2bdma_rd_rsp_ready; /* data return handshake */
input [513:0] mcif2bdma_rd_rsp_pd;
input mcif2bdma_wr_rsp_complete;
input [31:0] pwrbus_ram_pd;