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

NV_NVDLA_cvif.cpp

pdp2cvif_wr_req_b_transport


void NV_NVDLA_cvif::pdp2cvif_wr_req_b_transport(int ID, nvdla_dma_wr_req_t* payload, sc_time& delay) {
    
    
    uint32_t packet_id;
    uint8_t  *dma_payload_data_ptr;
    uint8_t  *data_ptr;
    uint32_t rest_size, incoming_size;
    client_cvif_wr_req_t * pdp_wr_req;

    packet_id = payload->tag;
    if (TAG_CMD == packet_id) {
    
    
        pdp_wr_req_count_ ++;
#pragma CTC SKIP
        if (true == has_pdp_onging_wr_req_) {
    
    
            FAIL(("NV_NVDLA_cvif::pdp2cvif_wr_req_b_transport, got two consective command request, one command request shall be followed by one or more data request."));
        }
#pragma CTC ENDSKIP
	else {
    
    
            has_pdp_onging_wr_req_ = true;
        }

        pdp_wr_req = new client_cvif_wr_req_t;
        pdp_wr_req->addr  = payload->pd.dma_write_cmd.addr;
        pdp_wr_req->size  = (payload->pd.dma_write_cmd.size + 1) * DMA_TRANSACTION_ATOM_SIZE;    //In byte
        pdp_wr_req->require_ack = payload->pd.dma_write_cmd.require_ack;
        cslDebug((50, "before write to pdp2cvif_wr_cmd_fifo_\x0A"));
        pdp2cvif_wr_cmd_fifo_->write(pdp_wr_req);
        cslDebug((50, "after write to pdp2cvif_wr_cmd_fifo_\x0A"));
        pdp_wr_req_got_size_ = 0;
        pdp_wr_req_size_ = pdp_wr_req->size;

    } 

这段代码位于名为 NV_NVDLA_cvif 的类中,主要用于处理从 PDP(Processor Direct Memory Access)模块到 CVIF(CIF)模块的写入请求。以下是代码的主要功能和步骤的解释:

  1. pdp2cvif_wr_req_b_transport 是一个函数,用于处理来自 PDP 模块的写入请求。它接受了三个参数:ID(标识请求的来源),payload(包含请求信息的数据结构),以及 delay(传输延迟,可能会被修改)。

  2. packet_id 用于存储从 payload 中获取的请求标识,这里将其命名为 tag

  3. 如果 packet_id 的值等于 TAG_CMD,表示接收到了一个命令请求。在此情况下,代码执行以下操作:

    • 增加 pdp_wr_req_count_ 计数器,用于跟踪接收到的命令请求数量。

    • 如果 has_pdp_onging_wr_req_ 已经为 true,则发出一个失败消息,因为命令请求应该紧随一个或多个数据请求。否则,将 has_pdp_onging_wr_req_ 设置为 true,表示有一个进行中的命令请求。

    • 创建一个 pdp_wr_req 对象,用于存储写入请求的地址(addr)、大小(size)以及是否需要确认(require_ack)等信息。

    • 计算写入请求的大小:pdp_wr_req->size 被设置为 (payload->pd.dma_write_cmd.size + 1) * DMA_TRANSACTION_ATOM_SIZE 字节。这里的 DMA_TRANSACTION_ATOM_SIZE 是一个事务原子的大小,用于计算请求的实际大小。

    • pdp_wr_req 对象写入名为 pdp2cvif_wr_cmd_fifo_ 的 FIFO 队列中,以便后续处理。

    • pdp_wr_req_got_size_ 重置为0,表示已经开始接收请求的数据部分。

    • 记录 pdp_wr_req_size_,以便后续追踪请求的总大小。

总之,这段代码用于处理从 PDP 模块到 CVIF 模块的写入请求。它首先检查请求的类型(命令或数据),然后根据类型采取不同的操作,包括将命令请求写入 FIFO 队列以进行后续处理。这有助于协调和管理来自不同模块的数据传输请求。

else {
    
    
        dma_payload_data_ptr = reinterpret_cast <uint8_t *> (payload->pd.dma_write_data.data);
        rest_size = pdp_wr_req_size_ - pdp_wr_req_got_size_;
        incoming_size = min(rest_size, uint32_t (DMA_TRANSACTION_MAX_SIZE));
        data_ptr = new uint8_t[DMA_TRANSACTION_ATOM_SIZE];
        memcpy(data_ptr, dma_payload_data_ptr, DMA_TRANSACTION_ATOM_SIZE);
        cslDebug((50, "before write to pdp2cvif_wr_data_fifo_\x0A"));
        pdp2cvif_wr_data_fifo_->write(data_ptr);   // Write to FIFO in 32Byte atom
        cslDebug((50, "after write to pdp2cvif_wr_data_fifo_\x0A"));
        pdp_wr_req_got_size_ += incoming_size;
        for(int i = 0; i < DMA_TRANSACTION_ATOM_SIZE; i++) {
    
    
            cslDebug((50, "%x ", data_ptr[i]));
        }
        cslDebug((50, "\x0A"));
        if (incoming_size==DMA_TRANSACTION_MAX_SIZE) {
    
     // The payload is 64B
            data_ptr = new uint8_t[DMA_TRANSACTION_ATOM_SIZE];
            memcpy(data_ptr, &dma_payload_data_ptr[DMA_TRANSACTION_ATOM_SIZE], DMA_TRANSACTION_ATOM_SIZE);
            cslDebug((50, "write to pdp2cvif_wr_data_fifo_\x0A"));
            pdp2cvif_wr_data_fifo_->write(data_ptr);
            for(int i = 0; i < DMA_TRANSACTION_ATOM_SIZE; i++) {
    
    
                cslDebug((50, "%x ", data_ptr[i]));
            }
            cslDebug((50, "\x0A"));
        }

        if (pdp_wr_req_got_size_ == pdp_wr_req_size_) {
    
    
            has_pdp_onging_wr_req_ = false;
        }
    }
}

