ref:
https://www.xilinx.com/html_docs/xilinx2020_2/vitis_doc/yii1603912637443.html
https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug1079-ai-engine-kernel-coding.pdf
https://github.com/Xilinx/Vitis-Tutorials/tree/2021.2/AI_Engine_Development/Feature_Tutorials/07-AI-Engine-Floating-Point/MatMult
1. Overview
2. Intrinsics
https://www.xilinx.com/html_docs/xilinx2020_2/aiengine_intrinsics/intrinsics/index.html
3. Dataflow
两级hierarchy(Data memory (DM)和 寄存器)。 这里假设DMA 已经把操作数搬到Data memory 中。
- 定义寄存器变量
v32int8 chess_storage(wr0) bufA; v8acc8 acc;
- DM <-> vector registers
假设声明了input_window_int8 A,output_window_int8 B,
可以直接用adf 定义好的函数。
window_read_v8(A); window_writeincr(B, srs(acc, shift))
也可以直接用指针
int8_t* i_ptr = (int8_t*)(A->ptr); v32int8 x = *((v32int8 chess_storage(DM_bankA) *restrict)(i_ptr));
- vector registers <-> vector registers
chess_copy();// 拷贝 upd()/concat();// 更新、拼接 acc = mul(XA, XB); // 进计算流水
- accumulator 相关
out: srs();// 舍入到向量寄存器 put_mcd(); // 推给下一个core的acc寄存器 in: mac();// 来自计算输出 ups();// 向量寄存器直接移位 get_scd();// 接收前core推送
4. Synchronization(Locks)
对于Data Memory, kernel code 和DMA都要对其进行读写,就需要同步操作,这里是用硬件锁来控制的。举一个不考虑ping-pong buffer的例子。
4.1 Kernel side
window 用来从软件角度描述一片Data Memory, 这个数据结构会有这片存储的起始地址,长度,绑定的Lock等信息。
kernel 侧是一个while(true) 的死循环,进去以后首先要申请操作数的读锁和结果的写锁,拿到锁以后开始kernel code处理,结束后释放锁。
v4int32 buf0[1]; v4int32 buf1[1]; #define LOCK_0 0 #define LOCK_1 1 #define FOR_WRITE 0 #define FOR_READ 1 int main(){ input_window_pi = window_init(buf0, LOCK_0); output_window_po = window_init(buf1, LOCK_1); while(true){ window_acquire(input_window_pi, FOR_READ); window_acquire(input_window_po, FOR_WRITE); kernel_func(input_window_pi, output_window_po); window_release(input_window_pi, FOR_WRITE); window_release(input_window_po, FOR_READ); } return 0; }
锁的初始值是0, 当程序进到window_acquire 的时候,先检查输入window pi 的锁的值, 发现LOCK_0 的值是0, 而FOR_READ 需要锁的值是1,程序就在这个地方等待。
当DMA 将数据写入Data memory 后,会修改LOCK_0 的值为1, 标识可以读了,kernel 就继续向下执行。
4.2 DMA side
DMA 侧描述一片Data Memory的是buffer descriptor(BD), 一组硬件寄存器,6x32bits。应该包含以下字段: 起始地址,长度,读写Memory的寻址模式(连续读写,跳地址读写),Lock 等。
和kernel侧类似,DMA 开始搬数前需要申请并获得锁,搬数完毕后释放锁。