05 06 Verilog基础语法与应用讲解

05. 1. 位操作

计数器实验升级,设计8个LED灯以每个0.5s的速率循环闪烁(跑马灯)

1.1 方法1:使用移位操作符<<来控制led灯的循环亮灭

设计代码

  1. Verilog中,判断操作的时候不加位宽限定是可以的,比如if(counter == 24999999)或者if(counter == 25’d24999999)都可以,但是在赋值的时候要加,比如counter <= counter + 1’d1;(赋0可以不加)

  2. [7:0] led,led有八个,所以用8'b0000_0001来代表八个led,使用移位操作符<<来控制led灯的循环亮灭。

module led_run(
    clk,
    rstn,
    led
);
    input clk;
    input rstn;
    output reg[7:0]  led;
    
    reg[25:0] counter;
    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        counter <= 0;
    else if(counter == 24999999)
    //else if(counter == 24999)
        counter <= 0;
    else
        counter <= counter + 1'd1;
        
    always@(posedge clk or negedge rstn)
    if(!rstn)
        led <= 8'b0000_0001;
    else if(counter == 24999999)begin
    //else if(counter == 24999)begin
        if(led == 8'b1000_0000)
            led <= 8'b0000_0001;
        else
            led <= led << 1;
    end
    else
        led <= led;
        
endmodule

仿真代码:

`timescale 1ns/1ns

module led_run_tb();

    reg clk;
    reg rstn;
    wire[7:0] led;
    
    led_run led_run(
        .clk(clk),
        .rstn(rstn),
        .led(led)
    );
    
    initial clk = 1;
    always #10 clk = !clk;
    
    initial begin
        rstn = 0;
        #201;
        rstn = 1;
        #4000000;
        $stop;
    end

endmodule

仿真波形:

05 06 Verilog基础语法与应用讲解_第1张图片

1.2 方法2:利用位拼接{led[6:0], led[7]}实现循环移位

设计代码

该方法应用场景不多,了解即可。

module led_run_1(
    clk,
    rstn,
    led
);
    input clk;
    input rstn;
    output reg[7:0]  led;
    
    reg[25:0] counter;
    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        counter <= 0;
    else if(counter == 24999999)
    //else if(counter == 24999)
        counter <= 0;
    else
        counter <= counter + 1'd1;
        
    always@(posedge clk or negedge rstn)
    if(!rstn)
        led <= 8'b0000_0001;
    else if(counter == 24999999)begin
    //else if(counter == 24999)
        led <= {led[6:0], led[7]};
    else
        led <= led;
        
endmodule

1.3 方法3:调用其他模块

设计代码

思路:用计数器产生8种状态,然后再把这8种状态拿去用三八译码器译码,就刚好能够去对应点亮8个led灯。

  1. 调用了底层模块3_8译码器后(3位输入[2:0],八位输出8'b0000_0001),顶层led_run_2的输出led的数据类型需要由reg变为wire形(或者不写wire)
  2. 模块的调用与tb里的调用方式一样,做好对应端口的连接即可。
module led_run_2(
    clk,
    rstn,
    led
);
    input clk;
    input rstn;
    output wire[7:0]  led; //注意1
    
    reg[25:0] counter;
    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        counter <= 0;
    else if(counter == 24999999)
    //else if(counter == 24999)
        counter <= 0;
    else
        counter <= counter + 1'd1;
        
        
    reg[2:0] counter2;
    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        counter2 <= 0;
    else if(counter == 24999999)
    //else if(counter == 24999)
        counter2 <= counter2 + 1'd1;
       
    decoder_3_8 decoder_3_8( //注意2
        .a(counter2[2]),
        .b(counter2[1]),
        .c(counter2[0]),
        .out(led)
);
          
        
endmodule

调用方法:

05 06 Verilog基础语法与应用讲解_第2张图片

05 06 Verilog基础语法与应用讲解_第3张图片

05. 2. 参数化设计

设计代码

  1. 将24999999用参数代替,好处1是增加代码复用性与可读性。好处2是我们可以在板级验证的时候使用24999999,在写tb做调试的时候将参数改为2499,节约仿真时间
module led_run(
    clk,
    rstn,
    led
);

    parameter MCNT = 25'd24999999; //注意1
    input clk;
    input rstn;
    output reg[7:0]  led;
    
    reg[25:0] counter;
    
    always@(posedge clk or negedge rstn)
    if(!rstn)
        counter <= 0;
    else if(counter == MCNT)
    //else if(counter == 24999)
        counter <= 0;
    else
        counter <= counter + 1'd1;
        
    always@(posedge clk or negedge rstn)
    if(!rstn)
        led <= 8'b0000_0001;
    else if(counter == MCNT)begin
    //else if(counter == 24999)begin
        if(led == 8'b1000_0000)
            led <= 8'b0000_0001;
        else
            led <= led << 1;
    end
    else
        led <= led;
        
endmodule

仿真代码

  1. 写法一,修改例化后的模块参数,defparam led_run_inst.MCNT = 2499;
  2. 写法二,例化前修改module,led_run里的参数
`timescale 1ns/1ns

module led_run_tb();

    reg clk;
    reg rstn;
    wire[7:0] led;
    
    
    led_run led_run_inst(
        .clk(clk),
        .rstn(rstn),
        .led(led)
    );
    defparam led_run_inst.MCNT = 2499; //写法一
    
    initial clk = 1;
    always #10 clk = !clk;
    
    initial begin
        rstn = 0;
        #201;
        rstn = 1;
        #4000000;
        $stop;
    end

endmodule

`timescale 1ns/1ns

module led_run_tb();

    reg clk;
    reg rstn;
    wire[7:0] led;
    
    
    led_run //写法二
    #(
        .MCNT(2499)
      )
    led_run_inst(
        .clk(clk),
        .rstn(rstn),
        .led(led)
    );
  
    
    initial clk = 1;
    always #10 clk = !clk;
    
    initial begin
        rstn = 0;
        #201;
        rstn = 1;
        #4000000;
        $stop;
    end

endmodule

仿真波形

05 06 Verilog基础语法与应用讲解_第4张图片

06 使用参数化的设计实现模块的重用

让八个led灯分别以不同的频率闪烁

思路:使用八个led灯闪烁模块,为了简化,我们分别以0.1s,0.2s,0.3s,0.4s让四个led闪烁。

1.设计代码

  1. 先构建一个led闪烁的设计代码,再给与不同的计数参数例化4次即可
module led_run8(
    clk,
    rstn,
    led
);
    parameter MCNT = 24999999;
    input clk;
    input rstn;
    output led;
    
    reg[25:0] counter;
    reg led;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        counter <= 0;
    else if(counter == MCNT)
        counter <= 0;
    else
        counter <= counter + 1'd1;
        
    always@(posedge clk or negedge rstn)
    if(!rstn)
        led <= 0;
    else if(counter == MCNT)
        led <= !led;

endmodule
  1.  例化4个模块,使用参数化的设计实现模块的重用
module led_run8_test(
    clk,
    rstn,
    led
);
    input clk;
    input rstn;
    output wire[3:0] led;
    
    
    led_run8 led_run8_inst0(
        .clk(clk),
        .rstn(rstn),
        .led(led[0])
    );
    defparam led_run8_inst0.MCNT = 25'd2499999;
    
    
    led_run8 led_run8_inst1(
        .clk(clk),
        .rstn(rstn),
        .led(led[1])
    );
    defparam led_run8_inst1.MCNT = 25'd4999999;
    
    
    led_run8 led_run8_inst2(
        .clk(clk),
        .rstn(rstn),
        .led(led[2])
    );
    defparam led_run8_inst2.MCNT = 25'd7499999;
    
    
    led_run8 led_run8_inst3(
        .clk(clk),
        .rstn(rstn),
        .led(led[3])
    );
    defparam led_run8_inst3.MCNT = 25'd9999999;
    



endmodule

 2.仿真代码

`timescale 1ns/1ns

module led_run8_test_tb();

    reg clk;
    reg rstn;
    wire[3:0] led;
    
    
    led_run8_test led_run8_test_inst(
        .clk(clk),
        .rstn(rstn),
        .led(led)
    );
    
    initial clk = 1;
    always #10 clk = !clk;
    
    initial begin
        rstn = 0;
        #201;
        rstn = 1;
        #400000000;
        $stop;
    end

endmodule

 3.仿真波形

05 06 Verilog基础语法与应用讲解_第5张图片

4.布置引脚(通过代码来布置引脚)

 

 

到此布置引脚就布置好了,后续生成bit流文件,打开硬件管理器之后就可以板级验证了。

你可能感兴趣的:(verilog学习,fpga开发,笔记,学习,经验分享)