2017-06-07 6 views
1

VerilogとHDLを初めて使用しています。
クロッククロック(正と負)をカウントし、入力clkの最初の立ち上がりエッジからカウント機構を開始するN分周器
を実装したいと思います。
さらに、clk分周器は同期rst_nをサポートしなければなりません。fsmを使用してfrequecny dividerのラッチを避ける - Verilog

私はCNTレジスタに使用ラッチについての警告を取得し、アルテラのQuartusし、次のコードの合成後

module clk_divider_fsm 
 
(
 
\t in_clk, 
 
\t rst_n, 
 
\t 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 
 
\t ps = S0; 
 
\t ns = S0; 
 
\t cnt = CNT_RESET; 
 
\t out_change = 1'b0; 
 
\t out = 1'b0; 
 
end 
 

 
always @ (in_clk) 
 
begin 
 
\t if(!rst_n) 
 
\t \t ps = S0; 
 
\t else 
 
\t \t ps = ns; 
 
// \t begin 
 
// \t \t if(ns != ps) 
 
// \t \t \t ps = ns; 
 
// \t end 
 
end 
 

 
always @ (in_clk) 
 
begin 
 
\t case(ps) 
 
\t \t S0: begin 
 
\t \t \t if(in_clk === 1'b1) 
 
\t \t \t begin 
 
\t \t \t \t out_change <= 1'b1; 
 
\t \t \t \t ns <= S1; 
 
\t \t \t \t cnt <= CNT_RESET + 1'b1; 
 
\t \t \t end 
 
\t \t \t else 
 
\t \t \t begin 
 
\t \t \t \t out_change <= 1'b0; 
 
\t \t \t \t cnt <= CNT_RESET; 
 
\t \t \t \t ns <= S0; 
 
\t \t \t end 
 
\t \t end 
 
\t \t S1: begin 
 
\t \t \t if(in_clk === 1'b0) 
 
\t \t \t begin 
 
\t \t \t \t if(cnt == prescaler) 
 
\t \t \t \t begin 
 
\t \t \t \t \t cnt <= CNT_RESET + 1'b1; 
 
\t \t \t \t \t out_change <= 1'b1; 
 
\t \t \t \t \t ns <= S2; 
 
\t \t \t \t end 
 
\t \t \t \t else 
 
\t \t \t \t begin 
 
\t \t \t \t \t cnt <= cnt + 1'b1; 
 
\t \t \t \t \t out_change <= 1'b0; 
 
\t \t \t \t \t ns <= S2; 
 
\t \t \t \t end 
 
\t \t \t end 
 
\t \t \t else 
 
\t \t \t begin 
 
\t \t \t \t out_change = 1'b0; 
 
\t \t \t \t ns = S1; 
 
\t \t \t \t cnt <= cnt; 
 
\t \t \t end 
 
\t \t end 
 
\t \t 
 
\t \t S2: begin 
 
\t \t \t if(in_clk == 1'b1) 
 
\t \t \t begin 
 
\t \t \t \t if(cnt == prescaler) 
 
\t \t \t \t begin 
 
\t \t \t \t \t cnt <= CNT_RESET + 1'b1; 
 
\t \t \t \t \t out_change <= 1'b1; 
 
\t \t \t \t \t ns <= S1; 
 
\t \t \t \t end 
 
\t \t \t \t else 
 
\t \t \t \t begin 
 
\t \t \t \t \t cnt <= cnt + 1'b1; 
 
\t \t \t \t \t out_change <= 1'b0; 
 
\t \t \t \t \t ns <= S1; 
 
\t \t \t \t end 
 
\t \t \t end 
 
\t \t \t else 
 
\t \t \t begin 
 
\t \t \t \t out_change = 1'b0; 
 
\t \t \t \t ns = S2; 
 
\t \t \t \t cnt <= cnt; 
 
\t \t \t end 
 
\t \t end 
 
\t \t default: begin 
 
\t \t \t out_change <= 1'b0; 
 
\t \t \t cnt <= CNT_RESET; 
 
\t \t \t ns <= S0; 
 
\t \t end 
 
\t endcase 
 
\t 
 
\t if(!rst_n) 
 
\t begin 
 
\t \t ns <= S0; 
 
\t \t cnt <= CNT_RESET; 
 
\t end 
 
end 
 

 
always @ (posedge out_change or negedge rst_n) 
 
begin 
 
\t if(!rst_n) 
 
\t \t out <= 1'b0; 
 
\t else 
 
\t \t out <= ~out; 
 
end 
 

 

 
assign out_clk = (prescaler == 1) ? (in_clk & rst_n) : out; 
 

 
endmodule

を使用しています。
何が間違っていますか?

このようなケースを避けるための良い練習のヒントや、これらの種類のRTLを実装するより洗練された方法を教えてもらえますか?

おかげ

答えて

1

あなたが同期したい場合は、あなたがそれを行うことはできません。あなたはin_clkの同じposedgeの値を変更する必要があります。 しかし、一般的には、クロックを分周するのにPLL/DCMを使用します。スペシャルバッファを使用したFPGAの特別なルーティングに従います。

[編集]

always @ (in_clk) 

これはラッチを合成します。ラッチを必要としない(そして同期している)場合は、クロックのと同じposedgeですべてのプロセス(常に@)をトリガする必要があります。 IN_CLKの同じposedgeとあなたのケースでは:

always @ (posedge in_clk) 

Synthesizing Latches

+0

を参照してくださいあなたの答えをありがとうございました。私は学習目的のための簡単なクロック分周器を実装しようとしています。上記のデザインを使用しているラッチはなぜですか? – vintox

+0

完全に同期していないため、ラッチがあります。 – FabienM

+0

ラッチはoutレジスタとout_changeレジスタではなくcntレジスタに使用されます。なぜout_changeメカニズムがステートマシンカウンタに影響を与えているのですか? – vintox

関連する問題