切换原理
一,同步另一个域的控制信号。
二、负沿 gating clock,通过保证时序,避免毛刺。
RTL代码
此代码仅为方便理解,实际中请使用std cell例化。
module async_clk_mux(
input clk0,clk1,rstn0,rstn1, //clk0 and clk1 has no assured phase relationship
input sel, //0 select clk0, 1 select clk1
output reg clkout
);
logic sel0, sel1;
logic ck0_dff_0, ck0_dff_1; //sync dff
logic ck1_dff_0, ck1_dff_1;
logic ck0_dff_1_qn, ck1_dff_1_qn;
logic clk0_out_pre, clk1_out_pre;
assign sel0 = ~sel;
assign sel1 = sel;
always_ff @(posedge clk0 or negedge rstn0)
if(!rstn0)
ck0_dff_0 <= 1'b0;
else
ck0_dff_0 <= sel0 & ck1_dff_1_qn;
always_ff @(negedge clk0 or negedge rstn0)
if(!rstn0)
ck0_dff_1 <= 1'b0;
else
ck0_dff_1 <= ck0_dff_0;
assign ck0_dff_1_qn = ~ck0_dff_1;
always_ff @(posedge clk1 or negedge rstn0)
if(!rstn0)
ck1_dff_0 <= 1'b0;
else
ck1_dff_0 <= sel1 & ck0_dff_1_qn;
always_ff @(negedge clk1 or negedge rstn0)
if(!rstn0)
ck1_dff_1 <= 1'b0;
else
ck1_dff_1 <= ck1_dff_0;
assign ck1_dff_1_qn = ~ck1_dff_1;
assign clk0_out_pre = clk0 & ck0_dff_1;
assign clk1_out_pre = clk1 & ck1_dff_1;
assign clkout = clk0_out_pre | clk1_out_pre;
endmodule
仿真环境供参考
module tb_top;
bit clk0, clk1, sel;
bit rstn0, rstn1;
integer dly0, dly1;
initial begin
clk0 = 1'b0;
dly0 = {$random}%100;
$display("dly0 is %0d", dly0);
forever
#(dly0) clk0 = ~clk0;
end
initial begin
clk1 = 1'b0;
dly1 = {$random}%77;
$display("dly1 is %0d", dly1);
forever
#(dly1) clk1 = ~clk1;
end
initial begin
sel = 1'b0;
rstn0 = 1'b0;
rstn1 = 1'b0;
#100;
rstn0 = 1'b1;
rstn1 = 1'b1;
repeat(4) begin
#10us;
sel = ~sel;
end
$finish;
end
initial begin
$fsdbDumpvars;
$fsdbDumpon;
end
async_clk_mux u_mux(
.clk0(clk0),
.rstn0(rstn0),
.clk1(clk1),
.rstn1(rstn1),
.sel(sel),
.clkout(clkout)
);
endmodule
电路结构
波形
clk0 --> clk1
clk0立即关闭
因为clk0_dff_1_qn的延迟,clk1会延迟打开。
clk1 --> clk0
clk1也会立即关闭
因为clk1_dff_1_qn的延迟,clk0会延迟打开。