HDL 编码指南

Posted by

介绍

本文档包含所有 HDL 项目必须遵循的编码和文档指南。本文档的目的是建立一组规则,指定 HDL 模块实现的布局、命名约定和一些通用编码实践。外部文档(例如12)描述了旨在从 FPGA 设计中获得最大性能的特定 HDL 编码实践,但未包含在本文档中。

规则有两种类型:应该规则必须规则

  • 规则应该是建议性规则。他们建议推荐的做事方式。
  • 必须规则是强制性要求。

编码规则旨在应用于使用 VHDL 或 Verilog 编写的 HDL 模块。

当使用外部 IP 时,应保留IP 实行的命名约定,即使它们与本文档中指定的规则不匹配。

编码风格

A、布局

A1:对于缩进,必须使用空格而不是制表符。这使得任何编辑器都可以正确地可视化代码。不要在行尾留下空格。必须使用 以下编辑器设置:制表符大小:2,缩进大小:2

A2 : 运算符周围必须插入一个空格,例如 =、==、&&、||、&、|、^ 等。

例子:

错误:

if((my_signal1==1'b0)&&(my_bus[3:0]==4'd5))
正确的:

if ((my_signal == 1'b0) && (my_bus[3:0] == 4'd5))

A3always块在@符号之前应该有一个空格。

例子:

错误:

always@(posedge clk) begin
  ...
end
正确的:

always @(posedge clk) begin
  ...
end

A4 :必须始终使用Verilog begin/end块,即使只有一条语句。这使得添加代码行变得更加容易并且错误更少。

A5必须使用缩进级别来显示代码嵌套。可以根据需要使用空行以提高代码可读性,但并非在所有情况下都如此。

例子:

错误:

