一个简单的时钟分频器模块
A simple clock divider module
我被要求为不同类型的输入设计简单的时钟分频器电路。
我有一个 enabler [1:0]
输入和一个输入 clock
,以及一个名为 clk_enable
的输出。
如果 enabler=01
那么我的输入时钟应该每 2 个时钟启用一次 signals.If enabler=10
那么我的输入应该除以 4 等等
我设法使用 case 关键字将我的输入时钟划分为不同的情况,但是对于 enabler=00
我的输入时钟应该等于我的输出 clk_enable
我无法做到这一点。
这是我试过的。我正在为 enabler=00
的情况寻求帮助。
module project(input [1:0] enabler,
input clock,
output reg clk_enable);
reg [3:0] count,c;
initial begin
count=4'b0000;
c=4'b0000;
end
always @( posedge clock)
case(enabler)
2'b00:clk_enable<=clock;
2'b01:clk_enable<=~clk_enable;
2'b10:begin
if (count >= 4'b0100-1)
count<=4'b0000;
else begin
count<=count + 4'b0001;
clk_enable<=(count<(4'b0100 / 2));
end
end
2'b11: begin
if (count >= 4'b1000-1)
count<=4'b0000;
else begin
count<=count + 4'b0001;
clk_enable<=(count<(4'b1000 / 2));
end
end
endcase
endmodule
这看起来你有很强的软件开发背景? :)
我的建议是你总是在组合逻辑和顺序逻辑之间划清界线。这包括关于设计的哪些部分实际上必须是顺序的,哪些可以是组合的一些想法。
对于你的情况,时钟分频显然必须是顺序的,因为你想在输入的 CLK 信号的每个上升沿反转生成的 CLK 信号(频率 f/2,情况 0'b01)(频率 f,案例 0'b00)。同样适用于 f/4(案例 0'b10)。
这部分需要是顺序的,因为你想反转之前的 CLK 状态......如果在组合逻辑中实现,这将导致 cmobinational 循环。因此,这里确实需要在 CLK 边沿上触发。
然而,正确的 CLK 输出信号的实际选择可以是组合的。您只想将正确的 CLK 信号分配给输出 CLK。
顺序部分的实现可能如下所示:
// frequency division from input CLK --> frequency: f/2
always @(posedge clk or negedge rst_neg) begin
if (rst_neg = 1'b0) begin
clk_2 <= 1'b0;
end else begin
clk_2 <= ~clk_2;
end
end
// frequency division from first divided CLK --> frequency: f/4
always @(posedge clk_2 or negedge rst_neg) begin
if (rst_neg = 1'b0) begin
clk_ 4 <= 1'b0;
end else begin
clk_4 <= ~clk_4;
end
end
// frequency division from first divided CLK --> frequency: f/8
always @(posedge clk_4 or negedge rst_neg) begin
if (rst_neg = 1'b0) begin
clk_ 8 <= 1'b0;
end else begin
clk_8 <= ~clk_8;
end
end
所以这个简单的时序逻辑负责生成您需要的 f/2 和 f/4 的分频 CLK 信号。我还在下降沿包含了复位信号,这是您通常需要的。并且您保留了计数器逻辑(增量和比较)。
现在我们用简单的组合逻辑来处理正确的选择:
always @(*) begin
case(enabler)
2'b00: clk_enable = clk;
2'b01: clk_enable = clk_2;
2'b10: clk_enable = clk_4;
2'b11: clk_enable = clk_8;
endcase
end
这与您的硬件描述非常接近(clk_enable 需要在此处注册)。
但是,组合部分的另一种方法如下(将 clk_enable 声明为电线):
assign clk_enable = (enabler == 2'b00) ? clk
: (enabler == 2'b01) ? clk_2
: (enabler == 2'b10) ? clk_4
: (enabler == 2'b11) ? clk_8;
这将生成上升速率与 div_ratio 输入相匹配的门控脉冲时钟。
div_ratio 输出
0 div1 时钟(clk 原样)
1 div2(每 2 个 clk 脉冲脉冲一次)
2格3
3 div4
当不需要在分频时钟的负边沿采样时,这通常更可取
如果你需要 50% 的占空比我可以给你另一个片段
module clk_div_gated (
input [1:0] div_ratio,
input clk,
input rst_n, // async reset - a must for clock divider
output clk_div
);
reg [1:0] cnt;
reg clk_en;
always @(posedge clk or negedge rst_n)
if (~rst_n)
cnt <= 2'h0;
else
cnt <= (cnt == div_ratio)? 2'h0 : cnt + 1'b1;
// clk_en toggled at negedge to prevent glitches on output clock
// This is ok for FPGA, synthesizeable ASIC design must use latch + AND method
always @(negedge clk)
clk_en <= (cnt == div_ratio);
assign clk_div <= clk & clk_en;
endmodule
我被要求为不同类型的输入设计简单的时钟分频器电路。
我有一个 enabler [1:0]
输入和一个输入 clock
,以及一个名为 clk_enable
的输出。
如果 enabler=01
那么我的输入时钟应该每 2 个时钟启用一次 signals.If enabler=10
那么我的输入应该除以 4 等等
我设法使用 case 关键字将我的输入时钟划分为不同的情况,但是对于 enabler=00
我的输入时钟应该等于我的输出 clk_enable
我无法做到这一点。
这是我试过的。我正在为 enabler=00
的情况寻求帮助。
module project(input [1:0] enabler,
input clock,
output reg clk_enable);
reg [3:0] count,c;
initial begin
count=4'b0000;
c=4'b0000;
end
always @( posedge clock)
case(enabler)
2'b00:clk_enable<=clock;
2'b01:clk_enable<=~clk_enable;
2'b10:begin
if (count >= 4'b0100-1)
count<=4'b0000;
else begin
count<=count + 4'b0001;
clk_enable<=(count<(4'b0100 / 2));
end
end
2'b11: begin
if (count >= 4'b1000-1)
count<=4'b0000;
else begin
count<=count + 4'b0001;
clk_enable<=(count<(4'b1000 / 2));
end
end
endcase
endmodule
这看起来你有很强的软件开发背景? :)
我的建议是你总是在组合逻辑和顺序逻辑之间划清界线。这包括关于设计的哪些部分实际上必须是顺序的,哪些可以是组合的一些想法。
对于你的情况,时钟分频显然必须是顺序的,因为你想在输入的 CLK 信号的每个上升沿反转生成的 CLK 信号(频率 f/2,情况 0'b01)(频率 f,案例 0'b00)。同样适用于 f/4(案例 0'b10)。 这部分需要是顺序的,因为你想反转之前的 CLK 状态......如果在组合逻辑中实现,这将导致 cmobinational 循环。因此,这里确实需要在 CLK 边沿上触发。 然而,正确的 CLK 输出信号的实际选择可以是组合的。您只想将正确的 CLK 信号分配给输出 CLK。
顺序部分的实现可能如下所示:
// frequency division from input CLK --> frequency: f/2
always @(posedge clk or negedge rst_neg) begin
if (rst_neg = 1'b0) begin
clk_2 <= 1'b0;
end else begin
clk_2 <= ~clk_2;
end
end
// frequency division from first divided CLK --> frequency: f/4
always @(posedge clk_2 or negedge rst_neg) begin
if (rst_neg = 1'b0) begin
clk_ 4 <= 1'b0;
end else begin
clk_4 <= ~clk_4;
end
end
// frequency division from first divided CLK --> frequency: f/8
always @(posedge clk_4 or negedge rst_neg) begin
if (rst_neg = 1'b0) begin
clk_ 8 <= 1'b0;
end else begin
clk_8 <= ~clk_8;
end
end
所以这个简单的时序逻辑负责生成您需要的 f/2 和 f/4 的分频 CLK 信号。我还在下降沿包含了复位信号,这是您通常需要的。并且您保留了计数器逻辑(增量和比较)。
现在我们用简单的组合逻辑来处理正确的选择:
always @(*) begin
case(enabler)
2'b00: clk_enable = clk;
2'b01: clk_enable = clk_2;
2'b10: clk_enable = clk_4;
2'b11: clk_enable = clk_8;
endcase
end
这与您的硬件描述非常接近(clk_enable 需要在此处注册)。
但是,组合部分的另一种方法如下(将 clk_enable 声明为电线):
assign clk_enable = (enabler == 2'b00) ? clk
: (enabler == 2'b01) ? clk_2
: (enabler == 2'b10) ? clk_4
: (enabler == 2'b11) ? clk_8;
这将生成上升速率与 div_ratio 输入相匹配的门控脉冲时钟。 div_ratio 输出 0 div1 时钟(clk 原样) 1 div2(每 2 个 clk 脉冲脉冲一次) 2格3 3 div4
当不需要在分频时钟的负边沿采样时,这通常更可取 如果你需要 50% 的占空比我可以给你另一个片段
module clk_div_gated (
input [1:0] div_ratio,
input clk,
input rst_n, // async reset - a must for clock divider
output clk_div
);
reg [1:0] cnt;
reg clk_en;
always @(posedge clk or negedge rst_n)
if (~rst_n)
cnt <= 2'h0;
else
cnt <= (cnt == div_ratio)? 2'h0 : cnt + 1'b1;
// clk_en toggled at negedge to prevent glitches on output clock
// This is ok for FPGA, synthesizeable ASIC design must use latch + AND method
always @(negedge clk)
clk_en <= (cnt == div_ratio);
assign clk_div <= clk & clk_en;
endmodule