本(běn)文(wén)摘自(zì)明(míng)德揚学員陳同(tóng)学:https://www.cnblogs.com/moluoqishi/p/9951866.html
一(yī)、前(qián)言
FPGA以(yǐ)擅长高(gāo)速并行數據(jù)处理而(ér)聞名,從有(yǒu)線(xiàn)/无線(xiàn)通(tòng)信(xìn)到(dào)图(tú)像处理中(zhōng)各(gè)種(zhǒng)DSP算法,再到(dào)現(xiàn)今火爆的(de)AI應(yìng)用(yòng),都離不(bù)開(kāi)卷(juǎn)積、濾波(bō)、變(biàn)換等基本(běn)的(de)數学運算。但由(yóu)于(yú)FPGA的(de)硬(yìng)件(jiàn)結構和(hé)開(kāi)發(fà)特(tè)性(xìng)使得其对(duì)很多(duō)算法不(bù)友好(hǎo),之前(qián)本(běn)人(rén)零(líng)散(sàn)地(dì)總(zǒng)結和(hé)轉(zhuǎn)载了(le)些基本(běn)的(de)數学運算在(zài)FPGA中(zhōng)的(de)实現(xiàn)方(fāng)式,今天(tiān)做一(yī)个(gè)系(xì)統的(de)總(zǒng)結歸納。
二(èr)、FPGA中(zhōng)的(de)加減乘除
1.硬(yìng)件(jiàn)資源
Xilinx 7系(xì)列的(de)FPGA中(zhōng)有(yǒu)DSP Slice ,叫做“DSP48E1”这(zhè)一(yī)專用(yòng)硬(yìng)件(jiàn)資源,这(zhè)是(shì)一(yī)个(gè)功能(néng)強(qiáng)大的(de)計(jì)算單元(yuán),單就(jiù)用(yòng)于(yú)基本(běn)運算的(de)部(bù)分(fēn)有(yǒu)加減單元(yuán)和(hé)乘法器。詳見(jiàn)參考文(wén)獻1.
因(yīn)此(cǐ)可(kě)以(yǐ)直(zhí)接用(yòng)HDL語(yǔ)言中(zhōng)的(de)加、減、乘符号(hào)实現(xiàn)變(biàn)量(liàng)與(yǔ)常量(liàng)間(jiān)運算操作以(yǐ)及(jí)變(biàn)量(liàng)與(yǔ)變(biàn)量(liàng)間(jiān)操作。而(ér)四(sì)則運算中(zhōng)的(de)除法沒(méi)有(yǒu)基本(běn)的(de)邏輯計(jì)算單元(yuán)可(kě)以(yǐ)对(duì)應(yìng),因(yīn)此(cǐ)計(jì)算除法需要(yào)調用(yòng)除法器IP核。
2.确認數據(jù)的(de)表(biǎo)示範圍
有(yǒu)符号(hào)數:(補碼)-2^(N-1) ~ 2^(N-1)-1 如(rú)N = 8,則表(biǎo)示範圍是(shì):-128 ~ 127.
无符号(hào)數:0~2^N-1 如(rú)N = 8,則表(biǎo)示範圍是(shì):0~255.
定(dìng)點(diǎn)數:2Q13 範圍是(shì):-4~4-2^(-13) 精度(dù)是(shì):2^(-13)
3.結果(guǒ)有(yǒu)效位宽(kuān)
首先(xiān)讨論結果(guǒ)位宽(kuān)問(wèn)題(tí)。在(zài)FPGA中(zhōng)往往采用(yòng)定(dìng)點(diǎn)運算替代(dài)浮點(diǎn)運算来(lái)降低硬(yìng)件(jiàn)資源占用(yòng)率和(hé)計(jì)算延遲,其中(zhōng)的(de)精髓就(jiù)是(shì)精度(dù)與(yǔ)資源的(de)權衡。若按照保留計(jì)算結果(guǒ)的(de)全(quán)部(bù)精度(dù),N bit數與(yǔ)Mbit數相加結果(guǒ)需要(yào)N+1bit(N>M)。N bit數與(yǔ)M bit數相乘之積需要(yào)N+M bit。而(ér)減法可(kě)以(yǐ)轉(zhuǎn)化(huà)为(wèi)加法,除法則轉(zhuǎn)換为(wèi)乘法和(hé)加減法的(de)組合。如(rú)果(guǒ)操作數是(shì)定(dìng)點(diǎn)小數,則在(zài)滿足以(yǐ)上(shàng)準則的(de)前(qián)提(tí)下(xià),A與(yǔ)B相加(A小數點(diǎn)位數>B小數點(diǎn)位數),結果(guǒ)小數點(diǎn)位數與(yǔ)A相同(tóng);A與(yǔ)B相乘(小數點(diǎn)位數分(fēn)别为(wèi)p和(hé)q),結果(guǒ)小數點(diǎn)位數是(shì)p+q。
4.定(dìng)點(diǎn)運算步驟
然而(ér)(話(huà)鋒一(yī)轉(zhuǎn)),在(zài)大多(duō)數场合下(xià),不(bù)需要(yào)以(yǐ)上(shàng)这(zhè)麼(me)多(duō)位来(lái)保留計(jì)算結果(guǒ),因(yīn)为(wèi)我(wǒ)们(men)在(zài)進(jìn)行數学運算时(shí),已經(jīng)知道(dào)輸入(rù)數據(jù)的(de)大致(zhì)範圍,一(yī)个(gè)數除以(yǐ)1000和(hé)除以(yǐ)1結果(guǒ)數據(jù)所(suǒ)需最(zuì)小位宽(kuān)能(néng)一(yī)樣(yàng)麼(me)?加減運算的(de)操作步驟是(shì)先(xiān)对(duì)齊小數點(diǎn)位數,後(hòu)加減。而(ér)乘法是(shì)先(xiān)計(jì)算後(hòu)取(qǔ)小數點(diǎn)。这(zhè)实際上(shàng)與(yǔ)十(shí)進(jìn)制運算一(yī)致(zhì),我(wǒ)们(men)看(kàn)看(kàn)具體(tǐ)的(de)計(jì)算步驟:
整數之間(jiān)加減以(yǐ)及(jí)乘法的(de)統一(yī)步驟:預估結果(guǒ)位宽(kuān)N --> 按照結果(guǒ)位宽(kuān)擴展(zhǎn)操作數符号(hào)位以(yǐ)防止溢出(chū) --> 運算取(qǔ)低N位。
定(dìng)點(diǎn)小數加減運算步驟:預估結果(guǒ)位宽(kuān)N --> 得到(dào)結果(guǒ)小數點(diǎn)後(hòu)位數 --> 对(duì)齊操作數整數位和(hé)小數位,确定(dìng)擴展(zhǎn)位宽(kuān)M(M≥N) --> 加減運算取(qǔ)低M位。
定(dìng)點(diǎn)小數乘法運算步驟:預估結果(guǒ)位宽(kuān)N --> 得到(dào)結果(guǒ)小數點(diǎn)後(hòu)位數 --> 擴展(zhǎn)操作數位宽(kuān) --> 相乘取(qǔ)低N位
5. 變(biàn)量(liàng)與(yǔ)常量(liàng)運算化(huà)簡
以(yǐ)上(shàng)讨論的(de)均是(shì)两(liǎng)變(biàn)量(liàng)之間(jiān)的(de)運算規則,當然結果(guǒ)位宽(kuān)及(jí)格式準則是(shì)适用(yòng)的(de)。變(biàn)量(liàng)與(yǔ)常量(liàng)的(de)運算的(de)优勢在(zài)于(yú),可(kě)以(yǐ)将乘除法轉(zhuǎn)換成(chéng)加減以(yǐ)及(jí)移位運算实現(xiàn),從而(ér)降低計(jì)算複雜度(dù)和(hé)延遲。當常數項C为(wèi)2的(de)整數次(cì)幂(C = 2^p),則乘C等于(yú)變(biàn)量(liàng)左(zuǒ)移p位,除以(yǐ)C等于(yú)變(biàn)量(liàng)右(yòu)移p位。幾(jǐ)个(gè)在(zài)書(shū)中(zhōng)看(kàn)到(dào)的(de)幾(jǐ)个(gè)簡單示例:A*16 = A <<4 A*20 = A<<4 + A<<2. A除以(yǐ)2 = A >>1 A除以(yǐ)3 = A*(0.25+0.0625+0.0156) = A>>2+A>>4+A>>6 A除以(yǐ)5 = A*(0.125+0.0625+0.0156) = A>>3 + A>>4 + A>>6.其中(zhōng)乘法完全(quán)等價对(duì)應(yìng)的(de)移位相加操作,而(ér)除法的(de)移位代(dài)替会(huì)損失精度(dù)。
三(sān)、如(rú)何計(jì)算特(tè)殊函(hán)數
FPGA內(nèi)部(bù)的(de)DSP Slice可(kě)以(yǐ)直(zhí)接進(jìn)行最(zuì)基本(běn)的(de)加法和(hé)乘法運算,但是(shì)对(duì)于(yú)其他(tā)比如(rú)对(duì)數、指數、三(sān)角(jiǎo)函(hán)數、開(kāi)根(gēn)号(hào)等特(tè)殊函(hán)數就(jiù)无能(néng)为(wèi)力了(le)。这(zhè)时(shí)需要(yào)借(jiè)助算法对(duì)这(zhè)些特(tè)殊函(hán)數進(jìn)行變(biàn)換和(hé)簡化(huà)。FPGA实現(xiàn)複雜函(hán)數的(de)常用(yòng)手(shǒu)段(duàn)一(yī)个(gè)是(shì)級數展(zhǎn)開(kāi),再一(yī)个(gè)就(jiù)是(shì)CORDIC算法。關(guān)于(yú)CORDIC的(de)理論知識和(hé)具體(tǐ)內(nèi)容詳見(jiàn)參考文(wén)獻2,这(zhè)里(lǐ)主(zhǔ)要(yào)闡述CORDIC的(de)IP核調用(yòng)以(yǐ)及(jí)應(yìng)用(yòng)示例。CORDIC算法就(jiù)是(shì)通(tòng)过(guò)一(yī)定(dìng)的(de)手(shǒu)段(duàn),将很多(duō)複雜的(de)特(tè)殊函(hán)數變(biàn)为(wèi)相加移位運算,这(zhè)一(yī)點(diǎn)对(duì)于(yú)硬(yìng)件(jiàn)芯片(piàn)实現(xiàn)来(lái)说(shuō)非(fēi)常友好(hǎo)。CORDIC分(fēn)为(wèi)旋轉(zhuǎn)模式和(hé)矢量(liàng)模式,配合圆(yuán)周坐标(biāo)、線(xiàn)性(xìng)坐标(biāo)和(hé)双(shuāng)曲(qū)線(xiàn)坐标(biāo)会(huì)有(yǒu)六(liù)種(zhǒng)組合,具體(tǐ)見(jiàn)下(xià)表(biǎo):
從表(biǎo)中(zhōng)發(fà)現(xiàn),基本(běn)的(de)乘除法、三(sān)角(jiǎo)函(hán)數、反(fǎn)三(sān)角(jiǎo)函(hán)數、双(shuāng)曲(qū)函(hán)數、反(fǎn)双(shuāng)曲(qū)函(hán)數、開(kāi)根(gēn)号(hào)都能(néng)够直(zhí)接求得,那(nà)其他(tā)函(hán)數怎麼(me)辦(bàn)?
常見(jiàn)的(de)函(hán)數計(jì)算需求基本(běn)都能(néng)滿足,虽上(shàng)述變(biàn)換式对(duì)自(zì)變(biàn)量(liàng)定(dìng)義域有(yǒu)限制,但同(tóng)樣(yàng)可(kě)以(yǐ)分(fēn)析輸入(rù)數據(jù)的(de)取(qǔ)值範圍并利用(yòng)簡單的(de)數学變(biàn)換得到(dào)想(xiǎng)要(yào)的(de)結果(guǒ)。Xilinx同(tóng)时(shí)提(tí)供了(le)浮點(diǎn)IP核以(yǐ)及(jí)CORDIC IP核,前(qián)者(zhě)調用(yòng)簡單但占用(yòng)資源大,延遲高(gāo),因(yīn)此(cǐ)利用(yòng)CORDIC算法計(jì)算函(hán)數是(shì)个(gè)較好(hǎo)的(de)選擇。
四(sì)、CORDIC計(jì)算e^x Demo
1. 算法仿真(zhēn)分(fēn)析
要(yào)計(jì)算e^x數值需要(yào)讓CORDIC工作在(zài)双(shuāng)曲(qū)坐标(biāo)的(de)旋轉(zhuǎn)模式下(xià),通(tòng)过(guò)e^x = sinhx+coshx關(guān)系(xì)式間(jiān)接求得。首先(xiān)看(kàn)下(xià)sinh和(hé)cosh函(hán)數的(de)曲(qū)線(xiàn),有(yǒu)个(gè)直(zhí)观認識。
我(wǒ)们(men)用(yòng)MATLAB毫(háo)不(bù)費力地(dì)验(yàn)證一(yī)下(xià)公式正(zhèng)确性(xìng):
在(zài)設計(jì)後(hòu)也(yě)同(tóng)樣(yàng)要(yào)借(jiè)助MATLAB進(jìn)行仿真(zhēn)验(yàn)證。
2. CORDIC IP核
現(xiàn)在(zài)通(tòng)过(guò)查看(kàn)user guide得知CORDIC IP核的(de)接口(kǒu)及(jí)主(zhǔ)要(yào)特(tè)性(xìng)。
接口(kǒu)包(bāo)括輸入(rù)笛卡(kǎ)爾數據(jù)輸入(rù)通(tòng)道(dào)、相位輸入(rù)通(tòng)道(dào)、全(quán)局(jú)信(xìn)号(hào)以(yǐ)及(jí)數據(jù)輸出(chū)通(tòng)道(dào)。該IP核有(yǒu)两(liǎng)種(zhǒng)結構:串行和(hé)并行,可(kě)根(gēn)據(jù)數據(jù)吞吐量(liàng)需求選擇,并行結構可(kě)以(yǐ)每个(gè)时(shí)鐘(zhōng)輸出(chū)一(yī)个(gè)計(jì)算結果(guǒ)。如(rú)果(guǒ)計(jì)算sinh和(hé)cosh,要(yào)向(xiàng)phase通(tòng)道(dào)輸入(rù)相位信(xìn)息,X_OUT是(shì)cosh(phase),Y_OUT是(shì)sinh(phase).輸入(rù)phase必須滿足數據(jù)範圍,否則出(chū)現(xiàn)不(bù)可(kě)預計(jì)結果(guǒ)。輸出(chū)幀結構及(jí)數據(jù)範圍如(rú)下(xià):
其中(zhōng)輸入(rù)數據(jù)格式为(wèi)2QN,輸出(chū)則是(shì)1QN。由(yóu)于(yú)均是(shì)有(yǒu)符号(hào)數,也(yě)就(jiù)是(shì)輸入(rù)整數部(bù)分(fēn)3bit,輸出(chū)整數部(bù)分(fēn)2bit。接下(xià)来(lái)对(duì)IP核進(jìn)行配置,重(zhòng)點(diǎn)是(shì)第(dì)一(yī)页(yè),此(cǐ)处将其配置为(wèi)計(jì)算sinh和(hé)cosh模式,采用(yòng)并行优化(huà)的(de)流水(shuǐ)線(xiàn)結構。相位以(yǐ)角(jiǎo)度(dù)为(wèi)單位,輸入(rù)輸出(chū)位宽(kuān)設置成(chéng)16bit。
3.HDL代(dài)碼設計(jì)及(jí)仿真(zhēn)验(yàn)證
設計(jì)代(dài)碼:
module cordic_ex#(parameter DIN_W = 16,
DOUT_W = 16)
(
input clk,
input [DIN_W-1:0] din,//2Q13
input din_vld,
output reg [DOUT_W+1-1:0] dout = 0,//2Q14
output reg dout_vld = 0
);
wire [DOUT_W*2-1 : 0] m_axis_dout_tdata;
wire m_axis_dout_tvalid;
wire signed [DOUT_W-1:0] sinh,cosh;
// ex = sinhx + coshx <1Q14+1Q14 = 2Q14>
always @(posedge clk)begin
dout <= sinh + cosh;
end
assign sinh = m_axis_dout_tdata[DOUT_W*2-1 -:DOUT_W];
assign cosh = m_axis_dout_tdata[DOUT_W-1 -:DOUT_W];
always @(posedge clk)begin
if(m_axis_dout_tvalid)begin
dout_vld <= 1'b1;
end
else
dout_vld <= 0;
end
cordic_0 cordic_cosh_sinh (
.aclk(clk), // input wire aclk
.s_axis_phase_tvalid(din_vld), // input wire s_axis_phase_tvalid
.s_axis_phase_tdata(din), // input wire [15 : 0] s_axis_phase_tdata
.m_axis_dout_tvalid(m_axis_dout_tvalid), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata(m_axis_dout_tdata) // output wire [31 : 0] m_axis_dout_tdata
);
endmodule
cordic_ex
用(yòng)MATLAB産生(shēng)两(liǎng)組數據(jù),并将角(jiǎo)度(dù)值定(dìng)點(diǎn)化(huà)後(hòu)作为(wèi)設計(jì)模块(kuài)數據(jù)激勵:
testbench:
module cordic_ex_tb();
parameter CYC = 20;
reg clk;
reg [16-1:0] din;
reg din_vld;
wire signed [17-1:0] dout;
wire dout_vld;
cordic_ex#(.DIN_W(16),
.DOUT_W(16))
uut(
.clk (clk) ,
.din (din) ,//2Q13
.din_vld (din_vld) ,
.dout (dout) ,//2Q14
.dout_vld (dout_vld)
);
initial begin
clk = 1;
forever #(CYC/2) clk = ~clk;
end
initial begin
#1;
din = 0;
din_vld = 0;
#(CYC*10);
din_vld = 1;
din = 16'b0001010000011011;//pi * 1/5
#(CYC*1);
din = 16'b1110011011011110;//-pi * 1/4
#5;
$stop;
end
endmodule
cordic_ex_tb
仿真(zhēn)結果(guǒ):
仿真(zhēn)波(bō)形表(biǎo)明(míng),計(jì)算結果(guǒ)與(yǔ)MATLAB浮點(diǎn)運算相近(jìn),滿足一(yī)般計(jì)算需求。若想(xiǎng)提(tí)高(gāo)精度(dù),可(kě)以(yǐ)增加CORDIC輸出(chū)數據(jù)位宽(kuān)。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~















