上升沿与下降沿的门控时钟设计
门控时钟方法学
门控时钟的目的
- 设计的时钟树会产生功耗
- 时钟树几乎消耗了整个芯片功耗的50%,因此最好时钟在根部产生或者关闭时钟,以使整个时钟树都关闭
不含锁存器的门控时钟电路
容易导致时钟过早地终止,如图
基于锁存器的门控时钟
RTL and testbench
module clk_gating
(
input clk,
input en,
output gated_clk
);
reg q;
always @(*)begin
if(~clk)
q = en;
end
assign gated_clk = q & clk;
endmodule
`timescale 1ns/1ps
module tb;
reg clk, rst_n;
initial begin
clk = 1'b0;
#5 clk = 1'b1;
forever #5 clk = ~clk;
end
reg en;
wire gated_clk;
initial begin
#66
en = 1'b1;
#10
en = 1'b0;
#40
en = 1'b1;
#10
en = 1'b0;
end
initial begin
#200
$finish;
end
clk_gating inst (clk, en, gated_clk);
initial begin
$dumpfile("showmebug.vcd");
$dumpvars(0, tb);
end
endmodule
输出波形
分析:
- 图中可以看出,锁存器的作用是clk低电平的时候 Q = EN,CLK高电平的时候锁存上一个状态的信号。
- 因此在图中稳定区域的部分,锁存器输出的Q是高电平,然后与CLK相与,因此可以保持到产生完整的时钟脉冲
- 因此使能信号只需要在时钟上升沿附近保持稳定即可
基于下降沿有效的锁存器门控时钟波形
RTL code
tb代码同上
module clk_gating_negedge
(
input clk,
input en,
output gated_clk
);
reg q;
always @(*)begin
if(clk)
q = en;
end
assign gated_clk = q | clk;
endmodule
基于锁存器的门控时钟上升沿和下降沿有效的时钟使用的锁存器类型和门类型
- 对于上升沿有效的时钟:使用低电平Q=EN(负沿触发)的锁存器寄存信号,使用与门进行控制。
- 对于下降沿有效的时钟:使用高电平有效(正沿触发)的锁存器寄存信号,使用或门进行控制。
基于寄存器的门控时钟
参考资料为这个
对于上升沿有效的门控时钟
首先这里需要说明的是,这里说的“上升沿有效”指的是以clk作为时钟信号的触发器,是采用上升沿有效,还是下降沿有效
对于上升有效的门控时钟,设计如下:
核心思路:
使用一个在时钟的无效沿触发的寄存器。采用这种配置,一次只能更改门的一个输入,从而防止输出出现毛刺或尖峰(spike)。如果时钟在上升沿有效,请使用AND门。相反,对于在下降沿有效的时钟,请使用OR门控制时钟和寄存器。
module gated_clk
(
input clk,
input ena,
output clk_out
);
reg ena_r;
always @(negedge clk)begin
ena_r <= ena;
end
assign clk_out = ena_r & clk;
endmodule
// ---------------- testbench -------------
`timescale 1ns/1ps
module tb;
reg clk, rst_n;
initial begin
clk = 1'b0;
#5 clk = 1'b1;
forever #5 clk = ~clk;
end
wire clk_out;
reg ena;
initial begin
ena = 1'b0;
#29 ena = 1'b1;
#89 ena = 1'b0;
end
gated_clk inst (clk, ena, clk_out);
initial begin
#200
$finish;
end
initial begin
$dumpfile("showmebug.vcd");
$dumpvars(0, tb);
end
endmodule
输出波形
下降沿有效的门控时钟
注意下降沿有效的时候,门控时钟module中使用的是上升沿有效的触发器,(对应核心思路中:使用时钟无效沿的触发器
module gated_neg_clk
(
input clk,
input ena,
output clk_out
);
reg ena_r;
always @(posedge clk)begin
ena_r <= ena;
end
assign clk_out = ena_r | clk;
endmodule
`timescale 1ns/1ps
module tb;
reg clk, rst_n;
initial begin
clk = 1'b0;
#5 clk = 1'b1;
forever #5 clk = ~clk;
end
initial begin
rst_n = 1'b0;
#19 clk = 1'b1;
end
wire clk_out;
reg ena;
initial begin
ena = 1'b0;
#29 ena = 1'b1;
#89 ena = 1'b0;
end
wire clk_neg_out;
gated_neg_clk instn (clk, !ena, clk_neg_out);
initial begin
#200
$finish;
end
initial begin
$dumpfile("showmebug.vcd");
$dumpvars(0, tb);
end
endmodule