本节介绍__NPU_ARCH__版本号为351x的硬件架构和其功能说明。
如下图所示,本架构中AI Core分为AIC和AIV两个独立的核,分别用于矩阵计算和向量计算。AIC核与AIV核配比为1:2。每个核都有自己的Scalar单元,能独立加载自己的代码段。

该架构的关键特点有:
|
SIMT硬件单元名称 |
说明 |
|---|---|
|
SIMT DCache |
SIMT访问GM需要经过SIMT DCache中转,SIMT支持最大128KB Data Cache,Data Cache直接复用UB作为cacheline,SIMT所有对外访存都是以128B为粒度。 |
|
Warp Scheduler |
实现硬件的多线程调度。 每个AIV有4个Warp Scheduler。 |
|
SIMT Register File |
为SIMT应用程序提供的总容量为128KB的超大容量寄存器。每个Thread可用的寄存器数和Thread数量有关,对应关系为:
|
Cube计算单元和Vector计算单元分离部署
本架构中,Cube计算单元和Vector计算单元分别部署在AIC核和AIV核上,每个核都有自己的Scalar单元,能独立加载自己的代码段。
Vector计算单元
Cube计算单元
Scalar单元
获取存储单元的内存空间大小
开发者可以通过平台信息获取接口查询各存储单元的内存空间大小。
各存储单元的最小访问粒度(对齐要求)
|
核 |
存储单元 |
对齐要求 |
|---|---|---|
|
AIV |
Unified Buffer |
32Byte对齐。 |
|
AIC |
L1 Buffer |
32Byte对齐。 |
|
L0A Buffer |
512Byte对齐。 |
|
|
L0B Buffer |
512Byte对齐。 |
|
|
L0C Buffer |
64Byte对齐。 |
|
|
BiasTable Buffer |
64Byte对齐。 |
|
|
Fixpipe Buffer |
64Byte对齐。 |
各存储单元推荐使用的数据排布格式
这些格式针对矩阵乘法等计算密集型任务进行优化,可显著提升计算效率。
存储单元的访问冲突
本NPU架构版本UB结构如下图所示,当多个操作尝试同时访问Unified Buffer同一个bank或者bank group时,可能会发生bank冲突,包括读写冲突、写写冲突、读读冲突,这种冲突会导致访问排队,降低性能。在NPU架构版本220x中,同一个bank group只有一组读口和写口,最多一拍完成一读或者一写,在本NPU架构版本中每个bank group有两组读口和写口,最多同时允许2读0写或者1读1写。相关读写约束如下:
Register寄存器
RegTensor用于存放Reg矢量计算数据, RegTensor位宽为VL(Vector Length,256字节)。
UnalignRegForLoad、UnalignRegForStore用作缓冲区来优化UB和RegTensor之间连续不对齐地址访问的开销。在读不对齐地址前,UnalignRegForLoad、UnalignRegForStore应该通过LoadUnAlignPre API初始化,然后使用LoadUnAlign API。在写不对齐地址时,先使用StoreUnAlign API,再使用StoreUnAlignPost API后处理。
AddrReg即为Address Register(地址寄存器),是用于存储地址偏移量的寄存器。AddrReg应该通过CreateAddrReg初始化,然后在循环之中使用AddrReg存储地址偏移量。AddrReg每层循环中根据所设置的stride进行自增。
搬运时的对齐要求
由于搬运后的数据用于参与数据计算,因此对搬运数据大小有要求,搬运到Unified Buffer的数据大小需要按照DataBlock对齐,其余存储单元的数据搬运必须按分形要求进行搬运。例如,数据从L1 Buffer搬运到L0A Buffer时,数据格式需要从NZ转换为ZN格式,搬运数据的大小要按分形大小对齐,如果L1 Buffer的剩余大小不足1个分形,则硬件执行中会出现异常。
MTE硬通道
支持Fixpipe硬件化加速
Fixpipe是NPU将典型操作进行硬化的加速模块,位于AIC内部,配合Cube计算单元完成随路计算,主要功能如下:
Channel merge支持S8、U8、S4和U4数据类型,而Channel split支持FP32数据类型。
对于转换为S8或U8的目标数据类型,分形矩阵通过硬件从16x16转换为16x32,如果输出通道数N是16的偶数倍,则N方向上每2个相邻的16x16分形矩阵将合并为1个16x32分形矩阵。如果N是16的奇数倍,则将通道1到通道(N–16)合并,最后16个通道保持未合并。
如下所示,目标数据类型为S8,M为32,N为48,首先将前2列16x16分形矩阵合并为一个16x32矩阵,然后将剩余的16x16分形矩阵直接移入L1 Buffer。

