最近は FPGA を弄ってていろいろしてみてるわけですが、
いろいろハマったので反省点をまとめ。
マルチクロックなんて二度とやらない
メインクロック 50MHz があって、ここから分周して 1MHz のクロックがあるわけです。
reg [7:0] clk_cnt; wire low_clk; assign low_clk = ( clk_cnt < 25 ); always @ ( posedge CLK, negedge RST_X ) begin if( ~RST_X ) begin clk_cnt <= 8'd0; end else begin if( clk_cnt >= 8'd49 ) begin clk_cnt <= 8'd0; end else begin clk_cnt <= clk_cnt + 8'd1; end end end
で、遅い方のクロックで外部の素子を駆動するために
always @ ( posedge low_clk, negedge RST_X ) begin if( ~RST_X ) begin // : snip end else begin // : snip end end
こうやって low_clk を FF の CLK として供給したら、
中身に何もない if 文(本来何の意味もない)の有無でタイミングが変わったり
いろいろとよくわからない怪しい現象に悩まされました。
ちょっと面倒だけども同期微分を使って立ち上がり検出をする…
以下のようにするとナイス。
reg b4clk; wire pedge; assign pedge = ( ~b4clk && low_clk ); always @ ( posedge CLK, negedge RST_X ) begin if( ~RST_X ) begin b4clk <= 1'b0; end else begin b4clk <= low_clk; end end always @ ( posedge CLK, negedge RST_X ) begin if( ~RST_X ) begin // : snip end else if( pedge ) begin // : snip end end
ちょっと面倒なんだよねーと思ってマルチクロックの回路にしたのが
決定的に裏目に出たパターン。もう二度としません。
できる限り同期回路で設計
「1clk余分にかかるの無駄だよね!」と思って非同期SRAMを使ってみました。
うん、おかげでえらい目にあったよ。
1clk の浪費で確実に動くならその方がいいよね…
「タイミングチャート見ればOKOK」そう思っていた時期が私にもありました。
ACスペックはきちんと確認しよう
FF のサンプリングの都合などで、tsuやtcoなどが決まってるので、
きちんとそれを満たすようにタイミングの設計をする必要があります。
たとえば相手の素子が「クロックの立ち上がりで読み込む」ならば、
こっちは「クロックの立ち下がりで状態を遷移させる」ように。
相手が「立ち上がり」で読むのにこっちも「立ち上がり」でバスのレベルが変わると
「どっち!?」ってなってしまいます...