【FPGA】verilog语法的学习与应用 —— 位操作 | 参数化设计

【FPGA】verilog语法的学习与应用 —— 位操作 | 参数化设计

学习新语法,争做新青年

计数器实验升级,让8个LED灯每个0.5s的速率循环闪烁,流水灯ahh好久不见~ 去年光这个就把我折磨够呛。。我肉眼可见的脱发就是从那时候开始的。。在那两个月我直接掉了10斤啊喂~ (没节食、没运动、没失恋哈哈哈

  • 产生0.5s周期的计数器

1. version 1 - 移位法

1.1 设计输入

module led_run(
    Clk,
    Reset_n,
    Led
);
    input Clk;
    input Reset_n;
    output reg[7:0]  Led;
    
    reg[24:0] counter;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == 24999999)
        counter <= 0;
    else
        counter <= counter + 1'b1; 
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 8'b0000_0001;
    else if(counter == 24999999) begin
        if(Led == 8'b1000_0000)
            Led <= 8'b0000_0001;
        else
            Led <= Led << 1;
    end
    else 
        Led <= Led; //当然了,时序逻辑中不加这句话默认保持状态
endmodule

1.2 功能仿真

为了避免仿真跑的时间太长,我们ba0.5s替换为0.05s,所以我们姑且把24999999999替换为24999,也就是500ms→500ums。

`timescale 1ns/1ns

module led_run_tb();
    //激励信号
    reg Clk;
    reg Reset_n;
    wire[7:0] Led;
    
 led_run led_run_inst(  //例化
    //连线
    .Clk(Clk),
    .Reset_n(Reset_n),
    .Led(Led)
);
    initial Clk = 1;
    always #10 Clk = ~Clk; //一个周期20ns
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #4000000; //8*500us = 40000000ns
        $stop;
    end
    
endmodule
image-20220920092850196

1.3 板子调试

别忘了把时间调回来啊喂!不然可看不出流水了~

是的,我写完这句话就忘调了。。不愧是我

2. version 2 - 循环移位

改进移位

module led_run1(
    Clk,
    Reset_n,
    Led
);
    input Clk;
    input Reset_n;
    output reg[7:0]  Led;
    
    reg[24:0] counter;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == 25'd24999999)
    //else if(counter == 25'd24999) 
        counter <= 0;
    else
        counter <= counter + 1'b1; 
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 8'b0000_0001;
    else if(counter == 25'd24999999) 
    //else if(counter == 25'd24999) 
        Led <= {Led[6:0], Led[7]};
    else 
        Led <= Led; //当然了,时序逻辑中不加这句话默认保持状态
endmodule
  • Led <= {Led[6:0], Led[7]};
    • {}:位拼接
    • 循环移位

虽然。。这种写法用的也不多~

那我们来仿真一下,test bench把例化时名称改一下就ok

没问题~~

3. version 3 - 3-8译码器

引入3-8译码器的逻辑

模块中调用模块:把文件拷贝过来 → Add files即可

image-20220921101453857

这里例化模块和test bench中是一模一样的方法~ 我我我悟了!

`timescale 1ns/1ns

module led_flash_tb();
    //激励信号
    reg Clk;
    reg Reset_n;
    wire[7:0] Led;
    
 led_run2 led_run_inst(  //例化
    //连线
    .Clk(Clk),
    .Reset_n(Reset_n),
    .Led(Led)
);
    initial Clk = 1;
    always #10 Clk = ~Clk; //一个周期20ns
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #4000000; //8*500ms = 40000000ns
        $stop;
    end
    
endmodule
  • 由于现在Led是由底层模块驱动的,我们在底层已经定义为reg型了,所以顶层要去掉

4. 参数化设计

是的,你看到了,我转头就忘了把时间改回来了~

啊这就相当于C语言中的**#define定义常量**

我们在led_run中添加 ——

    parameter MCNT = 25'd24999;

并在led_run_tb中这样写:

     led_run led_run_inst(  //例化
        //连线
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Led(Led)
    );    
    defparam led_run_inst.MCNT = 24999;

或者在led_run_tb中这样来写

    led_run2
    #(
        .MCNT(24999)
    )
	led_run_inst(  //例化
        //连线
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Led(Led)
    );

让4个LED灯以不同的频率进行闪烁

0.1s, 0.2s, 0.3s, 0.4s…

image-20220921111113398

led_flash.v

module led_flash (
    //端口
    Clk,
    Reset_n, //复位
    Led
);
    //端口定义
    input Clk;
    input Reset_n;
    output reg Led;
    
    parameter MCNT = 24999999;
    reg[24:0] counter;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        counter <= 0;
	else if(counter == MCNT) 
        counter <= 0;
    else     
        counter <= counter + 1'd1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Led <=0;
    else if(counter == MCNT) 
        Led <= !Led;

endmodule

led_run_8_test.v

