Verilog Tutorial(10)如何实现可复用的设计?

这篇具有很好参考价值的文章主要介绍了Verilog Tutorial(10)如何实现可复用的设计?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

在自己准备写verilog教程之前,参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错,只是没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。

这是网站原文:https://fpgatutorial.com/verilog/

这是系列导航:Verilog教程系列文章导航


本文将讨论可以用来实现代码可复用性的参数parameter和generate语句(生成语句)。

与大多数编程语言一样,设计者也应该尽量使verilog代码尽可能地具备可复用性----这能够减少未来项目的开发时间,因为设计者可以更轻松地将代码从一个设计移植到另一个设计。

在 verilog 中有两种语法可以帮助设计者编写可复用的代码——参数parameter和generate语句。这两种语法都允许设计者创建更通用的代码,以便在例化组件时可以通过修改代码的方式来满足其他的设计需求。

参数Parameter

参数parameter是常量(constant)的局部形式,它可以在例化模块时为其赋值。由于参数的作用范围有限,设计者可以多次调用同一个模块,并为参数赋不同的值。

在编写模块时必须定义一个模块接口,然后可以使用这个接口在FPGA 设计中与许多不同的模块实现互连。接口可以声明参数以及模块的输入和输出。

下面的 verilog 代码片段展示了在模块中声明参数的方法。当这样在 verilog 模块中声明参数时,我们称其为参数化模块(a parameterized module)。

module <module_name> #(
  parameter <parameter_name> = <default_value>    //声明参数
)
(
  //端口定义
);

上面代码中的 <parameter_name> 用于为参数提供标识符。设计者可以使用此标识符在代码中调用参数值--就像使用普通变量一样。

代码中的<default_value> 将为参数分配一个默认值,这很有用,因为它允许设计者例化组件而无需专门为参数分配值。

在例化一个模块时可以使用命名关联(named association)或位置关联(positional association)的方法来为参数赋值,这与直接将信号分配给模块上的输入或输出的作用完全相同。但是在使用verilog-1995标准编写代码时,只能使用位置关联方法来为参数赋值。

下面的 verilog 代码片段展示了在例化模块时用于为参数赋值的方法。

//名称关联
<module_name> # (
  .<parameter_name> (<parameter_value>)
)
<instance_name> (
  //端口连接
);
 
//位置关联
<module_name> # (<parameter_values>)
<instance_name> (
  //端口连接
);

示例

为了更好地理解如何在 verilog 中使用参数,请考虑一个基本示例:设计两个同步计数器,一个是 8 位宽,另一个是 12 位宽。

为了实现这个电路可以设计两个具有不同宽度的不同计数器,但这显然是一种低效的编码方式。相反,如果设计一个计数器并使用一个参数来更改输出中的位数,则会更加高效。

下面的 verilog 代码片段展示了如何为参数化计数器模块编写接口。

module counter #(
  parameter BITS = 8;
)
(
  input wire clock,
  input wire reset,
  output reg [BITS-1 : 0] count
);

这个例子展示了如何使用参数来调整 verilog 中信号的位宽。示例并不是使用固定数字来声明端口信号的位宽,而是将参数值替换到端口声明中。这是 verilog 中一个最常见的参数示例。

上面的verilog代码中定义了BITS参数的默认值为8。因此,如果想要一个不是 8 位的输出时,设计者只需要为参数重新赋值。

下面的代码片段展示了当需要 12 位输出时如何例化此模块。这种情况必须在例化 verilog 模块时重写参数的默认值。

counter # (
  .BITS (12)
) count_12 (
  .clock  (clock),
  .reset  (reset),
  .count  (count_out)
);

虽然上面的例子中只使用了命名关联方法,但其实也可以使用位置关联方法来为参数赋值。

下面的代码片段就展示了如何使用位置关联方法来将 12 赋给参数 BITS 。

counter # (12) count_12 (clock, reset, count_out);

Generate语句

generate 语句可以被用来在设计中生成条件的(Conditional)或迭代的(iterative)代码块。这允许设计可以有选择地包含或排除代码块或创建特定代码块的多个实例。

只能在并发verilog代码块(concurrent verilog code blocks)中使用 generate 语句,这意味着它不能被包含在always blocks或initial blocks中。此外,generate 关键字还必须结合if语句、case语句或者for循环语句来使用。

