FPGA秋招面试手撕代码20+

written by @hzj
//版本迭代//
# V1.0 2022.7.25
# V1.1 2022.7.27
# V1.2 2022.7.28
# V1.3 2022.8.1
# V1.4 2022.8.3
# V1.5 2022.8.8

前言

针对常用的代码(常用代码/面试常考察/基础代码)进行手撕训练,总共的实现代码总共将近20余个,将在一个月内更新完成,感兴趣的朋友可以及时关注下这篇博客,如果有任何的疑问,可以及时与我进行分享。
所有功能模块为了统一化,都将使用同一个工程名称“test”,包含src源文件以及tb测试文件,以及可能的RTL图

废话不多说,直接进入正题

1、序列检测器

(1)三段式状态机实现方式

功能:若检测序列00110,输出检测有效信号signal_en为1

  • SRC:
module test(
    input i_fpga_clk        ,
    input i_fpga_rst_n      ,

    input data_in           ,

    output reg signal_enable
);

//define state
localparam IDLE = 3'b000;
localparam S1   = 3'b001;
localparam S2   = 3'b010;
localparam S3   = 3'b011;
localparam S4   = 3'b100;
localparam S5   = 3'b101;

//three state
reg [2:0] current_state;
reg [2:0] next_state   ;
reg [7:0] count        ;


always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        current_state <= IDLE;
    end
    else begin
        current_state <= next_state;
    end
end

