最近在学习FPGA,感觉语言的学习到时很容易,但是由于缺乏电路图的硬件知识,所以看起来比较难懂,下面是对FPGA中仿真的一点理解,以后需要学习的地方还有很多啊。
一、使用ISE环境进行FPGA系统设计的时候,仿真是一个必不可少的步骤,即仿真过程是正确实现设计的关键环节,有两种:
相同:两者仿真使用的仿真器是相同的, 所需的流程和激励也是相同的;
不同:时序仿真加载到仿真器的设计包括基于实际布局布线设计的最坏情况的布局布线延时, 并且在仿真结果波形图中,时序仿真后的信号加载了时延, 而功能仿真没有。
ISE环境中前后仿真的选项:
以一个ALU的实现功能为例分析前后仿真的不同,其前仿真和后仿真的结果图为:
前仿真图
后仿真图
从时序仿真图可以看出,后仿真存在着延迟。本实验中存在的延迟也就是几ns,但是频率很高的时候,延迟可能会达到一个或者几个周期,这就要求工作频率不能超过最高工作频率。那么最高频率怎么计算呢?
二、计算最大工作频率
首先需要知道FPGA中存在 的延时有哪些,下面是常用的四种:
1、纯组合逻辑延时(输入引脚到输出引脚),如图:
2、输入引脚到同步元件之间的延时,如图delay2
3、同步元件到输出引脚之间的延时,如图delay3
4、不同时钟Clk1和Clk2之间的异步延时,如图delay4
我们知道,几乎所有的FPGA设计平台都包含静态时序分析工具,利用这类工具可以获得映射或布局布线后的时序分析报告,从而对设计的性能做出评估。
工作频率的计算受到时序延时delay1、 delay2、 delay3、 delay4的影响。在影响工作频率的参数中,由于针对某一个器件delay2 和delay3 是固定的,因此我们在设计中需要考虑的参数主要就是delay1 和delay4。从静态分析报告中我们可以得到工作频率的最大值,就是时序分析报告中所有延时的最大值。如果工作频率大于该值,则可能出现延时一个或几个周期的情况,从而导致输出结果错误。
上述仿真时序图的源码:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.all; use IEEE.STD_LOGIC_UNSIGNED.all; entity ALU is port ( CLK : in STD_LOGIC ; OP_CODE : in STD_LOGIC_VECTOR ( 3 downto 0 ) ; A,B : in STD_LOGIC_VECTOR ( 3 downto 0 ) ; C_IN : in STD_LOGIC; EN : in STD_LOGIC; Y : out STD_LOGIC_VECTOR (3 downto 0) ); end ALU; architecture Behavioral of ALU is signal OP_CODE_CI : STD_LOGIC_VECTOR ( 4 downto 0 ); begin OP_CODE_CI <= OP_CODE & C_IN ; process ( CLK ) begin if rising_edge ( CLK ) then if (EN = '1') then case OP_CODE_CI is when "00000" => Y <= A; when "00001" => Y <= A + 1 ; when "00010" => Y <= A + B ; when "00011" => Y <= A + B + 1; when "00100" => Y <= A + not B ; when "00101" => Y <= A + not B + 1; when "00110" => Y <= A - 1 ; when "00111" => Y <= A ; when "01000" => Y <= A and B ; when "01010" => Y <= A or B ; when "01100" => Y <= A xor B ; when "01110" => Y <= not A ; when "10000" => Y <= (others => '0') ; when others => Y <= (others => 'X' ); end case; end if; end if ; end process; end Behavioral;
Test Bench的测试激励:
LIBRARY ieee; USE ieee.std_logic_1164.ALL; ENTITY ALU_test IS END ALU_test; ARCHITECTURE behavior OF ALU_test IS COMPONENT ALU PORT( CLK : IN std_logic; OP_CODE : IN std_logic_vector(3 downto 0); A : IN std_logic_vector(3 downto 0); B : IN std_logic_vector(3 downto 0); C_IN : IN std_logic; EN : IN std_logic; Y : OUT std_logic_vector(3 downto 0) ); END COMPONENT; signal OP_CODE_SIG : STD_LOGIC_VECTOR(3 downto 0):= (others => '0'); signal A_SIG : STD_LOGIC_VECTOR(3 downto 0):= "0111" ; signal B_SIG : STD_LOGIC_VECTOR(3 downto 0):= "0011" ; signal C_IN_SIG : STD_LOGIC := '0'; signal EN_SIG : STD_LOGIC := '1'; signal Y_SIG : STD_LOGIC_VECTOR(3 downto 0); signal CLK : STD_LOGIC := '0' ; signal OP_CODE_CI_SIG : STD_LOGIC_VECTOR ( 4 downto 0 ) := (others => '0') ; BEGIN OP_CODE_SIG <= OP_CODE_CI_SIG(4 downto 1); C_IN_SIG <= OP_CODE_CI_SIG(0); UUT: ALU port map( OP_CODE => OP_CODE_SIG, A => A_SIG, B => B_SIG, C_IN => C_IN_SIG, Y => Y_SIG, EN => EN_SIG, CLK => CLK); CLK <= not CLK after 10 ns; process begin OP_CODE_CI_SIG <= "00000"; wait for 100 ns; OP_CODE_CI_SIG <= "00001"; wait for 100 ns; OP_CODE_CI_SIG <= "00010"; wait for 100 ns; OP_CODE_CI_SIG <= "00011"; wait for 100 ns; OP_CODE_CI_SIG <= "00100"; wait for 100 ns; OP_CODE_CI_SIG <= "00101"; wait for 100 ns; OP_CODE_CI_SIG <= "00110"; wait for 100 ns; OP_CODE_CI_SIG <= "00111"; wait for 100 ns; OP_CODE_CI_SIG <= "01000"; wait for 100 ns; OP_CODE_CI_SIG <= "01010"; wait for 100 ns; OP_CODE_CI_SIG <= "01100"; wait for 100 ns; OP_CODE_CI_SIG <= "01110"; wait for 100 ns; OP_CODE_CI_SIG <= "10000"; wait; end process; END;