对于转换为S4或U4的目标数据类型,分形矩阵通过硬件从16x16转换为16x64,如果输出通道数N是64的倍数,则N方向上每4个相邻的16x16分形矩阵将合并为1个单个的16x64分形矩阵。
例如,这里目标数据类型为S4,M为32,N为64,首先将第1行16x16分形矩阵合并为一个16x64矩阵,然后将第2行16x16分形矩阵也合并。
在这种情况下,N的配置必须是64的倍数。

对于目标类型为FP32,分形矩阵可以通过硬件从16x16转换为16x8,如果使能Channel split,则每个16x16分形矩阵将被分裂为2个16x8分形矩阵。
如下图所示,这里的目标数据类型是FP32,M是64,N是32,它将被拆分为16个16x8的分形。

该架构支持AIC: AIV为1:1和1:2的核间通信,核间通信通过SSBuf进行,这一点和NPU220架构有所不同,NPU220架构中核间通信通过GM来完成。

由于AI Core内部的执行单元(如MTE2搬运单元、Vector计算单元等)以异步并行的方式运行,在读写Local Memory(如Unified Buffer)时可能存在数据依赖关系。为确保数据一致性及计算正确性,需通过同步控制协调操作时序。
以MTE2从GM搬运数据至UB,进行Vector计算单元的Abs计算,再搬运回GM的流程为例,需满足以下同步条件:
同步控制流程如下图所示:

上图中,ID1、ID2、ID3、ID4、ID5、ID6表示事件ID(EventID),每个EventID对应一块存储数据的搬运状态,确保数据操作的正确性和一致性。
例如,SetFlag<HardEvent::S_MTE3>(1)和SetFlag<HardEvent::MTE3_MTE1>(1)设置的不是同一个EventID,因为其模板参数不同。只有当模板参数和事件ID完全一致时,才表示同一个EventID。
当不同核之间操作同一块全局内存时,可能存在读后写、写后读以及写后写等数据依赖问题,需要进行核间同步控制。
核间同步控制分为以下几种模式,如下图所示:

例如,在AIC中将L0C的计算结果搬运到GM后,AIV需要将GM的数据搬运到UB。此时,可以使用CrossCoreSetFlag和CrossCoreWaitFlag命令,确保数据从L0C成功搬运到GM后,再从GM搬运到UB,流程如下图所示。

CrossCoreSetFlag和CrossCoreWaitFlag接口配合使用。使用时需传入核间同步的标记ID(flagId),即上图中的ID1,每个ID对应一个初始值为0的计数器。执行CrossCoreSetFlag后ID对应的计数器增加1;执行CrossCoreWaitFlag时如果对应的计数器数值为0则阻塞不执行;如果对应的计数器大于0,则计数器减一,同时后续指令开始执行。flagId取值范围是0-10。
需要注意以下几点:
CrossCoreSetFlag和CrossCoreWaitFlag必须成对使用,否则可能导致算子超时问题。
CrossCoreSetFlag 的模板参数和flagId必须与CrossCoreWaitFlag完全一致,否则视为不同的flagId。例如,CrossCoreSetFlag<0x0, PIPE_MTE3>(0x8) 和 CrossCoreSetFlag<0x2, PIPE_FIX>(0x8) 设置的不是同一个flagId。
不允许连续设置同一个flagId,以防止计数器状态混乱。
Matmul高阶API内部实现中使用了本接口进行核间同步控制,所以不建议开发者同时使用该接口和Matmul高阶API,否则会有flagId冲突的风险。
同一flagId的计数器最多可以设置15次。
CrossCoreWaitFlag不需要显式设置指令所在的流水类型,默认使用PIPE_S。