当前位置: 代码迷 >> 综合 >> 【Verilog HDL】参数(Parameter)的作用案例
  详细解决方案

【Verilog HDL】参数(Parameter)的作用案例

热度:56   发布时间:2023-12-12 22:41:55.0

我在学习Verilog HDL的时候并没有系统的去学,只是大致的了解了下,然后就用一些常用的语法去设计简单常见的硬件电路,这样做的好处是节省时间,也不会感觉重新学习一门语言很累,但是也会遇到一些问题,例如,《基于PLL分频计数的LED灯闪烁实例》实验记录这篇博文中的一个小问题。

建议先看下上面提到的那篇博文,如果实在不想看,又想了解Parameter的作用,那就直接跳过下面的案例。

下面是顶层模块中的Verilog HDL设计代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    21:49:05 08/16/2018 
// Design Name: 
// Module Name:    sp6_pll 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module sp6_pll(input ext_clk_25m,	//外部输入25MHz时钟信号input ext_rst_n,	//外部输入复位信号,低电平有效output[7:0] led		//8个LED指示灯接口	);													wire clk_12m5;	//PLL输出12.5MHz时钟
wire clk_25m;	//PLL输出25MHz时钟
wire clk_50m;	//PLL输出50MHz时钟
wire clk_100m;	//PLL输出100MHz时钟
wire sys_rst_n;	//PLL输出的locked信号,作为FPGA内部的复位信号,低电平复位,高电平正常工作//-------------------------------------
//PLL例化pll_clk u1(// Clock in ports.CLK_IN1(ext_clk_25m),      // IN// Clock out ports.CLK_OUT1(clk_12m5),     // OUT.CLK_OUT2(clk_25m),     // OUT.CLK_OUT3(clk_50m),     // OUT.CLK_OUT4(clk_100m),     // OUT// Status and control signals.RESET(!ext_rst_n),// IN.LOCKED(sys_rst_n));      // OUT		//-------------------------------------
//12.5MHz时钟进行分频闪烁,计数器为23位															
led_control	#(23)		uut_led_controller_clk12m5(.clk(clk_12m5),		//时钟信号.rst_n(sys_rst_n),	//复位信号,低电平有效.sled(led[0])		//LED指示灯接口	);//-------------------------------------
//25MHz时钟进行分频闪烁,计数器为24位																
led_control	#(24)		uut_led_controller_clk25m(.clk(clk_25m),		//时钟信号.rst_n(sys_rst_n),	//复位信号,低电平有效.sled(led[1])		//LED指示灯接口	);//-------------------------------------
//25MHz时钟进行分频闪烁,计数器为25位																
led_control	#(25)		uut_led_controller_clk50m(.clk(clk_50m),		//时钟信号.rst_n(sys_rst_n),	//复位信号,低电平有效.sled(led[2])		//LED指示灯接口	);//-------------------------------------
//25MHz时钟进行分频闪烁,计数器为26位																
led_control	#(26)		uut_led_controller_clk100m(.clk(clk_100m),		//时钟信号.rst_n(sys_rst_n),	//复位信号,低电平有效.sled(led[3])		//LED指示灯接口	);		//-------------------------------------							
//高4位LED指示灯关闭							
assign led[7:4] = 4'b1111;			endmodule

上面代码中调用了下面的控制led灯闪烁的模块:

`timescale 1ns / 1ps//单个LED闪烁
module led_control(input clk,		//时钟信号input rst_n,	//复位信号,低电平有效output sled		//LED指示灯接口	);													parameter CNT_HIGH = 24;	//计数器最高位
//-------------------------------------
reg[(CNT_HIGH-1):0] cnt;		//24位计数器															//cnt计数器进行循环计数
always @ (posedge clk or negedge rst_n)									if(!rst_n) cnt <= 0;											else cnt <= cnt+1'b1;																		assign sled = cnt[CNT_HIGH-1];	//cnt从0开始计数时,led灯一直是亮的,然后计数达到最大值,led灯就灭了	endmodule

由于计数器使用不同的时钟计数,计同样的次数使用的时间不同,具体而言,12.5MHz的时钟计数到M花费的时间是25MHz的时钟的2倍,因此,若要二者计数时间相同,则25MHz的时钟要多计数一倍,也就是25MHz的时钟计数器的位数要多1位。这就是一个位数问题, 顶层模块调用同一个模块,可是被调用模块中的计数器位数不一致,如何解决这个调用问题呢?

这就引出了这篇博文的主题:parameter型常量的作用。

在被调用模块中声明了一个parameter型的常量,然后在顶层模块中调用该模块时,使用如下格式指定该参数的具体位数。

//12.5MHz时钟进行分频闪烁,计数器为23位                                                            
led_control    #(23)        uut_led_controller_clk12m5(
                                .clk(clk_12m5),        //时钟信号
                                .rst_n(sys_rst_n),    //复位信号,低电平有效
                                .sled(led[0])        //LED指示灯接口    
                            );


Verilog HDL中用parameter来定义常量,即用parameter来定义一个标识符来代表一个常量,称为符号常量,即标识符形式的常量,采用标识符代表一个常量可以提高程序的可读性和可维护性。

parameter型常量的声明格式如下:

parameter 参数名1 = 表达式, 参数名2 = 表达式,...,参数名n = 表达式。

parameter 参数名1 = 表达式;

parameter 参数名2 = 表达式;

...

parameter 参数名n = 表达式;

上面的表达式是常数表达式,也就是说只能包含数字或先前已经定义过的参数。

具体而言如下:

parameter msb = 7;

parameter byte_size = 8, byte_msb = byte_size - 1;

等等。

参数型常量经常用于定义延迟时间和变量宽度。

定义延迟时间太简单了,不在话下,本博文主要强调参数型常量用于定义变量宽度的作用。

本文开头举的一个例子就是定义变量宽度的实实在在的案例。

下面再举一个简单的例子说明:

module Top(...);//这是一个顶层模块wire [3:0] A4;
wire [4:0] A5;
wire [15:0] F16;
wire [31:0] F32;Decode #(4,0) U_D1(A4,F16); //使得Width = 4, Polarity = 0;
Decode #(5) U_D2(A5,F32); //使得 Width = 5,Polarity 不变,即为1;endmodulemodule Decode(A,F);    //这是一个子模块parameter Width = 1, Polarity = 1;
......endmodule

上面的顶层模块在对Decode模块进行实例化时,U_D1和U_D2的Width分别采用不同的值4和5,且U_D1的Polarity将为0。可以用例子中的方式来改变参数,即用#(4,0)向U_D1中传递Width = 4,Polarity = 0;用#(5)向U_D2中传递Width = 5,Polarity仍为1。

当然还有另外一种方式,即使用命令defparam命令来改变参数。这种方式我们下篇博文再说。

 

 

  相关解决方案