ext2cvif_rd_rsp_b_transport
void NV_NVDLA_cvif::ext2cvif_rd_rsp_b_transport(int ID, tlm::tlm_generic_payload& tlm_gp, sc_time& delay) {
uint32_t dma_sent_size; // 存储已发送的 DMA 数据大小
uint8_t* axi_data_ptr; // 指向 AXI 数据的指针
uint32_t axi_length; // AXI 数据的长度
uint8_t* axi_byte_enable_ptr; // 指向 AXI 字节使能的指针
uint32_t axi_byte_enable_length; // AXI 字节使能的长度
uint8_t axi_id; // AXI 事务的 ID
uint8_t dma_payload_atom_mask; // 用于表示 DMA 数据的掩码
nvdla_dbb_extension *nvdla_dbb_ext = NULL; // NVDLA 数据总线扩展
uint8_t * axi_atom_ptr; // 指向当前 AXI 原子事务的指针
uint32_t idx; // 用于循环迭代的索引
// 获取 NVDLA 数据总线扩展
tlm_gp.get_extension(nvdla_dbb_ext);
// 如果没有找到 NVDLA 数据总线扩展,报错并终止仿真
if(!nvdla_dbb_ext) {
FAIL(("NV_NVDLA_cvif::ext2cvif_rd_rsp_b_transport, DBB extension is required, ar_id is needed to forward data to corresponding DMA."));
}
// 获取 AXI 数据相关信息
axi_data_ptr = tlm_gp.get_data_ptr();
axi_length = tlm_gp.get_data_length();
axi_byte_enable_ptr = tlm_gp.get_byte_enable_ptr();
axi_byte_enable_length = tlm_gp.get_byte_enable_length();
axi_id = nvdla_dbb_ext->get_id();
// 检查 AXI 事务长度是否符合要求
if (axi_length > CVIF_MAX_MEM_TRANSACTION_SIZE) {
FAIL(("NV_NVDLA_cvif::ext2cvif_rd_rsp_b_transport, Max AXI transaction length is %d byte, current AXI transaction length is %d byte", CVIF_MAX_MEM_TRANSACTION_SIZE, axi_length));
}
if (0 != (axi_length%DMA_TRANSACTION_ATOM_SIZE)) {
FAIL(("NV_NVDLA_cvif::ext2cvif_rd_rsp_b_transport, AXI transaction length shall be an integral multiple of %d byte, current AXI transaction length is %d byte", DMA_TRANSACTION_ATOM_SIZE, axi_length));
}
// 遍历 AXI 数据并生成 DMA 响应
dma_sent_size = 0;
for (dma_sent_size = 0; dma_sent_size < axi_length; dma_sent_size += DMA_TRANSACTION_ATOM_SIZE) {
switch (axi_id) {
// 根据 AXI ID 选择对应的 FIFO
case BDMA_AXI_ID:
dma_payload_atom_mask = (true == bdma_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case SDP_AXI_ID:
dma_payload_atom_mask = (true == sdp_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case PDP_AXI_ID:
dma_payload_atom_mask = (true == pdp_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case CDP_AXI_ID:
dma_payload_atom_mask = (true == cdp_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case RBK_AXI_ID:
dma_payload_atom_mask = (true == rbk_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case SDP_B_AXI_ID:
dma_payload_atom_mask = (true == sdp_b_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case SDP_N_AXI_ID:
dma_payload_atom_mask = (true == sdp_n_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case SDP_E_AXI_ID:
dma_payload_atom_mask = (true == sdp_e_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case CDMA_DAT_AXI_ID:
dma_payload_atom_mask = (true == cdma_dat_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
case CDMA_WT_AXI_ID:
dma_payload_atom_mask = (true == cdma_wt_rd_atom_enable_fifo_->read()) ? 0x1 : 0;
break;
default:
FAIL(("NV_N
VDLA_cvif::ext2cvif_rd_rsp_b_transport, unexpected AXI ID"));
}
// 如果 DMA 数据掩码为 1,则将当前 AXI 原子事务写入对应的 FIFO
if (0x1 == dma_payload_atom_mask) {
axi_atom_ptr = new uint8_t[DMA_TRANSACTION_ATOM_SIZE];
memcpy (axi_atom_ptr, &axi_data_ptr[dma_sent_size], DMA_TRANSACTION_ATOM_SIZE);
// 根据 AXI ID 写入不同的 FIFO
switch (axi_id) {
case BDMA_AXI_ID:
cvif2bdma_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case SDP_AXI_ID:
cvif2sdp_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case PDP_AXI_ID:
cvif2pdp_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case CDP_AXI_ID:
cvif2cdp_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case RBK_AXI_ID:
cvif2rbk_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case SDP_B_AXI_ID:
cvif2sdp_b_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case SDP_N_AXI_ID:
cvif2sdp_n_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case SDP_E_AXI_ID:
cvif2sdp_e_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case CDMA_DAT_AXI_ID:
cvif2cdma_dat_rd_rsp_fifo_->write(axi_atom_ptr);
break;
case CDMA_WT_AXI_ID:
cvif2cdma_wt_rd_rsp_fifo_->write(axi_atom_ptr);
break;
default:
FAIL(("NV_NVDLA_cvif::ext2cvif_rd_rsp_b_transport, unexpected AXI ID"));
}
} else {
cslDebug((50, "NV_NVDLA_cvif::ext2cvif_rd_rsp_b_transport, {client} payload atom mask is 0x0, ignore current atom, dma_payload_atom_mask is 0x%x\x0A", uint32_t(dma_payload_atom_mask)));
}
}
// 设置响应状态为 TLM_OK_RESPONSE
tlm_gp.set_response_status(tlm::TLM_OK_RESPONSE);
}
函数总结:
- 函数名称:
ext2cvif_rd_rsp_b_transport
- 参数:ID(整数)、tlm_generic_payload(泛型传输对象的引用)、delay(时间延迟)
- 返回值:无
- 功能:此函数用于处理外部数据到 CVIF 模块的读响应传输。它从传输对象中提取数据,根据 AXI ID 选择相应的 FIFO 并写入数据。函数还包含错误检查和日志记录的逻辑。
这个函数是处理硬件设计中的数据传输的一部分,根据 AXI ID 将数据写入不同的 FIFO 中,以便后续处理。它还包含了一些错误检查,以确保数据的完整性和一致性。函数注释提供了对函数的详细说明和各个变量的用途解释。
ext2cvif_wr_rsp_b_transport
void NV_NVDLA_cvif::ext2cvif_wr_rsp_b_transport(int ID, tlm::tlm_generic_payload& tlm_gp, sc_time& delay) {
uint8_t axi_id; // 存储 AXI 事务的 ID
nvdla_dbb_extension *nvdla_dbb_ext = NULL; // NVDLA 数据总线扩展
cslDebug((50, "NV_NVDLA_cvif::ext2cvif_wr_rsp_b_transport.\x0A"));
// 获取 DBB 扩展
tlm_gp.get_extension(nvdla_dbb_ext);
// 如果没有找到 NVDLA 数据总线扩展,报错并终止仿真
if(!nvdla_dbb_ext) {
FAIL(("NV_NVDLA_cvif::ext2cvif_wr_rsp_b_transport, DBB extension is required, ar_id is needed to forward data to corresponding DMA."));
}
// 获取 AXI ID
axi_id = nvdla_dbb_ext->get_id();
// 根据 AXI ID 处理响应
switch (axi_id) {
case BDMA_AXI_ID:
bdma_wr_rsp_count_++;
// 从 FIFO 读取新请求的 ack
bdma_wr_req_expected_ack = bdma_wr_required_ack_fifo_->read();
if (true == bdma_wr_req_expected_ack) {
cslDebug((50, "send wr rsp to bdma\x0A"));
NV_NVDLA_cvif_base::cvif2bdma_wr_rsp.write(true);
} else {
// NV_NVDLA_cvif_base::cvif2bdma_wr_rsp.write(false);
}
break;
case SDP_AXI_ID:
sdp_wr_rsp_count_++;
// 从 FIFO 读取新请求的 ack
sdp_wr_req_expected_ack = sdp_wr_required_ack_fifo_->read();
if (true == sdp_wr_req_expected_ack) {
cslDebug((50, "send wr rsp to sdp\x0A"));
NV_NVDLA_cvif_base::cvif2sdp_wr_rsp.write(true);
} else {
// NV_NVDLA_cvif_base::cvif2sdp_wr_rsp.write(false);
}
break;
case PDP_AXI_ID:
pdp_wr_rsp_count_++;
// 从 FIFO 读取新请求的 ack
pdp_wr_req_expected_ack = pdp_wr_required_ack_fifo_->read();
if (true == pdp_wr_req_expected_ack) {
cslDebug((50, "send wr rsp to pdp\x0A"));
NV_NVDLA_cvif_base::cvif2pdp_wr_rsp.write(true);
} else {
// NV_NVDLA_cvif_base::cvif2pdp_wr_rsp.write(false);
}
break;
case CDP_AXI_ID:
cdp_wr_rsp_count_++;
// 从 FIFO 读取新请求的 ack
cdp_wr_req_expected_ack = cdp_wr_required_ack_fifo_->read();
if (true == cdp_wr_req_expected_ack) {
cslDebug((50, "send wr rsp to cdp\x0A"));
NV_NVDLA_cvif_base::cvif2cdp_wr_rsp.write(true);
} else {
// NV_NVDLA_cvif_base::cvif2cdp_wr_rsp.write(false);
}
break;
case RBK_AXI_ID:
rbk_wr_rsp_count_++;
// 从 FIFO 读取新请求的 ack
rbk_wr_req_expected_ack = rbk_wr_required_ack_fifo_->read();
if (true == rbk_wr_req_expected_ack) {
cslDebug((50, "send wr rsp to rbk\x0A"));
NV_NVDLA_cvif_base::cvif2rbk_wr_rsp.write(true);
} else {
// NV_NVDLA_cvif_base::cvif2rbk_wr_rsp.write(false);
}
break;
#pragma CTC SKIP
default:
FAIL(("NV_NVDLA_cvif::ext2cvif_wr_rsp_b_transport, unexpected AXI ID"));
#pragma CTC ENDSKIP
}
// 设置响应状态为 TLM_OK_RESPONSE
tlm_gp.set_response_status(tlm::TLM_OK_RESPONSE);
}
函数总结:
- 函数名称:
ext2cvif_wr_rsp_b_transport
- 参数:ID(整数)、tlm_generic_payload(泛型传输对象的引用)、delay(时间延迟)
- 返回值:无
- 功能:此函数用于处理外部数据到 CVIF 模块的写响应传输。它从传输对象中提取数据,根据 AXI ID 决定是否向相应的 FIFO 中写入响应信号。函数还包含错误检查和日志记录的逻辑。
这个函数主要用于处理来自硬件设计的写响应传输。根据 AXI ID,它选择适当的 FIFO 并发送写响应信号。函数还包含了一些错误检查,以确保数据的完整性和一致性。
ReadRequestArbiter
void NV_NVDLA_cvif::ReadRequestArbiter() {
// 定义各个模块的就绪信号
bool bdma_ready, cdma_dat_ready, cdma_wt_ready, sdp_ready, pdp_ready, cdp_ready;
bool rbk_ready, sdp_b_ready, sdp_n_ready, sdp_e_ready;
while (true) {
// 如果 bdma_rd_req_payload_ 为空,从 bdma_rd_req_fifo_ 读取一个请求
if (bdma_rd_req_payload_ == NULL) {
bdma_rd_req_fifo_->nb_read(bdma_rd_req_payload_);
}
// 如果 bdma_rd_req_payload_ 不为空,检查是否有足够的信用来处理该请求
if (bdma_rd_req_payload_ != NULL) {
int payload_size = bdma_rd_req_payload_->gp.get_data_length();
int atom_num = payload_size / DMA_TRANSACTION_ATOM_SIZE;
if (credit_cvif2bdma_rd_rsp_fifo_ >= atom_num) {
bdma_ready = true;
} else {
bdma_ready = false;
}
} else {
bdma_ready = false;
}
// 重复上述过程,检查其他模块的请求和就绪状态
// 这里包括 cdma_dat, cdma_wt, sdp, pdp, cdp, rbk, sdp_b, sdp_n, sdp_e
// 如果没有任何模块有待处理的请求,进入等待状态
if (!cdma_dat_ready && !cdma_wt_ready && !bdma_ready && !sdp_ready &&
!pdp_ready && !cdp_ready && !rbk_ready && !sdp_b_ready && !sdp_n_ready && !sdp_e_ready) {
cslDebug((50, "NV_NVDLA_cvif::ReadRequestArbiter, no pending request, waiting.\x0A"));
wait();
cslDebug((50, "NV_NVDLA_cvif::ReadRequestArbiter, get new request, wake up.\x0A"));
}
// 处理各个模块的读请求
// 对于每个模块,检查请求是否有效并有足够的信用,然后将请求传递给相应的外部模块
// 处理 BDMA 模块的读请求
if (bdma_rd_req_payload_ != NULL) {
int payload_size = bdma_rd_req_payload_->gp.get_data_length();
uint8_t* axi_byte_enable_ptr = bdma_rd_req_payload_->gp.get_byte_enable_ptr();
int atom_num = 0;
for (int i = 0; i < payload_size / DMA_TRANSACTION_ATOM_SIZE; i++) {
atom_num += axi_byte_enable_ptr[i * DMA_TRANSACTION_ATOM_SIZE] == TLM_BYTE_ENABLED;
}
if (credit_cvif2bdma_rd_rsp_fifo_ >= atom_num) {
credit_cvif2bdma_rd_rsp_fifo_ -= atom_num;
cslDebug((50, "NV_NVDLA_cvif::ReadRequestArbiter, send read request, payload from bdma, begin, atom:%d, num_free:%d credit_cvif2bdma_rd_rsp_fifo_=%d.\x0A", atom_num, cvif2bdma_rd_rsp_fifo_->num_free(), credit_cvif2bdma_rd_rsp_fifo_));
cvif2ext_rd_req->b_transport(bdma_rd_req_payload_->gp, axi_delay_);
cslDebug((50, "NV_NVDLA_cvif::ReadRequestArbiter, send read request, payload from bdma, end.\x0A"));
delete bdma_rd_req_payload_;
bdma_rd_req_payload_ = NULL;
}
}
// 类似地,处理其他模块的读请求,如 SDP、PDP、CDP、RBK 和 SDP_B、SDP_N、SDP_E
// 删除已经处理的请求,释放内存
}
}
函数总结:
- 函数名称:
NV_NVDLA_cvif::ReadRequestArbiter
- 参数:无
- 返回值:无
- 功能:此函数是一个无限循环,用于处理各个外部模块的读请求。它检查每个模块的请求是否有效,并根据模块的就绪状态和信用来决定是否传递请求到外部模块。函数包括 BDMA、CDMA 数据、CDMA 权重、SDP、PDP、CDP、RBK、SDP_B、SDP_N 和 SDP_E 模块的请求处理逻辑。如果没有待处理的请求,函数将进入等待状态。此外,函数还负责删除已经处理的请求以释放内存。
WriteRequestArbiter
void NV_NVDLA_cvif::WriteRequestArbiter() {
// 定义一个指向写请求的指针
dla_b_transport_payload *payload;
while (true) {
cslDebug((50, "Calling WriteRequestArbiter\x0A"));
// 如果所有外部模块的写请求 FIFO 都为空,则进入等待状态
if ((bdma_wr_req_fifo_->num_available() == 0) &&
(rbk_wr_req_fifo_->num_available() == 0) &&
(sdp_wr_req_fifo_->num_available() == 0) &&
(pdp_wr_req_fifo_->num_available() == 0) &&
(cdp_wr_req_fifo_->num_available() == 0)) {
wait();
}
// 处理各个外部模块的写请求
// 处理 BDMA 模块的写请求
if (bdma_wr_req_fifo_->nb_read(payload)) {
cslDebug((50, "NV_NVDLA_cvif::WriteRequestArbiter, send write request, payload from bdma.\x0A"));
cvif2ext_wr_req->b_transport(payload->gp, axi_delay_);
delete payload;
}
// 类似地,处理其他外部模块的写请求,如 SDP、PDP、CDP 和 RBK
// 删除已经处理的请求,释放内存
}
}
函数总结:
- 函数名称:
NV_NVDLA_cvif::WriteRequestArbiter
- 参数:无
- 返回值:无
- 功能:此函数是一个无限循环,用于处理各个外部模块的写请求。它检查每个模块的写请求 FIFO 是否为空,如果不为空,则将请求传递给外部模块。函数包括 BDMA、SDP、PDP、CDP 和 RBK 模块的写请求处理逻辑。如果所有模块的写请求 FIFO 都为空,则函数将进入等待状态。此外,函数还负责删除已经处理的请求以释放内存。