02 - 单芯片内部详解:一条指令从取指到执行完成
概述 -- 一条指令的完整旅程
在 TPUPerf 中,一条指令从外部进入到最终执行完毕,经历的完整链路可以概括为:
IfeMaster (指令源)
| TXI/AXI 接口
v
IFE (指令取指引擎)
| pack -> pre_decode -> async -> decode -> check -> issue
v
+-----------+ +-----------+
| TIU 引擎 | | GDMA 引擎 |
| (计算指令) | | (搬运指令) |
+-----------+ +-----------+
| |
| DPC 5 级流水 | ~22 个 SC_THREAD
| DES->GEN->ISSUE->ARB | 流水线阶段
| ->COMPUTE |
v v
LMEM (本地 SRAM) <----> DDR (全局内存)
^ ^
| |
+---- WDC 存储控制层 ------+
(Fabric 路由 + CAM + X2X + UMC/DRAM)
关键时钟域:IFE 使用 clk_i_(系统时钟)和 clk_ife_(IFE 专用时钟),TIU 使用 tiu_clock_,GDMA/LMEM 使用 dma_clk_,WDC 内部使用 clk2G_(2GHz)、clk800M_(800MHz)、clk400M_(400MHz)三级时钟。
两大执行通道:TIU 指令和 GDMA 指令在 IFE 中被分别解码并分发到独立引擎,通过 tiu_sync_id_ / tdma_sync_id_ 信号对实现跨引擎依赖同步(详见 01-system-architecture.md)。
IFE 指令取指引擎
IFE(Instruction Fetch Engine)是指令进入单核子系统的入口。源码位于 ip/include/ife/ife.h 和 ip/src/ife/ife.cpp。
指令输入接口
IFE 支持两种指令输入模式,由 IfeMaster::TXI_MODE 属性决定:
- TXI 模式:通过
txi_req_data1_(256-bit rs1)、txi_req_data2_(256-bit rs2)、req_inst_(32-bit)三组信号传入,txi_req_valid_/txi_req_ready_握手 - AXI 模式:通过
axi_pkg_(sc_fifo<RvtiAxiCmd>,深度 8)传入 AXI 命令包,axi_aw_valid_/axi_aw_ready_握手,AXI 响应延迟axi_slv_rsp_delay_ = 3拍
IfeSignalBus 类(ife_signal_bus.h)封装了 IfeMaster 和 IFE 之间的所有信号连接,包括 TXI 数据信号、AXI 命令 FIFO、响应通道。
IFE 内部流水线
IFE 内部是一条多级流水线,每级之间通过 std::deque FIFO 缓冲。从 ife.cpp 构造函数中注册的 SystemC 进程可以还原完整流水:
TXI/AXI 输入
|
v
[pre_decode_input_txi] SC_CTHREAD(clk_i_) -- 从 TXI 接收,打包到 cm_fifo_
| 容量: CM_FIFO_LENGTH = 8
v
[pre_decode_output] SC_THREAD(clk_i_) -- 预解码,输出到 vcix_predecode_output_fifo_
| 容量: PRE_DECODE_OUTPUT_FIFO_LENGTH = 4
v
[async_deal1] SC_CTHREAD(clk_i_) -- 跨时钟域缓冲 (clk_i_ -> clk_ife_)
| 容量: ASYNC_INPUT_FIFO_LENGTH = 8
v
[async_deal2] SC_CTHREAD(clk_ife_) -- 跨时钟域缓冲下游
| 容量: ASYNC_OUTPUT_FIFO_LENGTH = 8
v
[decode] SC_THREAD(clk_ife_) -- 指令解码 -> decode_fifo_
|
v
[check] SC_THREAD(clk_ife_) -- 依赖检查 -> check_fifo_
|
v
[issue] SC_THREAD(clk_ife_) -- 分发到 TIU 或 GDMA
|
+---> tiu_fifo_request_ (深度 2) --[pe_ife_tiu_main_th]--> TIU 引擎
|
+---> gdma_fifo_request_ (深度 2) --[pe_ife_gdma_main_th]--> GDMA 引擎
|
+---> mv_fifo_request_ (深度 MV_FIFO_REQ_LENGTH=2) --> MoveModule
AXI 模式的额外前处理:AXI 数据包先经过 axi_slv_req_mth(SC_METHOD)接收,再由 split_buf640 和 split_buf320(SC_THREAD)将 640-bit / 320-bit 缓冲拆分为 160-bit 指令粒度(axi_data_to_instr()),最终进入 instr_fifo_(深度 INSTR_FIFO_LENGTH=2)。
指令类型识别
IFE 内部的 Instruction 类(framework/include/instruction.h)封装了指令的完整元数据:
instr_type_:枚举{NONE_TYPE, CONFIG, TIU, GDMA, MOVE}- TIU 指令由
tiu_desc_parse.h中的get_tiu_instr_type()通过掩码匹配识别(支持 CONV、MM、POOL、AR、SFU、LIN、CMP、SG、RQDQ 等数十种指令类型) - GDMA 指令由
gdma_desc_parse.h中的get_dma_instr_type()识别(支持 LD/ST/CP/MLD/MST/HGATHER/HSCATTER/CMPR/DECMPR 等 20+ 种搬运操作) - MOVE 指令由
MoveModule处理,走独立的mv_fifo_request_/mv_fifo_response_通路
依赖 ID 计算
IFE::calc_dep_id() 是 IFE 的核心逻辑之一,负责计算每条指令的依赖 ID(cmd_id_dep),确定它需要等待对端引擎的哪些指令完成。
两种依赖模式(由 CSR 寄存器 CSR_CTRL_0_DIS_AUTO_DEP_ID 控制):
-
自动依赖模式(
DIS_AUTO_DEP_ID = 1):- 非 parallel 模式:GDMA 指令依赖当前
tiu_id_counter_,TIU 指令依赖当前gdma_id_counter_ - parallel 模式:使用保存的
saved_tiu_cmd_id_/saved_gdma_cmd_id_
- 非 parallel 模式:GDMA 指令依赖当前
-
Bitmap 依赖模式(
DIS_AUTO_DEP_ID = 0):- 基于 chunk 粒度的 Read-After-Write / Write-After-Read / Write-After-Write 依赖分析
chunk_last_r_id_[]和chunk_last_w_id_[]数组(大小 =Utility::get_chunk_num())记录每个 chunk 最后一次读/写的指令 ID- 通过
get_read_bitmap()/get_write_bitmap()获取指令的 chunk 访问 bitmap - 最终 dep_id 取所有冲突 chunk 的 max
IFE 到引擎的传输
IFE 通过 SimplePeInitiator TLM 接口将指令发送到 TIU 和 GDMA:
pe_ife_tiu_ini_:IFE -> TIU,pending 计数pe_ife_tiu_ini_cmd_pend_,最大目标容量pe_ife_tiu_tgt_cmd_max_ = 1pe_ife_gdma_ini_:IFE -> GDMA,同样的流控
反压机制:当下游引擎的命令 FIFO 满时(TIU: is_tiu_cmd_list_full(),GDMA: is_gdma_cmd_list_full()),IFE 的 issue 阶段会阻塞等待。GDMA 命令 FIFO 容量为 GDMA_CMD_FIFO_LENGTH = 8192 Byte,TIU 的命令 FIFO 容量为 TIU_FIFO_LENGTH = 32768 Byte。
Profiling 时间戳
Instruction 对象在流水线每一级记录时间戳(单位 ns),最终输出到 CSV:
txi_acq_cycle_:TXI 接收时刻pack_cycle_:打包时刻decode_cycle_:解码完成时刻check_cycle_:依赖检查完成时刻issue_cycle_:发射时刻
TIU 计算流水线
TIU 内部实现了两条独立的 DPC(Data Path Controller)流水线:向量引擎(TiuModuleTop)和 Cube 引擎(TiuModuleCubeTop)。两者共享相同的 5 级结构,但地址生成和仲裁逻辑不同。
向量引擎流水线(TiuModuleTop)
task_ ──> [DpcDes] ──> [DpcGen] ──> [DpcIssue] ──> [DpcArb] ──> [ComputeUnit]
(2 clk) (1 clk) (1 clk) (bank arb) (计算完成)
| | | | |
vld/rdy 6 bus 6 bus 3 bus last_done_
handshake (opd0~3, (r0,r1,w0) (r0,r1,w0)
res0~1)
每级之间通过 valid/ready 握手协议 实现流控,任何一级的 FIFO 满都会向上游反压。
Stage 1 - DpcDes(描述符加载):
- 延迟:
DPC_DES_DELAY_CYCLE = 2拍 - 缓冲区大小:
DPC_DES_BUFFER_SIZE = 1 - 功能:接收 task(
tiu_reg_t,即shared_ptr<TpuCmd>),经过 2 拍延迟后输出到 DpcGen start_in_信号控制是否接受新任务,已接收的任务不受影响继续流动
Stage 2 - DpcGen(地址生成):
- 延迟:
DPC_GEN_DELAY_CYCLE = 1拍 - 6 个独立地址总线:
opd0~opd3(4 个源操作数)、res0~res1(2 个目标操作数) - 每条总线宽度 =
lane_num个 64-bit 地址(典型值 16 lanes) - 每条总线有独立的 FIFO(深度 =
DPC_GEN_DELAY_CYCLE + 5)和独立的 valid/ready 握手 - 根据指令类型分派到不同的地址生成函数(如
dpc_gen_ar_copy、dpc_gen_sfu_normal、dpc_gen_pool_max等约 20 个 spec 函数)
Stage 3 - DpcIssue(发射/调度):
- 延迟:
DPC_ISSUE_DELAY_CYCLE = 1拍 - 缓冲区:
DPC_ISSUE_BUFFER_SIZE = DPC_ISSUE_DELAY_CYCLE + 15 = 16 - 将 6 路输入总线合并为 3 路输出(r0=opd0, r1=opd1, w0=res0),存入
bus_fifo_(BusFifoEntry结构) - 处理不同指令类型的操作数映射(约 20 个 spec 函数,如
dpc_issue_ar_copy、dpc_issue_sfu_taylor_4x等)
Stage 4 - DpcArb(Bank 仲裁):
calculate_flow_buffer_大小 = 32,每个单元包含BANK_NUM = 16个 bank 的 busy 标志- 检测 r0、r1、w0 三路地址是否访问同一 bank,产生冲突时插入气泡
- 根据指令类型计算
compute_cycle_(计算流水线延迟,详见 3.3)
Stage 5 - ComputeUnit(计算单元):
- 接收仲裁后的地址数据(r0_bus, r1_bus, w0_bus)
- 收到
last_flag_in_时输出last_done_信号,标记整条指令执行完成
Cube 引擎流水线(TiuModuleCubeTop)
Cube 引擎处理矩阵乘法(MM/CONV),流水线结构与向量引擎类似但参数不同:
task_ ──> [DpcDes] ──> [DpcGenCube] ──> [DpcIssueCube] ──> [DpcArbCube] ──> [ComputeUnit]
(2 clk) (12 clk) (5 clk) (5 clk) (计算完成)
关键差异:
| 参数 | 向量引擎 | Cube 引擎 |
|---|---|---|
| GEN 延迟 | 1 拍 | DPC_GEN_CUBE_DELAY_CYCLE = 12 拍 |
| ISSUE 延迟 | 1 拍 | DPC_ISSUE_CUBE_DELAY_CYCLE = 5 拍 |
| ISSUE 缓冲区 | 16 | DPC_ISSUE_CUBE_BUFFER_SIZE = 8 |
| ARB 延迟 | 动态 | DPC_ARB_CUBE_DELAY_CYCLE = 5 拍 |
| ARB 缓冲区 | 32 | DPC_ARB_CUBE_BUFFER_SIZE = 8 |
| 地址总线 | opd0 | opa, opb, w0 (3路) |
| 地址类型 | uint64_t | CubeAddrEntry (含 addr_flag_, psum_add_flag_) |
Cube 引擎的地址使用 CubeAddrEntry 结构体:
addr_:64-bit 物理地址addr_flag_:标记是否 LMEM 访问或 buffer 命中(命中时跳过实际内存访问)psum_add_flag_:标记是否与上一拍做部分和累加
DpcIssueCube 额外维护了 opa/opb 的 buffer 命中检测逻辑,通过 process_hit_detection() 和 calculate_access_cycles() 判断当前数据是否在内部 buffer 中,命中时减少访存延迟。opa_reuse_ / opb_reuse_ 标记操作数复用。
DpcGenCube 支持两种地址生成模式:dpc_gen_conv(卷积)和 dpc_gen_mm2(矩阵乘法),作为 friend 函数访问 DpcGenCube 内部状态。
计算延迟表(compute_cycle_)
DpcArb::get_compute_cycle() 根据 tsk_typ 和 eu_typ 返回不同指令的计算流水线延迟(单位:clock cycle):
| tsk_typ | 指令类型 | eu_typ | 延迟 (cycles) |
|---|---|---|---|
| 0 | Convolution | - | 5 |
| 1 | Depthwise/Pooling | 0 | 3 |
| 1 | Depthwise/Pooling | others | 5 |
| 2 | Matrix Multiply (MM/MM2) | - | 3 |
| 3 | Arithmetic (AR) | 12 (mul_satu) | 5 |
| 3 | Arithmetic (AR) | 13 | 1 |
| 3 | Arithmetic (AR) | others | 3 |
| 4 | RQDQ DQ_0 | - | 8 |
| 5 | TRANS/BC | 0 (CW trans) | 28 |
| 5 | TRANS/BC | 1 (WC trans) | 18 |
| 5 | TRANS/BC | 2 (BC lane copy) | 12 |
| 5 | TRANS/BC | 4 (BC static broad) | 0 |
| 5 | TRANS/BC | 5 (BC static dist) | 0 |
| 9 | SFU | - | 3 |
| 10 | LIN (AddSqr) | - | 11 |
| 11 | (未命名) | - | 10 |
| 12 | (未命名) | - | 9 |
| 13 | CMP (Compare) | - | 4 |
| 15 | SYS | 8 | 5 |
| 15 | SYS | 31 | 3 |
TIU 地址生成与 Bank 冲突
NCHW 地址计算
DpcGen::nchw_to_address() 是向量引擎的核心地址计算函数。它将 NCHW 张量坐标转换为 LMEM 物理地址:
address = base_addr + (n * n_stride +
(c + start_lane)/16 * c_stride +
h * h_stride +
w * w_stride) * precision_bits
per_lane_lmem_size = lmem_size / lane_num(典型值:4MB / 16 = 256KB per lane)start_lane = (base_addr / per_lane_lmem_size) % lane_num:从基址中提取 lane 索引precision_bits由calculate_stride_bits()根据数据类型返回(INT4=4, INT8/FP8=8, FP16/BFP16=16, FP32/TF32=32)
地址最终通过 align_256bit() 对齐到 eu_num_vec / 2 字节边界(典型值 eu_num_vec = 64,对齐到 32 字节)。
calculateEU_NUM() 根据精度返回每个 EU 处理的元素数:INT4=64, INT8/FP8=32, FP16/BFP16=16, FP32/TF32=8。
Bank 冲突检测
DpcArb::address_to_bank() 从物理地址提取 bank ID:
int bank_id = (address >> 14) % 16; // 右移 14 位后取模 16
即 LMEM 的 bank 交织粒度为 16KB(2^14),共 BANK_NUM = 16 个 bank。
冲突检测机制:calculate_flow_buffer_ 是一个 32 深度的 ring buffer,每个 entry 记录 16 个 bank 的 busy 状态。当 r0、r1、w0 三路中有两路或以上访问同一 bank 时,DpcArb 插入等待周期。
Cube 引擎的 DpcArbCube::bank_conflict_check() 对 opa 和 opb 两组向量地址做成对冲突检测,产生的冲突计数 bank_cflt_num_ 作为额外延迟。
FIFO 管理
DpcGen 为每个操作数维护独立的地址 FIFO:
向量引擎: opd0_fifo_, opd1_fifo_, opd2_fifo_, opd3_fifo_, res0_fifo_, res1_fifo_
每个 FIFO 存储 FifoEntry = {num, addresses[lane_num], write_time}
最大深度: DPC_GEN_DELAY_CYCLE + 5 = 6
Cube 引擎: opa_addr_fifo_, opb_addr_fifo_, w0_addr_fifo_, gen_addr_fifo_
存储 CubeGenEntry = {vector<CubeAddrEntry>, write_time}
DpcIssue 额外维护 bus_fifo_(BusFifoEntry),将多路输入合并为 r0/r1/w0 三路输出。
WDC 存储控制层次
WDC(Write/Data Controller)是连接 GDMA 和物理 DDR 之间的多级存储控制子系统。源码位于 ip/include/wdc/wdc.h。
总体拓扑
GDMA gmem_external_socket_
|
v
[AuxFab<1024,2> fab1t2_] -- 1-to-2 Fabric, clk2G_ (2GHz)
|
+----+----+
| |
v v
[ItlvDemux<1024>] x2 -- 地址交织解复用, clk800M_
| |
+--+ +--+
| | | |
v v v v
[private] [shared_fab1] -- 私有 / 共享 Fabric, clk800M_
AuxFab AuxFabSplit
<1024,8> <1024,1024,2>
| |
| +----+----+
| | |
| v v
| [shared_fab2] x2 -- 二级共享 Fabric, clk800M_
| AuxFabSplit
| <1024,1024,4>
| |
+--+---+ (每 channel 汇合)
|
v
[Fab2t1<1024,1024,1024>] x16 -- 2-to-1 Fabric, clk800M_
|
v
[AuxCam<1024>] x16 -- CAM 调度器, clk800M_
|
v
[X2x<1024,256>] x16 -- 频率/位宽转换, 800M->400M, 1024->256 bit
|
v
[UMC<256> / DramUnit] x16 -- DDR 时序模型, clk400M_
总计 2 个 channel,每 channel 8 个 UMC,共 16 个 DDR 控制器实例。
地址交织解复用(ItlvDemux)
ItlvDemux<1024> 继承自 AuxFab<BusWidth, 2>,重写了 decode() 函数。它根据 AXI 事务的 axi_region_extension 属性将流量分为两路:
- Port 0:私有 Fabric(
private_fab_[i]),8 个输出端口,直连 8 个 Fab2t1 - Port 1:共享 Fabric(
shared_fab1_[i]),2 个输出端口,每个再分为 4 路(shared_fab2_),总计 8 路
ItlvDemux 还检查 GDMA 扩展属性,对写操作判断是否启用 ARE(All-Reduce Engine):当 are_en_ 且 are_psum_op_ != 0,或 reduce_en_ 且 reduce_psum_op_ != 0 时,在事务上设置 "ARE" 用户属性。
Fabric 层级
AuxFab 是基础的 1-to-N 交叉开关,支持可配置的:
- 总线宽度(模板参数,典型 1024-bit)
- 目标端口数(模板参数
TargetNum) - 读/写 outstanding 数(
RD_OSTD_OUT/WR_OSTD_OUT) - 地址交织位(
itlv_bit_ = 12,即 4KB 交织粒度)
AuxFabSplit 是 AuxFab 的变体,支持主/从独立时钟域。共享 Fabric 的 outstanding 限制:
shared_fab1_: rd/wr outstanding = 128shared_fab2_: rd/wr outstanding = 64
Fab2t1 是 2-to-1 合并节点(fab_2t1.h),将私有和共享两路流量合并到单个输出,outstanding = 32。
CAM 事务调度(AuxCam)
AuxCam<1024> 位于 Fab2t1 下游,负责 DDR 访问的页面级调度优化。内部包含:
read_table_:CamTableSemiNested类型,读请求调度表write_table_:CamTableSemiNested类型,写请求调度表(构造时传入read_table_作为嵌套引用)ar_scheduler():读地址调度,SC_METHOD,每个clock_.pos()触发aw_scheduler():写地址调度,SC_METHOD,每个clock_.pos()触发
CAM 表的作用是对同一 DDR page 的访问进行重排序,减少 page miss 带来的延迟惩罚。
跨时钟域转换(X2x)
X2x<1024, 256> 实现从 800MHz / 1024-bit 到 400MHz / 256-bit 的频率和位宽转换:
- 主侧(master):
mst_clock_ = clk800M_,1024-bit 接口 - 从侧(slave):
slv_clock_ = clk400M_,256-bit 接口 data_width_ratio_ = MstWidth / SlvWidth = 4(每个主侧 beat 拆分为 4 个从侧 beat)
内部 5 个 FIFO 缓冲各 AXI 通道:
ar_fifo_(深度 16)、r_fifo_(深度 16)aw_fifo_(深度 16)、w_fifo_(深度 16)b_fifo_(深度 4)
5 个 SC_METHOD 处理各通道:ar_process/aw_process/w_process 在 slv_clock_.pos() 触发,r_process/b_process 在 mst_clock_.pos() 触发。
DDR 时序模型(DramUnit)
DramUnit(dram_unit.h)是最底层的 DDR 时序模型,通过 TLM nb_transport_fw 接口接收访问请求。核心参数:
open_page_cycle_:打开新页的延迟read_close_page_cycle_/write_close_page_cycle_:关闭页延迟minimum_read_to_write_cycle_/minimum_write_to_read_cycle_:读写切换延迟minimal_read_cycle_:最小读周期page_size_:页大小data_width_:数据宽度
时序计算逻辑:
- Page Hit + 同方向:
delay += data_beats * clock_period - Page Hit + 写转读:先等待
minimum_write_to_read_cycle_,再加数据传输时间 - Page Hit + 读转写:先等待
minimum_read_to_write_cycle_,再加数据传输时间 - Page Miss:
delay += close_page_cycle + open_page_cycle + data_beats * clock_period
其中 data_beats = ceil(data_len / data_width_)。DramUnit 严格保序:sc_assert(sc_time_stamp() + delay >= last_cmd_.first)。
UMC<256> 是 DramUnit 的封装:using UMC = DdrWrapper1c<UmcFtSocket<BusWidthBits>>。
GDMA 数据通路
GDMA(Global DMA)的实现类是 Tdma(c_model/include/sg2260/tdma.h、c_model/src/sg2260/tdma.cc)。它使用约 22 个 SC_THREAD 建模一条深度流水线化的数据搬运通路。
命令调度
cmd_list_ (sc_attribute<deque<gdma_des_t>>)
|
v
[cmd_dispatch_mth] SC_METHOD, 敏感于 reset_, transfer_done_, tiu_sync_id_, cmd_list_no_empty_
| 检查 cmd_id_dep <= tiu_sync_id_ 后发射
v
[cmd_collect_th] SC_THREAD, 等待命令完成, 更新 tdma_sync_id_
cmd_dispatch_mth 是 GDMA 的入口。它在以下信号变化时触发:
tiu_sync_id_:TIU 完成新指令,可能解除 GDMA 的依赖阻塞transfer_done_:上一条 GDMA 传输完成cmd_list_no_empty_:命令队列非空(check_cmd_list_no_empty每个时钟上升沿检查)
读写分段流水线
GDMA 的核心流水线由以下 SC_THREAD 组成,通过 sc_fifo 连接:
命令分发
|
+---> [rd_cmd_segmentation_th] ---> rcmd_req_fifo_ ---> [rd_tensor_to_fab_th]
| |
| v
| rd_cmd_fifo_ / rd_fab_req_fifo_
| |
| v
+---> [wr_cmd_segmentation_th] ---> wcmd_req_fifo_ ---> [wr_tensor_to_fab_th]
|
v
wr_cmd_fifo_ / wr_fab_req_fifo_
+--- [rd_ca_mux_th] ---+
| |
ca_req_in_fifo_ <--------+ +-------> ca_req_out_fifo_
| |
+--- [wr_ca_mux_th] ---+
|
v
[ca_to_fab_mux_th]
|
+-----------------------------------+----------------------------+
| |
v v
[fab_rrsp_mux_th] [fab_wrsp_mux_th]
| |
v v
fab_rsp_fifo_ fab_rsp_fifo_
| |
v v
[ca_rsp_th] [ca_rsp_th]
| |
v v
rrsp_to_dp_fifo_ wrsp_to_dp_fifo_
| |
v v
[dp_update_rd_th] [dp_update_wr_th]
| |
v v
[fab_to_tensor_th] [transform_datapath_th]
| |
v v
rd_tensor_rsp_fifo_ wr_tensor_rsp_fifo_
| |
v v
[rd_rsp_th] [wr_rsp_th]
| |
+-------> read_path_done_ / write_path_done_ -------> transfer_done_
特殊搬运模式
GDMA 除了标准的读/写分段外,还为特殊数据模式提供专用线程对:
| 模式 | 读线程 | 写线程 |
|---|---|---|
| Gather | gather_rd_idx_cmd_seg_th + gather_rd_data_cmd_seg_th | - |
| Scatter | scatter_rd_idx_cmd_seg_th + scatter_rd_data_cmd_seg_th | scatter_wr_cmd_seg_th |
| Randmask | randmask_rd_cmd_seg_th | randmask_wr_cmd_seg_th |
| Reverse | reverse_rd_cmd_seg_th | reverse_wr_cmd_seg_th |
| Nonzero | nonzero_rd_cmd_seg_th | nonzero_wr_cmd_seg_th |
| Masked Select | masked_sel_rd_mask_cmd_seg_th + masked_sel_rd_data_cmd_seg_th | masked_sel_wr_cmd_seg_th |
缓冲与 Outstanding 控制
GDMA 的关键缓冲区和流控参数:
- 读 Outstanding:
rd_outstanding_(默认 128),通过rd_ost_sema_map_信号量控制 - 写 Outstanding:
wr_outstanding_(默认 128),通过wr_ost_sema_map_信号量控制 - 读缓冲:
rd_buf_ch_[4](4 个Tensor1dChannel:dat/idx/meta/map) - 写缓冲:
wr_buf_ch_(1 个Tensor1dChannel) - CA 缓冲:
ca_req_in_fifo_/ca_rsp_in_fifo_(深度 32) - Fabric 响应:
fab_rsp_fifo_(深度 =rd_outstanding + wr_outstanding)
GDMA 通过两个 Agent 与外部存储交互:
lmem_agt_(LmemAgent):连接到 LMEM(本地 SRAM),1 端口gmem_agt_(GmemAgent):连接到 DDR(通过 SimpleBus),可配置端口数cache_(GsCache):DDR 访问前置缓存
关键数据结构
TIU 指令描述符(TpuCmd)
TpuCmd(spec/base/include/tiu_dma_cmd.h)是所有 TIU 指令的基类:
TpuCmd : BaseCmd
|-- des_cmd_short : bool // 短指令标记 (bit 0)
|-- des_tsk_typ : uint8_t // 任务类型 (bit 41-44, 4 bits)
|-- des_tsk_eu_typ : uint8_t // EU 类型 (bit 45-49, 3~5 bits)
|-- des_cmd_id_dep : uint64_t // 依赖 ID (20 bits)
|-- des_dep_id_en_ : bool // 依赖 ID 使能
|-- cmd_id : uint32_t // 指令 ID (继承自 BaseCmd)
|-- start_time_ : sc_time // 执行开始时间
|-- end_time_ : sc_time // 执行结束时间
|-- alg_ops_ : u64 // 算法级运算量
|-- u_arch_ops_ : u64 // 微架构级运算量
|-- alg_cycle_ : u32 // 算法级 cycle
|-- u_rate_ : float // 利用率
+-- get_des_{res0,opd0,...}_{n,c,h,w}() // NCHW 维度访问器
GDMA 指令描述符(gdma_des_t)
gdma_des_t 定义在 include/gdma_reg_parse.h(由 reg_tdma.h 引用),主要字段包括:
cmd_type_:命令类型(GDMA_TENSOR / GDMA_LOSSY_COMPRESS / GDMA_LOSSY_DECOMPRESS 等)cmd_id/cmd_id_dep_:指令 ID 和依赖 IDreduce_en_/reduce_psum_op_:Reduce 操作使能和操作类型- 源/目标地址、数据长度、stride 等搬运参数
TIU 模块配置(TiuModuleCfg)
TiuModuleCfg(tiu_module_cfg.h)通过 sc_attribute 存储所有架构参数,在仿真启动时从 JSON 配置加载:
| 参数 | 含义 | 访问方法 |
|---|---|---|
lane_num_ | Lane 数量 | get_lane_num() |
bank_num_per_lmem_ | 每个 LMEM 的 Bank 数 | get_bank_num_per_lmem() |
eu_num_vec_ | 向量 EU 数量 | get_eu_num_vec() |
eu_width_lmem_ | EU 宽度 (LMEM 侧) | get_eu_width_lmem() |
cube_ic_{4,8,16,32}bit_ | Cube IC 维度 (按精度) | get_cube_ic_Xbit() |
cube_ohow_{4,8,16,32}bit_ | Cube OHOW 维度 (按精度) | get_cube_ohow_Xbit() |
opa_reuse_num_ | OPA 复用次数 | get_opa_reuse_num() |
psum_h_ / psum_w_ | 部分和 H/W 维度 | get_psum_h/w() |
lmem_size_ | LMEM 总大小 (字节) | get_lmem_size() |
is_mix_bank_size_ | 是否混合 bank 大小 | get_is_mix_bank_size() |
r0_buffer_switch_ | R0 buffer 开关 | get_r0_buffer_switch() |
psum_add_delay_ | Psum 累加延迟 | get_psum_add_delay() |
全局实例 g_tiu_cfg 被所有 DPC 子模块引用。
时钟周期获取
tiu_module_utils.h 中定义了 get_clock_period() 内联函数,通过 Utility::get_tiu_clock_period() 从运行时配置读取 TIU 时钟频率并转换为 sc_time。宏 CLOCK_PERIOD 是其别名。WDC 内部使用三个独立频率:fab1t2 运行在 clk2G_(2GHz),Fabric/CAM 运行在 clk800M_(800MHz),UMC/DramUnit 运行在 clk400M_(400MHz)。