FPGA学习笔面试记录(六)——FPGA代码

1.二进制与格雷码转换

转格雷码:

module  binary2grey #(

        parameter   N       =       4

)(

        input         [N-1: 0]   binary                 ,

        output  wire  [N-1: 0]   grey

);

assign  grey =(binary>>1)^binary;

endmodule

转二进制:

module  grey2binary #(

        parameter   N       =       4

)(

        input         [N-1: 0]   grey                   ,

        output  wire  [N-1: 0]   binary

);

assign  binary[N-1]     =       grey[N-1]; endmodule

generate

genvar  i;

    for(i=0;i<N-1;i=i+1) begin:b2g

        assign  binary[i]     =       grey[i]^binary[i+1];

    end

endgenerate

endmodule

2.下降沿

always @(posedge clk or negedge rst_n)begin

    if(!rst_n) begin

        d0 <= 1'b0;

        d1 <= 1'b0;

    end

    else begin

        d0 <= gate;

        d1 <= d0;

    end

end

assign sign=d1&(~d0);

3.8bit 全加器

module adder_8(s, cout, a, b, cin);

       //输入输出端口及变量定义

       output [7 : 0] s;

       output cout;

       input [7 : 0] a, b;

       input cin;

       wire [6 : 0] carry;      

       //采用结构描述的方式实现一个8位加法器

       fulladder m0(s[0], carry[0], a[0], b[0], cin);

       fulladder m1(s[1], carry[1], a[1], b[1], carry[0]);

       fulladder m2(s[2], carry[2], a[2], b[2], carry[1]);

       fulladder m3(s[3], carry[3], a[3], b[3], carry[2]);

       fulladder m4(s[4], carry[4], a[4], b[4], carry[3]);

       fulladder m5(s[5], carry[5], a[5], b[5], carry[4]);

       fulladder m6(s[6], carry[6], a[6], b[6], carry[5]);

       fulladder m7(s[7], cout, a[7], b[7], carry[6]);

endmodule

//1位全加器模块

module fulladder(s, cout, a, b, cin);

       //输入输出端口定义

       output s, cout;

       input a, b, cin;  

       //采用行为描述的方式实现1位全加器

       assign s = a ^ b ^ cin;

       assign cout = a & b | a & cin | b & cin;

//    assign{cout,s} = x+y+cin;

endmodule

4.计数器0~Q(Q<2n)

   module counter(

         input clk,rst_n;

         output [n:0] cnt);

         always@(posedge clk or negedge rst_n)begin

             if(!rst_n)

                  cnt <=0;

             else begin

                if(cnt<=Q)

                     cnt <= cnt +1;

                else

                     cnt <=0;

             end

       end

always @(posedge clk or negedge rst_n)begin

    if(!rst_n)

        cnt <= 0;

    else if(add_cnt)begin

        if(end_cnt)

            cnt <= 0;

        else

            cnt <= cnt + 1;

    end

end

assign add_cnt = 1;

assign end_cnt = add_cnt && cnt==Q ;

设计一个2位十进制的循环计数器,从0到99,然后再回到0.输出为out0和out1,分别表示十进制数的高位和低位