这段代码是处理从 PDP 模块到 CVIF 模块的写入请求数据部分的代码。它主要包括以下步骤:

  1. 当收到非命令请求(即数据请求)时,代码会执行以下操作:

    • 将数据部分的指针 dma_payload_data_ptr 转换为 uint8_t* 类型,以便进行数据操作。

    • 计算尚未接收的数据的大小(rest_size)以及将要接收的数据的大小(incoming_size),其中 incoming_size 被限制为 DMA_TRANSACTION_MAX_SIZE 和剩余未接收的数据大小之间的较小值。

    • 创建一个名为 data_ptr 的动态数组,大小为 DMA_TRANSACTION_ATOM_SIZE 字节,用于存储接收的数据。

    • 使用 memcpy 将数据从 dma_payload_data_ptr 复制到 data_ptr 中。

    • data_ptr 中的数据写入名为 pdp2cvif_wr_data_fifo_ 的 FIFO 队列,每次写入一个大小为 DMA_TRANSACTION_ATOM_SIZE 字节的原子数据。

    • 更新 pdp_wr_req_got_size_,表示已经接收到的数据大小。

    • 输出一些调试信息,显示接收到的数据。

    • 如果 incoming_size 等于 DMA_TRANSACTION_MAX_SIZE,表示接收的数据大小为64字节,代码再次创建 data_ptr 动态数组,并将后续64字节的数据写入 FIFO 队列。

    • 最后,检查是否已经接收了整个请求的数据(pdp_wr_req_got_size_ 是否等于 pdp_wr_req_size_),如果是,则将 has_pdp_onging_wr_req_ 设置为 false,表示当前请求已经完成。

总之,这段代码用于逐步接收和处理从 PDP 模块传输到 CVIF 模块的写入请求数据部分。它将数据按照一定的原子大小写入 FIFO 队列,并在接收完成后更新状态。这有助于确保数据在传输过程中按照正确的原子边界进行处理。

WriteRequest_pdp2cvif

