Verilog基础语法——parameter、localparam与`define

news2024/11/17 19:39:12

Verilog基础语法——parameter、localparam与`define

  • 写在前面
  • 一、localparam
  • 二、parameter
  • 三、`define
  • 写在最后

写在前面

  在使用Verilog编写RTL代码时,如果需要定义一个常量,可以使用`define、parameter和localparam三种进行定义与赋值。

一、localparam

  localparam是一种局部常量,只在声明该常量的模块中有效,不可用于模块与模块之间的参数传递。一般在定义仅用于模块内部的参数时使用localparam,比如状态机状态的定义声明。例如:

// FSM Sate
localparam IDLE         = 4'b0001;
localparam INPUT        = 4'b0010;
localparam DECODE       = 4'b0100;
localparam COMPLETE     = 4'b1000;

// FSM
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        curr_state <= IDLE;
        //...
    end
    else begin
        case(curr_state) 
            IDLE:
            begin
            	if(start)
                    curr_state <= INPUT;
                else
                	curr_state <= IDLE;
                //...             
            end

            INPUT   :
            begin
                curr_state <= DECODE;
                //...
            end

            DECODE      :        
            begin
            	curr_state <= COMPLETE;
                //... 
            end

            ALL_COMPLETE:
            begin
            	curr_state <= IDLE;
            end

            default :;
        endcase
    end
end

二、parameter

  parameter与localparam相同的是,其作用范围仅仅是声明该参数的模块内部,而不同的是,parameter可以用于模块之间的参数传递,一般用于参数化设计。参数化设计是指对于所设计的功能子模块,通过修改其内部参数值即可使得该模块适用于其他场景。
  这里,parameter可以分为在模块头部中声明与在模块内部定义声明,两种定义方式需要不同的方式来进行参数传递。

(1)在模块头部中定义
  在模块头部中定义参数是一种常用的做法,其格式如下:

module counter
#(
    parameter CNT_NUM    = 8'd128 ,
    parameter DIN_WIDTH  = 4'd8   ,
    parameter DOUT_WIDTH = 5'd16   
)
(
    input    wire    [DIN_WIDTH-1:0]    din , 
    output   wire    [DOUT_WIDTH-1:0]   dout
);
    // 模块内部代码
    // ...

endmodule

  而在模块例化时,需要与例化模块输入输出端口一样,给参数接入不同的数值即可,其格式如下:

module top
(
    // 输出输入声明
    // ...
);

    localparam CNT_NUM = 8'd100;
    localparam DIN_WIDTH  = 4'd6;
    localparam DOUT_WIDTH = 5'd12;   

    wire    [DIN_WIDTH-1:0]    counter_din ; 
    wire    [DOUT_WIDTH-1:0]   counter_dout;


    // 模块例化
    counter 
    #(
        .CNT_NUM   (CNT_NUM   ), // 参数传递
        .DIN_WIDTH (DIN_WIDTH ), // 参数传递
        .DOUT_WIDTH(DOUT_WIDTH)  // 参数传递
    )
    counter_inst
    (
        .din (counter_din ), 
        .dout(counter_dout)
    )
    // ...

endmodule

(2)在模块内部定义
  在模块内部定义的paramter其格式如下:

module counter
(
    input    wire    [15:0]   din , 
    output   wire    [7:0]    dout
);

    parameter CNT_NUM    = 8'd128 ;
    parameter DIN_WIDTH  = 4'd8   ;
    parameter DOUT_WIDTH = 5'd16  ;

    // 模块内部代码
    // ...

endmodule

  在上层模块的例化中可以通过defparam进行修改所例化模块中定义参数的值,其格式如下:

module top
(
    // 输出输入声明
    // ...
) ;

    wire    [15:0]    counter_din ; 
    wire    [7:0]     counter_dout;

    // 模块例化
    counter counter_inst
    (
        .din (counter_din ), 
        .dout(counter_dout)
    );
	
	// 格式:
	// defparam 模块例化名称 参数名称 = 重新设定的参数值
	// 如果是多层嵌套子模块,在模块3中例化模块2,在模块2中例化模块1,则格式为:
	// defparam 模块3例化名称 模块2例化名称 模块1例化名称 参数名称 = 重新设定的参数值
    defparam counter_inst CNT_NUM = 8'd100;
    defparam counter_inst DIN_WIDTH  = 4'd6;
    defparam counter_inst DOUT_WIDTH = 5'd12; 

endmodule

  这种方式的缺点在于:该方式声明的parameter无法用于模块输入输出信号位宽的控制,因为参数定义声明在模块的内部。