if (my_signal == 1'b0) begin
  if (my_bus[3:0]==4'd5) begin
  statement1;
  statement2;
  end
statement3;
statement4;
end
else
statement5;
正确的:

if (my_signal == 1'b0) begin
  if (my_bus[3:0] == 4'd5) begin
    statement1;
    statement2;
  end
  statement3;
  statement4;
end else begin
  statement5;
end

A6:在定义中,必须case使用缩进级别来偏移封装的语句,但是可以使用或省略空行来最好地显示语句分组(如果确实有必要)。应按正确示例中的方式缩进。end

例子:

错误:

case ( my_bus[3:0] )
  4'b0000 : my_signal1 = TRUE;
  4'b0001 : my_signal1 = FALSE;
  4'b0010 :
  begin
  my_signal1 = TRUE;
  my_signal2 = FALSE;
  end
  4'b0100 : my_signal2 = FALSE;
  default : my_signal1 = TRUE;
endcase
正确的:

case (my_bus[3:0])
  4'b0000: begin
    my_signal1 = TRUE;
    end
  4'b0001: begin
    my_signal1 = FALSE;
    end
  4'b0010: begin
    my_signal1 = TRUE;
    my_signal2 = FALSE;
    end
  4'b0100: begin
    my_signal2 = FALSE;
    end
  default: begin
    my_signal1 = TRUE;
    end
endcase

A7:对齐应该用在声明、赋值、多行语句和行尾注释中。代码必须以表格格式编写。

例子:

错误:

    reg[3:0] my_signal1; //description
reg[31:0] my_decoded_signal1; //description
reg[4:0] my_signal2, my_signal3; //description
wire[2:0] my_select; //description
正确的:

reg  [ 3:0]  my_signal1;         //description
reg  [31:0]  my_decoded_signal1; //description
reg  [ 4:0]  my_signal2;         //description
reg          my_signal3;         //description

wire [ 2:0]  my_select;          //description

A8:所有布尔语句和复杂方程中都必须使用括号,以强制执行运算顺序并避免混淆。复杂的布尔表达式表示为多行对齐语句。

例子:

错误:

if ((my_signal1 && your_signal1) || (my_signal2 && your_signal2) || (my_signal3 && your_signal3)) begin
  my_signal1 = TRUE;
  my_delayed_signal1 = !your_signal;
end
正确的:

if ((my_signal1 && your_signal1) ||
    (my_signal2 && your_signal2) ||
    (my_signal3 && your_signal3)) begin
  my_signal1 = TRUE;
  my_delayed_signal1 = !your_signal;
end

A9:一行不得包含多个语句。不要在同一行上连接多个语句。

例子:

错误:

upper_en = (p5type && xadr1[0]); lower_en = (p5type && !xadr1[0]);
正确的:

upper_en = (p5type && xadr1[0]);
lower_en = (p5type && !xadr1[0]);

A10:在模块实例中:

A10.1所有参数和端口都必须写在单独的行上,即使它们的数量很少或者名称很短。

例子:

错误:

my_module #(.PARAMETER1 (PARAMETER1)) i_my_module (.clk (clk));
正确的:

my_module #(
  .PARAMETER1 (PARAMETER1)
) i_my_module (
  .clk (clk));

A10.2:实例化模块时,模块实例的标签必须位于单独的行上,带有参数列表的右括号(如果是这种情况)和端口列表的左括号。端口列表的右括号必须紧邻最后一个端口的最后一个括号。

例子:

my_module #(
  .PARAMETER1 (PARAMETER1),
  .PARAMETER2 (PARAMETER2)
) i_my_module (
  .clk (clk),
  .rst (rst),
  .data_in (data_in),
  .en (en),
  .response_out (response_out));

A10.3:代码的注释部分不得添加到主分支(即 if、case、模块实例等)。

A11:在模块声明中:

A11.1:Verilog 模块必须使用 Verilog-2001 风格的参数声明。这提高了易读性和一致性。

例子:

module my_module #(
  parameter PARAMETER1 = 0
) (
  input         clk,
  input         rst,
  input  [7:0]  data_0,
  input  [7:0]  data_1,
  input         enable,
  input         valid,

  // interface 1
  input         interf1_clk,
  inout         interf1_some_signal,
  output [15:0] interf1_data_i,
  output [15:0] interf1_data_q,

  // interface 2
  input         interf2_some_signal,
  output        interf2_data_out
);

A11.2:模块声明内允许注释,用于通过指定名称和提供补充说明来分隔接口。

A11.3:声明模块时,参数列表的右括号 必须与最后一个参数以及端口列表的左括号在同一行(如正确示例所示)。

A11.4:后面只能endmodule有一个换行符,后面不能有其他内容。

A12:端口必须单独注明;也就是说,每行必须声明一个端口,并使用每个端口的方向指示和数据类型。

A13:信号和变量必须单独声明;也就是说,每行必须声明一个信号/变量。

A14:所有端口和信号必须按接口分组。按方向对端口声明进行分组,从输入、输入输出和输出端口开始。

A15 :必须首先声明时钟和复位端口。

A16:Verilog 连线和寄存器声明必须分组在单独的部分中。首先注册类型,然后注册电线类型。

A17 : Verilog 代码的源文件具有附件 1 所示的格式,VHDL 代码的源文件应具有附件 2 所示的格式。

B. 命名约定

B1:源代码中的所有名称必须用英文书写。

B2:名称必须以字母开头,由字母数字字符或下划线组成[AZ, az, 0-9,_]

B3:所有模块、信号和寄存器名称必须小写,并用下划线“_”分隔。

例子:

module my_module (
  input           ena_fft,
  input           ena_mdi,
  input           fft_in,
  output          mdi_out,
  output [15:0]   my_signal1
);

B4:一个文件必须包含单个模块。文件名必须与模块名相同。对于子模块,名称必须按以下方式组成:

<top_module_name>_<sub_module_description>.

B5:所有参数名称必须大写并带有下划线分隔符。

B6 : 信号名称应按以下方式组成:

[interface|clock domain]_<signal_name>[_ns][_l][_p][_n][_m1][_m2][_s]

后缀组件可以如下所述使用,并且在同一信号名称中使用多个后缀的情况下,必须仅按照上述信号名称描述中指定的顺序使用。

_ns – 状态机的下一个状态。

_l – 锁存器输出。对于离开顶层模块或子模块的信号是可选的,对于模块内部的信号是必需的

_p – 差分信号的正极。

_n – 差分信号的负端。 – 低电平有效信号。也可用于差分信号的负端。

_m1/_m2 – 用于描述寄存器同步器(例如 up_ack_m1、up_ack_m2)

_s – 用于限定电线/信号(例如 up_ack_s)

此规则对于复杂模块很有用,如果信号名称不包含用于指定其用途的后缀,则可能会错误地使用信号。一般来说,此规则可能会导致不必要的命名复杂性,因此可以忽略,除非绝对必要。

B7:端口名称应按以下方式组成:

<interface_name>_<port_name>[_clk][_rst][_p][_n]

_clk – 时钟信号。例外:名称明显指示时钟的信号(例如system_clock或clk32m),或者指定具有特定频率的时钟时(在这种情况下使用clk作为前缀:例如clk_625mhz)

_rst / _rstn – 复位信号(例如 module_rst)。例外:其名称明显表明复位的信号。

_p – 差分信号的正极。

_n – 低电平有效信号。也可用于差分信号的负端。

B8‘define :指令指定的全局文本宏必须以顶级模块名称开头,如下所示:

<top_level_module_name>_<text macro name>

B9 :整个设计中必须使用一致的网络和变量的拼写和命名风格。

B10:模块中使用的缩写必须记录在案,并且避免不常见的缩写。

B11:复位和时钟名称在整个层次结构中必须保持相同。

三、评论

C1必须使用注释来描述 HDL 代码的功能。强烈鼓励自由使用评论。不鼓励添加明显的注释。基本上,对代码块进行的大量注释加上稀疏的反向引用可以引导读者浏览代码。

C2:代码的每个功能部分之前都应该有描述代码的意图和功能的注释。

C3 :必须解释不寻常或不明显的实现,并用注释记录它们的局限性。

C4:每个端口声明应该有一个描述性注释,在前一行。

C5:其他声明,例如regs、wires、局部参数,应该有描述性注释。要么在同一行(不鼓励),要么在前一行。对于自动生成的代码,此规则是可选的。

C6:所有综合特定指令必须在使用位置进行记录,标识使用它们的原因、所使用的工具和指令。

C7:代码中插入的注释必须符合附件 1(Verilog 代码)和附件 2(VHDL 代码)所示的格式。

D. 总则

D1:文件必须包含单个模块。

D2:文件必须包含:纯数字 Verilog 代码(扩展名为 .v 的文件);仅模拟的 Verilog 代码(扩展名为 .va 或 .vams 的文件);或混合信号 Verilog 代码(扩展名为 .vams 的文件)。

D3:符号常量(局部参数)应用于寄存器字段值,而不是固定的数字常量。这些字段可以是一位或多位或整个寄存器。

D4:端口连接宽度必须匹配。在模块实例化中,连接到端口的网络必须具有与相应端口声明相同的宽度。

D5:向量端口声明和网络/变量声明中的范围必须相等。

D6:操作数大小必须匹配。任何表达式的大小都不能隐式扩展或减小。在case语句中,所有case项表达式和case表达式必须具有相同的大小。

D7 :必须完整指定组合逻辑(即必须为所有输入组合的逻辑输出分配一个值)。在从caseor语句派生的构造中,可以在or语句if之前为输出分配默认值,然后完全指定逻辑。caseif

D8 :必须完整指定Verilogalways和 VHDLprocess结构 的敏感度列表。

D9:模块必须使用完整的 I/O 进行实例化 – 所有端口名称和信号连接必须在所有模块实例中列出。不要将任何输入端口保持打开状态(即使它们未使用),始终将它们连接到 0 或 1。将未使用的输出保持打开状态,但将其列出。

D10: Verilog 模块中使用timescale最适合仿真的指令。

D11:编译警告必须被视为潜在错误,并且 始终尝试解决。如果警告未得到解决,则必须充分了解其原因和影响。

D12 :必须处理和修复严重警告。

D13:每个文件必须包含许可证头,当对文件进行更改时,在制作 PR 时,年份更新为当前年份。

3. 附件

附件1 Verilog文件格式

// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
//   1. The GNU General Public License version 2 as published by the
//      Free Software Foundation, which can be found in the top level directory
//      of this repository (LICENSE_GPL2), and also online at:
//      <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
//   2. An ADI specific BSD license, which can be found in the top level directory
//      of this repository (LICENSE_ADIBSD), and also on-line at:
//      https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
//      This will allow to generate bit files and not release the source code,
//      as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
'timescale 1ns/100ps

module prescaler #(
  //Range = 1-16
  parameter FIRST_PARAMETER = 8,
  //Range = N/A
  parameter SECOND_PARAMETER = 12
) (
  input           core_32m_clk,         // 32 MHz clock
  input           system_clk,           // system clock
  input           scan_mode_test,       // scan mode clock
  input           reset_n,              // active low hard reset, synch w/
                                        // system_clk
  output  reg     div16_clk,            // input clock divided by 16
  output  reg     div16_clk_n           // input clock divided by 16 and inverted
);
  // Local Parameters
  
  // Registers Declarations
  
  reg     [3:0]   count;          // 4-bit counter to make clock divider
  reg     [3:0]   count1;         // 4-bit counter to make clock divider
  
  // Wires Declarations
  
  wire    [3:0]   count1_ns;      // clock divider next state input
  
  // Functions Definitions
  
  // This block updates the internal counter
  always @(posedge core_32m_clk or negedge reset_n) begin
    if (!reset_n) begin
      count <= 4’b0000;
    end else begin
      // update counter
      count <= count + 4’b0001;
    end
  end
  
  // This block updates the output clock signals
  always @(scan_mode_test or system_clk or count) begin
    if (!scan_mode_test) begin
      // normal operation clock assign
      div16_clk = count[3];
      div16_clk_n = ~count[3];
    end else begin
      // scan mode clock assign
      div16_clk = system_clk;
      div16_clk_n = system_clk;
    end
  end
  
  // Modules Instantiations

