HLS可以用于將C語(yǔ)言函數(shù)轉(zhuǎn)換成硬件模塊。這是一個(gè)革命性的工具,從此軟件人員也可以創(chuàng)建硬件模塊。下面從軟件工程師的角度,介紹使用HLS創(chuàng)建硬件模塊時(shí)的注意事項(xiàng)。為了避免重復(fù),請(qǐng)先閱讀UG871 《Vivado Design Suite Tutorial: High-Level Synthesis》。
進(jìn)行硬件加速,要先準(zhǔn)備好用來生成硬件模塊的函數(shù),它需要保存在一個(gè)單獨(dú)的文件里。在創(chuàng)建工程時(shí),指定它做為頂層函數(shù)。同時(shí)也要準(zhǔn)備一個(gè)實(shí)現(xiàn)相同功能的函數(shù),它不會(huì)被生成硬件模塊,用于驗(yàn)證硬件模塊的功能是否正確。最后還要準(zhǔn)備一個(gè)測(cè)試的main()函數(shù),它分別調(diào)用前面所述的兩個(gè)軟件函數(shù),并比較它們輸出的結(jié)果是否一致。在C語(yǔ)言驗(yàn)證和RTL驗(yàn)證時(shí),HLS工具都會(huì)調(diào)用它。
創(chuàng)建HLS工程的具體步驟,請(qǐng)參考UG871 《Vivado Design Suite Tutorial: High-Level Synthesis》。假設(shè)已經(jīng)創(chuàng)建好HLS工程。下面介紹最基本的約束。
下面是一個(gè)典型的C語(yǔ)言函數(shù)。
long long cmplx_dot_st_1port
(
long long* p_a,
unsigned int ui_vector_length,
unsigned int ui_test_param[2]
)
上面這個(gè)函數(shù)中,p_a是一個(gè)指針,用于存放有用于存儲(chǔ)大量輸入/輸出數(shù)據(jù)。CPU執(zhí)行這個(gè)函數(shù)時(shí),CPU指令會(huì)讀寫其中的數(shù)據(jù)。如果C語(yǔ)言函數(shù)轉(zhuǎn)換成硬件模塊,可以生成AXI Master接口,由硬件模塊自動(dòng)讀取數(shù)據(jù),相當(dāng)于集成了一個(gè)DMA控制器;也可以生成AXI Stream接口,AXI Stream Slave接口接受其它數(shù)據(jù)源生成的數(shù),AXI Stream master接口可以作為數(shù)據(jù)源。指針原來是32位的。為了提高帶寬,這個(gè)函數(shù)中將其改成了64位的指針。下面是為其生成AXI Master接口的約束:
#pragma HLS RESOURCE variable=p_a core=AXI4M
#pragma HLS INTERFACE ap_bus depth=1024 port=p_a
為指p_a生成AXI Stream接口的約束:
#pragma HLS INTERFACE axis port= p_a
ui_vector_length是一個(gè)輸入參數(shù),指定buffer的長(zhǎng)度。轉(zhuǎn)換成硬件模塊后,會(huì)生成一個(gè)可寫的寄存器,可以由AXI Lite總線訪問,由CPU寫入長(zhǎng)度。為輸入?yún)?shù)ui_vector_length生成AXI Lite寄存器的約束:
#pragma HLS RESOURCE variable=ui_vector_length core=AXI4LiteS
HLS為它生成寄存器后,還會(huì)為其生成兩個(gè)函數(shù),用于設(shè)置和讀取。
void XCmplx_dot_st_1port_SetUi_vector_length(XCmplx_dot_st_1port3a *InstancePtr, u32 Data)
u32 XCmplx_dot_st_1port_GetUi_vector_length(XCmplx_dot_st_1port3a *InstancePtr)
ui_test_param[2]是一個(gè)數(shù)組,既可以輸入?yún)?shù)又可以輸出參數(shù)。轉(zhuǎn)換成硬件模塊后,會(huì)生成可讀可寫的寄存器,因此硬件模塊既可以從它得到從CPU輸入的參數(shù),也可以用它向CPU返回?cái)?shù)據(jù)。由于硬件資源限制,這種數(shù)組不能太大。為數(shù)組生成寄存器的約束:
#pragma HLS RESOURCE variable=f_accum_param core=AXI4LiteS
#pragma HLS ARRAY_PARTITION variable=f_accum_param complete dim=1
HLS會(huì)為數(shù)組中每一個(gè)成員創(chuàng)建一個(gè)寄存器,也會(huì)創(chuàng)建對(duì)應(yīng)寄存器的讀寫函數(shù)。
函數(shù)的返回值也需要?jiǎng)?chuàng)建寄存器,這樣CPU讀這個(gè)寄存器就可以得到返回值。為返回值創(chuàng)建寄存器的約束:
#pragma HLS RESOURCE variable=return core=AXI4LiteS
HLS同樣會(huì)為返回值寄存器創(chuàng)建讀寫函數(shù)。
u64 XCmplx_dot_st_1port_GetReturn(XCmplx_dot_st_1port3a *InstancePtr);
如果是用戶自己的函數(shù),雖然參數(shù)個(gè)數(shù)和類型可能都不一樣,都可以參照上述類型做約束。HLS生成的硬件模塊的寄存器都是無符號(hào)32位數(shù)據(jù)。必要的時(shí)候,可以使用C語(yǔ)言的union來做類型轉(zhuǎn)換。
約束好與CPU的接口后,需要考慮性能優(yōu)化。HLS有很多性能優(yōu)化的技巧。但是作為軟件工程師,掌握基本的就可以了?!?pragma HLS DATAFLOW”是一個(gè)很有用的優(yōu)化命令,可以給每個(gè)函數(shù)添加一個(gè)。“#pragma HLS PIPELINE”也是非常有用的優(yōu)化命令,每個(gè)循環(huán)可以添加一個(gè)。這是最簡(jiǎn)單的優(yōu)化,而且比較有效果。
然后就可以綜合C語(yǔ)言的函數(shù),HLS工具會(huì)報(bào)告生成的硬件模塊的性能、資源情況。接下來導(dǎo)出硬件模塊,做成IP,直接在Vivado IP Integrator里使用,做一個(gè)嵌入式系統(tǒng)。這種IP,可以給Zyqn中的ARM使用,也可以給MicroBlaze使用。最后編譯Vivado工程,生成bit文件。
如果要替換原來的C語(yǔ)言函數(shù),還需要為硬件模塊寫驅(qū)動(dòng)。HLS自動(dòng)為每個(gè)輸入輸出參數(shù)生成了讀寫函數(shù)。它還為控制硬件模塊提供了下列控制函數(shù)。
void XCmplx_dot_Start(XCmplx_dot *InstancePtr);
u32 XCmplx_dot_IsDone(XCmplx_dot *InstancePtr);
u32 XCmplx_dot_IsIdle(XCmplx_dot *InstancePtr);
u32 XCmplx_dot_IsReady(XCmplx_dot *InstancePtr);
驅(qū)動(dòng)函數(shù)的實(shí)現(xiàn)挺簡(jiǎn)單。第一步是先調(diào)用XCmplx_dot_IsReady( )函數(shù)檢查硬件狀態(tài)。如果是就緒狀態(tài),則進(jìn)行第二步,調(diào)用輸入?yún)?shù)的寫函數(shù),向硬件模塊寫入輸入?yún)?shù)。第三步則是等待硬件模塊完成運(yùn)算,可以在循環(huán)中調(diào)用XCmplx_dot_IsDone( )函數(shù)檢查。如果完成,則進(jìn)行第四步,讀取運(yùn)算結(jié)果,比如調(diào)用XCmplx_dot_st_1port_GetReturn( ) 函數(shù)讀取返回值;如果結(jié)果在輸出參數(shù)中,則調(diào)用對(duì)應(yīng)參數(shù)的讀取函數(shù)得到結(jié)果。HLS生成的寄存器,都是32位的寄存器。HLS生成的驅(qū)動(dòng),缺省認(rèn)為結(jié)果是無符號(hào)32位數(shù)。如果是其它類型,可以使用指針或者union來做轉(zhuǎn)換。
比如要在64位數(shù)據(jù)、32位浮點(diǎn)數(shù)、32位整型數(shù)據(jù)之間做轉(zhuǎn)換,可以使用下面的數(shù)據(jù)結(jié)構(gòu)
struct u32_cmplx{
unsigned int real;
unsigned int img;
};
union ll_data_u
{
long long ll_data;
struct sp_cmplx cmplx_data;
struct u32_cmplx u32_cmplx_data;
};
從寄存器讀到的數(shù)據(jù),可以保存到u32_cmplx_data.real中;再以cmplx_data.real引用,就是浮點(diǎn)數(shù)。
用CPU做運(yùn)算,CPU的運(yùn)算能力通常是瓶頸。使用HLS生成硬件模塊加速后,運(yùn)算能力大大提高,通常運(yùn)算能力都不再是瓶頸。很多時(shí)候,存儲(chǔ)器和數(shù)據(jù)通道成了瓶頸。一個(gè)優(yōu)化辦法,就是提高數(shù)據(jù)通道的帶寬。C語(yǔ)言里,經(jīng)常用32位的指針。這種情況下,最好改成64bit的指針,可以提高數(shù)據(jù)通道的帶寬,降低運(yùn)算時(shí)間。
評(píng)論
查看更多