资讯详情

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

📅 2026/10/27 9:24:55 | 华诺云谱 👁 阅读
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 队列。如果写入请求需要确认处理单元将等待确认否则它将继续执行后续操作。这有助于管理内存写入请求的确认机制。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