|
CRG(时钟复位模块)做为soc芯片设计中的关键部分,主要包括以下内容:
CRG基本知识汇总
<hr/>下面针对以上内容详细展开
一:时钟部分
(一)基本概念
时钟源:用来产生时钟的器件,包括石英晶体,晶振等结构
时钟结构:
时钟结构
时钟属性:
- 时钟周期:决定时钟频率
- 占空比:高脉冲占时钟周期的比例,常见为1/2
- 时钟抖动(clk jitter):相对于理想时钟沿实际时钟存在不随时间积累的、时而超前、时而滞后的偏移称为时钟抖动,简称抖动,与时钟频率无关,如下图:
clk jitter
时钟的抖动可以分为随机抖动(Random Jitter,简称Rj)和固有抖动(Deterministic jitter):
- 随机抖动的来源为热噪声、Shot Noise 和Flick Noise,与电子器件和半导体器件的电子和空穴特性有关,比如ECL 工艺的PLL 比TTL 和CMOS工艺的PLL 有更小的随机抖动;
- 固定抖动的来源为:开关电源噪声、串扰、电磁干扰等等,与电路的设计有关,可以通过优化设计来改善,比如选择合适的电源滤波方案、合理的PCB 布局和布线。
- 时钟偏斜(clk skew):时钟分支信号在到达寄存器的时钟端口过程中,都存在有线网等延时,由于延时,到达寄存器时钟端口的时钟信号存在有相位差,也就是不能保证每一个沿都对齐,这种差异称为时钟偏移(clock skew),也叫时钟偏斜。时钟的偏移如下图所示:
clk skew
时钟skew 与时钟频率并没有直接关系,skew 与时钟线的长度及被时钟线驱动的时序单元的负载电容、个数有关。
时钟的偏移和时钟的抖动都影响着时钟网络分枝的延迟差异(相位差异),在Design Compiler 里面,我们用时钟的不确定性(uncertainty)来表示这两种情况的影响。
使用set_clock_uncertainty 命令来设置。
延时(latency):时钟从时钟源(比如说晶振)出发到达触发器时钟端口的延时,称为时钟的延时,包含时钟源延迟(source latency)和时钟网络的延迟(networklatency),如下图所示:
clk latency
时钟源延迟(clock source latency),也称为插入延迟(insertion delay),是时钟信号从其实际时钟原点到设计中时钟定义点(时钟的输入引脚)的传输时间,上图是3ns。
时钟网络的延迟( clock network latency)是时钟信号从其定义的点(端口或引脚)到寄存器时钟引脚的传输,经过缓冲器和连线产生的延迟(latency),上图是1ns。
- 转换时间:时钟的上升沿跳变到下降沿或者时钟下降沿跳变到上升沿的时间,这个时间并不是完全没有跳变时钟的,而是需要一定的转换时间。时钟的转换时间与与单元的延时时间(也就是器件特性)还有电容负载有关。
(二)功能单元
- 时钟门控:主要是为了降低芯片功耗,中后端在综合时可以自行插入。
clk gate的电路——时钟锁存器
代码:
module clk_gate (clk ,en,clkout);
input clk;
input en;
output clkout;
reg clk_en_reg;
always@(clk or en) begin
if(clk ==1&#39;b0)
clk_en_reg <= clk_en;
end
assign clkout = clk && clk_en_reg;
2. 时钟分频
- 偶数分频——占空比为50%:采用触发器反向输出端连接到输入端的方式,可构成简单的 2 分频电路。以此为基础进行级联,可构成 4 分频,8 分频电路。电路实现如下图所示,用 Verilog 描述时只需使用简单的取反逻辑即可。
偶数分频
module even_divisor
# (parameter DIV_CLK = 10 )
(
input rstn ,
input clk,
output clk_div2,
output clk_div4,
output clk_div10
);
//2 分频
reg clk_div2_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
clk_div2_r <= &#39;b0 ;
end
else begin
clk_div2_r <= ~clk_div2_r ;
end
end
assign clk_div2 = clk_div2_r ;
//4 分频
reg clk_div4_r ;
always @(posedge clk_div2 or negedge rstn) begin
if (!rstn) begin
clk_div4_r <= &#39;b0 ;
end
else begin
clk_div4_r <= ~clk_div4_r ;
end
end
assign clk_div4 = clk_div4_r ;
//N/2 计数
reg [3:0] cnt ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
cnt <= &#39;b0 ;
end
else if (cnt == (DIV_CLK/2)-1) begin
cnt <= &#39;b0 ;
end
else begin
cnt <= cnt + 1&#39;b1 ;
end
end
//输出时钟
reg clk_div10_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
clk_div10_r <= 1&#39;b0 ;
end
else if (cnt == (DIV_CLK/2)-1 ) begin
clk_div10_r <= ~clk_div10_r ;
end
end
assign clk_div10 = clk_div10_r ;
endmodule
需要奇数分频如果不要求占空比为 50%,可按照偶数分频的方法进行分频。即计数器对分频系数 N 进行循环计算,然后根据计数值选择一定的占空比输出分频时钟。
如果奇数分频输出时钟的高低电平只差一个 cycle ,则可以利用源时钟双边沿特性并采用&#34;与操作&#34;或&#34;或操作&#34;的方式将分频时钟占空比调整到 50%。
采用&#34;或操作&#34;产生占空比为 50% 的 3 分频时钟。
利用源时钟上升沿分频出高电平为 1 个 cycle、低电平为 2 个 cycle 的 3 分频时钟。
利用源时钟下降沿分频出高电平为 1 个 cycle、低电平为 2 个 cycle 的 3 分拼时钟。
两个 3 分频时钟应该在计数器相同数值、不同边沿下产生,相位差为半个时钟周期。然后将 2 个时钟进行&#34;或操作&#34;,便可以得到占空比为 50% 的 3 分频时钟。
以3分频为例,对应的代码如下:
module ood_div_and
#( parameter DIV_CLK = 3 )
(
input rstn ,
input clk,
output clk_div3
);
//计数器
reg [1:0] cnt ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
cnt <= &#39;b0 ;
end
else if (cnt == DIV_CLK-1) begin
cnt <= &#39;b0 ;
end
else begin
cnt <= cnt + 1&#39;b1 ;
end
end
//在上升沿产生3分频
reg clkp_div3_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
clkp_div3_r <= 1&#39;b0 ;
end
else if (cnt == (DIV_CLK>>1) ) begin //计数5-8位低电平
clkp_div3_r <= 0 ;
end
else if (cnt == DIV_CLK-1) begin //计数 0-4 为高电平
clkp_div3_r <= 1 ;
end
end
//在下降沿产生3分频
reg clkn_div9_r ;
always @(negedge clk or negedge rstn) begin
if (!rstn) begin
clkn_div3_r <= 1&#39;b0 ;
end
else if (cnt == (DIV_CLK>>1) ) begin
clkn_div3_r <= 0 ;
end
else if (cnt == DIV_CLK-1) begin
clkn_div3_r <= 1 ;
end
end
//与操作
assign clk_div3 = clkp_div3_r & clkn_div3_r ;
endmodule
3. 时钟切换
时钟mux:用于静态切换,动态切换会出现glitch
clk mux
时钟switch:可用于动态切换,切换过程中会短时间内无时钟,在两个电平相反的时候切换时钟,肯定有毛刺;电平相同的时候,即使不产生毛刺,时钟切换后的第一个时钟的周期或占空比也不是理想的。所以,为避免毛刺的产生,需要在两个时钟都为低电平的时候进行时钟切换。一种典型的时钟切换电路如下所示。
该电路利用时钟下降沿对时钟选择信号 sel_clk 进行缓存。同时一个时钟选择信号对另一个时钟进行反馈控制,保证同一时刻只能有一路时钟有效。最后采用&#34;或操作&#34;将两路时钟合并,完成时钟切换的过程。
clk switch
module clk_switch(
input rst_n ,
input clk1,
input clk2,
input sel_clk1 , // 1 clk1, 0 clk2
output clk_out
);
reg [2:0] sel_clk1_r ;
reg [1:0] sel_clk1_neg_r ;
reg [2:0] sel_clk2_r ;
reg [1:0] sel_clk2_neg_r ;
wire clk1_gate;
wire clk2_gate;
//使用3拍缓存,同步另一个时钟控制信号与本时钟控制信号的&#34;与&#34;逻辑操作
always @(posedge clk1 or negedge rstn) begin
if (!rstn) begin
sel_clk1_r <= 3&#39;b111 ; //注意默认值
end
else begin
//sel clk1, and not sel clk2
sel_clk1_r <= {sel_clk1_r[1:0], sel_clk1 & (!sel_clk2_neg_r[1])} ;
end
end
//在下降沿,使用2拍缓存时钟选择信号
always @(negedge clk1 or negedge rstn) begin
if (!rstn) begin
sel_clk1_neg_r <= 2&#39;b11 ; //注意默认值
end
else begin
sel_clk1_neg_r <= {sel_clk1_neg_r[0], sel_clk1_r[2]} ;
end
end
//使用3拍缓存,同步另一个时钟控制信号与本时钟控制信号的&#34;与&#34;逻辑操作
always @(posedge clk2 or negedge rstn) begin
if (!rstn) begin
sel_clk2_r <= 3&#39;b0 ; //注意默认值
end
else begin
//sel clk2, and not sel clk1
sel_clk2_r <= {sel_clk2_r[1:0], !sel_clk1 & (!sel_clk1_neg_r[1])} ;
end
end
//在下降沿,使用2拍缓存时钟选择信号
always @(negedge clk2 or negedge rstn) begin
if (!rstn) begin
sel_clk2_neg_r <= 2&#39;b0 ; //注意默认值
end
else begin
sel_clk2_neg_r <= {sel_clk2_neg_r[0], sel_clk2_r[2]} ;
end
end
//时钟逻辑运算时,一般使用特定的工艺单元库。
//这里用 Verilog 自带的逻辑门单元代替
and (clk1_gate, clk1, sel_clk1_neg_r[1]) ;
and (clk2_gate, clk2, sel_clk2_neg_r[1]) ;
or (clk_out, clk1_gate, clk2_gate) ;
endmodule
<hr/>二:复位
(一)基本概念
复位的作用:使电路(主要是触发器)进入一个能稳定操作的确定状态,主要表现为:
- 使电路从确定的初始状态下开始运行
- 修复系统,实现故障自愈,使电路从错误状态回到可以控制的确定状态
复位源:硬复位、上电复位、软复位、异常复位
复位控制:系统、应用环境决定何时复位
2. 复位结构
复位结构
(二)复位类型
同步复位
同步复位具有以下优点:
确保电路是同步的,触发器面积小,时钟可以滤除复位上的毛刺
缺点:依赖时钟,需要确保复位时钟必须有且保持足够时间,否则复位无法生效
module sync_reset(
input rst_n, //同步复位信号
input clk, //时钟
input din, //输入数据
output reg dout //输出数据
);
always @(posedge clk) begin //复位信号不要加入到敏感列表中
if(!rst_n) dout <= 1&#39;b0 ; //rstn 信号与时钟 clk 同步
else dout <= din ;
end
endmodule
2. 异步复位:不依赖时钟,立即生效
异步复位
module async_reset(
input rst_n, //异步复位信号
input clk, //时钟
input din, //输入数据
output reg dout //输出数据
);
//复位信号要加到敏感列表中
always @(posedge clk or negedge rst_n) begin
if(!rst_n) dout <= 1&#39;b0 ; //rstn 信号与时钟 clk 异步
else dout <= din ;
end
endmodule
异步复位撤离问题:
recovery time:复位撤离时,复位信号从有效跳变为无效的(由1变为0)时刻与下一个时钟沿之间的时间,类似于同步电路中的setup time。
remove time:复位撤离时,复位信号从有效跳变为无效时与上一个时钟沿之间的时间,类似于同步电路中的hold time。
recovery time和remove time
如图所示,rst_n为0表示复位,clk上升沿触发,rst_n从0到1的上升沿与时钟上升沿必须不小于recovery time才能保证寄存器恢复到正常状态。rst_n保持为0经过clk上升沿后仍需要保持一段时间,才能保证寄存器有效复位,防止亚稳态。
解决办法:异步复位,同步释放
异步复位,同步释放电路
相关代码:
module areset_srelease(
input rst_n, //异步复位信号
input clk, //时钟
input din, //输入数据
output reg dout //输出数据
);
reg rstn_r1, rstn_r2;
always @ (posedge clk or negedge rst_n) begin
if (!rstn) begin
rstn_r1 <= 1&#39;b0; //异步复位
rstn_r2 <= 1&#39;b0;
end
else begin
rstn_r1 <= 1&#39;b1; //同步释放
rstn_r2 <= rstn_r1; //同步打拍,时序差可以多延迟几拍
end
end
//使用 rstn_r2 做同步复位,复位信号可以加到敏感列表中
always @ (posedge clk or negedge rstn_r2) begin
if (!rstn_r2) dout <= 1&#39;b0; //同步复位
else dout <= din;
end
endmodule
异步复位毛刺问题:
当外部输入的异步信号产生毛刺时,任何满足触发器最小复位脉冲宽度的输入都有可能引起触发器复位
解决办法:使用滤毛刺电路
滤毛刺电路 |
|