• ベストアンサー

verilog HDL のレジスタ記述について

こんにちは verilog初心者です。論理合成をしていて気になる点があったので質問させていただきました。 二つのクロックの立ち上がりで書き込むレジスタを記述していて、 (全て1bit、clkはクロック) always @(posedge clk1 or posedge clk2) begin q <= d; end としたところ、シミュレーションはできますが論理合成はできませんでした。 自分の持っている参考書に「複数の書き込み信号があるレジスタはない」という記述があったので一応納得しました。 ところが、 always @(posedge clk1 or posedge clk2) begin if (clk1==1) q <= d; else if (clk2==1) q <= d; end と記述すると論理合成できてしまいます。 両者の書き込み信号に対する振る舞いは同じように思うのですが、一体何が違うのでしょうか。 わかる方いましたら是非ご教示下さい。よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • monova
  • ベストアンサー率68% (68/100)
回答No.1

コンパイラや仕向けのLSIによって解釈が異なる場合もありますが… > always @(posedge clk1 or posedge clk2) begin は、clk1,clk2 に対して同時に立ち上がりが来た場合、 出力が不定になる為、普通はエラーを返してくる筈です。 FPGAに入っているFFのセルは1入力のクロック端子しか 持っていないものが多いからです。 (FFをゲートで作る場合は話が変わってきますが…) >always @(posedge clk1 or posedge clk2) begin >if (clk1==1) >q <= d; >else if (clk2==1) >q <= d; >end この場合、コンパイラに寄って、若干解釈が異なってくる場合が 有ります。 always @(posedge clk1 or posedge clk2) begin この表記だけでエラーを返すものありますが、 今回の場合、if 文以下で強引に定義付けを行っていると 思われます。 if文に else が無いようなので、clk1 = 1,clk2 = 1 の時は 不定とせず、出力変化なし と解釈しているのでは無いでしょうか? 余談ですが、 always @(posedge clk1 or posedge clk2) begin if (clk1==1) q <= d; else if (clk2==1) q <= d; end という、表記は極力避けた方が良い思います。 クロックのエッジで、FFを動作させ、 且つ、レベルで出力を決定させる様な回路は、 フィッティングレベルで配線を複雑化させてしまう 可能性があります。 また、if 文 を使用する場合、else を記述した方が バグを発生させる可能性が小さくなると思います。

ppiiko
質問者

補足

>clk1,clk2 に対して同時に立ち上がりが来た場合、出力が不定になる為、普通はエラーを返してくる筈です。 なるほど、よく分かりました。 if文であれば、同時にクロックが立ち上がっても最初に定義されたclk1のほうが優先されエラーが出ないということですね。 >レベルで出力を決定させる様な回路は、フィッティングレベルで配線を複雑化させてしまう可能性があります。 とはどのようなことでしょうか。またどのような記述にすると良いでしょうか。よろしければもう少し詳しく教えていただけると幸いです。 else文は必ず記述するようにします。

その他の回答 (4)

  • syakoten
  • ベストアンサー率44% (4/9)
回答No.5

こんにちは。 質問を拝見いたしましたが、2クロックで動作するFFが、DCのライブラリにないのでしょう。 私も、そのようなFFは見たことがありません。 (2CLKで動くFFってあるんですか?どこのベンダのライブラリです?逆にちょっと知りたいです。) 普通は、 always @(posedge clk1 or negedge rst) begin とかですよ。 気をつけなければならないのは、Verilogでは構文エラーではないものも、DCでははじかれる(そのような回路が存在しない、合成できない)ということがあるので、気をつけてください。 DCの合成レポートは非常に大切です。

ppiiko
質問者

お礼

ご指摘ありがとうございます。合成レポートは十分にチェックするようにします。

  • txdata
  • ベストアンサー率0% (0/1)
回答No.4