`timescale 1ns / 1ps

module Test1030(clk,rst,out0,out1,data);

input clk;

input rst;

output  reg  [3:0] out0;

output reg [3:0] out1;

output reg [7:0] data;

always @(posedge clk or negedge rst)

   if(!rst)

      begin

         out0<=0;

         out1<=0;

      end

   else

      begin

         if(out0= =9)

            begin

               out0<=0;

               out1<=out1+1;

            end

         else

            out0<=out0+1;

         if(out1==10)

            out1<=0;

         else

            out1=out1;      

      end

assign data=(10*(out1))+out0;

endmodule

5.分频

module practice_demo(

    input clk,

    input arst,

    output clk_div

    );  

parameter N = 5;

reg [2:0] cnt;

reg clk_a;

reg clk_b;

wire clk_c;

always@(posedge clk or posedge arst)

begin

    if(arst)

        cnt <= 0;

    else if(cnt == N-1)

        cnt <= 0;

    else

        cnt <= cnt + 1;   

end

always@(posedge clk or posedge arst)

begin

    if(arst)

        clk_a<= 0;

    else if(cnt == (N-1)/2 || cnt == N-1)

        clk_a<= ~clk_a;

    else

        clk_a<= clk_a;   

end

always@(negedge clk or posedge arst)

begin

    if(arst)

        clk_b <= 0;

    else

        clk_b <= clk_a;

end

assign clk_c = clk_a | clk_b;

//N[0]=1奇数,否则偶数

assign clk_div = N[0] ? clk_c : clk_a;

endmodule

6.序列检测10010

module detector(clk, reset, d, y);

       input clk, reset, d;

       output y;

       reg [2 : 0] cstate,nstate;

       wire y;

       parameter idle = 3'b000, s1 = 3'b001, s2 = 3'b010, s3 = 3'b011,s4 = 3'b100, s5 = 3'b101, s6 = 3'b110, s7 = 3'b111;

       //状态机实现

       always@(posedge clk or posedge reset) 

if(reset)

         cstate <= idle;

     else

         cstate <= nstate;

end

always @(*)

begin

                     case(cstate)

                            idle: begin

                                          if(d == 1) nstate <= s1;

                                          else nstate <= idle;

                                     end

                            s1: begin

                                          if(d == 0) nstate <= s2;

                                          else nstate <= s1;

                                   end

                            s2: begin

                                          if(d == 0) nstate <= s3;

                                          else nstate <= s1;

                                   end

                            s3: begin

                                          if(d == 1) nstate <= s4;

                                          else nstate <= idle;

                                   end

                            s4:   begin

                                          if(d == 0) nstate <= s5;

                                          else nstate <= s1;

                                   end

                            s5: begin

                                          if(d == 1) nstate <= s1;

                                          else nstate <= idle;

                                   end

                            default: nstate <= idle;

                     endcase

              end

       end

mealy:    assign y = (state == s4 && d == 0) ? 1‘b1 : 1‘b0;

moore:  assign y = (state == s5) ? 1‘b1 : 1‘b0;

endmodule               

7.异步复位同步释放

module system_ctrl

 ( input  wire                 clk                 , //时钟,50Mhz

  input  wire                 rst_n               , //复位,低电平有效

  input  wire                 a                   , //输入信号

output reg                  b                     //输出信号

 );

//==    异步复位的同步化设计

reg        sys_rst_n_r;

 reg        sys_rst_n;

 always @(posedge clk or negedge rst_n) begin

     if(!rst_n) begin

        sys_rst_n_r <= 0;

        sys_rst_n   <= 0;

     end

     else begin

        sys_rst_n_r <= 1;

         sys_rst_n   <= sys_rst_n_r;

    end

 end

 always @(posedge clk or negedge sys_rst_n) begin

    if(!sys_rst_n)

       b <= 0;

    else

        b <= a;

end

 endmodule

8.高电平的个数

module test (

  input   wire                clk                 ,

 input   wire                rst_n               ,

 input   wire    [12:0]      data                ,

output  wire    [15:0]      num    

 );

reg     [ 3:0]              i    

always @(posedge clk or negedge rst_n) begin

    if(!rst_n) begin

       num = 0;

   end

    else begin

         num = 0;                    //注意清0

         for(i=0;i<13;i=i+1)

            if(data[i])

               num = num + 1;      //注意是阻塞赋值

    end

 end

endmodule

9.串并转换

module left_shifter_reg

(

input               clk     ,

input               rst_n   ,

input               din     ,

output  reg [7:0]   dout

);

always @(posedge clk or negedge rst_n) begin

    if(!rst_n)

        dout <= 8'b0;

    else

        dout <= {dout[6:0], din};

end 

endmodule

10.并串转换

module right_shifter_reg

(

input               clk         ,

input               rst_n       ,

input       [7:0]   din         ,

input               din_vld     ,

output              dout

);

reg     [7:0]       shift       ; 

always @(posedge clk or negedge rst_n) begin 

    if(!rst_n)

        shift <= 8'b0;

    else if(din_vld) //将值寄存住

        shift <= din;

    else

        shift <= {shift[0], shift[7:1]}; //不断右移

end 

assign dout = shift[0];//不断输出

endmodule

11.同步FIFO

module fifo(datain, rd, wr, rst, clk, dataout, full, empty);

input [7:0] datain;

input rd, wr, rst, clk;

output [7:0] dataout;

output full, empty;

wire [7:0] dataout;

reg full_in, empty_in;

reg [7:0] mem [15:0];                                    

reg [3:0] rp, wp;

assign full = full_in;

assign empty = empty_in;

// memory read out

assign dataout = mem[rp];

// memory write in

always@(posedge clk) begin

    if(wr && ~full_in) mem[wp]<=datain;

end

// memory write pointer increment

always@(posedge clk or negedge rst) begin

    if(!rst) wp<=0;

    else begin

      if(wr && ~full_in) wp<= wp+1'b1;

    end

end

// memory read pointer increment

always@(posedge clk or negedge rst)begin

    if(!rst) rp <= 0;

    else begin

      if(rd && ~empty_in) rp <= rp + 1'b1;

    end

end

// Full signal generate

always@(posedge clk or negedge rst) begin

    if(!rst) full_in <= 1'b0;

    else begin

      if( (~rd && wr)&&((wp==rp-1)||(rp==4'h0&&wp==4'hf)))

          full_in <= 1'b1;

      else if(full_in && rd) full_in <= 1'b0;

    end

end

// Empty signal generate

always@(posedge clk or negedge rst) begin

    if(!rst) empty_in <= 1'b1;

    else begin

      if((rd&&~wr)&&(rp==wp-1 || (rp==4'hf&&wp==4'h0)))

        empty_in<=1'b1;

      else if(empty_in && wr) empty_in<=1'b0;

    end

end

endmodule

12.异步FIFO

module asFIFO

 (parameter DATA_W = 8  //数据位宽

 parameter ADDR_W = 4 //地址位宽)

(input  rst_n  //复位

Input wr_clk ,//写时钟

input  wr_en,   //写使能

input [DATA_W-1:0] wr_data ,//写数据

output  wr_full,//写满

//FIFO读 -

Input  rd_clk ,//读时钟

input rd_en ,//读使能

output  reg [DATA_W-1:0] rd_data, //读数据

output rd_empt //读空);

reg     [ADDR_W  :0]        wr_addr_ptr         ;   //写指针,多1位

reg     [ADDR_W  :0]        rd_addr_ptr         ;   //读指针,多1位

wire    [ADDR_W  :0]        wr_addr_gray        ;   //写地址_格雷码

reg     [ADDR_W  :0]        wr_addr_gray_r      ;   //写地址打拍

reg     [ADDR_W  :0]        wr_addr_gray_rr     ;   //写地址打拍

wire    [ADDR_W  :0]        rd_addr_gray        ;   //读地址_格雷码

reg     [ADDR_W  :0]        rd_addr_gray_r      ;   //读地址打拍

reg     [ADDR_W  :0]        rd_addr_gray_rr     ;   //读地址打拍

wire    [ADDR_W-1:0]        wr_addr             ;   //写地址

wire    [ADDR_W-1:0]        rd_addr             ;   //读地址

reg     [DATA_W-1:0]        ram[2**ADDR_W-1:0]  ;   //ram,地址位宽4,共16个

//==    地址指针

always @(posedge wr_clk or negedge rst_n) begin

     if(!rst_n) begin

         wr_addr_ptr <= 0;

     end

else if(wr_en & (!wr_full)) begin

         wr_addr_ptr <= wr_addr_ptr + 1;

     end

end

always @(posedge rd_clk or negedge rst_n) begin

     if(!rst_n) begin

         rd_addr_ptr <= 0;

     end

    else if(rd_en & (!rd_empty)) begin

         rd_addr_ptr <= rd_addr_ptr + 1;

     end

end

//==    空满信号, //-- 格雷码转换

 assign wr_addr_gray = (wr_addr_ptr>>1) ^ wr_addr_ptr;

assign rd_addr_gray = (rd_addr_ptr>>1) ^ rd_addr_ptr;

//-- 跨时钟域,打两拍

always @(posedge wr_clk) begin

     rd_addr_gray_r  <= rd_addr_gray;

     rd_addr_gray_rr <= rd_addr_gray_r;

end

always @(posedge rd_clk) begin

     wr_addr_gray_r  <= wr_addr_gray;

     wr_addr_gray_rr <= wr_addr_gray_r;

end

-- 写满标志:高2位不同,其余位相同

Assign wr_full= (wr_addr_gray == ({~rd_addr_gray_rr[ADDR_W-:2],rd_addr_gray_rr[ADDR_W-2:0]}));

//-- 读空标志:读写地址相同

assign rd_empty = (rd_addr_gray == wr_addr_gray_rr);

//==    ram读写//-- 读写地址

assign wr_addr = wr_addr_ptr[ADDR_W-1:0];

assign rd_addr = rd_addr_ptr[ADDR_W-1:0];

//-- 写数据

integer i;

always @(posedge wr_clk or negedge rst_n) begin

     if(!rst_n) begin

        for(i=0; i<2**ADDR_W; i=i+1)

            ram[i] <= 0;

    end

   else if(wr_en & (!wr_full)) begin

            ram[wr_addr] <= wr_data;

     end 

end

//-- 读数据

always @(posedge rd_clk or negedge rst_n) begin

     if(!rst_n) begin

        rd_data <= 0;

    end

     else if(rd_en & (!rd_empty)) begin

        rd_data <= ram[rd_addr];

     end

end

endmodule

13.单bit信号进行毛刺滤除

module filter(

       input clk,

       input rst_n,

       input data_in,

       output reg data_out

);

       reg data_in_r;

       wire data_edge;

       reg [2:0]cnt;      

       always@(posedge clk or negedge rst_n)begin

              if(!rst_n)

                     data_in_r <= 1'b0;

              else

                     data_in_r <= data_in;

       end       

       assign data_edge = data_in ^ data_in_r;      

       always@(posedge clk or negedge rst_n)begin

              if(!rst_n)

                     cnt <= 'd0;

              else if(data_edge)

                     cnt <= 'd0;

              else

                     cnt <= cnt + 1'b1;

       end      

       always@(posedge clk or negedge rst_n)begin

              if(!rst_n)

                     data_out <= 1'b0;

              else if(&cnt)

                     data_out <= data_in_r;

              else

                     data_out <= data_out;

       end

endmodule

14.跨时钟域

  module Sync_Pulse

  (

     input   clka,

     input   clkb,

      input   rst_n,

      input   pulse_ina,      //脉冲或电平信号都可以

      output  pulse_outb,     //脉冲信号

      output  signal_outb     //电平信号

  );

reg         signal_a;

reg         signal_a_r1;

reg         signal_a_r2;

reg         signal_b;

reg         signal_b_r1;

//--------------------------------------------------------

//--    a时钟域生成展宽信号

//--------------------------------------------------------

always @(posedge clka or negedge rst_n)begin

     if(!rst_n)begin

         signal_a <= 1'b0;

    end

     else if(pulse_ina) begin        //检测到脉冲

         signal_a <= 1'b1;           //拉高

     end

     else if(signal_a_r2) begin      //同步到b后同步回a

         signal_a <= 1'b0;           //拉低,展宽使命完成

     end

 end

 //--------------------------------------------------------

//--    展宽信号同步到b时钟域再同步回a时钟域

//--------------------------------------------------------

always @(posedge clkb or negedge rst_n)begin

     if(!rst_n)begin

         signal_b    <= 1'b0;

         signal_b_r1 <= 1'b0;

    end

     else begin

         signal_b    <= signal_a;

         signal_b_r1 <= signal_b;

    end

end

always @(posedge clka or negedge rst_n)begin

   if(!rst_n)begin

         signal_a_r1 <= 1'b0;

         signal_a_r2 <= 1'b0;

     end

    else begin

        signal_a_r1 <= signal_b_r1;

         signal_a_r2 <= signal_a_r1;

    end

end

//--    脉冲信号输出,上升沿检测

assign pulse_outb = ~signal_b_r1 & signal_b;

 //--    电平信号输出,b时钟域展宽信号

assign signal_outb = signal_b_r1;

endmodule

15.按键消抖

module key_filter

//---------------------<参数定义>---------------------------------------

 #(

parameter   TIME_20MS   = 1000000           , //20ms时间

 parameter   TIME_W      = 20                , //20ms时间位宽

 parameter   KEY_W       = 4                   //按键个数)

//---------------------<端口声明>---------------------------------------

 (

 input                   clk                 , //时钟,50Mhz

input                   rst_n               , //复位,低电平有效

 input      [KEY_W-1:0]  key                 , //按键输入

 output reg [KEY_W-1:0]  key_vld               //按键消抖后的输出

 );

 //---------------------<信号定义>---------------------------------------

 reg  [TIME_W-1:0]       cnt                 ;

 wire                    add_cnt             ;

 wire                    end_cnt             ;

 reg  [KEY_W -1:0]       key_r0              ;

 reg  [KEY_W -1:0]       key_r1              ;

 reg                     flag                ;

//----------------------------------------------------------------------

 //--   信号同步 + 消除亚稳态

//----------------------------------------------------------------------

 always @(posedge clk or negedge rst_n)begin

     if(!rst_n)begin

        key_r0 <= 0;

        key_r1 <= 0;

   end

    else begin

         key_r0 <= key;      //信号同步

         key_r1 <= key_r0;   //打拍,防亚稳态

   end

 end

 //----------------------------------------------------------------------

 //--   20ms计时

 //----------------------------------------------------------------------

 always @(posedge clk or negedge rst_n)begin

     if(!rst_n)

        cnt <= 0;

     else if(add_cnt)begin

         if(end_cnt)

             cnt <= 0;

         else

            cnt <= cnt + 1;

    end

   else

         cnt <= cnt;

end

 assign add_cnt = flag==0 && key_r1!=0 ;        //允许计数 且 按键按下

 assign end_cnt = add_cnt && cnt==TIME_20MS-1;  //计到20ms

/计满指示

 always @(posedge clk or negedge rst_n)begin

     if(!rst_n)                  //复位

       flag <= 0;              //flag=0允许计数

    else if(end_cnt)            //20ms到

         flag <= 1;              //flag=1不再计数

     else if(key_r1==0)          //按键松开

        flag <= 0;              //flag=0,为下次计数做准备

     else                        //否则

         flag <= flag;           //维持自身

end

//----------------------------------------------------------------------

 //--   按键消抖完成,输出按键有效信号

 //----------------------------------------------------------------------

 always @(posedge clk or negedge rst_n)begin

     if(!rst_n)

       key_vld <= 0;

    else if(end_cnt)        //20ms到

        key_vld <= key_r1;  //按键已消抖,可以使用

    else

      key_vld <= 0;

end

endmodule

16.无毛刺的时钟切换

module glitch_free (

       input clk0,    // Clock

       input clk1,

       input select,

       input rst_n,  // Asynchronous reset active low

       output clkout

);

       wire mid_clk0;

       reg mid_clk0_r1, mid_clk0_r2, mid_clk0_r2n;

       wire mid_clk1;

       reg mid_clk1_r1, mid_clk1_r2, mid_clk1_r2n;

       assign mid_clk1 = select & mid_clk0_r2n;

       assign mid_clk0 = ~select & mid_clk1_r2n;

       //第一级触发器用上升沿采样,选择信号与反馈信号的与运算

       always@(posedge clk1 or negedge rst_n) begin

              if(~rst_n) mid_clk1_r1 <= 0;

              else mid_clk1_r1 <= mid_clk1;

       end

       //第二级触发器用下降沿采样

       always@(negedge clk1 or negedge rst_n) begin

              if(~rst_n) begin

                     mid_clk1_r2 <= 0;

                     mid_clk1_r2n <= 1;

              end

              else begin

                     mid_clk1_r2 <= mid_clk1_r1;

                     mid_clk1_r2n <= ~mid_clk1_r1;

              end

       end

       //第一级触发器用上升沿采样,选择信号与反馈信号的与运算

       always@(posedge clk0 or negedge rst_n) begin

              if(~rst_n) mid_clk0_r1 <= 0;

              else mid_clk0_r1 <= mid_clk0;

       end

       //第二级触发器用下降沿采样

       always@(negedge clk0 or negedge rst_n) begin

              if(~rst_n) begin

                     mid_clk0_r2 <= 0;

                     mid_clk0_r2n <= 1;

              end

              else begin

                     mid_clk0_r2 <= mid_clk0_r1;

                     mid_clk0_r2n <= ~mid_clk0_r1;

              end

       end

       wire mid_clk11, mid_clk00;

       assign mid_clk11 = clk1 & mid_clk1_r2;

       assign mid_clk00 = clk0 & mid_clk0_r2;

       assign clkout = mid_clk11 | mid_clk00;

endmodule

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是刺猬吖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值