本节首先介绍使用多时钟设计的好处,然后讲述如何使用共享存储器(Shared Memory)连接不同的时钟域,最后介绍“Multiple Subsystem Generator”模块的使用。所有这些通过实例一一介绍,虽然该例子中只包含两个时钟域,但并不影响其一般性。
1.使用多时钟设计FPGA的好处
一个良好的FPGA设计是尽量让所有模块都处在高速时钟的运行下,减少硬件资源的使用。一般来说,在System Generator设计中最好采用单时钟设计(一个系统时钟),多速率时采用Clock Enable配合系统时钟实现,但是这种设计的缺点是功耗高、并且很难做到高速的Clock Enable;所以在某些特定情况下,使用多时钟处理便成为一种很好的设计方案。
多时钟设计的一个典型应用是FPGA与不同速率的外设接口连接。这些外设接口包括很多,比如:
(1)I/O缓冲buffer与Microprocessor接口,Microprocessor使用处理器内部时钟采数据,与I/O缓冲buffer数据速率不同,需要处理两个不同时钟域的数据通信。
(2)数字信号送往DA转换器接口,该DA的时钟与数据速率不同,也同样需要处理不同时钟域的数据通信。
可见,当FPGA与外设的处理时钟不同时,都需要使用多时钟设计。
多时钟设计的另一个典型应用是在高速率处理单元中,比如下面一个例子:
设计一个4倍插值FIR滤波器,数据从外部输入(这个速率称为符号速率),FIR执行1到4的插值,并且完成滤波操作后以4倍输入速率输出(这个速率称为采样速率)。而该FIR模块的内部处理时钟可以采样下面三种方式:
(1)符号速率:一个符号周期内需要4个并行结构完成插值运算操作,这种结构需要消耗大量的硬件资源。
(2)采样速率:一个符号周期内只需要一个结构复用即可完成插值操作,这种结构较(1)中结构来说,节省了很多硬件资源。
(3)高于采样速率几倍的时钟:当符号速率很低,也就是采样速率也相对较低的时候,FIR内部处理模块时钟可以非常高,高于采样速率的几倍。这种情况下,一个符号周期内,FIR内部模块可以复用完成很多操作(包括插值和滤波操作都可以复用完成),大大减少了硬件资源的使用量。
在(3)设计中出现了三个时钟域:符号速率域、采样速率域,FIR内部时钟域,所以此种结构也为多时钟设计。
2.对设计进行时钟域分类
在多时钟设计中,对设计进行时钟域的划分是非常重要的一步,通常建议把系统中拥有相同频率时钟的模块构成一个时钟域,并且每个时钟域都用一个独立的子系统表示,这样做的好处在于:
(1)硬件实现时,每个域的时钟可以直接从子系统中得到。
(2)时钟域间的通信通过子系统间的接口可以明确定义。
(3)Sysgen针对每个子系统产生正确的时钟约束文件。
在每个子系统内部是同步时钟设计,Simulink仿真结果和HDL仿真结果一致,但对于顶层模块来说,包含多个不同频率的时钟域,此时Simulink仿真结果有可能和HDL仿真出现不一致的情况,设计人员需要注意这点。
3.时钟域的交互
当不同时钟域间有通信时,使用System Generator中的共享存储器。这些共享存储器包括:Shared Memory、To FIFO/From FIFO、To Register/From Register。
这些共享存储器都成对的形式出现在设计中,两者通过相同的名字确定唯一联系,在三者中,共享FIFO最经常使用,硬件映射为Xilinx FIFO Generator core,其非常适用于高带宽、连续数据的传输;Shared Memory映射为双口RAM,但一定要避免两个时钟域同时往同一个地址写/读数据的发生,此时会出现无效数据;共享Register映射为寄存器类型,有关共享存储器的详细介绍请参看1.4.4节。
4.样例介绍
通过本样例了解多时钟设计的一般流程,以及其中每一步的关键所在,本例可在附带光盘的“chapter1/exp1-5/multiple_clocks”路径中找到。
例1-5:两异步时钟域通过共享存储器通信交互。
(1)在Simulink下打开工程文件two_async_clks,如图1-38所示,本设计中包含两个子系统“ss_clk_domainA”和“ss_clk_domainB”,分别工作在各自独立的时钟域。时钟域内为同步系统,两个域间的交互通过shared memory对完成,一个位于“ss_clk_domainA”内,另一个位于“ss_clk_domainB”内,通过唯一名字“bram_iface”确定。这一对shared memory在System Generator设计中看似没有直接连接,但在硬件实现过程中,二者因为名字相同,故映射为同一个双口RAM。

