我是Verilog和HDL的新手。
我想实现n频分隔线,
哪个计数时钟滴答(pos and neg(,然后从输入库的第一个上升边缘开始计数机制。
另外,clk分隔器必须支持同步rst_n。
我正在使用Altera Quartus和以下代码
module clk_divider_fsm
(
in_clk,
rst_n,
out_clk
);
input in_clk, rst_n;
output out_clk;
parameter prescaler = 10;
parameter BIT_DEPTH = `CLOG2(prescaler);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10;
parameter CNT_RESET = {BIT_DEPTH{1'b0}};
//parameter CNT_FIRST = {BIT_DEPTH-1{1'b0}, 1'b1};
reg [1:0] ps, ns;
reg out_change;
reg out;
reg [BIT_DEPTH:0] cnt;
initial
begin
ps = S0;
ns = S0;
cnt = CNT_RESET;
out_change = 1'b0;
out = 1'b0;
end
always @ (in_clk)
begin
if(!rst_n)
ps = S0;
else
ps = ns;
// begin
// if(ns != ps)
// ps = ns;
// end
end
always @ (in_clk)
begin
case(ps)
S0: begin
if(in_clk === 1'b1)
begin
out_change <= 1'b1;
ns <= S1;
cnt <= CNT_RESET + 1'b1;
end
else
begin
out_change <= 1'b0;
cnt <= CNT_RESET;
ns <= S0;
end
end
S1: begin
if(in_clk === 1'b0)
begin
if(cnt == prescaler)
begin
cnt <= CNT_RESET + 1'b1;
out_change <= 1'b1;
ns <= S2;
end
else
begin
cnt <= cnt + 1'b1;
out_change <= 1'b0;
ns <= S2;
end
end
else
begin
out_change = 1'b0;
ns = S1;
cnt <= cnt;
end
end
S2: begin
if(in_clk == 1'b1)
begin
if(cnt == prescaler)
begin
cnt <= CNT_RESET + 1'b1;
out_change <= 1'b1;
ns <= S1;
end
else
begin
cnt <= cnt + 1'b1;
out_change <= 1'b0;
ns <= S1;
end
end
else
begin
out_change = 1'b0;
ns = S2;
cnt <= cnt;
end
end
default: begin
out_change <= 1'b0;
cnt <= CNT_RESET;
ns <= S0;
end
endcase
if(!rst_n)
begin
ns <= S0;
cnt <= CNT_RESET;
end
end
always @ (posedge out_change or negedge rst_n)
begin
if(!rst_n)
out <= 1'b0;
else
out <= ~out;
end
assign out_clk = (prescaler == 1) ? (in_clk & rst_n) : out;
endmodule
合成后,我会收到有关用于CNT登记的闩锁的警告。
我究竟做错了什么?
您能否通过良好的练习技巧来指导我以后避免这种情况或更优雅的方法来实施这种RTL?
谢谢
always @ (in_clk)
...
always @ (posedge out_change or negedge rst_n)
如果您想同步,就无法做到这一点。您必须在IN_CLK的同一posedge上更改值。但是通常,我们使用PLL/DCM分割时钟。时钟使用特价缓冲区在FPGA中的特殊路由。
[编辑]
always @ (in_clk)
这将合成闩锁。如果您不希望闩锁(和同步(,则必须使用时钟的相同 posedge 触发所有过程(始终@(。在您的情况下,IN_CLK相同的姿势:
always @ (posedge in_clk)
请参阅合成闩锁