endmodule

附件2 VHDL文件格式

-- ***************************************************************************
-- ***************************************************************************
-- Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved.
--
-- In this HDL repository, there are many different and unique modules, consisting
-- of various HDL (Verilog or VHDL) components. The individual modules are
-- developed independently, and may be accompanied by separate and unique license
-- terms.
--
-- The user should read each of these license terms, and understand the
-- freedoms and responsibilities that he or she has by using this source/core.
--
-- This core is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE.
--
-- Redistribution and use of source or resulting binaries, with or without modification
-- of this file, are permitted under one of the following two license terms:
--
--   1. The GNU General Public License version 2 as published by the
--      Free Software Foundation, which can be found in the top level directory
--      of this repository (LICENSE_GPL2), and also online at:
--      <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
--
-- OR
--
--   2. An ADI specific BSD license, which can be found in the top level directory
--      of this repository (LICENSE_ADIBSD), and also on-line at:
--      https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
--      This will allow to generate bit files and not release the source code,
--      as long as it attaches to an ADI device.
--
-- ***************************************************************************
-- ***************************************************************************

entity prescaler is
  Port (
    core_32m_clk      : in  std_logic,    -- 32 MHz clock
    system_clk        : in  std_logic,    -- system clock
    scan_mode_test    : in  std_logic,    -- scan mode clock
    reset_n           : in  std_logic,    -- active low hard reset, synch
    -- w/ system_clock
    div16_clk         : out std_logic,    -- input clock divided by 16
    div16_clk_n       : out std_logic     -- input clock divided by 16
     -- and inverted
  );