图1-38 two_async_clks的Sysgen工程
图1-38中,两个域的输入数据源不同,ss_clk_domainA输入为正弦波,ss_clk_domainB输入为锯齿波,shared memory分为等空间的两个部分A、B,分属于两个时钟域。子系统分别往对方的地址空间写数据(即ss_clk_domainA往B空间写数据,ss_clk_domainB往A空间写数据),写满后读取自己地址空间的数据。
(2)点击“Start”按钮仿真整个设计,双击“Scope”模块,可视化仿真波形如图1-39所示。左图中,clk_A_data和clk_B_data数据出现了正弦信号和锯齿信号交替出现的情况,这是由于双口RAM中同时写入了两种类型的数据。扩大仿真波形如图1-39右图所示,clk_A、clk_B时钟频率和相位都不同,属于不同的时钟域。

图1-39 two_async_clks工程仿真波形
System Generator如何实现了两个系统时钟的设计,这取决于Simulink的分层结构设计,顶层文件中并没有System Generator图标,而两个子系统中都有各自独立的System Generator图标(可以认为它们是独立的系统设计)。这样可以分别设置子系统中的系统时钟和Simulink仿真时钟,使得整个设计有两个独立的不同频率的时钟出现。
(3)分别双击两个子系统中的“System Generator”图标,ss_clk_domainA的FPGA时钟周期设置为10ns(即时钟速率100MHz),其相应的Simulink系统仿真周期归一化设为2s,而ss_clk_domainB的FPGA时钟周期设置为15ns(即时钟速率66.7MHz),相应的Simulink系统仿真周期归一化设为3s,属性设置如图1-40所示。

图1-40 two_async_clks中System Generator图标属性
在本实例中,两个子系统通过“Multiple Subsystem Generator”模块连接到顶层模块,将两个时钟作为顶层模块的输入端口。当映射到硬件实现时,两个子系统分别映射到独立的HDL Netlist中。
(4)双击顶层设计中的“Multiple Subsystem Generator”图标,芯片类型“Part”设置为“Virtex2 xc2v1000-4bf575”,HDL文件选择路径(本例中默认为“netlist”),采用XST综合工具,VHDL语言,属性设置如图1-41所示。

图1-41 Multiple Subsystem Generator图标属性
(5)点击“Generate”按钮,实现硬件映射。
在工程目录下打开“netlist”文件夹,查看该文件夹内容。该文件夹中含有两个NGC文件,“ss_clk_domaina_cw.ngc”和“ss_clk_domainb_cw.ngc”,包含对应子系统的网表信息和时钟约束信息,如果子模块含有多速率单元,那么网表文件中有相应的clock wrapper文件。此外文件夹还有双口RAM的core netlist:
dual_port_block_memory_virtex2_6_1_ef64ec122427b7be.edn
(6)打开顶层模块文件(“two_async_clks.vhd”),端口说明如下所示:
entity two_async_clks is
port (
din_a: in std_logic_vector(7 downto 0);
din_b: in std_logic_vector(7 downto 0);
ss_clk_domaina_cw_ce: in std_logic := '1';
ss_clk_domaina_cw_clk: in std_logic;
ss_clk_domainb_cw_ce: in std_logic := '1';
ss_clk_domainb_cw_clk: in std_logic;
dout_a: out std_logic_vector(7 downto 0);
dout_b: out std_logic_vector(7 downto 0)
);
end two_async_clks;
从顶层文件的端口说明看出,该设计有两个独立的时钟输入端口(上以黑体标注)分别对应ss_clk_domaina和ss_clk_domainb。所以使用“Multiple Subsystem Generator”产生硬件实现时,与“System Generator”不同,直接将时钟引入到顶层文件作为输入端口,当然设计者也可以自己编写一个时钟驱动电路,使用一个系统时钟产生两个子系统所需要的不同频率时钟。
如何添加一个顶层时钟驱动电路,需要做到以下三点:
例化已产生的顶层文件和时钟逻辑电路。
正确连接各个模块之间的逻辑关系。
新建一个顶层文件,将端口映射到内部模块中。
就上面例子得到的顶层文件two_async_clks.vhd添加时钟驱动电路构成最终的顶层文件top_wrapper.vhd,参看路径“chapter1/exp1-5/multiple_clocks/two_async_clks/top_wrapper.vhd”。


