NVDLA系列之C-model:cvif<99>

发布时间:2026/10/27 9:24:21

NVDLA系列之C-model:cvif<99> NV_NVDLA_cvif.cppWriteRequest_sdp2cvifvoidNV_NVDLA_cvif::WriteRequest_sdp2cvif(){uint64_tbase_addr;uint64_tfirst_base_addr;uint64_tlast_base_addr;uint64_tcur_address;uint32_tsize_in_byte;uint32_ttotal_axi_size;uint64_tpayload_addr;uint32_tpayload_size;uint8_t*axi_byte_enable_ptr;uint32_tbyte_iter;uint32_tatom_iter;uint32_tatom_num;boolis_base_64byte_align;boolis_rear_64byte_align;boolis_readfalse;uint8_t*axi_atom_ptr;nvdla_dbb_extension*nvdla_dbb_extNULL;client_cvif_wr_req_t*sdp_wr_req;dla_b_transport_payload*bt_payload;这段代码是一个 C 函数它位于名为 “NV_NVDLA_cvif” 的类中函数名为 “WriteRequest_sdp2cvif”。这个函数的主要功能是执行一些内存写入请求的处理操作。以下是代码中定义的变量和操作的简要总结定义了多个变量包括用于地址计算的base_addr、first_base_addr和last_base_addr以及用于循环迭代的cur_address用于数据大小的size_in_byte和total_axi_size以及其他用于字节操作的变量。定义了布尔类型的变量如is_base_64byte_align和is_rear_64byte_align用于检查地址是否按照64字节对齐。定义了一个布尔类型的变量is_read用于指示是否执行读取操作。定义了一个指针变量axi_atom_ptr它是一个指向字节的指针用于操作存储器中的数据。定义了一个指针nvdla_dbb_ext它指向 “nvdla_dbb_extension” 类型的对象用于处理一些数据扩展的操作。定义了两个指针变量sdp_wr_req和bt_payload它们分别指向 “client_cvif_wr_req_t” 和 “dla_b_transport_payload” 类型的对象用于处理写入请求和数据传输的操作。这段代码的主要目的是处理内存写入请求可能涉及地址计算、数据大小检查、数据传输等操作。while(true){// Read one write commandsdp_wr_reqsdp2cvif_wr_cmd_fifo_-read();payload_addrsdp_wr_req-addr;// Its aligend to 32B, not 64Bpayload_sizesdp_wr_req-size;cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, got one write command from sdp2cvif_wr_cmd_fifo_\x0A));cslDebug((50, payload_addr: 0x%lx\x0A,payload_addr));cslDebug((50, payload_size: 0x%x\x0A,payload_size));is_base_64byte_alignpayload_addr%AXI_TRANSACTION_ATOM_SIZE0;first_base_addris_base_64byte_align?payload_addr:payload_addr-DMA_TRANSACTION_ATOM_SIZE;// Align to 64Bis_rear_64byte_align(payload_addrpayload_size)%AXI_TRANSACTION_ATOM_SIZE0;// According to DBB_PV standard, data_length shall be equal or greater than DBB_PV m_size * m_length no matter the transactions is aglined or nottotal_axi_sizepayload_size(is_base_64byte_align?0:DMA_TRANSACTION_ATOM_SIZE)(is_rear_64byte_align?0:DMA_TRANSACTION_ATOM_SIZE);last_base_addrfirst_base_addrtotal_axi_size-AXI_TRANSACTION_ATOM_SIZE;这段代码是一个循环它用于处理内存写入请求。以下是代码的简要解释while(true)表示一个无限循环即这段代码将一直运行直到遇到显式的退出条件才会停止。sdp_wr_req sdp2cvif_wr_cmd_fifo_-read();从名为sdp2cvif_wr_cmd_fifo_的FIFO队列中读取一个写入命令并将其存储在sdp_wr_req变量中。payload_addr存储了从写入命令中获取的地址该地址可能不是64字节对齐的。payload_size存储了从写入命令中获取的数据大小。is_base_64byte_align和is_rear_64byte_align用于检查地址是否按照64字节对齐。is_base_64byte_align检查payload_addr是否是64字节对齐is_rear_64byte_align检查payload_addr payload_size是否是64字节对齐。first_base_addr和last_base_addr用于计算一系列地址以确保数据访问在64字节的边界上对齐。first_base_addr被设置为64字节对齐的地址而last_base_addr被设置为在first_base_addr的基础上加上总的AXI事务大小total_axi_size减去一个AXI事务的大小AXI_TRANSACTION_ATOM_SIZE。总体而言这段代码的目的是处理来自sdp2cvif_wr_cmd_fifo_队列的内存写入命令它计算了与地址对齐和数据大小相关的一些参数以便后续的内存访问和数据传输操作能够按照正确的边界和大小进行。这段代码在数据传输和内存管理的上下文中使用。// if ( total_axi_size AXI_TRANSACTION_ATOM_SIZE ) {// // The first and last transaction is actually the same// last_base_addr first_base_addr;// } else {// last_base_addr (first_base_addr total_axi_size) - (first_base_addr total_axi_size)%AXI_TRANSACTION_ATOM_SIZE;// }// if (total_axi_size first_base_addr%CVIF_MAX_MEM_TRANSACTION_SIZE CVIF_MAX_MEM_TRANSACTION_SIZE) {// // Base and last are in the same AXI transaction// } else {// // Base and last are in different AXI transaction// last_base_addr // }// } else if ((first_base_addr total_axi_size)%CVIF_MAX_MEM_TRANSACTION_SIZE ! 0) {// if (total_axi_size (first_base_addr total_axi_size)%CVIF_MAX_MEM_TRANSACTION_SIZE) {// last_base_addr first_base_addr total_axi_size - (first_base_addr total_axi_size)%CVIF_MAX_MEM_TRANSACTION_SIZE;// } else {// last_base_addr first_base_addr;// }// } else {// if (total_axi_size CVIF_MAX_MEM_TRANSACTION_SIZE) {// last_base_addr first_base_addr total_axi_size - CVIF_MAX_MEM_TRANSACTION_SIZE;// } else {// last_base_addr first_base_addr;// }// }cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif:\x0A));cslDebug((50, first_base_addr: 0x%lx\x0A,first_base_addr));cslDebug((50, last_base_addr: 0x%lx\x0A,last_base_addr));cslDebug((50, total_axi_size: 0x%x\x0A,total_axi_size));这段注释掉的代码部分似乎是在计算last_base_addr的具体值以确保内存访问和数据传输按照正确的AXI事务边界进行的。由于代码被注释掉了所以它实际上并没有执行。下面是对该段代码的解释这段代码在处理last_base_addr的计算时考虑了不同的情况以确保内存访问的正确性。last_base_addr是用于指示最后一个AXI事务的起始地址的。首先代码检查了total_axi_size是否小于等于AXI_TRANSACTION_ATOM_SIZE如果是则将last_base_addr设置为first_base_addr因为只有一个AXI事务。然后代码检查了是否first_base_addr和last_base_addr在相同的AXI事务中。如果在同一AXI事务中它可能需要进行一些特殊处理但是由于代码被注释掉了所以无法确定具体操作。最后代码通过计算余数来检查first_base_addr total_axi_size是否跨越了CVIF_MAX_MEM_TRANSACTION_SIZE的边界并相应地计算last_base_addr。总之这段代码的目的是确保内存访问按照AXI事务边界对齐和分割以适应底层硬件或协议的要求。// cur_address payload_addr;cur_addressis_base_64byte_align?payload_addr:first_base_addr;// Align to 64B//Split dma request to axi requests// while(cur_address payload_addr payload_size) {}while(cur_addresslast_base_addr){base_addrcur_address;size_in_byteAXI_TRANSACTION_ATOM_SIZE;// Check whether next ATOM belongs to current AXI transaction// while (((cur_address DMA_TRANSACTION_ATOM_SIZE) (payload_addr payload_size)) ((cur_address DMA_TRANSACTION_ATOM_SIZE) % CVIF_MAX_MEM_TRANSACTION_SIZE ! 0)) {// size_in_byte DMA_TRANSACTION_ATOM_SIZE;// cur_address DMA_TRANSACTION_ATOM_SIZE;// }while(((cur_addressAXI_TRANSACTION_ATOM_SIZE)(first_base_addrtotal_axi_size))((cur_addressAXI_TRANSACTION_ATOM_SIZE)%CVIF_MAX_MEM_TRANSACTION_SIZE!0)){size_in_byteAXI_TRANSACTION_ATOM_SIZE;cur_addressAXI_TRANSACTION_ATOM_SIZE;}// start address of next axi transactioncur_addressAXI_TRANSACTION_ATOM_SIZE;atom_numsize_in_byte/DMA_TRANSACTION_ATOM_SIZE;bt_payloadnewdla_b_transport_payload(size_in_byte,dla_b_transport_payload::DLA_B_TRANSPORT_PAYLOAD_TYPE_MC);axi_byte_enable_ptrbt_payload-gp.get_byte_enable_ptr();cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, base_addr0x%lx size_in_byte0x%x atom_num0x%x\x0A,base_addr,size_in_byte,atom_num));for(byte_iter0;byte_itersize_in_byte;byte_iter){if((base_addrfirst_base_addr)(falseis_base_64byte_align)(byte_iterDMA_TRANSACTION_ATOM_SIZE)){// Diable 1st DMA atom of the unaligned first_base_addraxi_byte_enable_ptr[byte_iter]TLM_BYTE_DISABLED;// All bytes should be enabled}elseif(((base_addrsize_in_byte)(last_base_addrAXI_TRANSACTION_ATOM_SIZE))(falseis_rear_64byte_align)(byte_itersize_in_byte-DMA_TRANSACTION_ATOM_SIZE)){// Diable 2nd DMA atom of the unaligned last_base_addraxi_byte_enable_ptr[byte_iter]TLM_BYTE_DISABLED;// All bytes should be enabled}else{axi_byte_enable_ptr[byte_iter]TLM_BYTE_ENABLED;// All bytes should be enabled}}cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, TLM_BYTE_ENABLE is done\x0A));这段代码的主要目的是将一个大的内存写入请求分割成多个小的 AXI 事务请求以便按照 AXI 事务边界进行传输并为每个小事务创建相应的 AXI 事务数据。以下是代码的主要步骤和功能cur_address初始化为payload_addr或first_base_addr具体取决于是否需要按照64字节对齐。这是为了确保起始地址在AXI事务边界上对齐。while(cur_address last_base_addr)循环迭代这个循环的目的是将大的内存写入请求分割成多个小的 AXI 事务请求。每次迭代base_addr被设置为cur_addresssize_in_byte被初始化为AXI_TRANSACTION_ATOM_SIZE表示一个AXI事务的大小。在内层循环中代码检查是否下一个 ATOM 是否仍然属于当前 AXI 事务以确保不会跨越AXI事务边界。如果是size_in_byte会增加一个 AXI 事务的大小cur_address也会相应地增加。在每次循环迭代中会创建一个dla_b_transport_payload对象bt_payload用于存储小的AXI事务数据。这个对象的大小等于size_in_byte。对于每个字节代码会根据地址对齐情况设置axi_byte_enable_ptr以确定哪些字节需要被禁用TLM_BYTE_DISABLED或启用TLM_BYTE_ENABLED。这是为了确保数据按照正确的方式传输特别是在不对齐的边界上。最后代码输出一些调试信息包括base_addr、size_in_byte和atom_num等信息。总之这段代码的功能是将大的内存写入请求分割成多个小的 AXI 事务请求并为每个小事务创建相应的 AXI 事务数据同时考虑了地址对齐和字节启用/禁用的情况以确保数据传输的正确性。这通常用于处理底层硬件或协议要求的内存访问和数据传输。for(atom_iter0;atom_iteratom_num;atom_iter){if((base_addrfirst_base_addr)(falseis_base_64byte_align)(0atom_iter)){// Disable 1st DMA atom of the unaligned first_base_addr// Use unaligned address as required by DBB_PVmemset(bt_payload-data[atom_iter*DMA_TRANSACTION_ATOM_SIZE],0,DMA_TRANSACTION_ATOM_SIZE);}elseif(((base_addrsize_in_byte)(last_base_addrAXI_TRANSACTION_ATOM_SIZE))(falseis_rear_64byte_align)((atom_iter1)atom_num)){// Disable 2nd DMA atom of the unaligned last_base_addrmemset(bt_payload-data[atom_iter*DMA_TRANSACTION_ATOM_SIZE],0,DMA_TRANSACTION_ATOM_SIZE);}else{cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, before read an atom from sdp2cvif_wr_data_fifo_, base_addr 0x%lx, atom_iter0x%x\x0A,base_addr,atom_iter));axi_atom_ptrsdp2cvif_wr_data_fifo_-read();for(inti0;iDMA_TRANSACTION_ATOM_SIZE;i){cslDebug((50,%02x ,axi_atom_ptr[i]));}cslDebug((50,\x0A));cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, after read an atom from sdp2cvif_wr_data_fifo_\x0A));memcpy(bt_payload-data[atom_iter*DMA_TRANSACTION_ATOM_SIZE],axi_atom_ptr,DMA_TRANSACTION_ATOM_SIZE);delete[]axi_atom_ptr;}}这段代码处理小的 AXI 事务请求的数据部分。它包括以下关键步骤for循环迭代atom_iter该迭代器控制了在一个小的 AXI 事务中处理的 DMA 原子数据的数量。在每次循环迭代中代码检查以下情况如果base_addr不是64字节对齐且atom_iter为0表示在当前 AXI 事务中的第一个 DMA 原子数据则会执行以下操作将bt_payload-data中与当前 DMA 原子数据对应的内存区域用0填充memset。这是为了在不对齐的情况下对第一个 DMA 原子数据进行禁用。如果base_addr size_in_byte不是64字节对齐且atom_iter为当前 AXI 事务中的最后一个 DMA 原子数据则会执行以下操作同样将bt_payload-data中与当前 DMA 原子数据对应的内存区域用0填充以禁用最后一个不对齐的 DMA 原子数据。否则代码将从sdp2cvif_wr_data_fifo_队列中读取一个 AXI 原子数据然后将其拷贝memcpy到bt_payload-data中以准备发送到 AXI 总线。读取和拷贝操作将小的 AXI 事务数据放入bt_payload-data中。无论哪种情况如果成功读取和处理了一个 DMA 原子数据代码都会使用delete[]来释放分配的内存以防止内存泄漏。总之这段代码的主要功能是处理小的 AXI 事务请求的数据部分它根据地址对齐情况禁用了不对齐的 DMA 原子数据并将合适的 DMA 原子数据从sdp2cvif_wr_data_fifo_队列中读取和拷贝到bt_payload-data中以准备发送到 AXI 总线。这有助于确保数据传输按照 AXI 事务边界正确进行。if((base_addrfirst_base_addr)(falseis_base_64byte_align)){base_addrDMA_TRANSACTION_ATOM_SIZE;}cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, base_address0x%lx size in byte0x%x\x0A,base_addr,size_in_byte));// Prepare write payloadbt_payload-configure_gp(base_addr,size_in_byte,is_read);bt_payload-gp.get_extension(nvdla_dbb_ext);cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, sending write command to sdp_wr_req_fifo_.\x0A));cslDebug((50, addr: 0x%016lx\x0A,base_addr));cslDebug((50, size: %d\x0A,size_in_byte));nvdla_dbb_ext-set_id(SDP_AXI_ID);nvdla_dbb_ext-set_size(64);nvdla_dbb_ext-set_length(size_in_byte/AXI_TRANSACTION_ATOM_SIZE);// if (base_addr%AXI_TRANSACTION_ATOM_SIZE ! 0) //Set length(in unit of 64B) to be same as RTL// nvdla_dbb_ext-set_length(((size_in_byte - DMA_TRANSACTION_ATOM_SIZE) DMA_TRANSACTION_ATOM_SIZE)/AXI_TRANSACTION_ATOM_SIZE);// else // base_addr is aligned to 64Bytes// nvdla_dbb_ext-set_length((size_in_byte DMA_TRANSACTION_ATOM_SIZE)/AXI_TRANSACTION_ATOM_SIZE-1);// write payload to arbiter fifosdp_wr_req_fifo_-write(bt_payload);这段代码的主要功能是准备和发送一个写入请求。以下是代码的主要步骤和功能首先代码检查是否base_addr不是64字节对齐且不是当前 AXI 事务中的第一个 DMA 原子数据。如果是它会将base_addr增加DMA_TRANSACTION_ATOM_SIZE以确保地址对齐。代码输出一些调试信息包括base_addr和size_in_byte等信息。接下来代码准备写入请求的 payload。它使用bt_payload-configure_gp方法来配置 payload 的一些参数包括base_addr写入的起始地址、size_in_byte写入的数据大小和is_read指示是否执行读取操作。通过bt_payload-gp.get_extension(nvdla_dbb_ext)获取一个扩展对象nvdla_dbb_ext该对象用于设置一些 AXI 相关的参数。代码输出一些额外的调试信息包括地址addr、大小size、IDSDP_AXI_ID和长度length等。最后代码将准备好的 payload 写入名为sdp_wr_req_fifo_的 FIFO 队列以便将写入请求发送到相应的处理单元或总线。总之这段代码的功能是准备和发送一个内存写入请求它首先检查地址对齐情况然后配置 payload 的参数设置 AXI 相关的扩展信息并将写入请求写入 FIFO 队列以进行后续处理。这有助于确保写入请求按照正确的格式和参数发送到相应的目标。// When the last split req is sent to ext, write true to sdp_wr_required_ack_fifo_ when ack is required.if(cur_address(payload_addrpayload_size)){if(sdp_wr_req-require_ack!0){cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, require ack.\x0A));sdp_wr_required_ack_fifo_-write(true);}else{cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, does not require ack.\x0A));sdp_wr_required_ack_fifo_-write(false);}}else{cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, does not require ack.\x0A));sdp_wr_required_ack_fifo_-write(false);}}deletesdp_wr_req;cslDebug((50,NV_NVDLA_cvif::WriteRequest_sdp2cvif, write command processing done\x0A));}}这段代码的主要功能是处理内存写入请求的最后部分并确定是否需要等待确认acknowledgment。代码首先检查cur_address是否大于或等于payload_addr payload_size这表示所有小的 AXI 事务请求都已经发送完毕。如果是这种情况代码继续执行下面的步骤否则跳过这一部分。在内部条件检查中代码判断了sdp_wr_req-require_ack是否为非零值这表示写入请求需要等待确认。如果需要等待确认代码将true写入名为sdp_wr_required_ack_fifo_的 FIFO 队列中以便后续处理单元知道需要发送确认。如果写入请求不需要等待确认代码将false写入sdp_wr_required_ack_fifo_。无论是否需要等待确认最后都会释放sdp_wr_req指针指向的内存对象以避免内存泄漏。最后代码输出一条调试信息表示写入命令的处理已完成。总结来说这段代码负责确定写入请求是否需要等待确认并相应地将确认信息写入 FIFO 队列。如果写入请求需要确认处理单元将等待确认否则它将继续执行后续操作。这有助于管理内存写入请求的确认机制。
延伸阅读

更多相关文章

2026/10/27 9:19:19

Linux显示驱动调试工具全解析:从硬件信号到内核链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 12:16:01

Android文本转语音(TTS)开发实战:TXT朗读器实现

1. 项目概述:TXT文本朗读器的核心功能与价值 这个基于Android Studio开发的TXT文本朗读器,本质上是一个能将纯文本文件转换为语音输出的实用工具。它解决了移动端用户无法方便地"听"文本内容的痛点——想象一下你在通勤路上想"读"一…

2026/10/27 12:16:01

r22 platform-tools:adb/fastboot老设备连接避坑

简介:platform-tools_r22-windows.zip 是面向 Android 应用开发与设备调试人员的 Windows 平台工具集合,定位为连接电脑与真机、完成固件刷写及性能分析的命令行工具箱。包内共 21 个文件,以 6 个 exe 可执行程序、2 个 dll 动态链接库和 2 个…

2026/10/27 12:16:01

Python智能家居语音控制:从麦克风到MQTT的完整链路

简介:面向学习嵌入式开发与语音交互原型的开发者、学生,这份智能家居语音控制系统提供一套可运行的树莓派 Python 项目参考。系统以“依米”为唤醒词,串联语音指令、图灵机器人、和风天气与百度人工智能平台,覆盖智能门禁、智能聊…

2026/10/27 12:16:01

ASN.1到C编解码工程:asn1c编译链路、编码规则与避坑

简介:asn1c v0.9.29 是面向通信协议、嵌入式与 C 语言开发者的 ASN.1 编译器工具包,可将 ASN.1 类型定义转换为可直接编译的 C 头文件和源文件,并生成构造函数、析构函数及 BER、DER、PER 等编码解码接口,适合处理网络协议栈、设备…

2026/10/27 12:11:00

Docker报错no command specified:ENTRYPOINT与CMD排查修复指南

docker run 敲下去,终端只回一行docker: Error response from daemon: no command specified.,很多人第一反应是镜像拉坏了、网络抽风了、还是 daemon 又闹脾气。我头一回碰到也这样,pull 了两遍、重启服务、换机器重试,折腾四十多…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