generate if 和 generate case 语句被用来来有条件地生成代码,而 generate for 语句则迭代地生成代码。generate块中可以编写需要的任何有效的 verilog 代码,包括always blocks、模块例化和其他generate语句。

generate语句是在verilog-2001标准中引入的,所以设计者不能在基于verilog-1995标准的设计中使用它。

Generate For 语句

设计者可以在generate块中使用verilog中的for循环来迭代地创建一段代码的多个实例。 generate for loop 语法通常被用来使用描述有规则的和重复的结构的硬件。

例如,设计者可能想要使用单个总线控制多个RAM模块。如果使用generate块而不是手动例化所有模块,那么就可以有效地减少代码行数。

下面的代码片段展示了generate for 块的一般语法。

//声明循环变量
genvar <name>;
 
//generate块的代码
generate
  for (<initial_condition>; <stop_condition>; <increment>) begin
    //要重复执行的代码
  end
endgenerate

从这里可以看出来,这种语句实际上可for循环语句是很类似的,但是两者之间仍有两个很大的区别。首先,设计者必须使用 genvar 类型来声明循环变量。其次,设计者应在 generate 块中声明循环,而不是像在always块这样的普通过程块中,这种差异很重要,因为它改变了代码的基本行为。

编写一个 generate for block 实际上是让编译工具创建代码的多个实例。相反,使用普通的 for 循环则是让编译工具创建代码的单个实例但要多次执行它。

作为示例,请看一个非常简单的用例:将数据分配给 2 bits向量。

下面的 verilog 代码展示了如何使用 generate for 和 for 循环来做到这一点。在这两种情况下,代码的功能相同,但生成的结构却大不相同。

//使用for循环的方法
always @(posedge clock) begin
  for (i = 0; i < 2; i = i + 1) begin
    sig_a[i] = 1'b0;
  end
end

//使用generate for循环的方法
generate
  for (i = 0; i < 2; i = i + 1) begin
    always @(posedge clock) begin
      sig_a[i] = 1'b0;
    end
  end
endgenerate

如果将for循环的代码展开,那么将得到如下所示的代码。

always @(posedge clock) begin
  sig_a[0] = 1'b0;
  sig_a[1] = 1'b0;
end

相反,将generate for的代码展开将如下所示。

always @(posedge clock) begin
  sig_a[0] = 1'b0;
end

always @(posedge clock) begin
  sig_a[1] = 1'b0;
end

由此可以看出 generate for 与 for 循环有何根本不同。

示例

为了更好地演示 verilog generate for 语句的工作原理,请考虑一个基本示例:连接到同一总线的 3 个 RAM 模块的数组,每个 RAM 模块都有一个写使能端口、一个 4 位地址输入和 4 位数据输入。这些信号都被连接到同一总线。此外,每个 RAM 都有一个 4 位数据输出总线和一个使能信号,它们对于每个 RAM 块都是独立的。下面的电路图展示了将要设计的电路。

Verilog Tutorial(10)如何实现可复用的设计?

为此需要声明一个 3 位的向量,可以使用它来连接到 RAM 使能端口,庵后可以根据循环变量的值将不同的位连接到每个 RAM。

对于数据输出总线,可以创建一个 12 位向量并将读取的数据输出连接到该向量的不同 4 位向量。然而,更高效的解决方案是使用由 3 个 4 位向量组成的数组。同样也可以使用循环变量根据需要赋值该数组的不同元素。

下面的 verilog 代码片段展示了如何使用 for generate 语句对这个电路进行设计。


wire [3:0] rd_data [2:0];    //读数据数组
wire [2:0] enable;           //使能信号构建的向量


genvar i;        //循环变量
generate
  for (i=0; i<=2; i=i+1) begin
    ram ram_i (
      .clock    (clock),
      .enable   (enable[i]),
      .wr_en    (wr_en),
      .addr     (addr),
      .wr_data  (wr_data),
      .rd_data  (rd_data[i])
    );
  end
endgenerate

综合这段代码后,将得到如下所示的电路。

Verilog Tutorial(10)如何实现可复用的设计?

Generate If语句

