本帖最后由 abner_ma 于 2020-11-27 21:39 编辑

FPGA设计的一个难点,就是设计技巧和规则的掌握,下面来看一个简单例子的实现过程,作为初级入门案例。

一、按键按下实现LED点亮

当LED引脚输出低电平时LED点亮,

(1)代码实现如下

module test(clk,rst_n,led);
  • input clk ;
  • input rst_n ;
  • output reg led ;
  • always @ ( posedge clk or negedge rst_n)
  • begin
  •         if(!rst_n)
  •                 begin
  •                         led<=0;
  •                 end
  •         else
  •         begin
  •                         led<=1;
  •         end
  • end
  • endmodule
  • 复制代码

    (2)基础语法要点:

    在always里面被赋值必须是reg变量。

    凡是在时序电路中被赋值的变量 必须是非阻塞赋值。always @ ( posedge clk or negedge rst_n)

    凡是在组合电路中被赋值的变量 必须是阻塞赋值always @ ( *)

    (3)Modelsim仿真测试文件。
          
    `timescale 1 ps/ 1 ps
  • module test_tb();
  • reg clk;
  • reg rst_n;                                             
  • wire led;                 
  • test i1 (
  •         .clk(clk),
  •         .led(led),
  •         .rst_n(rst_n)
  • );
  • initial                                                
  • begin                                                                                            
  • $display("Running testbench");      
  • clk=0;
  • rst_n=0;
  • #1000 rst_n=1;
  • end                                                   
  • always #10 clk=~clk;                                                   
  • endmodule
  • 复制代码
                                             


    • 输入都改为reg(系统产生)
    • 输出都改为wire:连线(系统产生)
    • 实例化模块并连接导线。(系统产生)
    • initial中初始化变量。(自己修改)
    • always产生时钟。(自己修改)

    (4)Modelsim仿真

    仿真中常用命令:

    do wave.do

    restart

    run 0.1ms

    (5)如果点亮四个LED呢?

    改变led输出变量的位宽:

    module test(clk,rst_n,led);
  • input clk ;
  • input rst_n ;
  • output reg [3:0]]led ;
  • always @ ( posedge clk or negedge rst_n)
  • begin
  •         if(!rst_n)
  •                 begin
  •                         led<=4'b1111;
  •                 end
  •         else
  •         begin
  •                         led<=4'b0000;
  •         end
  • end
  • endmodule
  • 复制代码

    同样改变测试文件位宽

    wire [3:0] led ;

    二、状态机设计实现流水灯

    (1)模块代码

    module test(clk,rst_n,led);
  • input clk ;
  • input rst_n ;
  • output reg [3:0]led ;
  • reg[1:0] state;
  • always @ ( posedge clk or negedge rst_n)
  • begin
  •         if(!rst_n)
  •                 begin
  •                         led<=4'b1111;
  •                         state<=0;
  •                 end
  •         else
  •         begin
  •                 case(state)
  •                         0:begin
  •                                 led<=4'b0111;
  •                                 state<=1;
  •                         end
  •                         1:begin
  •                                 led<=4'b1011;
  •                                 state<=2;                       
  •                         end
  •                         2:begin
  •                                 led<=4'b1101;       
  •                                 state<=3;                               
  •                         end
  •                         3:begin
  •                                 led<=4'b1110;
  •                                 state<=0;                       
  •                         end
  •                         default:
  •                                 state<=0;
  •                         endcase
  •         end
  • end
  • endmodule
  • 复制代码
    (2)状态机正确仿真:



    (3)设计要点

    注意state变量的赋初值。

    (4)频率反转太快、看不出LED效果。

    改善方法1:

    状态机中增加计数器。

    module test(clk,rst_n,led);
  • input clk ;
  • input rst_n ;
  • output reg [3:0]led ;
  • reg[1:0] state;
  • reg [3:0] counter;
  • always @ ( posedge clk or negedge rst_n)
  • begin
  •         if(!rst_n)
  •                 begin
  •                         led<=4'b1111;
  •                         state<=0;
  •                         counter<=0;
  •                 end
  •         else
  •         begin
  •                 case(state)
  •                         0:begin
  •                                 led<=4'b0111;
  •                                 if(counter<12)
  •                                         counter<=counter+1;
  •                                 else
  •                                         begin
  •                                                 counter<=0;
  •                                                 state<=1;
  •                                         end
  •                         end
  •                         1:begin
  •                                 led<=4'b1011;
  •                                 if(counter<12)
  •                                         counter<=counter+1;
  •                                 else
  •                                         begin
  •                                                 counter<=0;
  •                                                 state<=2;
  •                                         end               
  •                         end
  •                         2:begin
  •                                 led<=4'b1101;       
  •                                 if(counter<12)
  •                                         counter<=counter+1;
  •                                 else
  •                                         begin
  •                                                 counter<=0;
  •                                                 state<=3;
  •                                         end                               
  •                         end
  •                         3:begin
  •                                 led<=4'b1110;
  •                                 if(counter<12)
  •                                         counter<=counter+1;
  •                                 else
  •                                         begin
  •                                                 counter<=0;
  •                                                 state<=0;
  •                                         end                       
  •                         end
  •                         default:
  •                                 state<=0;
  •                         endcase
  •         end
  • end
  • endmodule
  • 复制代码


    (5)设计要点:

    同一变量不能同时在两个always块内复制,如分频和状态机的两个always块,复位时复位什么变量由本块内用到的变量决定。

    基础十分重要,是FPGA设计的前提。通过以上学习我们学会了状态机  计数器  时钟分频电路的设计。

    以上代码中包含了分频,LED状态机等多个功能模块。

    module test(clk,rst_n,led);
  • input clk ;
  • input rst_n ;
  • output reg [3:0]led ;
  • reg[1:0] state;
  • reg [3:0] counter;
  • reg clk_show;
  • always @ ( posedge clk or negedge rst_n)
  • begin
  •         if(!rst_n)
  •                 begin
  •                         clk_show<=0;
  •                         counter<=0;
  •                 end
  •         else
  •                 if(counter<12)
  •                         counter<=counter+1;
  •                 else
  •                         begin
  •                                 counter<=0;                       
  •                                 clk_show=~clk_show;
  •                         end
  • end
  • always @ ( posedge clk_show or negedge rst_n)
  • begin
  •         if(!rst_n)
  •                 begin
  •                         led<=4'b1111;
  •                         state<=0;
  •                 end
  •         else
  •         begin
  •                 case(state)
  •                         0:begin
  •                                 led<=4'b0111;
  •                                 state<=1;
  •                         end
  •                         1:begin
  •                                 led<=4'b1011;
  •                                 state<=2;       
  •                         end
  •                         2:begin
  •                                 led<=4'b1101;       
  •                                 state<=3;                       
  •                         end
  •                         3:begin
  •                                 led<=4'b1110;
  •                                 state<=0;       
  •                         end
  •                         default:
  •                                 state<=0;
  •                         endcase
  •         end
  • end
  • endmodule
  • 测试:
  • `timescale 1 ps/ 1 ps
  • module test_tb();
  • // constants                                          
  • // general purpose registers
  • // test vector input registers
  • reg clk;
  • reg rst_n;
  • // wires                                               
  • wire [3:0]led;
  • // assign statements (if any)                          
  • test i1 (
  • // port map - connection between master ports and signals/registers   
  •         .clk(clk),
  •         .led(led),
  •         .rst_n(rst_n)
  • );
  • initial                                                
  • begin                                                  
  • // code that executes only once                        
  • // insert code here --> begin                          
  •                                                       
  • // --> end                                             
  • $display("Running testbench");      
  • clk=0;
  • rst_n=0;
  • #1000 rst_n=1;
  •                  
  • end                                                   
  • always #10 clk=~clk;                                                   
  • endmodule
  • 复制代码