`timescale 1ns / 1ps

module led_run_8_test(
        //端口
        Clk,
        Reset_n, //复位
        Led
    );
    
     //端口定义
     input Clk;
     input Reset_n;
     output[3:0] Led;    
     
    led_flash led_flash_inst0(
        .Clk(Clk),
        .Reset_n(Reset_n), 
        .Led(Led[0])
    );
    defparam led_flash_inst0.MCNT = 2499999;//0.1s
    
     led_flash led_flash_inst1(
        .Clk(Clk),
        .Reset_n(Reset_n), 
        .Led(Led[1])
    );
    defparam led_flash_inst1.MCNT = 4999999;//0.2s

    
    led_flash led_flash_inst2(
        .Clk(Clk),
        .Reset_n(Reset_n), 
        .Led(Led[2])
    );
    defparam led_flash_inst2.MCNT = 7499999; //0.3s 150ms = 150000000ns/20ns = 7500000

    
     led_flash led_flash_inst3(
        .Clk(Clk),
        .Reset_n(Reset_n), 
        .Led(Led[3])
    );
    defparam led_flash_inst3.MCNT = 9999999; //0.4s 200ms = 200000000/20ns = 10000000

   
endmodule

添加约束文件

右击,手动设置为target

image-20220921112522635

复制之前自动生成的代码,并稍作改动,然后下载到板子上就okk啦~ 就是为了巩固一下参数化设计~~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: FPGA Verilog编程规范是指在使用Verilog进行FPGA设计时应遵循的一系列规范和准则。通过遵守这些规范,可以提高设计的可读性、可维护性和可重用性,从而更好地完成FPGA设计任务。 以下是一些常见的FPGA Verilog编程规范: 1. 注释规范:对于每个模块、端口和信号,都应添加详细的注释,以便理解其功能和作用。 2. 端口规范:对于每个模块的输入输出端口,应指定其方向(输入/输出)和宽度(位数)。 3. 变量命名规范:变量的命名应具有描述性,并使用驼峰命名法或下划线分隔单词。 4. 模块规范:模块应具有清晰的输入输出接口、良好结构和适当的功能划分。 5. 忽略无用的警告:避免设计中出现不必要的警告,以确保代码的整洁和可靠性。 6. 合适的时间和空间建模:根据设计需求,选择适当的时间和空间的建模方法和语法。 7. 参数化设计:合理使用参数化设计,以便在不同场景下方便地修改设计参数。 8. 文件和文件目录管理:确保代码和文件结构的整洁,使用合理的文件名和文件目录组织方式。 9. 避免使用不推荐的语言特性:避免使用已被弃用或不推荐使用的语言特性,以提高代码的可移植性和兼容性。 10. 遵循公司或项目的编程规范和工作流程:如果有特定的公司或项目编程规范和工作流程,应遵守并在设计中加以体现。 总之,遵循FPGA Verilog编程规范可以提高设计的质量和效率,并促使代码更易于维护和理解。 ### 回答2: FPGA Verilog编程规范是指在使用Verilog进行FPGA设计时需要遵守的一些规范和约定。这些规范旨在提高代码的可读性、可维护性和可重用性,同时还可以确保设计的正确性和性能。 首先,命名规范是编程规范中的重要部分。命名应该具有一定的描述性,能够准确反映变量、信号或模块的用途。变量和信号应该使用小写字母和下划线,而模块名采用大写字母开头的驼峰命名法。此外,命名应该具备一致性和易读性,以便在团队协作中更方便地理解代码。 其次,代码布局也是一个重要的方面。应该使用缩进和合适的空格来使代码具有良好的层次结构和可读性。同时,应该避免使用过长的代码行,可以使用换行符将代码分成多行,方便查看和理解。 第三,模块化设计FPGA Verilog编程规范中的关键概念。应该将复杂的功能划分成多个模块,每个模块负责一个特定的任务。模块应该按照功能和层次进行组织,并且应该编写清晰的接口定义和文档注释,以方便其他人使用和理解。 此外,应该注意避免使用不明确的语法和技术。应该优先选择可读性好、简洁明了的语法和技术,以避免产生歧义和错误。 最后,对于代码的注释和文档也是必不可少的。应该为代码添加适量的注释,解释代码的作用、原理和使用方法,以方便后续维护和团队交流。同时,还应该编写清晰的文档,用于记录设计的性能要求、接口定义和使用方法等重要信息。 在FPGA设计中,遵守Verilog编程规范可以提高代码的质量和可维护性,减少设计错误和调试时间。因此,遵守编程规范是FPGA设计者应该重视的一个方面。 ### 回答3: FPGA Verilog编程规范是一种用于FPGA设计的编码规范,旨在提高代码的可读性、可维护性和可重用性。它定义了设计工程师在编写Verilog代码时应遵循的一系列规则和标准。 首先,FPGA Verilog编程规范要求采用模块化设计方法。这意味着将设计划分为多个模块,每个模块负责一个特定的功能或任务。每个模块应该有清晰的输入和输出接口,以便于与其他模块的集成。 其次,规范强调代码的结构和命名的重要性。代码应该有清晰的缩进和层次结构,以增强可读性。变量和信号的命名应该具有描述性,以便于理解其用途和功能。 此外,规范要求遵循良好的命名约定。比如,模块名称应该以大写字母开头,信号和变量名称应该以小写字母开头。常量应该使用全大写字母表示。这些命名约定有助于提高代码的可读性和可维护性。 规范还要求进行适当的注释。注释应该解释代码的功能、用途和设计意图。它们可以帮助其他开发人员理解代码,并在维护或修改代码时提供指导。 此外,规范还包括一些特定的Verilog编码实践,例如使用非阻塞赋值语句(<=)来避免时序问题,以及使用延迟语句(#)来控制时序信号的生成等。 通过遵循FPGA Verilog编程规范,可以提高代码质量和可维护性,减少错误和调试时间,并支持代码重用。这样的规范在团队开发中尤为重要,可以提高团队成员之间的合作效率和代码交付的质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浮光 掠影

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

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

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

打赏作者

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

抵扣说明:

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

余额充值