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

     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示例:

扫描二维码关注公众号,回复: 6612108 查看本文章
//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种

  1. $readmemb("<数据文件名>",<存储器名>);
  2. $readmemb("<数据文件名>",<存储器名>,<起始地址>);
  3. $readmemb("<数据文件名>",<存储器名>,<起始地址>,<结束地址>);
  4. $readmemh("<数据文件名>",<存储器名>);
  5. $readmemh("<数据文件名>",<存储器名>,<起始地址>);
  6. $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%60;

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

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

猜你喜欢

转载自blog.csdn.net/qq_26652069/article/details/90486732