Vivado使用:综合篇(三)综合属性

    xiaoxiao2022-07-13  431

         Vivado 开发套件中,Vivado综合能够综合多种类型的属性,大多数情况下,这些属性的使用语法和行为都一样。当使用综合属性时,假如Vivado能够识别该属性,那么就使用这个属性并创建反映已经使用该属性的逻辑;Vivado也可能无法识别所给的属性,这时Vivado就综合器就会将属性及其值传递给生成的网表文件。

          下面介绍Viado开发工具支持的综合属性。


    1.async_reg (用在跨异步时钟域场合) 


            FPGA设计中经常会遇到跨时钟域问题,在跨时钟域场合,对于控制信号而言(通常都1bit的,_en,flag,hsync...)一般通过打两拍的方法实现跨时钟域操作(由两级触发器实现的“一位同步器”)。如下图所示。

    此时图中标记为1的触发器需要使用综合属性:async_reg。使用该属性有两个目的:

    (1)告诉综合器,1号的触发器能够将接收来自异步时钟域的数据(即数据与接本地采样时钟不同步);

    (2)同时也说明了2号触发器是同步链路上的触发器。

          当遇到此属性的时候,Vivado综合器就会将其视为DONT_TOUCH属性,并在网表中向前推送ASYNC_REG属性。后续的流程中,布局布线的工具也会收到该属性正确处理, 在后面布局的时候就能保证1号和2号触发器被放置到同一个SLICE中,可以减少线延时对时序的影响。

           假如没有这个属性,综合器很可能就把它们给优化掉,并且在后续的流程中也无法正确处理了。

       这个属性可以用在RTL和XDC文件中。

    HDL示例:

    //Verilog 用法 (*ASYNC_REG = "TRUE" *) reg [2:0] sync_regs; //VHDL用法 attribute ASYNC_REG: string; attribute ASYNC_REG of synv_regs : siganl is "TRUE";

    2.BLACK_BOX


     

     


    存储相关的综合 属性


    RAM_STYLE

          指示综合工具如何实现一个RAM存储器,可设置为:

                  block(使用BRAM即块RAM来实现);

                  distributed(使用LUT搭建分布式RAM);

                  registers使用寄存器组来替代RAM)或ultra(使用UltraScale中的URAM)。

         默认情况下工具会为了得到最好的设计效果而自动选择。如果该属性在定义RAM的信号处申明,则仅作用于该信号;如果在某一层次结构处申明,将作用于该层次中的所有RAM(但不会影响到该层次的子层次)。可以在RTL或XDC中设置,示例如下:

    (* ram_style = “distributed” *) reg [size-1:0] myram [2**addr-1:0]; //Verilog示例 attribute ram_style : string; attribute ram_style of myram : signal is "distributed"; //VHDL示例

     


     

    RAM_DECOMP

           该属性用于指示综合工具如何用块RAM(BRAM)来实现一个较大的RAM。比如需要一个2K*36的RAM,通常会用两个2K18的BRAM组合实现(为了提高设计速度)。

           如果将该属性设置为power,则会用两个1K36的BRAM来组合实现,这样在读写过程中,使用地址使只需要一个BRAM处于活跃状态,因此可以降低功耗。

           该属性只有一个可配置值即power,虽然可以降低功耗,但是会增加地址解码的时间。可以在RTL或XDC中设置,示例如下:

    (* ram_decomp = “power” *) reg [size-1:0] myram [2**addr-1:0]; //Verilog示例 set_property ram_decomp power [get_cells myram] #XDC示例 ROM_STYLE

         指示综合工具如何推断一个ROM存储器,可设置为block(使用BRAM即块RAM来实现)或distributed(使用LUT搭建分布式ROM),默认情况下工具会为了得到最好的设计效果而自动选择。可以在RTL或XDC中设置,示例如下:

    (* rom_style = “distributed” *) reg [data_size-1:0] myrom [2**addr-1:0]; //Verilog示例 attribute rom_style : string; attribute rom_style of myrom : signal is “distributed”;//VHDL 示例

     HDL Coding Example

      Distributed RAM Examples

               Dual-Port RAM with Asynchronous Read Coding Example (Verilog)

    // Dual-Port RAM with Asynchronous Read (Distributed RAM) // File: rams_dist.v module rams_dist (clk, we, a, dpra, di, spo, dpo); input clk; input we; input [5:0] a; input [5:0] dpra; input [15:0] di; output [15:0] spo; output [15:0] dpo; reg[15:0] ram [63:0]; always @(posedge clk) begin if (we) ram[a] <= di; end assign spo = ram[a]; assign dpo = ram[dpra]; endmodule

    Simple Dual-Port Block RAM with Single Clock (VHDL)

    -- Simple Dual-Port Block RAM with One Clock -- Correct Modelization with a Shared Variable -- File:simple_dual_one_clock.vhd library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; entity simple_dual_one_clock is port( clk : in std_logic; ena : in std_logic; enb : in std_logic; wea : in std_logic; addra: in std_logic_vector(9 downto 0); addrb: in std_logic_vector(9 downto 0); dia : in std_logic_vector(15 downto 0); dob : in std_logic_vector(15 downto 0) ); end simple_dual_one_clock; architecture syn of simple_dual_one_clock is type ram_type is array (1023 downto 0) of std_logic_vector(15 downto 0); shared variable RAM : ram_type; begin process(clk) begin if clk'event and clk = '1' then if ena = '1' then if wea = '1' then RAM(conv_integer(addra)) := dia; end if end if end if end process; process(clk) begin if clk'event and clk = '1' then if enb = '1' then dob <= RAM(conv_integer(addrb)); end if end if end process; end syn;

     Simple Dual-Port Block RAM with Dual Clocks (Verilog)

    // Simple Dual-Port Block RAM with Two Clocks // File: simple_dual_two_clocks.v module simple_dual_two_clocks (clka,clkb,ena,enb,wea,addra,addrb,dia,dob); input clka,clkb,ena,enb,wea; input [9:0] addra,addrb; input [15:0] dia; output [15:0] dob; reg[15:0] ram [1023:0]; reg[15:0] dob; always @(posedge clka) begin if(ena == 1'b1) begin if(wea == 1'b1) ram(addra) <= dia; end end always@(posedge clkb) begin if(enb) begin dob <= ram(addrb); end end end module

     

     更多示例参见ug901 chapter3 HDL coding Techniques


    RAM内容的初始化方式

        有一下两种对RAM进行初始化的方式:

        (1)在HDL代码中指定RAM的初始值;

        (2) 靠外部数据文件来指定RAM的初始值。

    (1)HDL中指定

        依靠信号的默认值机制直接在HDL源代码中描述初始RAM内容。

    VHDL编码

    type ram_type is array (0 to 31) of std_logic_vector(19 downto 0); signal RAM : ram_type := ( X”0200A”, X”00300”, X”08101”, X”04000”, X”08601”, X”0233A”, X”00300”, X”08602”, X”02310”, X”0203B”, X”08300”, X”04002”, X”08201”, X”00500”, X”04001”, X”02500”, X”00340”, X”00241”, X”04002”, X”08300”, X”08201”, X”00500”, X”08101”, X”00602”, X”04003”, X”0241E”, X”00301”, X”00102”, X”02122”, X”02021”, X”0030D”, X"08201" );

    也可将RAM中所有bit位置都初始化为同一个值:

    type ram_type is array (0 to 127) of std_logic_vector (15 downto 0); signal RAM : ram_type := (others => (others => '0'));

    Verilog Coding Examples :

    所有可寻址的字都被初始化为相同值:

    reg [DATA_WIDTH-1:0] ram [DEPTH-1:0]; integer i; initial for (i=0; i<DEPTH; i=i+1) ram[i] = 0; end

    (2)外部数据文件指定RAM初始值

        使用HDL原码中的文件读写功能来从外部文件中下载数据到RAM中。

    •外部数据文件可以是任何名称的ASCII文本文件。 •外部数据文件中的每一行描述RAM中地址位置的初始内容。 •外部数据文件中的行必须与RAM阵列中的行一样多。 标记的行数不足。 •与给定行相关的可寻址位置由建模RAM的信号的主要范围的方向定义。 •您可以用二进制或十六进制表示RAM内容。 你不能混合两者。 •外部数据文件不能包含任何其他内容,例如注释。 •以下外部数据文件使用二进制值初始化8 x 32位RAM:

     

    Verilog Example

     使用系统任务$readmemb或$readmemh来分别下载二进制和16进制格式的数据。

    使用格式共有6种

    $readmemb("<数据文件名>",<存储器名>);$readmemb("<数据文件名>",<存储器名>,<起始地址>);$readmemb("<数据文件名>",<存储器名>,<起始地址>,<结束地址>);$readmemh("<数据文件名>",<存储器名>);$readmemh("<数据文件名>",<存储器名>,<起始地址>);$readmemh("<数据文件名>",<存储器名>,<起始地址>,<结束地址>); reg [31:0] ram [0:63]; initial begin $readmemb(“rams_20c.data”, ram, 0, 63); end

    顺便介绍一下系统任务$random

         这个任务提供了一个产生随机数的手段。当函数被调用时会返回一个32bit的随机数,并且是一个有符号的整型数。

        一般用法:

           $random %b,其中b>0。这样结果就能返回一个范围在(-b+1):(b-1)中的随机数。例如

    reg[23:0] rand; rand = $random`;

     这就给出一个范围在-59~59之间的随机数。下面例子通过拼接操作产生一个0~59的数。

    reg[23:0] rand; rand = {$random}`;

     

    最新回复(0)