0%

中科院实习——FPGA

FPGA巩固及新知识学习
该篇包括3-8译码器、计数器完成跑马灯、参数化设计、例化3-8译码器完成跑马灯。

3-8译码器

本科数电都学过三八译码器,他就是将三位的输入信号翻译位8位的输出信号。
image.png
真值表:
image.png

开始编写

创建项目

需要注意的几项是:
image.png
image.png
image.png
image.png

开始编程

image.png
点击create design sources;
image.png
点击create file-选择语言(verilog),文件名称与工程名一致;
最后点击finish即可。
编程:
image.png
程序如下:

module decoder_3_8(
    a,
    b,
    c,
    out
);
    input a;
    input b;
    input c;
    output [7:0]out;
    reg [7:0]out;
    
    //以always块描述的信号赋值,被赋值的对象必须定义为reg型
    always@(*)begin //always@(a,b,c)  
        case({a,b,c})//{a,b,c}独立的三个信号变成了一个三位的信号:位拼接 此外,还有wire [3:0]d: assign d= {a,1'b0,b,c}使得第二位始终为0
            3'b000:out = 8'b0000_0001;//b,d,h都是格式限定符,分别为二进制,十进制,十六进制 3'b101=3'd5 ; 8'b0000_1100=8'd12=8'hc
            3'b001:out = 8'b0000_0010;
            3'b010:out = 8'b0000_0100;
            3'b011:out = 8'b0000_1000;
            3'b100:out = 8'b0001_0000;
            3'b101:out = 8'b0010_0000;
            3'b110:out = 8'b0100_0000;
            3'b111:out = 8'b1000_0000;
        endcase
    end
endmodule  
   

分析综合

image.png

功能仿真

与创建功能源文件一样,不过点击add source后修改为创建仿真源文件
image.png
image.png

`timescale 1ns/1ns

module decoder_3_8_tb;
reg s_a;
reg s_b;
reg s_c;
wire [7:0]out;

decoder_3_8 decoder_3_8(
    .a(s_a),
    .b(s_b),
    .c(s_c),
    .out(out)
);

initial begin
    s_a = 0;s_b = 0;s_c = 0;
    #200;
    s_a = 0;s_b = 0;s_c = 1;
    #200;
    s_a = 0;s_b = 1;s_c = 0;
    #200;
    s_a = 1;s_b = 0;s_c = 0;
    #200;
    s_a = 0;s_b = 1;s_c = 1;
    #200;
    s_a = 1;s_b = 0;s_c = 1;
    #200;
    s_a = 1;s_b = 1;s_c = 0;
    #200;
    s_a = 1;s_b = 1;s_c = 1;
    #200;
    $stop;
end

endmodule    

分析综合,与上述内容一样
查看波形
image.png

布局布线和实际仿真略;

扳机调试

image.png
image.png
image.png
修改端口。
IMPLEMENTATION =>点击Open Implemented Design=>Layout=>I/O planing=>根据自己的板子设置端口=>ctrl+S保存=>Gennerate Bitstream=>open hardware manager=>open target
本文再次详细的介绍了整个项目的创建及调试过程,之后的项目会省略相关步骤。

时序逻辑设计之计数器

1.时序逻辑基本概念(相比于之前的三八译码器)
image.png
image.png
2.计数器基本概念,基本的四位加法器结构图
cnt <= cnt + 1
此图略:一个上升沿到来自加1.
3.设计一个一1秒频率闪烁的LED灯(亮和灭各500ms)
4.计数值与计数器的关系。

实现

image.png
50MHz 20ns:500ms->计数为25000000时

module led_flash(
    Clk,
    Reset_n,
    Led

    );
    
    input Clk;
    input Reset_n;
    output reg Led;
    
    reg[24:0]counter;
    
//    always@(posedge Clk or negedge Reset_n)
//    if(!Reset_n)begin
//        counter <= 0 ; //<=是非阻塞赋值的意思
//        Led <= 0;
//     end
//    else if(counter == 25000000)begin
//        Led <= !Led;
//        counter <= 0;
//    end
//    else 
//        counter <= counter + 1'd1;  //也可以分开写,推荐分开写
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0 ; //<=是非阻塞赋值的意思
       
   
    else if(counter == 25000000 - 1)
      
        counter <= 0;
 
    else 
        counter <= counter + 1'd1; 
   
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 1;
     
    else if(counter == 25000000 - 1) //0-1 1-2 2-3 3-0
        Led <= !Led;
         
endmodule   

====================================================

`timescale 1ns/1ns

module led_flash_tb;

    reg Clk;
    reg Reset_n;
    wire Led;

    led_flash led_flash(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Led(Led)
        
       );
       
       initial Clk = 1;
       always #10 Clk =!Clk;
       
       initial begin
            Reset_n = 0;
            #201;
            Reset_n = 1;
            #2000000000;
            $stop;
       end
 endmodule