こんにちは。 always文の定義からするとシミュレーションはどちらでもできます。 但し論理合成を前提にする場合はかなり制約を受けます。 それは同期式回路設計を前提にLSIの論理セルや論理合成ツールが設計されていることが多いためです。 同期式設計でクロックを2系用意するのはおすすめしませんが、 あえて記述すると次のように記述するといいでしょう。 always @(posedge clk1) begin  q1 <= d; end always @(posedge clk2) begin  q2 <= d; end assign q = q1 | q2; FPGA用などフリーの合成ツールの論理合成では、 always @( a 0r b )内の  第一項a クロック → posedge clk  立ち上がりエッジラッチ  第二項b リセット → posedge rst  省略時はリセットなし になることが殆どです。これはFPGAの内部単位セル(Logic Element)がクロック1系統、非同期リセット1系統のマルチプレクサデータ入力付きエッジラッチとしてあらかじめ組み込まれているためです。 第一項aのposedgeをなくすとレベルラッチになるはずですが、どうマッピング(配線)されるか分りません。なお二項目bは、posedgeをつけても非同期リセット線にマッピングされます。 通常はリセットをつないで初期化することが多いので、 次の形式を基本にするとたいてい論理合成できます。 always @( posedge clk or posedge rst ) begin  if( rst ) q <= 0;       q <= d; end 以上から同期式回路設計の場合 clk1,clk2より倍速以上のクロックclkをシステムクロックとして用意しリセットrstも追加して次のように記述します。 assign clkor = clk1 | clk2; always @( posedge clk or posedge rst ) begin  if ( rst ) q <= 0;  else if ( clkor ) q <= d; end この記述は確実に合成できて動作します。 質問で合成できた後半の式も似ていますね。ですがclk1かclk2のどちらかがdとANDをとって非同期リセットラインにマッピングされる可能性があり正しく動作しないかもしれません。

ppiiko
質問者

お礼

わかりやすい解説ありがとうございます。とても参考になりました。

  • monova
  • ベストアンサー率68% (68/100)
回答No.3

No.1 です。 補足…と、いいますか私の思いこみで、 always @(posedge clk1 or posedge clk2) begin を、非同期クリアDFFとしての使用を前提に答えてしまいました。 申し訳ありません。 clk1 、もしくは、clk2 を同期クリア or ロードとして使うのなら この表記はありだと思います。 例 (clk2 で同期クリア) output q; reg q; always @(posedge clk1 or posedge clk2) begin if(clk2) q<=0; else q<=d; end と、なります。 今回の様に、clk1,clk2 の両方で d(入力) のラッチを試みる場合 先に、clk1 と clk2 の OR をとってしまうのが素直な流れでは ないでしょうか? assign clk = clk1 | clk2; always @(posedge clk) begin if(clk1) q<=d; end しかし、基本的にはクロックラインに 論理ゲートを通す事は トラブルの元になるので避けた方が良いとは思います。 (例外もありますが) 今回は、最終的にどの様に動作させたいのか私には解らないので clk1 と clk2 の OR でラッチして良いのかハッキリと答えられません。 シミュレーションで動作の違いを見たいだけなら OR を 通してみるのも有りだと思います。 >レベルで出力を決定させる様な回路は、フィッティングレベルで配線を複雑化させてしまう可能性があります。 これは、実務上の話なので、シミュレーションしかしないのであれば あまりに気にしなくもてよいです。 参考までに… フィッティングとは、verilog記述した回路を実際のFPGAなりLSIに配線を行う データを作成する事を言います。 (ツールや会社によって言い方が異なるかもしれませんが…) verilog で回路を書くという事は、最終的には何らかのハードウェアに書き込む 訳ですよね。 その際、不必要に配線を長くしたり、セルを消費する様な回路は 出来るだけ避けておきたいのです。 (回路が煩雑になっても必要な回路は当然あります) この辺りは、言語記述を回路図に置き換えてみると、回路が煩雑になりそうか 推察できます。

ppiiko
質問者

お礼

今回は全く別の動作をする回路を記述していたのですが、途中で今回質問したものと似たような動作をする回路で躓いてしまい、その部分を抽出して質問させていただきました。 疑問を解決させていただいただけでなく、設計上の注意点等も教えていただけてとても感謝しています。ありがとうございました。

  • ss__s
  • ベストアンサー率0% (0/1)
