ModelSim 5.8 SE
Synplify Pro 7.6
編程語言 VHDL
在ISE 中調(diào)用ModelSim 進(jìn)行仿真
一、 基本概念和基礎(chǔ)知識(shí)
Testbench 不僅要產(chǎn)生激勵(lì)也就是輸入,還要驗(yàn)證響應(yīng)也就是輸出。當(dāng)然也可以只產(chǎn)生激勵(lì),然后通過波形窗口通過人工的方法去驗(yàn)證波形,這種方法只能適用于小規(guī)模的設(shè)計(jì)。
在ISE 環(huán)境中,當(dāng)前資源操作窗顯示了資源管理窗口中選中的資源文件能進(jìn)行的相關(guān)操作。在資源管理窗口選中了testbench 文件后,在當(dāng)前資源操作窗顯示的ModelSim Simulator 中顯示了4 種能進(jìn)行的模擬操作,分別是:Simulator Behavioral Model(功能仿真)、Simulator Post-translate VHDL Model(翻譯后仿真)、Simulator Post-Map VHDL Model(映射后仿真)、Simulator Post-Place & Route VHDL Model(布局布線后仿真)。如圖1 所示:
圖1

Simulator Behavioral Model 也就是所說的功能仿真、行為仿真、前仿真。驗(yàn)證功能是否正確,這是設(shè)計(jì)的步。功能仿真正確的程序不一定能被正確綜合,也就是硬件實(shí)現(xiàn)。有的在綜合時(shí)報(bào)錯(cuò)誤,有的雖然能綜合但結(jié)果并不正確。當(dāng)然,功能仿真如果都不能通過,以后的步驟也就無法進(jìn)行。這是必做的仿真。
Simulator Post-translate VHDL Model 也就是翻譯后仿真。對(duì)源程序進(jìn)行編譯后首先排除了語法錯(cuò)誤,對(duì)一些像類屬命令(Generic)、生成語句(Generate)等進(jìn)行了展開。不是必做的仿真。
Simulator Post-Map VHDL Model也就是映射后仿真。不同的器件內(nèi)部結(jié)構(gòu)也不盡相同,映射的作用就是將綜合后產(chǎn)生的網(wǎng)表文件對(duì)應(yīng)到實(shí)際的器件上去。由于映射不包含布線,也就是要用什么類型的邏輯單元雖然已經(jīng)確定但要用哪個(gè)位置的還沒有確定,因此,映射后仿真不包含布線延時(shí)。不是必做的仿真。
Simulator Post-Place & Route VHDL Model 也就是所說的布局布線后仿真、時(shí)序仿真、后仿真。這是完整的仿真,既包含邏輯延時(shí)又包含布線延時(shí)。在做布局布線后仿真時(shí)要用到一個(gè)叫SDF的文件。SDF文件包含設(shè)計(jì)中每個(gè)單元(Cell)的延時(shí)和時(shí)序約束數(shù)據(jù)。通過加載這個(gè)文件就能得到完整的時(shí)序情況。它是必做的仿真。
一般必須進(jìn)行功能仿真和布局布線后仿真。
常見問題:
為什么有的testbench在進(jìn)行功能仿真時(shí)能正確進(jìn)行,而在進(jìn)行布局布線后仿真時(shí)就不能運(yùn)行。
有兩點(diǎn)要注意的地方:
?。?)、在做映射后仿真或布局布線后仿真時(shí),都已經(jīng)經(jīng)過了綜合工具的綜合,源程序中的類屬命令(Generic)、生成語句(Generate)等都已經(jīng)進(jìn)行展開。例如,如果用Generic 定義了一個(gè)參數(shù)width,綜合工具進(jìn)行綜合時(shí)已經(jīng)按照一個(gè)確定的width 值進(jìn)行了綜合。它生成的電路已經(jīng)具有一個(gè)確定的結(jié)構(gòu),不能再隨意調(diào)整。所以在映射后仿真和布局布線后仿真的testbench中,往往不能出現(xiàn)Generic 語句。
(2)映射后仿真和布局布線后仿真都要用到SDF 文件,并且要將SDF文件關(guān)聯(lián)到設(shè)計(jì)中的實(shí)例。所以在映射后仿真和布局布線后仿真的testbench中,,要將你的設(shè)計(jì)聲明成一個(gè)元件。第二,實(shí)例化你設(shè)計(jì)的元件并且實(shí)例名要取為UUT(默認(rèn)的,當(dāng)然也可以改)。
關(guān)于斷言語句
在仿真中為了能得到更多信息,經(jīng)常要用到斷言語句(assert)。其語法如下:
Assert<條件>
Report<消息>
Severity<出錯(cuò)級(jí)別>;
出錯(cuò)級(jí)別共有5 種:
Note
Warning
Error
Failure
Fatal
在VHDL 模型的模擬過程中,一旦斷言語句的條件為假,則發(fā)送消息并將出錯(cuò)級(jí)別發(fā)送給模擬器。通常可以設(shè)置一個(gè)中止模擬器運(yùn)行的出錯(cuò)級(jí)別,一般默認(rèn)的中止運(yùn)行的出錯(cuò)級(jí)別為Failure。
我們來看一個(gè)例子:
assert false
report "********* " & IMAGE(DWIDTH) & "BIT DIVIDER SEQUENCE FINISHED
AT " & IMAGE(now) & " !" & " *********"
severity note;
斷言的條件不是一個(gè)條件表達(dá)式,而直接是false。這說明只要程序執(zhí)行到這里斷言就一定會(huì)成立,送出消息。出錯(cuò)級(jí)別為note,在模擬器的輸出窗口將會(huì)顯示:
圖2
再看一個(gè)例子:
assert (s_cyi((DWIDTH-1)/4) = '0')
and (s_ovi = '0')
and (s_qutnt = conv_std_logic_vector(v_quot,DWIDTH))
and (s_rmndr = conv_std_logic_vector(v_remd,DWIDTH))
report "ERROR in division!"
severity failure;
斷言的條件有4 個(gè)并且是與的關(guān)系,只要其中一個(gè)條件不成立則整個(gè)表達(dá)式為假,斷言成立。如果斷言成立將輸出“ERROR in division!“這個(gè)消息。并且通知模擬器出錯(cuò)級(jí)別為failure,這一般會(huì)停止模擬。這個(gè)斷言實(shí)際是在對(duì)結(jié)果進(jìn)行驗(yàn)證。
二、實(shí)際testbench分析
下面將詳細(xì)分析一個(gè)實(shí)際的testbench,它是用來測(cè)試8051 的ALU單元的除法功能的。8 位的除法器,被除數(shù)和除數(shù)的組合共有256×256=65536 種。我們采用的方法是窮舉所有的輸入組合,這樣的代碼覆蓋率可以達(dá)到100%。它的驗(yàn)證必須通過程序自動(dòng)完成,否則通過人工方法工作量太大。
把要測(cè)試的程序當(dāng)作一個(gè)元件,例如想象成一個(gè)74 系列數(shù)字電路。Testbench 的作用是在被測(cè)試電路的輸入端加上激勵(lì),然后比較被測(cè)試電路的輸出和計(jì)算出來的期望值是否一致。對(duì)我們這個(gè)例子來說,在要仿真的ALU 輸入端產(chǎn)生65536 種輸入組合,然后將ALU產(chǎn)生的對(duì)應(yīng)輸出值和testbench 算出的期望值相比較,如果有錯(cuò)誤產(chǎn)生則停止模擬并輸出信息。ALU 的除法單元的輸入有4 個(gè),分別是被除數(shù)、除數(shù)、進(jìn)位、溢出位;輸出也有4 個(gè),分別是商、余數(shù)、新的進(jìn)位、新的溢出位。
1、 testbench 的輸出s_dvdnd(被除數(shù))、s_dvsor(除數(shù))、s_cyo(進(jìn)位)、s_ovo(溢出位)連接到ALU 的輸入acc_i(被除數(shù))、ram_data_i(除數(shù))、cy_i(進(jìn)位)、ov_i(溢出位);
2、 testbench 的輸入s_qutnt(商)、s_rmndr(余數(shù))、s_cyi(進(jìn)位)、s_ovi(溢出位)連接到ALU的輸出result_a_o(商)、 result_b_o(余數(shù))、new_cy_o(進(jìn)位)、new_ov_o(溢出位)。
3、 總之,testbench 驅(qū)動(dòng)被測(cè)試單元,同時(shí)對(duì)被測(cè)試單元的輸出進(jìn)行驗(yàn)證。
4、assert (s_cyi((DWIDTH-1)/4) = '0')
and (s_ovi = '0')
and (s_qutnt = conv_std_logic_vector(v_quot,DWIDTH))
and (s_rmndr = conv_std_logic_vector(v_remd,DWIDTH))
report "ERROR in division!"
severity failure;
根據(jù)51 指令系統(tǒng)規(guī)定,除法運(yùn)算的cy 位固定為0,如果除數(shù)為0則ov 置1,否則置0。
程序中
s_qutnt = conv_std_logic_vector(v_quot,DWIDTH)
s_rmndr = conv_std_logic_vector(v_remd,DWIDTH)
用來對(duì)運(yùn)算結(jié)果進(jìn)行比較。conv_std_logic_vector()是類型轉(zhuǎn)換函數(shù)。
――首先是對(duì)庫(kù)的引用
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
library work;
use work.mc8051_p.all;
library STD;
use STD.textio.all;
――定義結(jié)構(gòu)體,testbench程序的結(jié)構(gòu)體是空的。因?yàn)閠estbench是用來仿真的,不存在
--對(duì)外的接口,所以entity是空的。但是必須要有,這是語法的要求。
entity TBX_mc8051_alu is
end TBX_mc8051_alu;
-------------------------------------------------------------------------------
architecture TBX_ARCH_DIV of TBX_mc8051_alu is
――定義元件,映射后仿真和布局布線后仿真要使用SDF 文件,必須指定實(shí)例名。要實(shí)例
--化元件首先必須定義元件。
component mc8051_alu
port (
new_ov_o : out STD_LOGIC; ――新的ov位,輸出
ov_i : in STD_LOGIC := 'X'; ――ov位,輸入
new_cy_o : out STD_LOGIC_VECTOR ( 1 downto 0 ); ――新的cy位,輸出
acc_i : in STD_LOGIC_VECTOR ( 7 downto 0 ); ――acc,輸入
rom_data_i : in STD_LOGIC_VECTOR ( 7 downto 0 ); ――rom_data,輸入
cmd_i : in STD_LOGIC_VECTOR ( 5 downto 0 ); ――命令,輸入
ram_data_i : in STD_LOGIC_VECTOR ( 7 downto 0 ); ――ram_data,輸入
cy_i : in STD_LOGIC_VECTOR ( 1 downto 0 ); ――cy,輸入
result_b_o : out STD_LOGIC_VECTOR ( 7 downto 0 ); ――結(jié)果b,輸出
result_a_o : out STD_LOGIC_VECTOR ( 7 downto 0 ) -―結(jié)果a,輸出
);
end component;
――定義函數(shù)
-----------------------------------------------------------------------------
--
-- IMAGE - Convert a special data type to string --
--
This function uses the STD.TEXTIO.WRITE procedure to convert different --
-- VHDL data types to a string to be able to output the information via --
-- a report statement to the simulator. --
-- (VHDL'93 provides a dedicated predefinded attribute 'IMAGE) --
-----------------------------------------------------------------------------
――定義了一個(gè)函數(shù)IMAGE,之所以有兩個(gè)定義,是因?yàn)閷?duì)IMAGE進(jìn)行了重載,一個(gè)是把
――time變量轉(zhuǎn)換成string,另一個(gè)是把integer變量轉(zhuǎn)換成string
function IMAGE (constant tme : time) return string is
variable v_line : line;
variable v_tme : string(1 to 20) := (others => ' ');
begin
write(v_line, tme);
v_tme(v_line.all'range) := v_line.all;
deallocate(v_line);
return v_tme;
end IMAGE;
function IMAGE (constant nmbr : integer) return string is
variable v_line : line;
variable v_nmbr : string(1 to 11) := (others => ' ');
begin
write(v_line, nmbr);
v_nmbr(v_line.all'range) := v_line.all;
deallocate(v_line);
return v_nmbr;
end IMAGE;
――定義過程,它產(chǎn)生所有的測(cè)試輸入數(shù)據(jù)并將產(chǎn)生結(jié)果和期望值進(jìn)行比較,如果有誤
――產(chǎn)生,模擬將停止并輸出一個(gè)錯(cuò)誤信息。注意到testbench要產(chǎn)生被測(cè)試單元的輸入
――信號(hào),因此testbench的輸出接到被測(cè)試單元的輸入,被測(cè)試單元的輸出接到
――testbench的輸入。
procedure PROC_DIV_ACC_RAM (
constant DWIDTH : in positive;
constant PROP_DELAY : in time;
signal s_cyi : in std_logic_vector;
signal s_ovi : in std_logic;
signal s_qutnt : in std_logic_vector;
signal s_rmndr : in std_logic_vector;
signal s_cyo : out std_logic_vector;
signal s_ovo : out std_logic;
signal s_dvdnd : out std_logic_vector;
signal s_dvsor : out std_logic_vector;
signal s_dvdr_end : out boolean) is
variable v_quot : integer;
variable v_remd : integer;
variable v_flags : std_logic_vector((DWIDTH-1)/4+1 downto 0);
begin
s_dvdr_end <= false;
for j in 0 to 2**DWIDTH-1 loop
s_dvdnd <= conv_std_logic_vector(j,DWIDTH); ――產(chǎn)生被除數(shù)
for i in 0 to 2**DWIDTH-1 loop
s_dvsor <= conv_std_logic_vector(i,DWIDTH); ――產(chǎn)生除數(shù)
for f in 0 to 2**(((DWIDTH-1)/4)+2)-1 loop ――產(chǎn)生cy和ov
v_flags := conv_std_logic_vector(f,((DWIDTH-1)/4)+2);
s_cyo <= v_flags(((DWIDTH-1)/4) downto 0); ――s_cyo和s_ovo輸出到
s_ovo <= v_flags(v_flags'HIGH); ――mc8051_alu的cy_i和ov_i
wait for PROP_DELAY; ――等待100ns
if i /= 0 then
v_quot := j/i; ――產(chǎn)生期待的商
v_remd := j rem i; ――產(chǎn)生期待的余數(shù)
assert (s_cyi((DWIDTH-1)/4) = '0') ――對(duì)結(jié)果進(jìn)行比較
and (s_ovi = '0')
and (s_qutnt = conv_std_logic_vector(v_quot,DWIDTH))
and (s_rmndr = conv_std_logic_vector(v_remd,DWIDTH))
report "ERROR in division!"
severity failure;
else ―― 否則除數(shù)為0
assert (s_cyi((DWIDTH-1)/4) = '0')
and (s_ovi = '1')
report "ERROR in division by zero - flags not correct!"
severity failure;
end if;
end loop; -- f
end loop; -- i
end loop; -- j
assert false ―― 程序執(zhí)行到這里表示沒有問題產(chǎn)生
report "********* " & IMAGE(DWIDTH) & "BIT DIVIDER SEQUENCE FINISHED AT "
& IMAGE(now) & " !" & " *********"
severity note;
s_dvdr_end <= true;
wait;
end PROC_DIV_ACC_RAM;
-----------------------------------------------------------------------------
――定義常數(shù)和信號(hào)
constant PROP_DELAY : time := 100 ns;
signal rom_data_DIV_ACC_RAM : std_logic_vector(7 downto 0);
signal ram_data_DIV_ACC_RAM : std_logic_vector(7 downto 0);
signal acc_DIV_ACC_RAM : std_logic_vector(7 downto 0);
signal hlp_DIV_ACC_RAM : std_logic_vector(7 downto 0);
signal cmd_DIV_ACC_RAM : std_logic_vector(5 downto 0);
signal cy_DIV_ACC_RAM : std_logic_vector(1 downto 0);
signal ov_DIV_ACC_RAM : std_logic;
signal new_cy_DIV_ACC_RAM : std_logic_vector(1 downto 0);
signal new_ov_DIV_ACC_RAM : std_logic;
signal result_a_DIV_ACC_RAM : std_logic_vector(7 downto 0);
signal result_b_DIV_ACC_RAM : std_logic_vector(7 downto 0);
signal end_DIV_ACC_RAM : boolean;
-----------------------------------------------------------------------------
begin
-----------------------------------------------------------------------------
-- Test the DIV_ACC_RAM command --
-----------------------------------------------------------------------------
rom_data_DIV_ACC_RAM <= conv_std_logic_vector(0,8);
cmd_DIV_ACC_RAM <= conv_std_logic_vector(43,6); ――43表示除法命令
UUT : mc8051_alu ――例化元件
port map (
rom_data_i => rom_data_DIV_ACC_RAM(7 downto 0),
ram_data_i => ram_data_DIV_ACC_RAM(7 downto 0),
acc_i => acc_DIV_ACC_RAM(7 downto 0),
cmd_i => cmd_DIV_ACC_RAM,
cy_i => cy_DIV_ACC_RAM(1 downto 0),
ov_i => ov_DIV_ACC_RAM,
new_cy_o => new_cy_DIV_ACC_RAM(1 downto 0),
new_ov_o => new_ov_DIV_ACC_RAM,
result_a_o => result_a_DIV_ACC_RAM(7 downto 0),
result_b_o => result_b_DIV_ACC_RAM(7 downto 0));
――mc8051_alu的被除數(shù)、除數(shù)、cyi、ovi由PROC_DIV_ACC_RAM產(chǎn)生
――注意到PROC_DIV_ACC_RAM的商(s_qutnt)、余數(shù)(s_rmndr)的Port方向是in,
――用來連接mc8051_alu的輸出result_a_DIV_ACC_RAM和result_b_DIV_ACC_RAM
PROC_DIV_ACC_RAM (DWIDTH => 8, ――調(diào)用過程
PROP_DELAY => PROP_DELAY,
s_cyi => new_cy_DIV_ACC_RAM(1 downto 0),
s_ovi => new_ov_DIV_ACC_RAM,
s_qutnt => result_a_DIV_ACC_RAM(7 downto 0), ――商
s_rmndr => result_b_DIV_ACC_RAM(7 downto 0), ――余數(shù)
s_cyo => cy_DIV_ACC_RAM(1 downto 0),
s_ovo => ov_DIV_ACC_RAM,
s_dvdnd => acc_DIV_ACC_RAM(7 downto 0), ――被除數(shù)
s_dvsor => ram_data_DIV_ACC_RAM(7 downto 0), ――除數(shù)
s_dvdr_end => end_DIV_ACC_RAM);
-----------------------------------------------------------------------------
end TBX_ARCH_DIV;
――配置,表示TBX_mc8051_alu這個(gè)entity使用TBX_ARCH_DIV這個(gè)architecture
configuration TBX_CFG_mc8051_alu_TBX_ARCH_DIV of TBX_mc8051_alu is
for TBX_ARCH_DIV
end for;
end TBX_CFG_mc8051_alu_TBX_ARCH_DIV;