void NV_NVDLA_cvif::WriteRequest_pdp2cvif() {
    
    
    uint64_t base_addr;
    uint64_t first_base_addr;
    uint64_t last_base_addr;
    uint64_t cur_address;
    uint32_t size_in_byte;
    uint32_t total_axi_size;
    uint64_t payload_addr;
    uint32_t payload_size;
    uint8_t* axi_byte_enable_ptr;
    uint32_t byte_iter;
    uint32_t atom_iter;
    uint32_t atom_num;
    bool     is_base_64byte_align;
    bool     is_rear_64byte_align;
    bool     is_read=false;
    uint8_t  *axi_atom_ptr;
    nvdla_dbb_extension *nvdla_dbb_ext = NULL;
    client_cvif_wr_req_t   * pdp_wr_req;
    dla_b_transport_payload *bt_payload;

这段代码看起来非常类似于之前提到的用于 SDP(Processor Direct Memory Access)到 CVIF(CIF)模块的写入请求处理的代码。它的主要目的是将一个大的内存写入请求分割成多个小的 AXI 事务请求,并为每个小事务创建相应的 AXI 事务数据。以下是主要的变量和步骤的解释:

  1. base_addrfirst_base_addrlast_base_addr:这些变量用于跟踪当前和首尾的地址,以确定小的 AXI 事务请求的边界。

  2. cur_address:表示当前处理的地址,初始时可能需要根据地址对齐进行调整。

  3. size_in_byte:表示当前小事务的大小(字节)。

  4. total_axi_size:表示整个内存写入请求的总大小。

  5. payload_addrpayload_size:表示原始内存写入请求的地址和大小。

  6. axi_byte_enable_ptr:用于指定哪些字节需要启用或禁用。

  7. byte_iteratom_iter:循环迭代变量,用于处理字节和原子数据。

  8. atom_num:表示一个小事务中包含的原子数量。

  9. is_base_64byte_alignis_rear_64byte_align:表示当前地址是否按照64字节对齐。

  10. is_read:表示是否执行读取操作。

  11. axi_atom_ptr:指向当前处理的 AXI 原子数据的指针。

  12. nvdla_dbb_ext:用于设置 AXI 相关的扩展信息。

  13. pdp_wr_req:用于存储内存写入请求的相关信息。

  14. bt_payload:用于存储小的 AXI 事务数据。

这段代码的主要功能与之前提到的相似,它将大的内存写入请求分割成多个小的 AXI 事务请求,并考虑了地址对齐和字节启用/禁用的情况,以确保数据传输的正确性。这种分割和准备小事务的过程通常用于处理底层硬件或协议要求的内存访问和数据传输。不过,具体的细节需要在代码的后续部分中查看,以了解如何处理和发送这些小事务请求。


    while(true) {
    
    
        // Read one write command
        pdp_wr_req = pdp2cvif_wr_cmd_fifo_->read();
        payload_addr = pdp_wr_req->addr;   // It's aligend to 32B, not 64B
        payload_size = pdp_wr_req->size;
        cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, got one write command from pdp2cvif_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_align = payload_addr%AXI_TRANSACTION_ATOM_SIZE == 0;
        first_base_addr = is_base_64byte_align? payload_addr: payload_addr - DMA_TRANSACTION_ATOM_SIZE; // Align to 64B
        is_rear_64byte_align = (payload_addr + payload_size) % AXI_TRANSACTION_ATOM_SIZE == 0;
        // 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 not
        total_axi_size = payload_size + (is_base_64byte_align? 0: DMA_TRANSACTION_ATOM_SIZE) + (is_rear_64byte_align? 0: DMA_TRANSACTION_ATOM_SIZE);
        last_base_addr = first_base_addr + total_axi_size - AXI_TRANSACTION_ATOM_SIZE;
        // 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_pdp2cvif:\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));

这段代码的主要功能是处理从 PDP 模块到 CVIF 模块的写入请求命令部分。以下是代码的主要步骤和变量的解释:

  1. while(true) 循环表示这是一个无限循环,用于不断地处理写入请求命令。

  2. 在循环内部,首先从名为 pdp2cvif_wr_cmd_fifo_ 的 FIFO 队列中读取一个写入请求命令,将其存储在 pdp_wr_req 变量中。这个命令包含了写入请求的地址和大小等信息。

  3. 代码提取了命令中的 payload_addr(地址)和 payload_size(大小),并将它们存储在相应的变量中。

  4. is_base_64byte_align 变量用于检查 payload_addr 是否按照64字节对齐,如果是,则为 true,否则为 false

  5. first_base_addr 变量根据 is_base_64byte_align 的值调整 payload_addr,以确保对齐到64字节的边界。

  6. is_rear_64byte_align 变量用于检查 payload_addr 加上 payload_size 是否按照64字节对齐,如果是,则为 true,否则为 false

  7. 计算 total_axi_size,它表示整个 AXI 事务的大小。这个大小考虑了是否需要在前后填充数据以满足特定的对齐要求。

  8. last_base_addr 表示 AXI 事务的最后地址,它根据 first_base_addrtotal_axi_size 计算得出。

  9. 这段代码还包括了一些被注释掉的部分,似乎是在讨论不同的地址计算方案,但被注释掉了,因此不会被执行。

  10. 最后,代码输出了一些调试信息,包括 first_base_addrlast_base_addrtotal_axi_size 的值,以便进行调试和监视。

总结来说,这段代码用于处理从 PDP 模块传递到 CVIF 模块的写入请求命令部分。它计算并调整地址以满足对齐要求,并计算整个 AXI 事务的大小。这些信息将用于后续的小事务请求的生成和处理。


        // cur_address = payload_addr;
        cur_address = is_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_address <= last_base_addr) {
    
    
            base_addr    = cur_address;
            size_in_byte = AXI_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_address + AXI_TRANSACTION_ATOM_SIZE) < (first_base_addr + total_axi_size)) && ((cur_address + AXI_TRANSACTION_ATOM_SIZE) % CVIF_MAX_MEM_TRANSACTION_SIZE != 0)) {
    
    
                size_in_byte += AXI_TRANSACTION_ATOM_SIZE;
                cur_address  += AXI_TRANSACTION_ATOM_SIZE;
            }
            // start address of next axi transaction
            cur_address += AXI_TRANSACTION_ATOM_SIZE;

            atom_num = size_in_byte / DMA_TRANSACTION_ATOM_SIZE;

            bt_payload = new dla_b_transport_payload(size_in_byte, dla_b_transport_payload::DLA_B_TRANSPORT_PAYLOAD_TYPE_MC);
            axi_byte_enable_ptr = bt_payload->gp.get_byte_enable_ptr();
            cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, base_addr=0x%lx size_in_byte=0x%x atom_num=0x%x\x0A", base_addr, size_in_byte, atom_num));

            for (byte_iter=0; byte_iter < size_in_byte; byte_iter++) {
    
    
                if ( (base_addr == first_base_addr) && (false == is_base_64byte_align) && (byte_iter < DMA_TRANSACTION_ATOM_SIZE)) {
    
    
                    // Diable 1st DMA atom of the unaligned first_base_addr
                    axi_byte_enable_ptr[byte_iter] = TLM_BYTE_DISABLED;  // All bytes should be enabled
                } else if (( (base_addr + size_in_byte) == (last_base_addr+AXI_TRANSACTION_ATOM_SIZE)) && (false == is_rear_64byte_align) && (byte_iter >= size_in_byte - DMA_TRANSACTION_ATOM_SIZE)) {
    
    
                    // Diable 2nd DMA atom of the unaligned last_base_addr
                    axi_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_pdp2cvif, TLM_BYTE_ENABLE is done\x0A"));

这部分代码是在处理从 PDP 模块到 CVIF 模块的写入请求时,将大的内存写入请求分割为小的 AXI 事务请求的过程。以下是代码的主要步骤和变量的解释:

  1. cur_address 的设置:根据地址对齐情况,初始化 cur_addresspayload_addrfirst_base_addr。这是要处理的当前地址,根据对齐情况进行调整。

  2. 循环处理小 AXI 事务请求:通过一个 while 循环,不断处理小的 AXI 事务请求,直到 cur_address 大于等于 last_base_addr

  3. base_addrsize_in_byte:在每次循环迭代中,将 base_addr 设置为当前地址 cur_address,并将 size_in_byte 初始化为 AXI_TRANSACTION_ATOM_SIZE,表示每个小事务的大小。

  4. 检查下一个原子是否属于当前 AXI 事务:通过内层的 while 循环,检查下一个原子是否属于当前 AXI 事务。这个循环的条件是检查下一个原子的地址是否小于 (first_base_addr + total_axi_size) 并且是否满足对 CVIF_MAX_MEM_TRANSACTION_SIZE 的对齐要求。如果是,则将 size_in_byte 增加一个原子的大小,并将 cur_address 增加一个原子的大小,以处理下一个原子。

  5. 更新 cur_address:在内层循环之后,通过 cur_address += AXI_TRANSACTION_ATOM_SIZE 更新 cur_address,以处理下一个 AXI 事务。

  6. 计算 atom_num:根据 size_in_byteDMA_TRANSACTION_ATOM_SIZE 计算 atom_num,表示一个小事务中包含的原子数量。

  7. 创建 bt_payload:创建一个 dla_b_transport_payload 对象,用于存储小 AXI 事务请求的数据。这个对象的大小为 size_in_byte,类型为 DLA_B_TRANSPORT_PAYLOAD_TYPE_MC

  8. 设置字节使能(axi_byte_enable_ptr):根据对齐情况和事务边界,设置字节的使能状态,以确定哪些字节需要启用或禁用。这些字节使能信息存储在 axi_byte_enable_ptr 中。

  9. 根据对齐情况禁用字节:根据对齐情况,禁用未对齐的第一个 DMA 原子的第一个字节,以及未对齐的最后一个 AXI 事务的最后一个 DMA 原子的最后一个字节。

  10. 输出调试信息:输出一些调试信息,显示 base_addrsize_in_byteatom_num 的值。

总之,这段代码负责将大的内存写入请求分割为多个小的 AXI 事务请求,并为每个小事务准备了相应的 AXI 事务数据。它还考虑了地址对齐和字节使能的情况,以确保数据传输的正确性。后续的代码将用于将这些小事务发送到相应的硬件模块以执行实际的写入操作。


            for (atom_iter=0; atom_iter < atom_num; atom_iter++) {
    
    
                if ( (base_addr == first_base_addr) && (false == is_base_64byte_align) && (0 == atom_iter)) {
    
    
                    // Disable 1st DMA atom of the unaligned first_base_addr
                    // Use unaligned address as required by DBB_PV
                    memset(&bt_payload->data[atom_iter*DMA_TRANSACTION_ATOM_SIZE], 0, DMA_TRANSACTION_ATOM_SIZE);
                } else if (((base_addr + size_in_byte) == (last_base_addr+AXI_TRANSACTION_ATOM_SIZE)) && (false == is_rear_64byte_align) && ( (atom_iter + 1) == atom_num)) {
    
    
                    // Disable 2nd DMA atom of the unaligned last_base_addr
                    memset(&bt_payload->data[atom_iter*DMA_TRANSACTION_ATOM_SIZE], 0, DMA_TRANSACTION_ATOM_SIZE);
                } else {
    
    
                    cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, before read an atom from pdp2cvif_wr_data_fifo_, base_addr = 0x%lx, atom_iter=0x%x\x0A", base_addr, atom_iter));

                    axi_atom_ptr = pdp2cvif_wr_data_fifo_->read();
                    for(int i=0; i<DMA_TRANSACTION_ATOM_SIZE; i++) {
    
    
                        cslDebug((50, "%02x ", axi_atom_ptr[i]));
                    }
                    cslDebug((50, "\x0A"));
                    cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, after read an atom from pdp2cvif_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 事务请求的数据。具体步骤和变量的解释如下:

  1. for 循环迭代:循环迭代处理每个原子(atom_iter)。

  2. 检查是否需要禁用原子:根据当前 base_addris_base_64byte_alignatom_iter 和对齐情况,检查是否需要禁用当前原子。

    • 如果当前原子是第一个未对齐的 DMA 原子,且 atom_iter 为 0,则禁用该原子。这是因为首个 DMA 原子在未对齐的情况下需要特殊处理,即使用未对齐的地址。

    • 如果当前原子是最后一个未对齐的 AXI 事务中的第二个 DMA 原子,且 atom_iter 等于 atom_num - 1,则禁用该原子。这是因为最后一个 AXI 事务中的最后一个 DMA 原子需要特殊处理,即使用未对齐的地址。

    • 否则,不禁用原子。

  3. 读取数据:如果当前原子不需要禁用,就从 pdp2cvif_wr_data_fifo_ 中读取一个原子的数据,并将数据存储在 axi_atom_ptr 中。

  4. 输出调试信息:输出一些调试信息,显示从 pdp2cvif_wr_data_fifo_ 中读取的原子数据。

  5. 将数据复制到 bt_payload:将从 pdp2cvif_wr_data_fifo_ 中读取的原子数据复制到 bt_payload 的数据缓冲区中。

  6. 释放内存:释放之前分配的 axi_atom_ptr 的内存,以防止内存泄漏。

这段代码的主要作用是将小 AXI 事务请求的数据从 FIFO 中读取并存储到 bt_payload 中,以便后续将数据传输到相应的硬件模块执行写入操作。在读取和处理数据时,还考虑了未对齐的情况,确保数据处理的正确性。


            if ( (base_addr == first_base_addr) && (false == is_base_64byte_align) ) {
    
    
                base_addr += DMA_TRANSACTION_ATOM_SIZE;
            }
            cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, base_address=0x%lx size in byte=0x%x\x0A", base_addr, size_in_byte));
            // Prepare write payload
            bt_payload->configure_gp(base_addr, size_in_byte, is_read);
            bt_payload->gp.get_extension(nvdla_dbb_ext);
            cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, sending write command to pdp_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(PDP_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 fifo
            pdp_wr_req_fifo_->write(bt_payload);

这部分代码处理了生成和发送到 PDP 存储器接口(pdp_wr_req_fifo_)的写请求。下面是代码的解释:

  1. 如果当前 base_addr 不是 64 字节对齐(is_base_64byte_align 为 false),则增加 base_addr 的值,以确保下一个 AXI 事务从 64 字节对齐的地址开始。这是因为 AXI 事务应始终以 64 字节的倍数对齐。

  2. 输出调试信息,显示 base_addr 和请求的字节大小(size_in_byte)。

  3. 准备写入请求的 payload(bt_payload):使用 base_addrsize_in_byteis_read 配置 bt_payload,以便进行写入操作。

  4. 获取 nvdla_dbb_ext 扩展:从 bt_payload 中获取 DBB 扩展(nvdla_dbb_ext)以设置 AXI 相关的参数。

  5. 输出调试信息,显示即将发送的写入命令的地址(base_addr)和大小(size_in_byte)。

  6. 设置 AXI 相关参数:将 AXI ID 设置为 PDP_AXI_ID,设置数据总线大小(size)为 64,设置 AXI 事务的长度(length)为 size_in_byte 除以 AXI 事务原子大小(AXI_TRANSACTION_ATOM_SIZE)。

  7. 将写入请求的 payload 写入到 pdp_wr_req_fifo_ 中,以便发送到 PDP 存储器接口进行处理。

这段代码的主要作用是准备和发送到 PDP 存储器接口的写入请求。在发送请求之前,它确保了地址的正确对齐,配置了请求的 payload 和 AXI 参数,并将请求推送到 FIFO 中,以便异步处理。这样,写入请求可以按照正确的顺序发送到存储器接口。

     // When the last split req is sent to ext, write true to pdp_wr_required_ack_fifo_ when ack is required.
            if (cur_address >= (payload_addr + payload_size)) {
    
    
                if(pdp_wr_req->require_ack!=0) {
    
    
                    cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, require ack.\x0A"));
                    pdp_wr_required_ack_fifo_->write(true);
                }
                else {
    
    
                    cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, does not require ack.\x0A"));
                    pdp_wr_required_ack_fifo_->write(false);
                }
            }
            else {
    
    
                cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, does not require ack.\x0A"));
                pdp_wr_required_ack_fifo_->write(false);
            }
        }
        delete pdp_wr_req;
        cslDebug((50, "NV_NVDLA_cvif::WriteRequest_pdp2cvif, write command processing done\x0A"));
    }
}

这部分代码处理了在发送完写请求后,将是否需要应答(acknowledge)的信息写入 pdp_wr_required_ack_fifo_ 中的逻辑。以下是代码的解释:

  1. 首先,它检查 cur_address 是否大于或等于当前写请求的结束地址(payload_addr + payload_size)。如果是,表示已经发送了所有的写入请求,因此需要确定是否需要应答。

  2. 如果写入请求需要应答(pdp_wr_req->require_ack 不等于零),则向 pdp_wr_required_ack_fifo_ 中写入 true,表示需要应答。

  3. 如果写入请求不需要应答(pdp_wr_req->require_ack 等于零),则向 pdp_wr_required_ack_fifo_ 中写入 false,表示不需要应答。

  4. 如果 cur_address 小于当前写请求的结束地址,则继续向 pdp_wr_required_ack_fifo_ 中写入 false,以确保不需要应答。

  5. 最后,删除已处理的写入请求对象(pdp_wr_req)以释放内存。

  6. 输出调试信息,表示写命令处理完成。

这段代码的主要作用是在发送完所有写入请求后,确定是否需要等待应答信号,并将相应的信息写入 pdp_wr_required_ack_fifo_ 中,以便外部模块知道是否需要发送应答信号。

猜你喜欢

转载自blog.csdn.net/lincolnjunior_lj/article/details/132962906