关于FPGA设计中的参数化设计

在设计中引入参数化设计可以大大提高模块的可重用性以及节约资源,下面用点灯来记录一下几种常见的设计方式和例化方式。

一、在设计中引入parameter参数

底层模块设计

实现500ms时,led自动翻转,led的闪烁周期是1s,亮500ms,灭500ms。

module param_design
(
    input       wire            clk             ,
    input       wire            rst_n           ,
    
    output      reg             led
);

    reg     [24:0]  cnt;
    parameter   CNT_MAX = 25'd24_999_999;

always@(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt <= 25'd0;
    else if(cnt == CNT_MAX)
        cnt <= 25'd0;
    else
        cnt <= cnt + 1'b1;
        
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        led <= 1'b1;
    else if(cnt == CNT_MAX)
        led <= ~led;
    else
        led <= led;

endmodule

1、defparam方式传入数据

在tb中改变CNT_MAX的数值可以大大减少仿真时等待时间。

`timescale 1ns/1ns
`define clk_period 20
module param_design_tb;

//============================<端口>==============================

reg     clk;
reg     rst_n;

wire    led;

//================================================================
//==                         模块例化
//================================================================
param_design param_design_inst_0
(
   .clk             (clk),
   .rst_n           (rst_n),

   .led             (led)
);

defparam param_design_inst_0.CNT_MAX = 25'd24_99;

//================================================================
//==                         时钟信号
//================================================================
initial clk = 1'b1;
always #(`clk_period/2) clk = ~clk;

//================================================================
//==                       设计输入信号
//================================================================
initial begin
    rst_n = 0;
    #201;
    rst_n = 1;
    #20000000;
    $stop; 
end

endmodule

仿真结果

根据defparam传入的24_99可知2500个时钟周期翻转一次,测试结果验证了设计的正确性。

实用顶层设计

defparam应用在顶层时,可以提高模块的可重用性。该顶层实现了两个led的亮灭。

module led_top
(
    input       wire            clk     ,
    input       wire            rst_n   ,
    
    output      wire     [1:0]  led
);


param_design param_design_inst0
( 
    .clk             (clk),
    .rst_n           (rst_n),

    .led             (led[0])
);

defparam    param_design_inst0.CNT_MAX = 25'd24_999_999; //500ms翻转



param_design param_design_inst1
( 
    .clk             (clk),
    .rst_n           (rst_n),

    .led             (led[1])
);

defparam    param_design_inst1.CNT_MAX = 25'd12_499_999;//250ms翻转


endmodule

2、例化时传入数据

还是同样的模块设计,采用在例化时传入数据。(要特别注意这种方式的书写方式

`timescale 1ns/1ns
`define clk_period 20
module param_design_tb;

//============================<端口>==============================

reg     clk;
reg     rst_n;

wire    led;

//================================================================
//==                         模块例化
//================================================================
param_design
#(
   .CNT_MAX(25'd24_99)
)
param_design_inst_0
(
   .clk             (clk),
   .rst_n           (rst_n),

   .led             (led)
);

//defparam param_design_inst_0.CNT_MAX = 25'd24_99;

//================================================================
//==                         时钟信号
//================================================================
initial clk = 1'b1;
always #(`clk_period/2) clk = ~clk;

//================================================================
//==                       设计输入信号
//================================================================
initial begin
    rst_n = 0;
    #201;
    rst_n = 1;
    #20000000;
    $stop; 
end

endmodule

二、定义端口时添加一个数据输入端口

module param_design
(
    input       wire                clk             ,
    input       wire                rst_n           ,
    input       wire     [24:0]     CNT_MAX         ,
    output      reg                 led
);

    reg     [24:0]  cnt;

always@(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt <= 25'd0;
    else if(cnt == CNT_MAX)
        cnt <= 25'd0;
    else
        cnt <= cnt + 1'b1;
        
always@(posedge clk or negedge rst_n)
    if(!rst_n)
        led <= 1'b1;
    else if(cnt == CNT_MAX)
        led <= ~led;
    else
        led <= led;

endmodule

1、tb数据传入

`timescale 1ns/1ns
`define clk_period 20
module param_design_tb;

//============================<端口>==============================

reg                     clk;
reg                     rst_n;
reg     [24:0]          CNT_MAX;

wire                    led;

//================================================================
//==                         模块例化
//================================================================
param_design param_design_inst_0
(
   .clk             (clk),
   .rst_n           (rst_n),
   .CNT_MAX         (25'd24_99),
   .led             (led)
);

//defparam param_design_inst_0.CNT_MAX = 25'd24_99;

//================================================================
//==                         时钟信号
//================================================================
initial clk = 1'b1;
always #(`clk_period/2) clk = ~clk;

//================================================================
//==                       设计输入信号
//================================================================
initial begin
    rst_n = 0;
    #201;
    rst_n = 1;
    #20000000;
    $stop; 
end

endmodule


2、仿真结果

验证方法室可行的。

三、总结

  1. 总体分为两种引入方式,一种是使用parameter参数,一种是添加端口。

  1. 采用第一种方式时,可以采取两种方式传入数据,各有优缺点吧,defparam书写起来简单,但是模块例化过多时容易晕,而例化时传入则非常容易区分和维护,但要注意其书写方式,比较容易出现语法错误。

  1. 二是定义端口时添加一个input数据输入端口。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李亚有鸭梨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值