generate if语句可以在设计中有条件地生成 verilog 代码。当设计者只想将代码在特定条件下使用时,可以使用 generate if 语句。与此有关的一个例子是当设计者想在设计中包含一个专门用于测试的功能时,为此可以使用 generate if 语句来确保仅将此函数包含在调试版本的代码中,而不会包含在生产版本代码中。

下面的代码片段展示了 generate if 语句的一般语法。

generate
  if (<condition1>) begin
    //要执行的代码
  end
  else if (<condition2>) begin
    //要执行的代码
  end
  else begin
    //要执行的代码
  end
endgenerate

从这个示例可以看到,该语法虽然与verilog中的if语法是类似的,但这两种方法之间存在根本区别。

编写 generate if 语句时,实际上是让编译工具根据某些条件创建代码块的实例。这意味着只有一个分支会被编译,而任何其他分支都将被排除在编译之外。

相反,使用 if 语句时,整个 if 语句将被编译并且可以执行语句的每个分支。每次在仿真期间触发 if 语句时,都会判断条件以确定执行哪个分支。

示例

为了更好地演示generate if 语句的工作原理,请考虑一个基本示例:编写一个输出 4 位计数器值的测试电路。由于这是一个测试功能,所以只需要在使用调试版本时激活它;构建生产版本代码时,将计数器输出接地。为此将使用一个参数来确定何时应该构建调试版本的电路。

下面的代码片段展示了如何实现这个示例。

parameter debug_build = 0;

generate
  if (debug_build) begin
    always @(posedge clock, posedge reset) begin
      if (reset) begin
        count <= 4'h0;
      end
      else begin
        count <= count + 1;
      end
    end
  end
  else begin
    initial begin
      count <= 4'h0;
    end
  end
endgenerate

当 debug_build 被设置为 1 时,综合工具会生成如下所示的电路----四位计数器电路。

Verilog Tutorial(10)如何实现可复用的设计?

但当 debug_build 被设置为 0 时,综合工具则会生成如下所示的电路----计数信号的所有位均接地。

Verilog Tutorial(10)如何实现可复用的设计?

Generate Case语句

generate case 语句可以被用来有条件地在设计中包含 verilog 代码块。generate case 语句基本上与 generate if 语句功能相同,但语法不同。这意味着如果只想在特定条件下将某部分包含在设计中时,设计者也可以使用 generate case 语句。

例如,如果设计者想要设计一个只想包含在调试版本中的测试电路,就可以使用 generate case 语句来确定构建哪个版本的代码。

下面的代码片段展示了generate case 语句的一般语法。

generate
  case (<variable>)
    <value1> : begin
      //当<variable> = <value1>执行这个分支语句
    end
    <value2> : begin
      //当<variable> = <value2>执行这个分支语句
    end
    default : begin
    //其他情况执行这个分支语句
    end
  endcase
endgenerate

从这个示例可以看到,该语法虽然与verilog中的case语法是类似的,但这两种方法之间存在根本区别。

编写 generate case 语句时,实际上是让编译工具根据某些条件创建代码块的实例。这意味着只有一个分支会被编译,而任何其他分支都将被排除在编译之外。

相反,使用 case 语句时,整个 case 语句将被编译并且可以执行语句的每个分支。每次在仿真期间触发 case语句时,都会判断条件以确定执行哪个分支。

示例

由于generate case语句与 if generate 语句功能类似,所以仍以generate if章节中使用的示例为例。下面的 verilog 代码展示了如何使用 generate case 语句来实现这个例子。

parameter debug_build = 0;

generate
  case (debug_build)
    1 : begin
      always @(posedge clock, posedge reset) begin
        if (reset) begin
          count <= 4'h0;
        end
        else begin
          count <= count + 1;
        end
      end
    end
    default : begin
      initial begin
        count <= 4'h0;
      end
    end
  endcase
endgenerate

当 debug_build 被设置为 1 时,综合工具会生成如下所示的电路----四位计数器电路。

Verilog Tutorial(10)如何实现可复用的设计?

但当 debug_build 被设置为 0 时,综合工具则会生成如下所示的电路----计数信号的所有位均接地。

Verilog Tutorial(10)如何实现可复用的设计?

  • 📣您有任何问题,都可以在评论区和我交流📃

  • 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net

  • 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏文章来源地址https://www.toymoban.com/news/detail-408970.html