三、`define

  通过`define定义的参数作用范围是整个设计工程文件,遇到`undef则失效,其格式如下:

`define CNT_NUM 8'd128
module counter
(
    // 输出输入声明
    // ...
)

    // 模块内部代码
    // ...

endmodule

  也可以将所以`define定义声明的参数放在一个单独文件中,并在每个模块中使用`include包含声明文件,以作用于整个工程项目。其格式如下:

// para_def.vh
// 独立参数声明文件
`define CNT_NUM 8'd128
`define DIN_WIDTH  4'd6;
`define DOUT_WIDTH 5'd12; 

  然后再每个模块的前面使用`include包含该参数声明文件即可使用,格式如下:

// `include "路径/参数声明文件名"
`include "F/xxx/RTL/para_def.vh"
module counter
(
    // 输出输入声明
    // ...
)
 
    // 模块内部代码
    // ...
	
	// 使用格式:`参数名
	always @(posedge clk) begin
		if(cnt == `CNT_NUM)
			
		else
		
	end

endmodule

写在最后

  在本文中,我们学习了Verilog基础语法中三种不同的参数定义方式——localparam、parameter与`define,其中,`define定义的参数作用范围最广,且支持用于模块之间的参数传递;localparam作用范围仅为模块内部,且不支持参数传递;而parameter是两者的折中,作用范围为模块内部,但是支持参数传递。在实际代码编写过程中,应选择合适的方式对不同参数进行声明,使用时可以参考下表。

关键字适用场景
localparam仅用于模块内部的参数,且在不同场景下无需进行修改
parameter仅用于模块内部的参数,但是在不同场景下需要进行修改
`define整个工程文件中都会用到的参数

  本文到此结束,欢迎评论区交流探讨。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1625203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

施耐德EOCR-2CT-300/5电流互感器 50HZ 5VA

EOCR主要产品有电子式电动机保护继电器&#xff0c;电子式过电流继电器&#xff0c;电子式欠电流继电器&#xff0c;电子式欠电压继电器&#xff0c;其它保护和监视装置&#xff0c;电流互感器。 施耐德EOCR-2CT-300/5电流互感器 EOCR-2CT系列型号&#xff1a; EOCR 2CT 100…

操作系统安全:Linux安全审计,Linux日志详解

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

18.Nacos配置管理-微服务读取Nacos中的配置

需要解决的问题 1.实现配置更改热更新&#xff0c;而不是改动了配置文件还要去重启服务才能生效。 2.对多个微服务的配置文件统一集中管理。而不是需要对每个微服务逐一去修改配置文件&#xff0c;特别是公共通用的配置。 配置管理服务中的配置发生改变后&#xff0c;回去立…

leetcode-二叉树的镜像-91

题目要求 思路1 1.遍历一遍二叉树&#xff0c;将左边的结点对应创建一个右边的结点 2.用此方法空间复杂度O(n)&#xff0c;并不是最优 思路2 1.将一个结点的左右子树进行交换&#xff0c;如果左子树还有左右结点&#xff0c;就再交换左子树的左右结点&#xff0c;以此递归下去…

vscode 创建代码模版

在vscode中快捷创建代码模版 1.在VSCode中&#xff0c;按下Ctrl Shift P&#xff08;Windows/Linux&#xff09;或Cmd Shift P&#xff08;Mac&#xff09;打开命令面板。 2.然后输入"Preferences: Configure User Snippets"并选择该选项。打开一个json文件用户…

Python函数小知识

目录 一、函数的定义和调用 二、函数参数 三、函数作用域 四、递归函数和匿名函数 一、函数的定义和调用 def 函数名(参数): 自定义函数可以分为有参函数和无参函数 。 函数的作用&#xff1a; 在Python中定义函数可以提高代码的复用率&#xff0c;避免重复的代码&#xff0c;…

matlab保存示波器数据

再重新运行一下示波器 然后就可以在工作区看见&#xff08;这里没有运行所以没有&#xff09; 将保存到文件夹中方便后续绘图

服务于金融新核心系统 星辰天合与中电金信完成产品兼容认证

近日&#xff0c;北京星辰天合科技股份有限公司&#xff08;简称&#xff1a;XSKY星辰天合&#xff09;与中电金信软件有限公司&#xff08;简称&#xff1a;中电金信&#xff09;完成产品兼容性认证&#xff0c;星辰天合的企业级分布式统一数据平台 XEDP 符合金融级数字底座&q…

“一个有趣的C语言代码”分析

“一个有趣的C语言代码” 一个有趣的C语言代码-流浪的海豚-ChinaUnix博客 #include <stdio.h> int print() {printf("hello world!\n");return 0; } int main(void) {long base[0];long* result base3;*(result1) *result;*result (long)print;return 0; …

Qt : 在QTreeWidget中添加自定义右键菜单

一、引言 如图&#xff0c;我们需要在一个QTreeWidget 控件中添加了自定义右键菜单。 二、思路 如何做到的呢&#xff0c;很简单。浅浅记录和分享一下。 继承QTreeWidget&#xff0c;定义一个子类CustomTreeWidget &#xff0c;在重写contextMenuEvent 事件即可。 三、代…

数据结构初阶——树和二叉树

数据结构初阶——树和二叉树 1. 树的概念和结构1.1 树的概念1.2 树的表示 2. 二叉树2.1 二叉树的概念和结构2.2 二叉树的存储结构2.2.1 顺序存储2.2.2 链式存储 3. 二叉树的顺序结构及实现——堆3.1 堆的概念和结构3.2 堆的实现3.2.1 堆的定义3.2.2 堆的向上调整3.2.3 堆的向下…

Pycharm/Dataspell中使用jupyter导入ros humble包

配置ros humble对应python包路径文件 首先在~/.local/lib/python3.10/site-packages目录下新建一个.pth文件&#xff0c;如下图所示。 将对应的ros humble的python包的路径配置在上述文件中&#xff0c;一行放置一个路径&#xff0c;对应的路径如下图所示。 完成上述操作后…

ESP32 IDF环境 连接WIFI

新建wifi.h #ifndef __WIFI_H_ #define __WIFI_H_#include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_wifi.h&…

IntelliJ IDEA - 10 款 IDEA 宝贝插件,YYDS!

好久没发这种实用贴了&#xff0c;最近用到了一些能提升工作效率的IDEA插件&#xff0c;给小伙伴们分享一下。相信我&#xff0c;我分享的这些插件&#xff0c;都是实实在在能解决实际开发场景中痛处的。 1、POJO to JSON 开发工作中&#xff0c;常常在设计完API后&#xff0c…

recat组件使用Antd

安装和初始化 项目中进行安装yarn add antd或者npm i antd安装 使用 在App.js文件中引入按钮并使用 需要引入自己的css文件 模块化 import React, { Component } from react import { Button } from antd; //引入按钮 import antd/dist/antd.css; //还需要引入css样式 …

javascript使用setTimeout函数来实现仅执行最后一次操作

在JavaScript中&#xff0c;setTimeout函数用于在指定的毫秒数后执行一个函数或计算表达式。它的主要用途是允许开发者延迟执行某些代码&#xff0c;而不是立即执行。 当我们想要确保仅最后一次更新UI时&#xff0c;我们可以使用setTimeout来合并多次连续的更新请求。具体做法…

Ansible自动化

Ansible自动化 自动化的需求&#xff1a; 1. 在什么样的场景下需要自动化&#xff1f; 批量化的工作&#xff1a; 装软件包、配置服务、升级、下发文件… 2. 为什么在自动化工具中选择ansible&#xff1f; 对比shell脚本&#xff1a; 相对于用shell的脚本来实现自动化&#x…

vue+element 树形结构 改成懒加载模式(原理element有),这里只做个人理解笔记

1 找到属性标签添加 lazy 和 :load"loadNode" 这两个属性 2 引入树形接口,并和后端约定好传值,(拿我的举例 第一次获取全部父级默认第一次传参数:{ parentId : 0},可获取全部父级 第二次通过点击的子级把子级id传进去,这一步就用到了:load"loadNode&quo…

场内股票期权和场外期权(附场内期权交易攻略)

期权是交易双方关于未来买卖权利达成的合约。 就股票期权来说&#xff0c;期权的买方(权利方)通过向卖方(义务方)支付一定的费用(即期权费或权利金)&#xff0c;获得一种权利&#xff0c;即有权在约定的时间以约定的价格向期权卖方买入或卖出约定数量的标的股票或ETF。 买方(…

阶跃星辰:探索智能科技的星辰大海

引言 在当今快速发展的科技时代&#xff0c;人工智能已经成为推动社会进步的重要力量。阶跃星辰&#xff0c;正是在这一背景下诞生的。 阶跃星辰是一家专注于通用人工智能探索的公司&#xff0c;成立于2023年4月。该公司的创始团队由一群对人工智能充满热情和渴望的人组成&am…