|
发表于 2005-11-11 16:57:23
|
显示全部楼层
时钟信号的切换
闲着没事,做个小例子,看看行不行?
用了四个同步器,可能比较笨笨,并测试了一下:
module clkswitch ( clkout, async_clk0, async_clk1, sel, rst_n);
output clkout; //输出时钟
input async_clk0; //输入异步时钟0
input async_clk1; //输入异步时钟1
input sel; //选择端,0则选择时钟0,1则选择时钟1
input rst_n;
wire sync_sel_clk0;
wire sync_sel_clk1;
wire clk0_g;
wire clk1_g;
wire handshake_f1t0;
wire handshake_f0t1;
wire clk0_gating;
wire clk1_gating;
//下面是同步器用的一堆reg
reg latch2_1;
reg latch1_1;
reg latch0_1;
reg latch2_0;
reg latch1_0;
reg latch0_0;
reg hs_latch_f1_t0_2nd;
reg hs_latch_f1_t0_1st;
reg hs_latch_f0_t1_2nd;
reg hs_latch_f0_t1_1st;
// 产生输出时钟的组合逻辑
assign sync_sel_clk1 = latch1_1;
assign sync_sel_clk0 = latch1_0;
assign handshake_f1t0 = hs_latch_f1_t0_2nd;
assign handshake_f0t1 = hs_latch_f0_t1_2nd;
assign clk0_g = clk0_gating & async_clk0;
assign clk0_gating = (~sync_sel_clk0) & (~handshake_f1t0);
assign clk1_g = clk1_gating & async_clk1;
assign clk1_gating = (sync_sel_clk1 & handshake_f0t1);
assign clkout = clk0_g | clk1_g;
// 在clk1域内同步sel
always @(posedge async_clk1 or negedge rst_n) begin
if (rst_n == 0) begin
latch2_1 <= 1'b0;
latch1_1 <= 1'b0;
latch0_1 <= 1'b0;
end
else begin
latch2_1 <= latch1_1;
latch1_1 <= latch0_1;
latch0_1 <= sel;
end
end
// 在clk0域内同步sel
always @(posedge async_clk0 or negedge rst_n) begin
if (rst_n == 0) begin
latch2_0 <= 0;
latch1_0 <= 0;
latch0_0 <= 0;
end
else begin
latch2_0 <= latch1_0;
latch1_0 <= latch0_0;
latch0_0 <= sel;
end
end
// 将clk1中同步后的sel送到clk0域内再同步一下
always @(posedge async_clk0 or negedge rst_n) begin
if (rst_n == 0) begin
hs_latch_f1_t0_2nd <= 0;
hs_latch_f1_t0_1st <= 0;
end
else begin
hs_latch_f1_t0_2nd <= hs_latch_f1_t0_1st;
hs_latch_f1_t0_1st <= latch2_1;
end
end
// 将clk0中同步后的sel送到clk1域内再同步一下
always @(posedge async_clk1 or negedge rst_n) begin
if (rst_n == 0) begin
hs_latch_f0_t1_2nd <= 0;
hs_latch_f0_t1_1st <= 0;
end
else begin
hs_latch_f0_t1_2nd <= hs_latch_f0_t1_1st;
hs_latch_f0_t1_1st <= latch2_0;
end
end
endmodule
|
|