end prescaler;

architecture Behavioral of  prescaler is

-- Components Declarations

-- Local Types Declarations

--  Constants Declarations

-- Signals Declarations
  signal count        : std_logic_vector(3 downto 0); -- 4-bit counter to
  -- make clock divider
  signal count_ns     : std_logic_vector(3 downto 0); -- clock divider next
  -- state input

-- Module Implementation
begin

  -- This process updates the internal counter
  process(core_32m_clk)
  begin
    if (rising_edge(core_32m_clk)) then
      if (reset_n = '0') then
        -- reset counter
        count <= "0000";
      else
        -- update counter
        count <= count + "0001";
      end if;
    end if;
  end process;

  -- This process updates the output clock signals
  process(scan_mode_test, system_clk, count)
  begin
    if (scan_mode_test = '0') then
      -- normal operation clock assign
      div16_clk <= count(3);
      div16_clk_n <= not count(3);
    else
      -- scan mode clock assign
      div16_clk <= system_clk;
      div16_clk_n <= system_clk;
    end if;
  end process;

end Behavioral;

4. 参考文献

1 Philippe Garrault、Brian Philofsky,“加速设计性能的 HDL 编码实践”,Xilinx,2006 年,在线文档可访问: http://www.xilinx.com/support/documentation/white_papers/wp231.pdf

2 Peter Chambers,“优秀设计的十诫”,VLSI Technology,1997 年,在线文档可访问:
http://www.asic-world.com/code/verilog_tutorial/peter_chambers_10_commandments.pdf

[ 3] “Verilog 编码技术,v3.2”,飞思卡尔半导体,2005 年,在线文档可访问: http://courses.cit.cornell.edu/ece576/Verilog/FreescaleVerilog.pdf

[ 4] Jane Smith,“Verilog 编码指南,Rev. B”,Cisco Systems,2000 年,在线文档可访问:http://www.engr.sjsu.edu/cpham/VERILOG/VerilogCodingStyle.pd

致谢: 以上规范文档来自ADI官网

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

我们将24小时内回复。
取消