时序逻辑设计之计数器(Verilog语法学习与应用)

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

module led_run(
    Clk,
    Reset_n,
    Led

);
   input Clk;
   input Reset_n;
   output reg [3:0]Led;
   reg [24:0]counter;
   
  always@(posedge Clk or negedge Reset_n)
  if(!Reset_n)
        counter <= 0;
   else if(counter == 25'd24999999)
        counter <= 0;
   else 
        counter <= counter + 1'd1;
    
   always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 4'b0001;
    else if(counter == 25'd24999999)begin
        if(Led == 4'b1000)
            Led <=  4'b0001;
         else 
            Led <= Led << 1;
     end
     else 
        Led <= Led;
        
endmodule
          

==================================================

`timescale 1ns/1ns

module led_run_tb;

    reg Clk;
    reg Reset_n;
    wire [3:0]Led;

    led_run led_run(
    .Clk(Clk),
    .Reset_n(Reset_n),
    .Led(Led)

);
    
    initial Clk = 1;
    always #10Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #2000000000;
        $stop;
    end

endmodule

改进

module led_run(
    Clk,
    Reset_n,
    Led

);
   input Clk;
   input Reset_n;
   output reg [3:0]Led;
   reg [24:0]counter;
   
  always@(posedge Clk or negedge Reset_n)
  if(!Reset_n)
        counter <= 0;
   else if(counter == 25'd24999999)
        counter <= 0;
   else 
        counter <= counter + 1'd1;
    
   always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 4'b0001;
    else if(counter == 25'd24999999)begin
//        if(Led == 4'b1000)
//            Led <=  4'b0001;
//         else 
//            Led <= Led << 1;
            
        Led <= {Led[2:0],Led[3]};
     end
     else 
        Led <= Led;
        
endmodule

例化3-8译码器(模块中调用模块)

复制文件到相应目录下;
ADD sources添加已有文件即可。
修改代码为:

module led_run2(
    Clk,
    Reset_n,
    Led

);
   input Clk;
   input Reset_n;
   output [7:0]Led;/此处不需要再写reg,因为译码器中已有
   reg [24:0]counter;
   
  always@(posedge Clk or negedge Reset_n)
  if(!Reset_n)
        counter <= 0;
   else if(counter == 25'd24999)
        counter <= 0;
   else 
        counter <= counter + 1'd1;
    
    reg [2:0]counter2;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter2 <= 0;
    else if(counter == 25'd24999)
        counter2 <= counter2 + 1'd1;
        
    decoder_3_8 decoder_3_8(
        .a(counter2[2]),
        .b(counter2[1]),
        .c(counter2[0]),
        .out(Led)
);    //此处
    
        
endmodule
          

参数化设计

我们在仿真时为了避免时间过长,通常会把时间缩小,但是在板机调试时又会把时间恢复,在忘记恢复时间的情况下会导致实际错误,因此这里提出参数化设计方法。

module led_run2(
    Clk,
    Reset_n,
    Led

);
   input Clk;
   input Reset_n;
   output [7:0]Led;
   reg [24:0]counter;
   
   parameter MCNT = 25'd24999999;//此处为修改的地方
   
  always@(posedge Clk or negedge Reset_n)
  if(!Reset_n)
        counter <= 0;
   else if(counter == MCNT)//此处为修改的地方
        counter <= 0;
   else 
        counter <= counter + 1'd1;
    
    reg [2:0]counter2;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter2 <= 0;
    else if(counter == MCNT) //此处为修改的地方
        counter2 <= counter2 + 1'd1;
        
    decoder_3_8 decoder_3_8(
        .a(counter2[2]),
        .b(counter2[1]),
        .c(counter2[0]),
        .out(Led)
);    
    
        
endmodule

===================================

`timescale 1ns/1ns

module led_run_tb;

    reg Clk;
    reg Reset_n;
    wire [3:0]Led;

    led_run2 led_run_inst0(
    .Clk(Clk),
    .Reset_n(Reset_n),
    .Led(Led)

);
    defparam led_run_inst0.MCNT = 24999;
    
    initial Clk = 1;
    always #10Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #2000000000;
        $stop;
    end

endmodule

或者:

`timescale 1ns/1ns

module led_run_tb;

    reg Clk;
    reg Reset_n;
    wire [3:0]Led;

    led_run2 
    #(
        .MCNT(2499)

        )

    led_run_inst0(
    .Clk(Clk),
    .Reset_n(Reset_n),
    .Led(Led)

);
    
    
    initial Clk = 1;
    always #10Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #2000000000;
        $stop;
    end

endmodule

假如3-8译码器也有一个
parameter WIDTH = 4;
reg [WIDTH - 1 : 0]OUT;
那么在led_run2对译码器例化时
加上一个 defparam 名字.WIDTH = ?;也是可以的
参数化设计嵌套

-------------本文结束感谢您的阅读-------------