网上下载的一个三分频电路说明
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
always@( negedge resetn or posedge clk or negedge clk) begin
if (resetn==1'b0)
begin
counter[2:0]<=3'd0;
out_clk<=1'b0;
end
else
begin
if (counter[2:0]==3'd5)
begin
counter[2:0]<=3'd0;
end
else
beign
counter[2:0]<= counter[2:0]+1;
end
////////////////////////////////////////////////////
if (counter[2:0]==3'd5 || counter[2:0]==3'd2)
begin
out_clk<=~out_clk;
end
end
end
其仿真结果是正确的
这个逻辑无法综合。存在半导体工艺问题。
2.下面给出一个逻辑图。
逻辑是用器件画出来的,保证不存在物理上的实现问题。
仿真图如下:
也许有人要问,既然仿真都是对的,那么为什么要说实际中是80%工作呢?
看到波形图上的clk1(黄色)上的那些毛刺了么,毛刺并不可怕,但是这个电路工作的基础却是那些毛刺,准确地说,那些毛刺是必须有的,是工作过程的比不可少的部份。这样的电路是否能正常工作就很让人匪夷所思了。
我们能不能让电路的正常功能不依赖于毛刺呢?
小结一下:
以上的思路都是试图在输入的clk上做改造,试图在恰当的地
方取正沿,恰当的地方取反沿。但是要知道,这一定会导致竞争和冒险。虽然逻辑上是可性的,但是实践中却没有那么简单。这个时候,我们需要调整一下思路了:
能不能营造一个安全的时机来切换时钟沿的选择?显然,这需要在切换时钟沿时,强制时钟输出固定电平,当切换完成后,在取消这个强制条件。对么?我们来试试看。
3. 看看以下的代码,也是一段有趣的东西。
always@(negedge resetn or posedge clk)
begin
if (resetn==1'b0)
begin
cnt1[1:0]<=2'd0;
end
else
begin
if(cnt1[1:0]==2'd2)
begin
cnt1[1:0]<=2'd0;
end
else
begin
cnt1[1:0]<=cnt1[1:0]+1;
end
end
end
always@(negedge resetn or negedge clk)
begin
if (resetn==1'b0)
begin
cnt2[1:0]<=2'd0;
end
else
begin
if(cnt2[1:0]==2'd2)
begin
cnt2[1:0]<=2'd0;
end
else
begin
cnt2[1:0]<=cnt2[1:0]+1;
end
end
end
always@*
begin
if (cnt1[1:0]==2'd2 || cnt2[1:0]==2'd0)
begin
clk1 = 1'b0;
end
else if (cnt1[1:0]==1'b1)
begin
clk1 = ~clk;
end
else
begin
clk1 = clk;
end
end
always@(negedge resetn or posedge clk1)
begin
if (resetn==1'b0)
begin
clk_out<=1'b0;
end
else
begin
clk_out<=~clk_out;
end
end
最后用的时钟clk1是clk和clk的反,但是在切换之间加上的强制为0的逻辑。
这段代码肯定是可综合的,而且简单的约束一下时序就可以生产。
但重要的是看了这段逻辑后我们突然明白了一件事情:要想长生质量好的3分频时钟,我们似乎必须要用到clk的下降沿来做点控制逻辑,这是被反复求证后逼出来的(不知道其它人是否有同感)。那么我们为什么不愿意用下降沿触发的的寄存器呢?因为有些库里可能没有这样的器件,而必须在时钟树上上加反向。如果有下降沿的寄存器,那么今后的扫瞄链又要多一些麻烦,虽然这些麻烦都可以客服,但是作为一个成熟的工程师要明白:尽量不要给自己找麻烦。在工程上,最平常的东西最可靠。
4. 到这里我们的命题似乎解决了,但是我们的思考还不应该停止。既然我们要用clk的下降沿,呢就完全可以打破以前的思路,来看看这个新的手段能给我们带来什么。
always@(negedge resetn or posedge clk)
begin
if (resetn==1'b0)
begin
cnt1[1:0]<=2'd0;
clk1<=1'b0;
end
else
begin
if(cnt1[1:0]==2'd2)
begin
cnt1[1:0]<=2'd0;
clk1<=1'b1;
end
else
begin