这是一个根据现有始终估计输入数值的频率,基本原理是数1秒时间,作为计数区间,统计被测频率的计数。之后穿越时钟域输出。
代码写好了 还没有进行仿真和实际运行,应该没啥问题了。
module clk_estimator #(
parameter REF_FRQ = 100*1000*1000
)(
input rst,
input clk,
input meas_clk,
output [31:0] cntr_data,
output [31:0] seconds ,
output reg update ,
);
reg [31:0] c ;
wire c_of = c == REF_FRQ /2 -1 ;
always@(posedge clk )if (rst) c<=0 ;else c <= ( c_of ) ? 0: c+1 ;
reg div_gate ;always@(posedge clk )if ( c_of ) div_gate <= ~ div_gate ;
wire out_dclk;
//sync_reg
clk_estimator_sync_reg self_estim(
.clk( meas_clk ),
.rst( rst ),
.in( div_gate ),
.out( out_dclk)
);
reg [31:0] cntr_clk;
reg [31:0] ref_cntr_data_r;
reg [31:0] evnts;
assign seconds = evnts ;
reg prev_out_dclk;
reg updater ;
always @(posedge meas_clk) begin
if (rst) begin
cntr_clk <= 0;
prev_out_dclk <= 0;
ref_cntr_data_r <= 0;
evnts <= 0;
end else begin
prev_out_dclk <= out_dclk;
if (prev_out_dclk == 0 && out_dclk == 1'b1) begin
cntr_clk <= 0;
ref_cntr_data_r <= cntr_clk;
evnts <= evnts + 1'b1;
updater <=1;
end else begin
updater <=0;
cntr_clk <= cntr_clk + 1'b1;
end
end
end
// Self clock estimation
//assign cntr_datar = ref_cntr_data_r[27:0] ;
one_entry_fifo_1 one_entry_fifo #(.dw(128) )(
.rd_clk(clk ),
.wr_clk(meas_clk),
.rd_rst(0),
.wr_rst(0),
.we( updater &(~full ) ),
.re( ~empty ),
.d ( { evnts, ref_cntr_data_r }),
.reset_value(),
.q ({ seconds , cntr_data}),
.empty() ,
.full(full )
);
always @ (posedge clk ) update <= ~empty ;
endmodule
module one_entry_fifo_1 #(parameter dw=16 )(
input rd_clk, wr_clk, rd_rst,wr_rst,we,re,
input [dw-1:0] d ,reset_value,
output reg [dw-1:0] q ,
output reg empty , full
);
//synopsys sync_set_reset "rd_rst_n,wr_rst_n"
wire legal_wr = we &(~full);
wire legal_rd = re & (~empty) ;
reg wr_ptr ,rd_ptr ;// only one bit !
reg wr_ptr_r,wr_ptr_rr;
reg rd_ptr_r,rd_ptr_rr;
always @(posedge rd_clk)wr_ptr_r <=wr_ptr;
always @(posedge rd_clk)wr_ptr_rr <=wr_ptr_r;
always @(posedge wr_clk)rd_ptr_r <= rd_ptr;
always @(posedge wr_clk)rd_ptr_rr <= rd_ptr_r;
always @(posedge rd_clk)if( wr_ptr_rr == rd_ptr ) empty<=1;else empty <= legal_rd ;
always @(posedge wr_clk)if( rd_ptr_rr != wr_ptr ) full<=1 ;else full <= legal_wr ;
always @(posedge rd_clk)if (rd_rst) rd_ptr <= 0;else if ( legal_rd ) rd_ptr <= ~ rd_ptr ;
always @(posedge wr_clk)if (wr_rst) wr_ptr <= 0;else if ( legal_wr ) wr_ptr <= ~ wr_ptr ;
reg [dw-1:0] buff ; always @(posedge wr_clk)if ( legal_wr ) buff <= d ;
always @(posedge rd_clk)if ( rd_rst ) q <= reset_value ;else if ( legal_rd ) q <= buff;
endmodule
//
// Copyright (c) 2016-2020 Fairwaves, Inc.
// SPDX-License-Identifier: CERN-OHL-W-2.0
//
module clk_estimator_sync_reg #(
parameter INIT = 0,
parameter ASYNC_RESET = 0
) (
input clk,
input rst,
input in,
output out
);
(* ASYNC_REG = "TRUE" *) reg sync1;
(* ASYNC_REG = "TRUE" *) reg sync2;
assign out = sync2;
generate
if (ASYNC_RESET) begin
always @(posedge clk or posedge rst) begin
if (rst) begin
sync1 <= INIT;
sync2 <= INIT;
end else begin
sync1 <= in;
sync2 <= sync1;
end
end
end else begin
always @(posedge clk) begin
if (rst) begin
sync1 <= INIT;
sync2 <= INIT;
end else begin
sync1 <= in;
sync2 <= sync1;
end
end
end
endgenerate
endmodule