CDC设计实例-02
CDC设计实例
加速器
假设要处理一项业务比如图像处理,有两种方向,第一种选择一些通用的处理器CPU\GPU\DSP等通用的处理器,第二种是将算法映射成IP,直接使用IP进行处理图像处理等专门的业务就是加速器。加速器是挂接到总线上的,类似于DMA,需要CPU派发一些任务给加速器执行。
软件配置
C代码--》编译成二进制文件--》二进制文件存放在RAM中--》CPU通过I-Cache读入二进制文件进行执行
CPU动态切换时钟,不能出现glitch
以三个时钟为例,有一个2bit的选择信号,DFT模式下选择Clk_scan进行输出;首先clk的enable信号经过几级寄存器打拍操作,然后输入到ICG中,滤除毛刺;ICG使用的是打过几拍之后的信号,ICG的enable是高电平有效的
如果选择clk1信号,select信号选择clk1会从0到1进行拉高,同时clk1到ICG的enable信号会被拉低,但是经过三级打拍之后,会延迟3个周期enable信号才会被拉低,在延迟的3个周期内,让clk2和clk3的enable失效,即使此时clk2和clk3的select信号拉高,但是不能用,形成一个真空区域(在这个时间内,没有时钟可用),经过三个周期之后,再输出选择的时钟
通过mux实现二选1得时钟,毛刺出现在时钟切换的过程中,通过硬件实现时钟切换,就是在切换时钟的过程中,产生一个真空地带,在这个区域中不会出现任何时钟,输出一直是低电平,经过这个地带之后,输出选择的稳定的时钟信号
CPU时钟切换的代码
module glitch_free(
clk_out,
cgm_sel,
clk_in0,
clk_in1,
clk_in2,
rst_clk_n,
scan_dc_mode,
icg_scan_mode,
clk_scan
);
output clk_out;
input [1:0] cgm_sel; // 时钟选择信号2bit
input clk_in0;
input clk_in1;
input clk_in2;
input rst_clk_n;
input icg_scan_mode; // scan mode
input scan_dc_mode;
input clk_scan; // dft使用的时钟
// 定义三组打三拍的寄存器,9个register
reg in0_en_sync1,in0_en_sync2,in0_en_sync3;
reg in1_en_sync1,in1_en_sync2,in1_en_sync3;
reg in2_en_sync1,in2_en_sync2,in2_en_sync3;
// 判断是不是scan mode,如果是scan mode会将时钟切换为clk_scan
assign clk_in0_scan = scan_dc_mode ? clk_sacn : clk_in0;
assign clk_in1_scan = scan_dc_mode ? clk_sacn : clk_in1;
assign clk_in2_scan = scan_dc_mode ? clk_sacn : clk_in2;
// 选择信号,三个enable信号
assign in0_sel = (cgm_sel [1:0] == 2'b00)
assign in1_sel = (cgm_sel [1:0] == 2'b01)
assign in2_sel = (cgm_sel [1:0] == 2'b10)
// 三个时钟信号可用的标识,in0_en可用的所有可能情况
assign in0_used = in0_sel | in0_en_sync1 | in0_en_sync2 | in0_en_sync3;
assign in1_used = in1_sel | in1_en_sync1 | in1_en_sync2 | in1_en_sync3;
assign in2_used = in2_sel | in2_en_sync1 | in2_en_sync2 | in2_en_sync3;
// en信号(与其他时钟相斥)
assign in0_en = ~in1_used & ~in2_used;
assign in1_en = ~in0_used & ~in2_used;
assign in2_en = ~in0_used & ~in1_used;
always @(posedge clk_in0_sacn or negedge rst_clk_n) begin
// 复位信号,将寄存器输出置0
if(!rst_clk_n) begin
in0_en_sync1 <= 1'b0;
in0_en_sync2 <= 1'b0;
in0_en_sync3 <= 1'b0;
end
else begin
// 不是复位信号,进行三级寄存器打拍
in0_en_sync1 <= in0_en;
in0_en_sync2 <= in0_en_sync1;
in0_en_sync3 <= in0_en_sync2;
end
end
always @(posedge clk_in1_sacn or negedge rst_clk_n) begin
// 复位信号,将寄存器输出置0
if(!rst_clk_n) begin
in1_en_sync1 <= 1'b0;
in1_en_sync2 <= 1'b0;
in1_en_sync3 <= 1'b0;
end
else begin
// 不是复位信号,进行三级寄存器打拍
in1_en_sync1 <= in1_en;
in1_en_sync2 <= in1_en_sync1;
in1_en_sync3 <= in1_en_sync2;
end
end
always @(posedge clk_in2_sacn or negedge rst_clk_n) begin
// 复位信号,将寄存器输出置0
if(!rst_clk_n) begin
in2_en_sync1 <= 1'b0;
in2_en_sync2 <= 1'b0;
in2_en_sync3 <= 1'b0;
end
else begin
// 不是复位信号,进行三级寄存器打拍
in2_en_sync1 <= in2_en;
in2_en_sync2 <= in2_en_sync1;
in2_en_sync3 <= in2_en_sync2;
end
end
// 经过三级打拍的信号生成时钟门控信号
assign ind_in0 = in0_en_sync2; // generate the enable signal from the second stage synchronizer
assign ind_in1 = in1_en_sync2;
assign ind_in2 = in2_en_sync2;
// 例化门控单元
cell_clock_gating u_clk_gate_out0 (
.TE (icg_scan_mode), // DFT:test mode
.E (ind_in0),
.CP (clk_in0),
.Q (clk_ou0)
);
assign ind_in1_scan = ~scan_dc_mode & ind_in1;
// 例化门控单元
cell_clock_gating u_clk_gate_out1 (
.TE (icg_scan_mode), // DFT:test mode
.E (ind_in1),
.CP (clk_in1),
.Q (clk_out1)
);
assign ind_in2_scan = ~scan_dc_mode & ind_in2;
// 例化门控单元
cell_clock_gating u_clk_gate_out2 (
.TE (icg_scan_mode), // DFT:test mode
.E (ind_in2),
.CP (clk_in2),
.Q (clk_out2)
);
assign clk_out = clk_out0 | clk_out1 | clk_out2;
endmodule
- 时钟的使能信号在时钟的上升沿的时候有效,才能消除glitch