always @(*) begin
    case(current_state)
        IDLE:
            if(data_in == 1'b0)
                next_state <= S1;
            else 
                next_state <= IDLE;
        S1  :
            if(data_in == 1'b0)
                next_state <= S2;
            else 
                next_state <= IDLE;
        S2  :
            if(data_in == 1'b1)
                next_state <= S3;
            else
                next_state <= S2;
        S3  :
            if(data_in == 1'b1)
                next_state <= S4;
            else 
                next_state <= S1;
        S4  :
            if(data_in == 1'b0)
                next_state <= S5;
            else 
                next_state <= IDLE;
        S5  :
            if(data_in == 1'b0)
                next_state <= S2;
            else 
                next_state <= IDLE;
        default:
            next_state <= IDLE;
    endcase
end

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        signal_enable <= 1'b0;
    end
    else if(current_state == S5)begin
        signal_enable <= 1'b1;
    end
    else begin
        signal_enable <= 1'b0;
    end
end

endmodule   
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;


reg   clk_368                             ;
reg   rst_n_368                           ;


initial
begin
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end


initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;
reg  data_in;
reg  [7:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        data_in <= 'd0;
        count <= 8'b00110001;
    end
    else begin
        count   <= {count[6:0], count[7]};
        data_in <= count[7]              ;
    end
end

test module_test(
    .i_fpga_clk   (i_fpga_clk   )     ,
    .i_fpga_rst_n (i_fpga_rst_n )     ,
    .data_in      (data_in      )     ,
    .signal_enable(signal_enable)
);
endmodule

  • 仿真结果:

在这里插入图片描述

  • 电路:

在这里插入图片描述

(2)移位寄存器实现方式

  • SRC:
module test(
    input i_fpga_clk        ,
    input i_fpga_rst_n      ,

    input data_in           ,

    output reg signal_enable
);

//00110

reg [4:0] data_state;

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        data_state <= 5'b00000;
    end
    else begin
        data_state <= {data_state[3:0], data_in};
    end
end

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        signal_enable <= 1'b0;
    end
    else if(data_state == 5'b00110)begin
        signal_enable <= 1'b1;
    end
    else begin
        signal_enable <= 1'b0;
    end
end

endmodule   
  • TB:
    同1、序列检测器(三段式状态机实现方式)的TB代码

  • 仿真结果:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

2、序列生成器

功能:若检测序列00110,输出检测有效信号signal_en为1

(1)移位寄存器方式实现

  • SRC:
module test(
    input i_fpga_clk        ,
    input i_fpga_rst_n      ,
        
    output reg signal_out
);

reg [4:0] signal_register;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        signal_register <= 5'b11010                                  ; 
    end
    else begin
        signal_register <= {signal_register[3:0], signal_register[4]};
    end
 end

always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        signal_out <= 1'b0              ;
    end
    else begin
        signal_out <= signal_register[4];
    end
end

endmodule 
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;


reg   clk_368                             ;
reg   rst_n_368                           ;


initial
begin
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end


initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;

wire signal_out;
test module_test(
    .i_fpga_clk  (i_fpga_clk  ),
    .i_fpga_rst_n(i_fpga_rst_n),

    .signal_out  (signal_out  ) 
);

endmodule
  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

(2)计数器方式实现

  • SRC:
module test(
    input i_fpga_clk,
    input i_fpga_rst_n,
        
    output signal_out
);
//11010

reg [2:0] count;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        count <= 1'b0;
    end
    else if(count == 'd4)begin
        count <= 'd0;
    end
    else begin
        count <= count + 1'b1;
    end
end

assign signal_out = ((!count[2])&(!count[1])&(!count[0])) | ((!count[2])&(!count[1])&(count[0])) | ((!count[2])&(count[1])&(count[0]));

endmodule 
  • TB:
    同2(1)

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

(3)三段式状态机方式实现

  • SRC:
module test(
    input i_fpga_clk,
    input i_fpga_rst_n,
        
    output reg signal_out
);
localparam  IDLE = 3'b000;
localparam  S1   = 3'b001;
localparam  S2   = 3'b010;
localparam  S3   = 3'b011;
localparam  S4   = 3'b100;

reg [2:0] current_state;
reg [2:0] next_state   ;

always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        current_state <= IDLE;
    end
    else begin
        current_state <= next_state;
    end
end

always@(*)begin
    case(current_state)
        IDLE: 
            next_state <= S1;
        S1  :
            next_state <= S2;
        S2  :
            next_state <= S3;
        S3  :
            next_state <= S4;
        S4  :
            next_state <= IDLE;
        default:
            next_state <= IDLE;
    endcase
end

always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
       signal_out <= 1'b0; 
    end
    else begin
        case(current_state)
            IDLE: 
                signal_out <= 1'b1;
            S1  :
                signal_out <= 1'b1;
            S2  :
                signal_out <= 1'b0;
            S3  :
                signal_out <= 1'b1;
            S4  :
                signal_out <= 1'b0;
            default:
                signal_out <= 1'b0;       
        endcase
    end
end

endmodule 
  • TB:
    同2(1)

  • 仿真:在这里插入图片描述

  • 电路:
    在这里插入图片描述

3、分频

(1)偶数分频

功能:实现4分频电路

  • SRC:
module test(
    input i_fpga_clk,
    input i_fpga_rst_n,
        
    output reg div
);

reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        count <= 2'b00;
    end
    else begin
        count <= count + 2'b01;
    end
end

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        div <= 1'b0;
    end
    else if(count == 2'd1 || count == 2'd3)begin
        div <= ~div;
    end
    else begin
        div <= div;
    end
end

endmodule 
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;


reg   clk_368                             ;
reg   rst_n_368                           ;


initial
begin
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end


initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;

wire div;
test module_test(
    .i_fpga_clk  (i_fpga_clk  ),
    .i_fpga_rst_n(i_fpga_rst_n),

    .div  (div  ) 
);

endmodule
  • 仿真:
    在这里插入图片描述
  • 电路:
    在这里插入图片描述

(2)奇数分频

功能:实现奇数分频的三分频电路

①相与实现
  • SRC:
module counter(
    input           i_fpga_clk        ,
    input           i_fpga_rst_n      , 
    
    output          div 
);

reg wave_1;
reg wave_2;

reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        count <= 'd0;
    end
    else if(count == 2'd2)begin
        count <= 'd0;
    end
    else begin
        count <= count + 1'b1;
    end
end

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        wave_1 <= 1'b0;
    end
    else if(count == 2'd2)begin
        wave_1 <= 1'b0;
    end
    else begin
        wave_1 <= 1'b1;
    end
end

always @(negedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        wave_2 <= 'd0;
    end
    else if(count == 2'd2)begin
        wave_2 <= 1'b0;
    end
    else begin
        wave_2 <= 1'b1;
    end
end

assign div = wave_1 & wave_2;

endmodule 
  • TB:
`timescale  1ns / 1ps //1000M

module tb_complex_mult;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
integer i;
integer j;


initial
begin
    i <= 0;
    j <= 0;
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
    clk_245        <= 'd0      ;
    rst_n_245      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end

initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;

  
wire div ;



counter module_counter(
    .i_fpga_clk  (i_fpga_clk  )      ,
    .i_fpga_rst_n(i_fpga_rst_n)      , 
    
    .div         (div         )       
);

endmodule
  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

②相或实现
  • SRC:
module counter(
    input           i_fpga_clk        ,
    input           i_fpga_rst_n      , 
    
    output          div 
);

reg wave_1;
reg wave_2;

reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        count <= 'd0;
    end
    else if(count == 2'd2)begin
        count <= 'd0;
    end
    else begin
        count <= count + 1'b1;
    end
end

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        wave_1 <= 1'b0;
    end
    else if(count == 2'd0)begin
        wave_1 <= 1'b1;
    end
    else begin
        wave_1 <= 1'b0;
    end
end

always @(negedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        wave_2 <= 'd0;
    end
    else if(count == 2'd0)begin
        wave_2 <= 1'b1;
    end
    else begin
        wave_2 <= 1'b0;
    end
end

assign div = wave_1 | wave_2;

endmodule 
  • TB:
    同4(1)

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

③相异或实现
  • SRC:
module counter(
    input           i_fpga_clk        ,
    input           i_fpga_rst_n      , 
    
    output          div 
);

reg wave_1;
reg wave_2;

reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        count <= 'd0;
    end
    else if(count == 2'd2)begin
        count <= 'd0;
    end
    else begin
        count <= count + 1'b1;
    end
end

always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        wave_1 <= 1'b0;
    end
    else if(count == 2'd0)begin
        wave_1 <= ~wave_1;
    end
    else begin
        wave_1 <= wave_1;
    end
end

always @(negedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'd0)begin
        wave_2 <= 'd0;
    end
    else if(count == 2'd2)begin
        wave_2 <= ~wave_2;
    end
    else begin
        wave_2 <= wave_2;
    end
end

assign div = wave_1 ^ wave_2;

endmodule 
  • TB:
    同4(1)

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

4、FIFO

(1)同步FIFO

*功能:实现深度大小为8,位宽大小为32的同步FIFO*

①采用地址技术的方式实现
  • SRC:
module test#(
    parameter DATA_DEPTH = 16,
    parameter DATA_WIDTH = 16
)(
    input                        i_fpga_clk        ,
    input                        i_fpga_rst_n      , 

    input                        wr_en             ,
    input  [DATA_WIDTH-1:0]      wr_data           ,

    input                        rd_en             ,
    
    output reg [DATA_DEPTH-1:0]  rd_data           ,
    output                       full_signal       ,
    output                       empty_signal    
);

reg [DATA_WIDTH-1:0] memory [DATA_DEPTH-1:0];//定义一个数组元素用作存储

function integer c2log(input [DATA_DEPTH-1:0] data_depth);
begin
    for(c2log = 0; data_depth > 0 ;c2log = c2log + 1)begin
        data_depth = data_depth >> 1;
    end
end
endfunction

reg [c2log(DATA_DEPTH - 1)-1 :0]  wr_addr;
reg [c2log(DATA_DEPTH - 1)-1 :0]  rd_addr;

//wr_addr
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        wr_addr <= 'd0;
    end
    else if(wr_en == 1'b1 && full_signal != 1'b1)begin
        wr_addr <= wr_addr + 1'b1;
    end
    else begin
        wr_addr <= wr_addr;
    end
end

//rd_addr
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        rd_addr <= 'd0;
    end
    else if(rd_en == 1'b1 && empty_signal != 1'b1)begin
        rd_addr <= rd_addr + 1'b1;
    end
    else begin
        rd_addr <= rd_addr;
    end
end

//mem_wr
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        memory[wr_addr] <= 'd0;
    end
    else if(wr_en == 1'b1 && full_signal != 1'b1)begin
        memory[wr_addr] <= wr_data;
    end
    else begin
        memory[wr_addr] <= memory[wr_addr];
    end
end

//mem_rd
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        rd_data <= 'd0;
    end
    else if(rd_en == 1'b1 && empty_signal != 1'b1)begin
        rd_data <= memory[rd_addr];
    end
    else begin
        rd_data <= rd_data;
    end
end

//judege_empty_full
assign empty_signal = (wr_addr     == rd_addr     )? 1'd1: 1'd0;
assign full_signal  = ((wr_addr[2:0]== rd_addr[2:0])&&(wr_addr[3] != rd_addr[3]))? 1'd1: 1'd0;

endmodule 
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
integer i;
integer j;


initial
begin
    i <= 0;
    j <= 0;
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
    clk_245        <= 'd0      ;
    rst_n_245      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end

initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;


reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        counter <= 'd0;
        wr_en   <= 'd0;
        rd_en   <= 'd0;
        flag    <= 'd0;
    end
    else if(counter == 'd7 && flag == 'd0)begin
        flag  <= 'd1;
        wr_en <= 'd1;
    end
    else if(counter == 'd7 && flag == 'd1)begin
        counter <= 'd0;
        wr_en   <= ~wr_en;
        rd_en   <= ~rd_en;
    end
    else begin
        counter <= counter + 1'b1;
    end
end


always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        wr_data <= 'd0;
    end
    else if(wr_data == 'd20)begin
        wr_data <= 'd0;
    end
    else begin
        wr_data <= wr_data + 1;
    end
end

wire [15:0]rd_data;

test#(
    .DATA_DEPTH(16),
    .DATA_WIDTH(16)
)module_test(
    .i_fpga_clk   (i_fpga_clk  ),
    .i_fpga_rst_n (i_fpga_rst_n), 
    .wr_en        (wr_en       ),
    .wr_data      (wr_data     ),

    .rd_en        (rd_en       ),
    .rd_data      (rd_data     ),
    .full_signal  (full_signal ),
    .empty_signal (empty_signal)   
);
endmodule

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

②采用计数器计数的方式实现
  • SRC:
module test#(
    parameter DATA_WIDTH = 16,
    parameter DATA_DEPTH =  8
)( //sync_fifo
    input i_fpga_clk                        ,
    input i_fpga_rst_n                      ,
    
    input [DATA_WIDTH - 1 : 0] wr_data      ,
    input wr_en                             ,
    
    output reg [DATA_WIDTH -1 : 0] rd_data  ,
    input  rd_en                            ,
    
    output full_signal                      ,
    output empty_signal
 );

 //calculate the DEPTH bits
 function integer c2log(input [DATA_DEPTH - 1: 0] data_depth);
    begin
        for(c2log = 0; data_depth >0 ; c2log = c2log + 1)begin
            data_depth = data_depth >> 1; 
        end
    end
 endfunction
 
 //define the dignal
 reg [c2log(DATA_DEPTH-1) - 1 : 0] wr_addr               ;
 reg [c2log(DATA_DEPTH-1) - 1 : 0] rd_addr               ;
 reg [DATA_WIDTH - 1 : 0] mem [DATA_DEPTH-1 : 0];

 //wr_addr
 always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        wr_addr <= 16'd0;
    end
    else if(wr_en == 1'b1 && full_signal == 1'b0)begin
        wr_addr <= wr_addr + 1'b1;
    end
 end
 
 //rd_addr
 always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        rd_addr <= 16'b0;
    end
    else if(empty_signal == 1'b0 && rd_en == 1'b1)begin
        rd_addr <= rd_addr + 1'b1;
    end
 end

 //wr_data
 integer bit_width;
 
 always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        for(bit_width = 0; bit_width < DATA_DEPTH; bit_width = bit_width + 1)begin
            mem[bit_width] <= 32'd0;
        end
    end
    else if(wr_en == 1'b1 && full_signal == 1'b0)begin
        mem[wr_addr] <= wr_data;
    end
 end
 
 //rd_data
 always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        rd_data <= 'd0;
    end
    else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
        rd_data <= mem[rd_addr];
    end
 end
 
 //count
 reg [3:0] count;
  
 always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
    if(i_fpga_rst_n == 1'b0)begin
        count <= 'd0;   
    end
    else if(wr_en == 1'b1 && full_signal == 1'b0)begin
        count <= count + 1'b1;
    end
    else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
        count <= count - 1'b1;
    end
    else begin
        count <= count;
    end
 end
 
 assign full_signal  = (count == 'd8 ? 1 : 0);
 assign empty_signal = (count == 'd0 ? 1 : 0);  
 
 endmodule
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
integer i;
integer j;


initial
begin
    i <= 0;
    j <= 0;
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
    clk_245        <= 'd0      ;
    rst_n_245      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end

initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;


reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        counter <= 'd0;
        wr_en   <= 'd0;
        rd_en   <= 'd0;
        flag    <= 'd0;
    end
    else if(counter == 'd7 && flag == 'd0)begin
        flag  <= 'd1;
        wr_en <= 'd1;
    end
    else if(counter == 'd7 && flag == 'd1)begin
        counter <= 'd0;
        wr_en   <= ~wr_en;
        rd_en   <= ~rd_en;
    end
    else begin
        counter <= counter + 1'b1;
    end
end


always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        wr_data <= 'd0;
    end
    else if(wr_data == 'd20)begin
        wr_data <= 'd0;
    end
    else begin
        wr_data <= wr_data + 1;
    end
end

wire [15:0]rd_data;


test#(
    .DATA_WIDTH(16),
    .DATA_DEPTH( 8)
)module_test( //sync_fifo
    .i_fpga_clk   (i_fpga_clk  ),
    .i_fpga_rst_n (i_fpga_rst_n),
    
    .wr_data      (wr_data     ),
    .wr_en        (wr_en       ),
    
    .rd_data      (rd_data     ),
    .rd_en        (rd_en       ),
    
    .full_signal  (full_signal ),
    .empty_signal (empty_signal)
 );


endmodule

  • 仿真:
    在这里插入图片描述
  • 电路:
    在这里插入图片描述

(2)异步FIFO

功能:实现异步FIFO功能,具备gray码

  • SRC:
module test#(
    parameter DATA_WIDTH = 16,
    parameter DATA_DEPTH =  8
)( //sync_fifo
    input i_fpga_clk_wr                 ,
    input i_fpga_rst_n_wr               ,
    input i_fpga_clk_rd                 ,
    input i_fpga_rst_n_rd               ,
    
    input [DATA_WIDTH - 1 : 0] wr_data  ,
    input wr_en                         ,
    
    output reg [DATA_WIDTH -1 : 0] rd_data  ,
    input  rd_en                        ,
    
    output full_signal                  ,
    output empty_signal
 );

 //calculate the DEPTH bits
 function integer c2log(input [DATA_DEPTH - 1: 0] data_depth);
    begin
        for(c2log = 0; data_depth >0 ; c2log = c2log + 1)begin
            data_depth = data_depth >> 1; 
        end
    end
 endfunction
 
 //define the dignal
 reg [c2log(DATA_DEPTH-1) : 0] wr_ptr                   ;
 wire[c2log(DATA_DEPTH-1) : 0] gray_wr_ptr_0            ;
 reg [c2log(DATA_DEPTH-1) : 0] gray_wr_ptr_1            ;
 reg [c2log(DATA_DEPTH-1) : 0] gray_wr_ptr_2            ;
 reg [c2log(DATA_DEPTH-1) : 0] rd_ptr                   ;
 wire[c2log(DATA_DEPTH-1) : 0] gray_rd_ptr_0            ;
 reg [c2log(DATA_DEPTH-1) : 0] gray_rd_ptr_1            ;
 reg [c2log(DATA_DEPTH-1) : 0] gray_rd_ptr_2            ;
 reg [DATA_WIDTH - 1 : 0] mem [DATA_DEPTH-1 : 0];
 
 //wr data
 always @(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
    if(i_fpga_rst_n_wr == 1'b0)begin
        wr_ptr <= {(c2log(DATA_DEPTH)){1'b0}};
    end
    else if(wr_en == 1'b1 && full_signal == 1'b0)begin
        wr_ptr <= wr_ptr + 1'b1;
    end
 end

//rd c2log
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
    if(i_fpga_rst_n_rd == 1'b0)begin
        rd_ptr <= {(c2log(DATA_DEPTH-1)){1'b0}};
    end
    else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
        rd_ptr <= rd_ptr + 1'b1;
    end
end

//gray generate 
assign gray_wr_ptr_0 = wr_ptr ^ (wr_ptr >> 1);
assign gray_rd_ptr_0 = rd_ptr ^ (rd_ptr >> 1);

//CDC sync wr
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
    if(i_fpga_rst_n_rd == 1'b0)begin
        gray_wr_ptr_1  <= {(c2log(DATA_DEPTH-1)){1'b0}};
        gray_wr_ptr_2  <= {(c2log(DATA_DEPTH-1)){1'b0}};
    end
    else begin
        gray_wr_ptr_1 <= gray_wr_ptr_0;
        gray_wr_ptr_2 <= gray_wr_ptr_1;
    end
end

//CDC sync rd
always@(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
    if(i_fpga_rst_n_wr == 1'b0)begin
        gray_rd_ptr_1  <= {(c2log(DATA_DEPTH-1)){1'b0}};
        gray_rd_ptr_2  <= {(c2log(DATA_DEPTH-1)){1'b0}};
    end
    else begin
        gray_rd_ptr_1 <= gray_rd_ptr_0;
        gray_rd_ptr_2 <= gray_rd_ptr_1;
    end
end


//full_signal && empty signal
assign full_signal = (gray_wr_ptr_0 == {~gray_rd_ptr_2[c2log(DATA_DEPTH-1) : c2log(DATA_DEPTH-1) - 1], gray_rd_ptr_2[c2log(DATA_DEPTH-1)-2 : 0]} ? 1 : 0 );
assign empty_signal= (gray_rd_ptr_0 == gray_wr_ptr_2);

//addr generate 
wire [c2log(DATA_DEPTH - 1) - 1 : 0]wr_addr;
wire [c2log(DATA_DEPTH - 1) - 1 : 0]rd_addr; 
assign  wr_addr = wr_ptr [c2log(DATA_DEPTH - 1) - 1 : 0];
assign  rd_addr = rd_ptr [c2log(DATA_DEPTH - 1) - 1 : 0];

//wr_data
integer  i;

always@(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
    if(i_fpga_rst_n_wr == 1'b0)begin
        for(i = 0 ; i < DATA_DEPTH ; i = i + 1)begin
            mem[i] <= {DATA_DEPTH{1'b0}};
        end
    end
    else if(wr_en == 1'b1 && full_signal == 1'b0)begin
        mem[wr_addr] <= wr_data;
    end
end

//rd_data
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
    if(i_fpga_rst_n_rd == 1'b0)begin
        rd_data <= {DATA_WIDTH{1'b0}};
    end
    else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
        rd_data <= mem[rd_addr];
    end
end

 endmodule
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
integer i;
integer j;


initial
begin
    i <= 0;
    j <= 0;
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
    clk_245        <= 'd0      ;
    rst_n_245      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end



initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

initial
begin
    forever #(PERIOD_245P76/2)  clk_245 =~clk_245; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;
assign i_fpga_clk_wr = clk_368 ;
assign i_fpga_rst_n_wr = rst_n_368;
assign i_fpga_clk_rd  = clk_245;
assign i_fpga_rst_n_rd = rst_n_245;

reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        counter <= 'd0;
        wr_en   <= 'd0;
        flag    <= 'd0;
    end
    else if(counter == 'd7 && flag == 'd0)begin
        flag  <= 'd1;
        wr_en <= 'd1;
    end
    else if(counter == 'd7 && flag == 'd1)begin
        //counter <= 'd0;
        wr_en   <= ~wr_en;
    end
    else if(counter == 'd15)begin
        counter <= 'd0;
    end
    else begin
        counter <= counter + 1'b1;
    end
end

//reg flag_rd;
//reg [4:0] count_rd;
//always @(posedge i_fpga_clk_rd  or negedge i_fpga_rst_n_rd begin
//    if(i_fpga_rst_n_rd  == 1'b0)begin
//        rd_en   <= 'd0;
//        flag_rd<= 'd0;
//    end
//    else if(count_rd == 'd && flag_rd== 'd0)begin
//        flag_rd<= 'd1;
//    end
//    else if(count_rd == 'd7 && flag_rd== 'd1)begin
//        rd_en   <= ~rd_en;
//    end
//end


always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
    if(i_fpga_rst_n == 1'b0)begin
        wr_data <= 'd0;
    end
    else if(wr_data == 'd20)begin
        wr_data <= 'd0;
    end
    else begin
        wr_data <= wr_data + 1;
    end
end

wire [15:0]rd_data;

reg [8:0]count_time;
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin 
	if(i_fpga_rst_n_rd == 1'b0)begin
		count_time <= 'd0;
		rd_en 	   <= 'd1;
	end
	else if(count_time == 'd100)begin
		rd_en <= 'd0;
	end
	else begin 
		count_time <= count_time + 1'b1;
		rd_en <= rd_en;
	end
end


 test#(
    .DATA_WIDTH(16),
    .DATA_DEPTH( 8)
)test( //sync_fifo
    .i_fpga_clk_wr   (i_fpga_clk_wr   )              ,
    .i_fpga_rst_n_wr (i_fpga_rst_n_wr )              ,
    .i_fpga_clk_rd   (i_fpga_clk_rd   )              ,
    .i_fpga_rst_n_rd (i_fpga_rst_n_rd )              ,
    
    .wr_data (wr_data ) ,
    .wr_en   (wr_en   )                      ,
    
    .rd_data  (rd_data) ,
    .rd_en    (rd_en  )                     ,
    
    .full_signal (full_signal )                 ,
    .empty_signal(empty_signal)
 );
endmodule


  • 仿真:
    请添加图片描述

请添加图片描述

  • 电路:
    请添加图片描述

5、单比特CDC

(1)单比特信号从慢时钟域->快时钟域

功能:单比特信号CDC(采用打两拍实现)

  • SRC:
module test(
    input i_fpga_clk_src    ,//slow
    input i_fpga_rst_n_src  ,
    input i_fpga_clk_des    ,//fast
    input i_fpga_rst_n_des  ,
    
    input i_pulse_in        ,
    
    output o_pulse_out
);

reg r_pluse_r1;
reg r_pluse_r2;

always @(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des) begin
    if(i_fpga_rst_n_des == 1'b0)begin
        r_pluse_r1 <= 1'b0;
        r_pluse_r2 <= 1'b0;
    end
    else begin
        r_pluse_r1 <=  i_pulse_in;
        r_pluse_r2 <=  r_pluse_r1;
    end
end

assign o_pulse_out = r_pluse_r2;

endmodule
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
integer i;
integer j;


initial
begin
    i <= 0;
    j <= 0;
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
    clk_245        <= 'd0      ;
    rst_n_245      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end



initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

initial
begin
    forever #(PERIOD_245P76/2)  clk_245 =~clk_245; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;
assign i_fpga_clk_rd = clk_368 ;
assign i_fpga_rst_n_rd = rst_n_368;
assign i_fpga_clk_wr  = clk_245;
assign i_fpga_rst_n_wr = rst_n_245;

reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;

always@(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
	if(i_fpga_rst_n == 1'b0)begin
		counter <= 'd0;
		wr_en 	<= 1'b0;
	end
	else if(counter == 'd7 | counter == 'd8)begin
		wr_en <= 1'b1;
		counter <= counter + 1'b1;
	end
	else begin 
		wr_en <= 1'b0;
		counter <= counter + 1'b1;
	end
end
wire o_pulse_out;

test module_test(
    .i_fpga_clk_src  (i_fpga_clk_wr  ),
    .i_fpga_rst_n_src(i_fpga_rst_n_wr),
    .i_fpga_clk_des  (i_fpga_clk_rd  ),
    .i_fpga_rst_n_des(i_fpga_rst_n_rd),
    
    .i_pulse_in      (wr_en          ),
    
    .o_pulse_out	 (o_pulse_out)
);


endmodule
  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

(2)单比特信号从快时钟域->慢时钟域

功能:单位脉冲信号单比特信号从快时钟域->慢时钟域CDC

①一般实现方式
  • SRC:
module test(
    input i_fpga_clk_src    ,
    input i_fpga_rst_n_src  ,
    input i_fpga_clk_des    ,
    input i_fpga_rst_n_des  ,
    
    input i_pulse_in        ,
    
    output o_pulse_out
);
//define reg
reg req_signal;
reg req_signal_r1;
reg req_signal_r2;

reg ack_signal;
reg ack_signal_r1;
reg ack_signal_r2;

//req mamaegement

always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
    if(i_fpga_rst_n_src == 1'b0)begin
        req_signal <= 1'b0;
    end
    else if(i_pulse_in == 1'b1)begin
        req_signal <= 1'b1;
    end
    else if(ack_signal_r2 == 1'b1)begin
        req_signal <= 1'b0;
    end
    else begin
        req_signal <= req_signal;
    end
end

//CDC req_signal
always@(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des)begin
    if(i_fpga_rst_n_des == 1'b0)begin
        req_signal_r1   <= 1'b0;
        req_signal_r2   <= 1'b0;
    end
    else begin
        req_signal_r1   <= req_signal   ;
        req_signal_r2   <= req_signal_r1;
		ack_signal   	<= req_signal_r2;
    end
end

//CDC ack_signal
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
    if(i_fpga_rst_n_src == 1'b0)begin
        ack_signal_r1 <= 1'b0;
        ack_signal_r2 <= 1'b0;
    end
    else begin
        ack_signal_r1 <= ack_signal	  ;
        ack_signal_r2 <= ack_signal_r1;
    end 
end

//output signal generate
assign o_pulse_out = req_signal_r2 & ~ack_signal;

endmodule

  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
integer i;
integer j;


initial
begin
    i <= 0;
    j <= 0;
    clk_368        <= 'd0      ;
    rst_n_368      <= 'd0      ;
    clk_245        <= 'd0      ;
    rst_n_245      <= 'd0      ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end



initial
begin
    forever #(PERIOD_368P64/2)  clk_368 =~clk_368; //clk_368的周期
end

initial
begin
    forever #(PERIOD_245P76/2)  clk_245 =~clk_245; //clk_368的周期
end

assign i_fpga_clk   = clk_368  ;
assign i_fpga_rst_n = rst_n_368;
assign i_fpga_clk_wr = clk_368 ;
assign i_fpga_rst_n_wr = rst_n_368;
assign i_fpga_clk_rd  = clk_245;
assign i_fpga_rst_n_rd = rst_n_245;

reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;

always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
	if(i_fpga_rst_n == 1'b0)begin
		counter <= 'd0;
		wr_en 	<= 1'b0;
	end
	else if(counter == 'd7 | counter == 'd8)begin
		wr_en <= 1'b1;
		counter <= counter + 1'b1;
	end
	else begin 
		wr_en <= 1'b0;
		counter <= counter + 1'b1;
	end
end

test module_test(
    .i_fpga_clk_src  (i_fpga_clk_wr  ),
    .i_fpga_rst_n_src(i_fpga_rst_n_wr),
    .i_fpga_clk_des  (i_fpga_clk_rd  ),
    .i_fpga_rst_n_des(i_fpga_rst_n_rd),
    
    .i_pulse_in      (wr_en)  ,
    
    . o_pulse_out	  ()
);

endmodule

  • 仿真:
    请添加图片描述
  • 电路:
    在这里插入图片描述
②脉冲较近校准(输出错误信息模式)

可以校准相邻较近的脉冲信号,若相邻太近输入,那么将会输出error

  • SRC:
module test(
    input i_fpga_clk_src    ,
    input i_fpga_rst_n_src  ,
    input i_fpga_clk_des    ,
    input i_fpga_rst_n_des  ,
    
    input i_pulse_in        ,
    
    output o_pulse_out
);
//define reg
reg req_signal;
reg req_signal_r1;
reg req_signal_r2;

reg ack_signal;
reg ack_signal_r1;
reg ack_signal_r2;

wire idle_state;

reg error_state;
//idle_state setting
assign idle_state = ~(req_signal | req_signal_r2);

//error state detect
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
    if(i_fpga_rst_n_src == 1'b0)begin
        error_state <= 1'b0;
    end
    else if(idle_state == 1'b1 & i_pulse_in == 1'b1)begin
        error_state <= 1'b1;
    end
    else begin
        error_state <= 1'b0;
    end
end

//req mamaegement

always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
    if(i_fpga_rst_n_src == 1'b0)begin
        req_signal <= 1'b0;
    end
    else if(i_pulse_in == 1'b1 && idle_state == 1'b1)begin
        req_signal <= 1'b1;
    end
    else if(ack_signal_r2 == 1'b1)begin
        req_signal <= 1'b0;
    end
    else begin
        req_signal <= req_signal;
    end
end

//CDC req_signal
always@(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des)begin
    if(i_fpga_rst_n_des == 1'b0)begin
        req_signal_r1   <= 1'b0;
        req_signal_r2   <= 1'b0;
        ack_signal      <= 1'b0;
    end
    else begin
        req_signal_r1   <= req_signal   ;
        req_signal_r2   <= req_signal_r1;
        ack_signal      <= req_signal_r2;
    end
end

//CDC ack_signal
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
    if(i_fpga_rst_n_src == 1'b0)begin
        ack_signal_r1 <= 1'b0;
        ack_signal_r2 <= 1'b0;
    end
    else begin
        ack_signal_r1 <= ack_signal   ;
        ack_signal_r2 <= ack_signal_r1;
    end 
end

//output signal generate
assign o_pulse_out = ack_signal_r1 & ~ack_signal_r2;



endmodule
  • TB:
    同7(1)

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

6、时钟切换电路

功能:实现不同时钟的切换

(1)使用组合逻辑实现(不推荐)

有很多毛刺,后级时钟信号不安全,无法直接使用

  • SRC:
module test(
    input i_fpga_clk_frq1   ,
    input i_fpga_clk_frq2   ,
    input i_seletion        ,
    input i_fpga_rst        ,

    output o_fpga_clk
);

    assign o_fpga_clk = i_seletion ? i_fpga_clk_frq1 : i_fpga_clk_frq2;
    //no suggest to use 

endmodule
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_368P64  = 1000/368.64;
parameter PERIOD_245P76  = 1000/245.76;

//define
reg   clk_368                             ;
reg   clk_245;
reg   rst_n_368                           ;
reg   rst_n_245 ;
reg   selection ;

//initial
initial
begin
        clk_245   = 0  ;
        clk_368   = 0  ;
        rst_n_245 = 0  ;
        rst_n_368 = 0  ;
        selection = 0  ;
        repeat(10) @ (posedge clk_368);
        selection = 1  ;
        repeat(30) @ (posedge clk_368);
        selection = 0  ;
end

initial begin
    #(PERIOD_368P64) rst_n_368 = 1'b1;
end

initial begin
    #(PERIOD_245P76) rst_n_245 = 1'b1;
end

//clk generate
    always #(PERIOD_368P64) clk_368 = ~clk_368;
    always #(PERIOD_245P76) clk_245 = ~clk_245;


//module
wire o_fpga_clk;

test tb_test(
    .i_fpga_clk_frq1(clk_368  ),
    .i_fpga_clk_frq2(clk_245  ),
    .i_seletion     (selection),
    .i_fpga_rst     (rst_n_368),

    .o_fpga_clk     (o_fpga_clk)
);


endmodule

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

(2)时钟切换电路(giltch_free同源)

  • SRC:
module test(
    input i_fpga_clk_frq1   ,
    input i_fpga_clk_frq2   ,
    input i_seletion        ,
    input i_fpga_rst        ,

    output o_fpga_clk
);

    //define
    reg enable_1;
    reg enable_2;

    //domain 1
    always @(negedge i_fpga_clk_frq1 or negedge i_fpga_rst) begin
        if(i_fpga_rst == 1'b0)begin
            enable_1 <= 1'b0;
        end
        else begin
            enable_1 <= (~enable_2) & i_seletion;
        end
    end

    //domain 2
    always @(negedge i_fpga_clk_frq2 or negedge i_fpga_rst) begin
        if(i_fpga_rst == 1'b0)begin
            enable_2 <= 1'b0;
        end
        else begin
            enable_2 <= (~enable_1) & (~i_seletion);
        end
    end

    //generate 
    assign o_fpga_clk = (enable_1 & i_fpga_clk_frq1) | (enable_2 & i_fpga_clk_frq2);

endmodule 
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_400  = 4000/400;
parameter PERIOD_200  = 4000/200;

//define
reg   clk_400                             ;
reg   clk_200;
reg   rst_n_400                           ;
reg   rst_n_200 ;
reg   selection ;

//initial
initial
begin
        clk_200   = 0  ;
        clk_400   = 0  ;
        rst_n_200 = 0  ;
        rst_n_400 = 0  ;
        selection = 0  ;
        repeat(10) @ (posedge clk_400);
        selection = 1  ;
        repeat(30) @ (posedge clk_400);
        selection = 0  ;
end

initial begin
    #(PERIOD_400) rst_n_400 = 1'b1;
end

initial begin
    #(PERIOD_200) rst_n_200 = 1'b1;
end

//clk generate
    always #(PERIOD_400) clk_400 = ~clk_400;
    always #(PERIOD_200) clk_200 = ~clk_200;


//module
wire o_fpga_clk;

test tb_test(
    .i_fpga_clk_frq1(clk_400  ),
    .i_fpga_clk_frq2(clk_200  ),
    .i_seletion     (selection),
    .i_fpga_rst     (rst_n_400),

    .o_fpga_clk     (o_fpga_clk)
);


endmodule

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

(3)时钟切换电路(giltch_free异步)

  • SRC:
module test(
    input i_fpga_clk_frq1   ,
    input i_fpga_clk_frq2   ,
    input i_selection        ,
    input i_fpga_rst        ,

    output o_fpga_clk
);

    //define
    reg enable_1  ;
    reg enable_1_r;
    reg enable_2  ;
    reg enable_2_r;

    //domain 1
    always @(posedge i_fpga_clk_frq1 or negedge i_fpga_rst) begin
        if(i_fpga_rst == 1'b0)begin
            enable_1 <= 1'b0;
        end
        else begin
            enable_1 <= (~enable_2_r) & i_selection   ;
        end
    end

    always @(negedge i_fpga_clk_frq1 or negedge i_fpga_rst) begin
        if(i_fpga_rst == 1'b0)begin
            enable_1_r <= 1'b0                       ;
        end
        else begin
            enable_1_r <= enable_1                   ;
        end
    end

    //domain 2
    always @(posedge i_fpga_clk_frq2 or negedge i_fpga_rst) begin
        if(i_fpga_rst == 1'b0)begin
            enable_2 <= 1'b0;
        end
        else begin
            enable_2 <= (~enable_1_r) & (~i_selection);
        end
    end

    always @(negedge i_fpga_clk_frq2 or negedge i_fpga_rst) begin
        if(i_fpga_rst == 1'b0)begin
            enable_2_r <= 1'b0                       ;
        end
        else begin
            enable_2_r <= enable_2                   ;
        end
    end

    //generate 
    assign o_fpga_clk = (enable_1_r & i_fpga_clk_frq1) | (enable_2_r & i_fpga_clk_frq2);

endmodule 
  • TB:
`timescale  1ns / 1ps //1000M

module tb_test;

parameter PERIOD_400  = 4000/399;
parameter PERIOD_200  = 4000/200;

//define
reg   clk_400                             ;
reg   clk_200;
reg   rst_n_400                           ;
reg   rst_n_200 ;
reg   selection ;

//initial
initial
begin
        clk_200   = 0  ;
        clk_400   = 0  ;
        rst_n_200 = 0  ;
        rst_n_400 = 0  ;
        selection = 0  ;
        repeat(10) @ (posedge clk_400);
        selection = 1  ;
        repeat(30) @ (posedge clk_400);
        selection = 0  ;
end

initial begin
    #(PERIOD_400) rst_n_400 = 1'b1;
end

initial begin
    #(PERIOD_200) rst_n_200 = 1'b1;
end

//clk generate
    always #(PERIOD_400) clk_400 = ~clk_400;
    always #(PERIOD_200) clk_200 = ~clk_200;


//module
wire o_fpga_clk;

test tb_test(
    .i_fpga_clk_frq1(clk_400  ),
    .i_fpga_clk_frq2(clk_200  ),
    .i_selection    (selection),
    .i_fpga_rst     (rst_n_400),

    .o_fpga_clk     (o_fpga_clk)
);


endmodule

  • 仿真:
    在这里插入图片描述

  • 电路:
    在这里插入图片描述

7、

功能:

(1)\

  • SRC:

  • TB:

  • 仿真:
  • 电路:

8、

功能:

(1)\

  • SRC:

  • TB:

  • 仿真:
  • 电路:
  • 8
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值