回答No.2

どのようなプリミティブがライブラリにあるか(FPGA or LSIなど)によっても異なるとは思いますが、 非同期セットリセットのFFが推定されているのではないでしょうか。 論理合成された回路を確認するのが一番と思いますが、このような回路になっているのではないでしょうか。 assign clk = 0; assign ar = (clk1 && !d) || ((clk2 && !d) && !clk1) assign as = (clk1 && d) || ((clk2 && d) && !clk1); always @ ( posedge clk or posedge ar or posedge as ) begin if ( ar ) begin q = 0; end else if ( as ) begin q = 1; end else begin q = d; end end

ppiiko
質問者

お礼

自分は学生であり、企業のライブラリを使用させていただいて論理合成しているので、合成後のファイルを見ても確認することができない状況です。 今度フリーの論理合成ソフトを探してやってみようと思います。 ありがとうございました。

関連するQ&A

  • Verilog-HDLのFF記述について

    先程アップしたのは、図が変になってしまいました。 改めて質問します。 1つのFF(非同期リセット)をVerilog-HDLで記述すると、以下のように記述出来ますよね? always @ ( posedge CLK or negedge RESET ) begin if ( !RESET ) begin Q <= 1'b0 ; xQ <= 1'b1 ; end else begin Q <= D ; xQ <= ~D ; end end この1つのFFをalways文を2つ使って記述出来るんですか? ご回答宜しくお願いします。

  • Verilog HDLについて質問

    以下のプログラムを入力し、試してもうまくいきません。どこがいけないのでしょうか。 しようとおもっていることを大まかにいうと、 ・x1の立ち上がりに、money1に1を足す ・x2の立ち上がりに、money2に2を足す ・クロックの立ち上がりに、sumにmoney1とmoney2を足したものを入れて、 sumが3だったら、z1に割り当てたLEDを光らせる sumが4だったら、z2に割り当てたLEDを光らせる というものです。 試してみると結果はz1,z2両方のLEDが、x1,x2を立ち上げなくても最初から光ってしまいます。 module vendmachine(x1,x2,z1,z2,clk); input x1,x2,clk; output z1,z2; reg [2:0] money1; reg [2:0] money2; reg [2:0] sum; reg ledz1,ledz2; always@(posedge x1) begin money1=money1+3'd1; end always@(posedge x2) begin    money2=money2+3'd2; end always@(posedge clk) begin sum=money1+money2; if(sum==3'd3)begin ledz1=1'b1; end if(sum==3'd4)begin ledz1=1'b1; ledz2=1'b1; end end assign z1=ledz1; assign z2=ledz2; endmodule

  • verilogでの記述、always@の使い方

    verilogでの記述の仕方について質問です。 画像のようなタイミングチャートを考えています。 clkとplsは入力、dataが出力です。 構成は、  pls↑の次のclk↑で、dataをアサートする。 というのを考えています。 pls↑やclk↑は、posedgeを使えばよいと思うのですが、 私の考え通りに記述すると always @(posedge pls)begin @(posedge clk)begin data <= 1; end end こんな感じになるのか?となってしまいます。 @()begin end の中に@()beginを記述することが出来るのか というところから疑問です。 出来たとしても、これが私が意図したとおりに動作するのかがよくわかりません。 ネットで、 always @() @() と記述すると順序回路ができるとあったのですが、いまいち動作が分かりません。 どなたか、動作を教えていただけないでしょうか。 また、pls↑の次のclk↑で、dataをアサートする方法を教えていただけないでしょうか。 よろしくお願い致します。

  • verilogである信号の数クロック遅れの信号を生成させる記述方法をお

    verilogである信号の数クロック遅れの信号を生成させる記述方法をお伺いします。 動作記述でOKです。 通常、「sig_a」 から2クロック遅れの「sig_b」を生成させるのなら: > sig_a - 2clockおくれ -> sig_b ----------------------------------- reg [2:0] regs; assign sig_b = regs[2]; asisgn regs[0] = sig_a; always @(posedge CLK) regs[2:0] <= {regs[1:0], sig_a}; ----------------------------------- のように、パイプラインに信号を通すことで実現できるですが、 何クロック遅れるかを可変(動的に設定する)としたいのです。 動作モデル的な記述で簡単にかけないのでしょうか? ------------------------------------ [NGの例]: これだとNcycle_delayがSIM途中で更新されたとき、反映できない。。。 initial begin  sig_b <= #D 1'b0;   while(1) begin   repeat(Ncycyle_delay) @(posedge CLK);    while(1) begin     sig_b <= sig_a;     repeat(1) @(posedge CLK);    end   end end ------------------------------------ 宜しくお願い致します。

  • verilog HDLについての質問

    verilogで以下のようなコードだと、エラーが起こります。 何故起こるのか、対処法はどのようにすればよいか教えてください。 //-----ソースコード---------------------------- modele Test(CLK1,CLK2,PG1); input CLK1; input CLK2; output PG1; reg dmy; always @(posedge CLK) begin dmy = 1; end always @(posedge CS) begin dmy = 0; end assign PG1 = dmy; //-----エラー内容------------------------------- Only one always block may assign a given variable dmy //-----以上---------------------------------------- regは複数のalwaysで変化させることはできませんということでしょうが、なぜでしょうか。

  • Verilog記述方法に関して

    以下のVerilog記述についてどの様な記述が一般的か教えてほしい のですが? QuartusIIにて合成を行っているのですが、 「Can't resolve multiple constant drive for net ****」の エラーメッセージが発生します。 記述は以下の様なもので、別々のクロックでalways内から同じ変数 に代入しています。これが問題の様ですが、これを回避するための 一般的な処理方法はどの様にすればよいのでしょうか? Verilog初心者で、この様な処理自体がナンセンスなのかもしれません が、どなたか分かる方御願い致します。 【抜粋のため分かり難いですが記述内容は以下の様なもの】 always@(posedge clkB) begin : ClrV<= 1'b1; : end always@(posedge clkA) begin : if(ClrV) ClrV<= 1'b0; : end 以上

  • 2ビットのレジスタのVerilog HDL記述

    QuatusIIで2ビットのレジスタをつくっているのですが、ブロック図をコンパイルするときにエラーがでてしまいます。 エラー内容をみるとVerilog HDL記述が間違えているみたいなのですが、どこが間違えているか教えてください。 /* REG2 */ module REG2module ( EN, CLR_B, IN1, IN2, CLK, Q ); input CLR_B, CLK; input IN1, IN2; output [1:0] Q; output EN; assign EN=FUNC_EN (IN1, IN2); function FUNC_EN; input IN1,IN2; if (IN1>0|IN2>0) FUNC_EN=1; else FUNC_EN=0; endfunction wire [1:0] D; CONECT (IN1,D[0]); CONECT (IN2,D[1]); reg [1:0] Q; always @( posedge CLK or negedge CLR_B ) if( !CLR_B ) Q <= 0; else if(EN) Q <= D; endmodule エラーにはError: Node instance "comb_8" instantiates undefined entity "CONECT" Error: Node instance "comb_9" instantiates undefined entity "CONECT" と出ています。意味を調べたのですが、CONECTが定義されていない?という事は具体的にどうすればいいでしょうか。 CONECT (IN1,D[0]); CONECT (IN2,D[1]); の部分が間違っているのはなんとなくわかるのですが、どうしたらいいかわかりません。 よろしくお願いします

  • Verilog HDL で 74165 相当の機能

    Verilog HDL で非同期のパラレル入力をシフトレジスタで取り出したいので、SN74165 相当の機能を次の式のように考えました。 always @(negedge clk or load or indt) begin if (load) begin sftdt <= indt; end else if (!load) begin sftdt <= {sftdt[6:0], 1'b0}; end end SILOS でシュミレートしたところ、思ったように動作しましたが、 Quatus IIでは、次のエラーが出てしまいます。 single- and double-edge expressions are not supported 良い方法は無いでしょうか。

  • Verilogの文法

    Verilogの文法について、教えてください。 下のリストのように、if文をネストして2つのカウンタを作っています。 reg1が特定の値になったらreg2をカウントアップするという動作です。 ここで、リスト真ん中当たりの、reg2がカウントアップされるところで、 ネストしたif文(※1の箇所)のelseを入れると、そのif文の上(※2)が 実行されません。 Verilogの場合、elseは直前のif文に対応するはずなので、 影響してしまう理由が分かりません。 どなたか教えてください。 reg [9:0] reg1; // 水平レジスタ reg [9:0] reg2; // 垂直レジスタ always @(posedge clk25m or negedge rst_n) begin if(rst_n == 1'b0) begin // リセット reg1 <= 10'h000; reg2 <= 10'h000; end else if(clk25m == 1'b1) begin if(10'd800 < reg1) begin reg1 <= 10'h000; reg2 <= reg2 + 10'h001; // ※2 if(10'd600 < reg2) // ※1 reg2 <= 10'h000; // else // reg2 <= reg2; // コメントアウトしないと reg2 <= reg2 + 10'h001;(※2)が実行されない   end else reg1 <= reg1 + 10'h001; end else reg1 <= reg1; end

  • Verilog-HDLによる設計において

    現在Z8085のCPUを設計しており、テンポラリレジスタにラッチする部分でなかなか上手くいきませんので質問させていただきます。 always文を使用したステートマシンにより制御しようとしているのですが次のようなWarningが出ます。 Warning: Latch IR[0]$latch has unsafe behavior Warning: Latch IR[1]$latch has unsafe behavior            : Warning: Latch IR[7]$latch has unsafe behavior Warning: Latch TMP1[0]$latch has unsafe behavior Warning: Latch TMP1[1]$latch has unsafe behavior            : Warning: Latch TMP1[7]$latch has unsafe behavior Warning: Latch TMP2[0]$latch has unsafe behavior Warning: Latch TMP2[1]$latch has unsafe behavior            : Warning: Latch TMP2[7]$latch has unsafe behavior Warning: Latch NEXT_STATE[0]$latch has unsafe behavior Warning: Latch NEXT_STATE[1]$latch has unsafe behavior <ソース> module CPU_TMP( CLK, nRST, FROM_DCD, IR, TMP1, TMP2, STATE, NEXT_STATE ); input CLK;//クロック input nRST;//リセット input [7:0] FROM_DCD;//入力命令 output [7:0] IR;//命令レジスタ output [7:0] TMP1;//テンポラリレジスタ1 output [7:0] TMP2;//テンポラリレジスタ2 output [1:0] STATE;//現在のステート output [1:0] NEXT_STATE;//次のステート reg [7:0] IR; reg [7:0] TMP1; reg [7:0] TMP2; reg [1:0] STATE; reg [1:0] NEXT_STATE; //状態 parameter S0 = 2'b00; parameter S1 = 2'b01; parameter S2 = 2'b10; parameter SD = 2'b11; //命令 parameter INRA = 8'h11; parameter MVIA = 8'h22; parameter JMP = 8'h33; always @( posedge CLK ) begin     if( nRST == 0 )       STATE <= SD;     else       STATE <= NEXT_STATE; end always @( STATE ) begin    case( STATE )      SD : begin            IR <= 0;            TMP1 <= 0;            TMP2 <= 0;            NEXT_STATE <= S0;          end      S0 : begin            IR <= FROM_DCD;            case( FROM_DCD )              INRA : NEXT_STATE <= S0;              MVIA : NEXT_STATE <= S1;              JMP : NEXT_STATE <= S2;            endcase          end      S1 : begin              TMP1 <= FROM_DCD;              NEXT_STATE <= S0;          end      S2 : begin              TMP2 <= FROM_DCD;              NEXT_STATE <= S0;          end endcase end endmodule どのようにしたらこのWarningを消すことができるでしょうか。

専門家に質問してみよう