到了这里,关于Verilog Tutorial(10)如何实现可复用的设计?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • m基于FPGA的半带滤波器verilog设计,对比普通结构以及乘法器复用结构

    目录 1.算法描述 2.仿真效果预览 3.verilog核心程序 4.完整FPGA         HBF模块由半带滤波器(HBF)和抽取模块组成。该模块的任务是实现2倍抽取进一步降低信号采样速率。由于HBF的冲激响应h(k)除零点外其余偶数点均为零,所以用HBF实现2倍抽取可以节省一半的运算量,对增强软

    2023年04月08日
    浏览(76)
  • Verilog Tutorial(8)循环语句

    在自己准备写verilog教程之前,参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错,只是没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。 这是网站原文:https://fpgatutorial.com/verilog/ 这是系列导航:Verilog教程系列文章导航 这篇文

    2023年04月10日
    浏览(40)
  • Verilog Tutorial(2)数据类型和数组简介

    在自己准备写verilog教程之前,参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错,只是没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。 这是网站原文:https://fpgatutorial.com/verilog/ 这是系列导航:Verilog教程系列文章导航 在这篇

    2023年04月25日
    浏览(32)
  • Verilog Tutorial(7)If语句和Case语句

    在自己准备写verilog教程之前,参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错,只是没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。 这是网站原文:https://fpgatutorial.com/verilog/ 这是系列导航:Verilog教程系列文章导航 这篇文

    2023年04月10日
    浏览(40)
  • MySQL用的在溜,不知道业务如何设计也白搭!!!

    作者: 博学谷狂野架构师 GitHub: GitHub地址 (有我精心准备的130本电子书PDF) 只分享干货、不吹水,让我们一起加油!😄 范式设计 范式概述 第一范式: 当关系模式R的所有属性都不能在分解为更基本的数据单位时,称R是满足第一范式的,简记为1NF。满足第一范式是关系模式

    2023年04月27日
    浏览(50)
  • 手势交互!人人都会用的交互方式应该如何设计?

    手势交互是指通过手部动作来进行人机交互的一种方式。随着移动设备和触摸屏技术的普及,手势交互成为了一种重要的交互方式。它可以使用户更加直观地操作设备,提升用户体验,同时也可以拓展设备的交互维度,使得用户可以通过更加丰富的手势来完成各种操作。 手势

    2024年01月21日
    浏览(36)
  • Verilog数字系统设计——10进制计数器,具有异步复位功能

    编程实现10进制计数器,具有异步复位功能,十位和个位用8421BCD码表示,各端口定义如下图所示: 仔细考虑端口定义中每个端口的含义; 要求完成程序编辑、编译、时序仿真; 实验提交Verilog设计文件(.v文件)、仿真波形截图以及对于第3个步骤所提出问题的回答,文件打包

    2024年02月11日
    浏览(35)
  • FFmpeg: 自实现ijkplayer播放器--07解复用线程设计

    解复用 解复用,读取视频文件,生成数据包(packet),同时,实现数据包队列,存储数据包,用来解码生成数据帧(frame) 解复用线程 read_thread : 创建上下文结构体: avformat_alloc_context 打开文件 avformat_open_input 获取流信息 avformat_find_stream_info 区分视频流和音频流 av_find_best_st

    2024年04月17日
    浏览(63)
  • java中线程池是如何实现复用的?

    Java 中线程池实现线程复用的核心机制在于通过维护一定数量的核心线程和可扩展的工作队列来处理任务。线程复用的过程可以分为以下几个步骤: 核心线程复用: 线程池会维护一定数量的核心线程,这些线程在处理任务时会一直保持存活,不会被回收。当有新任务提交时,

    2024年02月04日
    浏览(49)
  • 【FPGA/verilog -入门学习10】verilog 查表法实现正弦波形发生器

    用查找表设计实现一个正弦波形发生器 寻址的位宽是10位,数据量是1024个,输出的数据是16位 数据量是1024个: x = linspace(0,2*pi,1024) 输出数据是16位: y范围:0~2^16 -1 = 0~65535 y =( sin(x)+1)*65535/2 寻址的位宽是10位 输入是0~1023 1023 占用10位 操作步骤 1,使用matlab 生成数据,制作

    2024年02月05日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包