FPGA 非常適合進(jìn)行數(shù)學(xué)運(yùn)算,但是需要一點(diǎn)技巧,所以我們今天就看看如何在 FPGA 中進(jìn)行簡(jiǎn)單和復(fù)雜的數(shù)學(xué)運(yùn)算。
介紹
由于FPGA可以對(duì)算法進(jìn)行并行化,所以FPGA 非常適合在可編程邏輯中實(shí)現(xiàn)數(shù)學(xué)運(yùn)算。我們可以在 FPGA 中使用數(shù)學(xué)來(lái)實(shí)現(xiàn)信號(hào)處理、儀器儀表、圖像處理和控制算法等一系列應(yīng)用。這意味著 FPGA 可用于從自動(dòng)駕駛汽車圖像處理到雷達(dá)和飛機(jī)飛行控制系統(tǒng)的一系列應(yīng)用。
因?yàn)?FPGA 寄存器豐富并且包含專用乘法器累加器 (DSP48) 等功能,所以在 FPGA 中實(shí)現(xiàn)數(shù)學(xué)運(yùn)算需要一些技巧。
這使它們成為實(shí)現(xiàn)定點(diǎn)數(shù)學(xué)運(yùn)算的理想選擇,但是這與我們傾向于使用的浮點(diǎn)運(yùn)算不同,因此在進(jìn)行浮點(diǎn)運(yùn)算時(shí)候我們需要一點(diǎn)技巧。
定點(diǎn)數(shù)學(xué)運(yùn)算
定點(diǎn)數(shù)的小數(shù)點(diǎn)位于向量中的固定位置。小數(shù)點(diǎn)左邊是整數(shù)元素,小數(shù)點(diǎn)右邊是小數(shù)元素。這意味著我們可能需要使用多個(gè)寄存器來(lái)準(zhǔn)確量化數(shù)字。幸運(yùn)的是 FPGA 中的寄存器通常很多。
相比之下,浮點(diǎn)數(shù)可以存儲(chǔ)比固定寄存器寬度(例如,32 位)寬得多的范圍。寄存器的格式分為符號(hào)、指數(shù)和尾數(shù),小數(shù)點(diǎn)可以浮動(dòng),因此直接使用 32 位寄存器時(shí),其能表達(dá)的值遠(yuǎn)遠(yuǎn)超過(guò) 2^32-1。
然而,在可編程邏輯中實(shí)現(xiàn)定點(diǎn)數(shù)學(xué)運(yùn)算有幾個(gè)優(yōu)點(diǎn),而且實(shí)現(xiàn)起來(lái)要簡(jiǎn)單得多。由于定點(diǎn)解決方案使用的資源顯著減少,因此可以更輕松地進(jìn)行布線,從而提高性能,因此在邏輯中進(jìn)行定點(diǎn)數(shù)學(xué)運(yùn)算時(shí)可以實(shí)現(xiàn)更快的解決方案。
需要注意的一點(diǎn)是,在處理定點(diǎn)數(shù)學(xué)運(yùn)算時(shí)會(huì)使用一些規(guī)則和術(shù)語(yǔ)。第一個(gè)也是最重要的問(wèn)題之一是工程師如何描述向量中小數(shù)點(diǎn)的位置。最常用的格式之一是 Q 格式(長(zhǎng)格式的量化格式)。Q 格式表示為 Qx,其中 x 是數(shù)字中小數(shù)位數(shù)。例如,Q8 表示小數(shù)點(diǎn)位于第 8 和第 9 個(gè)寄存器之間。
我們?nèi)绾未_定必要的小數(shù)元素的數(shù)量取決于所需的精度。例如,如果我們想使用 Q 格式存儲(chǔ)數(shù)字 1.4530986319x10^-4,我們需要確定所需的小數(shù)位數(shù)。
如果我們想使用 16 個(gè)小數(shù)位,我們將數(shù)字乘以 63356 (2^16),結(jié)果將是 9.523023。這個(gè)值可以很容易地存儲(chǔ)在寄存器中;然而,它的精度不是很好,因?yàn)槲覀儾荒艽鎯?chǔ)小數(shù)元素,所以因?yàn)?.523023≈9, 9/65536 = 1.37329101563x10^-4。這會(huì)導(dǎo)致準(zhǔn)確性下降,從而可能影響最終結(jié)果。
我們可以使用 28 個(gè)小數(shù)位,而不是使用 16 個(gè)小數(shù)位,結(jié)果就是 39006(1.4530986319x10^-4 x 2^28) 的值存儲(chǔ)在小數(shù)寄存器中。這給出了更準(zhǔn)確的量化結(jié)果。
了解了量化的基礎(chǔ)知識(shí)后,下一步就是了解有關(guān)數(shù)學(xué)運(yùn)算小數(shù)點(diǎn)對(duì)齊的規(guī)則。如果我們執(zhí)行運(yùn)算操作但是小數(shù)點(diǎn)沒(méi)有對(duì)齊,我們就不會(huì)得到正確的結(jié)果。
加法——小數(shù)點(diǎn)必須對(duì)齊
減法——小數(shù)點(diǎn)必須對(duì)齊
除法——小數(shù)點(diǎn)必須對(duì)齊
乘法——小數(shù)點(diǎn)不需要對(duì)齊
我們還需要考慮操作對(duì)結(jié)果向量的影響。不考慮結(jié)果的大小可能會(huì)導(dǎo)致溢出。下表顯示了結(jié)果大小調(diào)整的規(guī)則。
假設(shè)我們有兩個(gè)向量(一個(gè) 16 位,另一個(gè) 8 位),在進(jìn)行運(yùn)算的時(shí)候?qū)⒊霈F(xiàn)以下情況:
C(16 ?downto ?0)= A(15 ?downto ?0)+ B(7 ?downto ?0)
C(16 ?downto ?0)= A(15 ?downto ?0)- B(7 ?downto ?0)
C(22 ?downto ?0)= A(15 ?downto ?0)* B(7 ?downto ?0)
C(8 ?downto -1)= A(15 ?downto 0)/ B(7 ?downto 0)
做除法時(shí)的 -1 ,反映了小數(shù)元素的寄存器大小的增加。根據(jù)所使用的類型,如果使用 VHDL 定點(diǎn)包,這可能是 8 到 -1,如果使用 Q1 時(shí)可能是 9 到 0。
關(guān)于除法的最后一點(diǎn)說(shuō)明它可能會(huì)占用大量資源,因此通常最好盡可能使用移位實(shí)現(xiàn)除法運(yùn)算。
簡(jiǎn)單算法
現(xiàn)在我們了解了定點(diǎn)數(shù)學(xué)的規(guī)則,讓我們來(lái)看看我們?nèi)绾文軌驅(qū)崿F(xiàn)一個(gè)簡(jiǎn)單的算法。在這種情況下,我們將實(shí)現(xiàn)一個(gè)簡(jiǎn)單的滑動(dòng)平均(exponential moving average)函數(shù)。
要開始使用此應(yīng)用程序,我們需要先打開一個(gè)新的 Vivado 項(xiàng)目并添加兩個(gè)文件。第一個(gè)文件是源文件,第二個(gè)文件是測(cè)試文件。
?
library?IEEE; use?IEEE.STD_LOGIC_1164.ALL; --library?ieee_proposed; use?ieee.fixed_pkg.all; entity?math_example?is?port( ?clk?:?in?std_logic; ?rst?:?in?std_logic; ? ?ip_val?:?in?std_logic; ?ip?:?in?std_logic_vector(7?downto?0); ? ?op_val?:?out?std_logic; ?op?:?out?std_logic_vector(7?downto?0)); end?math_example; architecture?Behavioral?of?math_example?is constant?divider?:?ufixed(-1?downto?-16):=?to_ufixed(?0.1,?-1,-16?)?;? signal?accumulator?:?ufixed(11?downto?0)?:=?(others?=>?'0'); signal?average?:?ufixed(11?downto?-16?)?:=?(others?=>?'0'); begin acumm?:?process(rst,clk) begin ? ?if?rising_edge(clk)?then? ????if?rst?=?'1'?then? ????????accumulator?<=?(others?=>?'0'); ????????average?<=?(others?=>?'0'); ????elsif?ip_val?=?'1'?then? ????????accumulator?<=?resize?(arg?=>?(accumulator?+?to_ufixed(ip,7,0)-average(11?downto?0)),?size_res?=>?accumulator); ????????average?<=?accumulator?*?divider; ????end?if; ?end?if; end?process; op?<=?to_slv(average(7?downto?0)); end?Behavioral;
?
測(cè)試文件如下所示:
?
library?IEEE; use?IEEE.STD_LOGIC_1164.ALL; use?ieee.numeric_std.all; entity?tb_math?is --??Port?(?); end?tb_math; architecture?Behavioral?of?tb_math?is component?math_example?is?port( ?clk?:?in?std_logic; ?rst?:?in?std_logic; ? ?ip_val?:?in?std_logic; ?ip?:?in?std_logic_vector(7?downto?0); ? ?op_val?:?out?std_logic; ?op?:?out?std_logic_vector(7?downto?0)); end?component?math_example; type?input?is?array(0?to?59)?of?integer?range?0?to?255; signal?stim_array?:?input?:=?(70,71,69,67,65,68,69,66,65,72,70,69,67,65,70,64,69,65,68,64,69,70,72,68,65,72,69,67,67,68,70,71,69,67,65,68,69,66,65,72,70,69,67,65,70,64,69,65,68,64,69,70,72,68,65,72,69,67,67,68); constant?clk_period?:?time?:=?100?ns; signal?clk?:?std_logic?:=?'0'; signal?rst?:??std_logic:='0'; signal?ip_val?:??std_logic?:='0'; signal?ip?:??std_logic_vector(7?downto?0):=(others=>'0'); signal?op_val?:??std_logic?:='0'; signal?op?:?std_logic_vector(7?downto?0):=(others=>'0'); begin clk_gen?:?clk?<=?not?clk?after?(clk_period/2); uut:?math_example?port?map(clk,?rst,?ip_val,?ip,?op_val,?op); stim?:?process begin? ?rst?<=?'1'?; ?wait?for?1?us; ?rst?<=?'0'; ?wait?for?clk_period; ?wait?until?rising_edge(clk); ?for?i?in?0?to?59?loop ??wait?until?rising_edge(clk); ??ip_val?<=?'1'; ??ip?<=?std_logic_vector(to_unsigned(stim_array(i),8)); ??wait?until?rising_edge(clk); ??ip_val?<=?'0'; ?end?loop; ?wait?for?1?us; ?report?"simulation?complete"?severity?failure; end?process; ? end?Behavioral;
?
這些文件利用了 VHDL 2008 包文件。
讓我們一步一步地看一下這些文件以及它們?cè)谧鍪裁矗?/p>
Clock - 模塊的同步時(shí)鐘
Reset - 將模塊復(fù)位為已知狀態(tài)
Input Valid (op_val) - 這表示新的輸入值可用于計(jì)算
ip = 8 bit (7 downto 0) - 輸入平均值
Output Valid (in_val) - 這表示計(jì)算后的值可用
op = 8 bit (7 downto 0) - 輸出平均值
?
entity?math_example?is?port( ?clk?:?in?std_logic; ?rst?:?in?std_logic; ? ?ip_val?:?in?std_logic; ?ip?:?in?std_logic_vector(7?downto?0); ? ?op_val?:?out?std_logic; ?op?:?out?std_logic_vector(7?downto?0)); end?math_example;
?
我們架構(gòu)的第一部分是除法器,它是一個(gè)常數(shù)。它被定義為無(wú)符號(hào)定點(diǎn)類型 (ufixed),因?yàn)槲覀兪褂玫氖菬o(wú)符號(hào)數(shù)。這是完全小數(shù),沒(méi)有整數(shù)位,所以我們將它定義為從 -1 到 -16。
?
constant?divider?:?ufixed(-1?downto?-16):=?to_ufixed(?0.1,?-1,-16?)?;?
?
精度可以通過(guò)以下方式確定:
0.1 x 2^16 = 6553.6
6553/2^16 = 0.999 = 99.9% 準(zhǔn)確度
To_ufixed (0.1, -1, -16)
0.1 -我們要轉(zhuǎn)換的值
-1 -數(shù)組的上限
-16 -數(shù)組的下界
信號(hào)累加器 - 存儲(chǔ)我們的值
初始化為0進(jìn)行仿真
最多可以累加 10 個(gè) 8 位值。
如果所有 10 個(gè) 8 位數(shù)字都達(dá)到其最大計(jì)數(shù) (max = 255) 并將它們加在一起,我們將需要一個(gè) 12 位數(shù)字,因此我們將 ufixed 定義為 (11 downto 0)。
我們只存儲(chǔ)整數(shù)位,沒(méi)有小數(shù)位。
?
signal?accumulator?:?ufixed(11?downto?0)?:=?(others?=>?'0');
?
信號(hào)平均值-輸出值
初始化為0進(jìn)行仿真
12 位數(shù)字(整數(shù))乘以 0.1(我們的分頻器數(shù)字),結(jié)果為 -16。這給了我們 11 downto -16 的范圍。
?
signal?average?:?ufixed(11?downto?-16?)?:=?(others?=>?'0');
?
讓我們繼續(xù)看代碼——有一個(gè)同步復(fù)位的進(jìn)程。在使用 AMD FPGA時(shí),我們應(yīng)該使用同步復(fù)位。
如果對(duì)模塊進(jìn)行復(fù)位,那么將會(huì)對(duì)所有內(nèi)容設(shè)置為零。
?
if?rising_edge(clk)?then? ????if?rst?=?'1'?then? ????????accumulator?<=?(others?=>?'0'); ????????average?<=?(others?=>?'0');
?
如果復(fù)位信號(hào)為“0”,則在時(shí)鐘的上升沿并且輸入有效 (ip_val) = 1,進(jìn)行以下操作:
將獲取輸入值(作為標(biāo)準(zhǔn)邏輯向量出現(xiàn)),將其添加到當(dāng)前累加器值
To_ufixed (ip, 7, 0) - VHDL 會(huì)將值從標(biāo)準(zhǔn)邏輯向量轉(zhuǎn)換為無(wú)符號(hào)定點(diǎn)
然后,因?yàn)樗腔瑒?dòng)平均值,將從累加器中減去之前的平均值
?
elsif?ip_val?=?'1'?then? ????????accumulator?<=?resize?(arg?=>?(accumulator?+?to_ufixed(ip,7,0)-average(11?downto?0)),?size_res?=>?accumulator);
?
完成累加后,我們將累加器的值乘以"除法器"(乘法器實(shí)現(xiàn)的除法器)
?
average?<=?accumulator?*?divider;
?
最后我們輸出結(jié)果縮放平均值
?
op?<=?to_slv(average(7?downto?0));
?
仿真結(jié)果如下:
上面就簡(jiǎn)單介紹了一個(gè)簡(jiǎn)單的運(yùn)算系統(tǒng),該系統(tǒng)使用加法、減法和乘法代替除法。
然而,我們可能會(huì)面臨需要在 FPGA 中實(shí)現(xiàn)的更復(fù)雜的數(shù)學(xué)運(yùn)算。
復(fù)雜算法
更復(fù)雜的算法可能具有挑戰(zhàn)性,例如用于將 PRT 電阻轉(zhuǎn)換為溫度的 Callendar-Van Dusen 方程:
上面的公式,簡(jiǎn)單的運(yùn)算我們知道怎么實(shí)現(xiàn),但是平方根是一個(gè)新的運(yùn)算,我們可以使用 CORDIC 算法實(shí)現(xiàn)平方根。
上面說(shuō)的很簡(jiǎn)單,但是實(shí)施起來(lái)卻很復(fù)雜,并且驗(yàn)證過(guò)程中要捕獲所有極端情況會(huì)很耗時(shí)。
如果我們?cè)诟信d趣的溫度范圍內(nèi)繪制方程,我們可以采用更好的方法-使用多項(xiàng)式近似方式。
我們可以從此圖中提取趨勢(shì)線:
在 FPGA 中實(shí)現(xiàn)這個(gè)多項(xiàng)式方程比實(shí)現(xiàn)上面所示的復(fù)雜方程要容易得多。
我們需要做的第一件事是量化參數(shù),為此,我們需要使用 Excel (MatLab也行)進(jìn)行相關(guān)的數(shù)據(jù)處理。
通過(guò)上面的表格計(jì)算出量化參數(shù),接下來(lái)就可以使用HDL實(shí)現(xiàn)算法。這次我們將使用二進(jìn)制補(bǔ)碼的符號(hào)數(shù)字進(jìn)行運(yùn)算。
完整的實(shí)現(xiàn)如下所示
?
library?IEEE; use?IEEE.STD_LOGIC_1164.ALL; use?ieee.fixed_pkg.all; entity?complex_example?is?port( clk?:?in?std_logic;? ip_val?:?in?std_logic; ip?????:?in?std_logic_vector(7?downto?0); op_val?:?out?std_logic; op?????:?out?std_logic_vector(8?downto?0)); end?complex_example; architecture?Behavioral?of?complex_example?is type?fsm?is?(idle,?powers,?sum,?result); signal?current_state?:?fsm?:=?idle; signal?power_a?:?sfixed(35?downto?0):=(others=>'0'); signal?power_b?:?sfixed(26?downto?0):=(others=>'0'); signal?power_c?:?sfixed(17?downto?0):=(others=>'0'); signal?calc??:?sfixed(49?downto?-32)?:=(others=>'0'); signal?store?:?sfixed(8?downto?0)?:=?(others?=>'0'); constant?a?:?sfixed(9?downto?-32):=?to_sfixed(?2.00E-09,?9,-32?);? constant?b?:?sfixed(9?downto?-32):=?to_sfixed(?4.00E-07,?9,-32?); constant?c?:?sfixed(9?downto?-32):=?to_sfixed(?0.0011,?9,-32?);? constant?d?:?sfixed(9?downto?-32):=?to_sfixed(?2.403,?9,-32?);? constant?e?:?sfixed(9?downto?-32):=?to_sfixed(?251.26,?9,-32?);? begin cvd?:?process(clk) begin? ?if?rising_edge(clk)?then? ??op_val?<='0'; ??case?current_state?is? ???when?idle?=>? ????if?ip_val?=?'1'?then? ?????store?<=?to_sfixed('0'&ip,store); ?????current_state?<=?powers; ????end?if; ???when?powers?=> ????power_a?<=?store?*?store?*?store?*?store; ????power_b?<=?store?*?store?*?store; ????power_c?<=?store?*?store; ????current_state?<=?sum; ???when?sum?=> ????calc?<=?(power_a*a)?-?(power_b?*?b)?+?(power_c?*?c)?+?(store?*?d)?-?e; ????current_state?<=?result; ???when?result?=> ????current_state?<=?idle; ????op?<=?to_slv(calc(8?downto?0)); ????op_val?<='1'; ???end?case; ??end?if; end?process; end?Behavioral;
?
加下來(lái)我們簡(jiǎn)單介紹下代碼:
時(shí)鐘 (clk) - 驅(qū)動(dòng)模塊的主時(shí)鐘
Input Valid (ip_val) 和 Input (ip) - 表示我們?cè)?8 位輸入上有有效數(shù)據(jù)(7 downto 0)
Output Valid (op_val) 和 Output (op) ?- 一旦我們運(yùn)行了我們的算法,我們輸出一個(gè) 9 位數(shù)(8 downto 0)
?
entity?complex_example?is?port( clk?:?in?std_logic;? ip_val?:?in?std_logic; ip?????:?in?std_logic_vector(7?downto?0); op_val?:?out?std_logic; op?????:?out?std_logic_vector(8?downto?0)); end?complex_example;
?
接下來(lái)我們做的是為狀態(tài)機(jī)定義狀態(tài),狀態(tài)機(jī)中有 4 個(gè)狀態(tài):
Idle- 從第一個(gè)狀態(tài)開始等待輸入有效
Powers- 計(jì)算
Sum - 將所有的算子相加
Result- 將結(jié)果傳遞給下游模塊
?
type?fsm?is?(idle,?powers,?sum,?result);
?
在類型聲明之后是我們?cè)谠O(shè)計(jì)中使用的信號(hào)
計(jì)算出的信號(hào) a-c 當(dāng)它們?cè)谒惴ㄖ斜惶嵘礁髯缘膬鐣r(shí)。
用于存儲(chǔ)每個(gè)結(jié)果的位數(shù)取決于輸入的大小和它們的冪次。首先要做的是將 8 位無(wú)符號(hào)數(shù)轉(zhuǎn)換為 9 位有符號(hào)數(shù)。然后對(duì)于 power_a,生成的向量大小是四次九位向量乘法,這意味著一個(gè) 36 位向量。對(duì)于 power_b,這是三個(gè)九位向量乘法等等。
?
signal?power_a?:?sfixed(35?downto?0):=(others=>'0'); signal?power_b?:?sfixed(26?downto?0):=(others=>'0'); signal?power_c?:?sfixed(17?downto?0):=(others=>'0');
?
計(jì)算結(jié)果-輸出值的計(jì)算結(jié)果位寬 -49 downto -32
Signal Store - 轉(zhuǎn)換為有符號(hào)數(shù)時(shí)我們存儲(chǔ)輸入的轉(zhuǎn)換
我們的輸入被轉(zhuǎn)換成什么。
這是一個(gè) 9 位存儲(chǔ),代表 8 位加上一個(gè)符號(hào)位來(lái)組成 9 位
實(shí)際輸入永遠(yuǎn)不會(huì)是負(fù)數(shù),因?yàn)檩斎氪硪粋€(gè)大約在 70 歐姆到幾百歐姆之間的電阻值
?
signal?calc??:?sfixed(49?downto?-32)?:=(others=>'0'); signal?store?:?sfixed(8?downto?0)?:=?(others?=>'0');
?
常數(shù) ae - 先前在 excel 中使用 Callendar-Van Dusen 方程計(jì)算的系數(shù)
to_sfixed 中的第一個(gè)值是電子表格中的值
第二個(gè)值是我們存儲(chǔ)值的整數(shù)位數(shù)。在本例中它是 9 位,因?yàn)槌A啃枰_(dá)到 251.26 的值
第三個(gè)值是我們將使用的小數(shù)位數(shù),它是 -32,由 2.00E-09 的最低常量值決定。定義小數(shù)位數(shù)是我們有效計(jì)算量化的地方
?
constant?a?:?sfixed(9?downto?-32):=?to_sfixed(?2.00E-09,?9,-32?);? constant?b?:?sfixed(9?downto?-32):=?to_sfixed(?4.00E-07,?9,-32?); constant?c?:?sfixed(9?downto?-32):=?to_sfixed(?0.0011,?9,-32?);? constant?d?:?sfixed(9?downto?-32):=?to_sfixed(?2.403,?9,-32?);? constant?e?:?sfixed(9?downto?-32):=?to_sfixed(?251.26,?9,-32?);?
?
在時(shí)鐘的上升沿,該過(guò)程將被執(zhí)行。op_val 是默認(rèn)賦值,除非在流程的其他地方將其設(shè)置為“1”,否則它將始終為“0”輸出。在進(jìn)程中,信號(hào)被分配最后一個(gè)分配給它們的值,默認(rèn)分配使代碼更具可讀性。
Idle狀態(tài) -如果一個(gè)值進(jìn)來(lái)(ip_val) = 1,那么
我們將值加載到存儲(chǔ)寄存器并將符號(hào)位設(shè)置為 0 (指示正數(shù))
然后狀態(tài)機(jī)進(jìn)入Power狀態(tài)。
?
if?ip_val?=?'1'?then? ?????store?<=?to_sfixed('0'&ip,store); ?????current_state?<=?powers; end?if;
?
Power 狀態(tài)- 在Power狀態(tài)下,我們計(jì)算三個(gè)冪運(yùn)算,然后進(jìn)入求和狀態(tài)。
Power a - 將存儲(chǔ)的值乘以自身 4 次。Power b - 將存儲(chǔ)的值乘以自身 3 倍Power c - 將存儲(chǔ)的值乘以自身 2 倍
?
when?powers?=> ????power_a?<=?store?*?store?*?store?*?store; ????power_b?<=?store?*?store?*?store; ????power_c?<=?store?*?store; ????current_state?<=?sum;
?
Sum狀態(tài)——這是我們將所有值輸入 excel 圖表的多項(xiàng)式近似值并進(jìn)行加法和減法以獲得最終輸出值的地方。
請(qǐng)注意,無(wú)論我們的數(shù)字有多大,上面定義的常量都將小數(shù)點(diǎn)對(duì)齊到 -32 位,這對(duì)于計(jì)算總和很重要。
?
?calc?<=?(power_a*a)?-?(power_b?*?b)?+?(power_c?*?c)?+?(store?*?d)?-?e; ?current_state?<=?result;
?
Results狀態(tài)- 此處我們采用最終值(并將其作為標(biāo)準(zhǔn)邏輯向量放入輸出中。斷言 Op_val 表示存在新的輸出值)。
下面的仿真文件用來(lái)仿真這次的算法核心。
?
library?IEEE; use?IEEE.STD_LOGIC_1164.ALL; use?IEEE.NUMERIC_STD.ALL; entity?tb_complex?is --??Port?(?); end?tb_complex; architecture?Behavioral?of?tb_complex?is component?complex_example?is?port( clk????:?in?std_logic;? ip_val?:?in?std_logic; ip?????:?in?std_logic_vector(7?downto?0); op_val?:?out?std_logic; op?????:?out?std_logic_vector(8?downto?0)); end?component?complex_example; signal?clk????:??std_logic:='0';? signal?ip_val?:??std_logic:='0'; signal?ip?????:??std_logic_vector(7?downto?0):=(others=>'0'); signal?op?????:??std_logic_vector(8?downto?0):=(others=>'0'); signal?op_val?:??std_logic:='0'; constant?clk_period?:?time?:=?100?ns; begin clk?<=?not?clk?after?(clk_period/2); uut:?complex_example?port?map(clk,ip_val,ip,op_val,op); stim?:?process begin? ?wait?for?1?us; ?wait?until?rising_edge(clk); ?ip_val?<=?'1'; ?ip?<=?std_logic_vector(to_unsigned(61,8)); ?wait?until?rising_edge(clk); ?ip_val?<=?'0'; ?wait?for?1?us; ?report?"?simulation?complete"?severity?failure; end?process; end?Behavioral;
?
仿真結(jié)果如下:
總結(jié)
在這個(gè)項(xiàng)目中,從簡(jiǎn)單算法到復(fù)雜算法,我們逐步了解了如何使用 HDL 在 FPGA 上進(jìn)行數(shù)學(xué)運(yùn)算。
審核編輯:劉清
評(píng)論
查看更多