これは少々意地の悪い課題であった。テキスト通りに組めば以下のようになろう。
module JKFF (J, K, CLK, Q, QB); input J, K, CLK; output Q, QB; wire A, B, C, D, E, F; assign A = ~(QB & J & CLK); assign B = ~(Q & K & CLK); assign C = ~(A & D); assign D = ~(B & C); assign E = ~(A & C); assign F = ~(B & D); assign Q = ~(E & QB); assign QB = ~(F & Q); endmodule |
しかし、これをそのままシミュレートしても X しか出力されないはずである。X は不定値であり、0 か 1 か分からない値である。電源をオンにしたとき、フリップフロップが記憶している値は 0 かもしれないし 1 かもしれない。どちらかではあるが、どちらかは定まらない。このような状態をシミュレータは不定値 X で表す。よくJKフリップフロップの回路構成を検討すれば、初期値が0であっても 1であっても最終的に正常動作をするようにできていることが分かる。しかし、不定値 を 0でも 1でもなくX で表現するシミュレータでは、この仕組みを再現できない。
論理合成の項でも説明したが、RTLレベルの verilog-HDL は実際の回路構成をそのまま記述する言語ではなくではなく、もっと高位な記述を実現する言語である。verilog-HDL はフリップフロップをreg型変数という一種のブラックボックスとして記述することができ、また回路設計者がその記述を利用することを想定している。verilog-HDL においてはフリップフロップの内部構成を記述することまでは想定していない。もちろんフリップフロップの内部構成を記述できる言語、シミュレートできるシミュレータは存在する。ただ、それは verilog-XDL や GPL Cver ではない。(GPL Cver でも強引に初期値を与えることでシミュレートすることは可能である。ただそれはやはり本来の使い方ではない。)
参考までに、verilog-HDL での JKフリップフロップの記述法を紹介する。フリップフロップは reg型変数と always文 を用いて記述できる。変数を reg型であると宣言することにより、その変数はフリップフロップになりえる。(reg型変数は他の用途もあり、必ずフリップフロップになるわけではない) always@(posedge CLK) 文の中はクロックの立ち上がり時のみに実行される。(この記述はフリップフロップを作成するための決まり文句である。)always 文の中について、詳細な文法説明は省くが、C言語ライクな記述がされており、中括弧 {} の代わりにbegin, end を用いることと、代入演算子に = ではなく <= を用いることを知っていれば、大体読めるだろう。このように verilog-HDL では、その内部構成を記述できない代わりに、フリップフロップの機能を記述する方法を用意している。
module JKFF (J, K, CLK, Q, QB); input J, K, CLK; output Q, QB; reg Q; // reg型変数宣言 assign QB = ~Q; // QB は常にQ の否定をとる always@(posedge CLK) begin // クロックの立ち上がり時に実行 if(J==1) begin if(K==1) begin Q <= ~Q; // 反転 end else begin Q <= 1; // セット end end else begin if(K==1) begin Q <= 0; // リセット end /* J==0, K==0 のときは Q の値は変化しない */ end end endmodule |
以下は JKフリップフロップの検証用モジュールの例である。
`timescale 10ps / 10ps module TESTBENCH; reg J, K, CLK; wire Q, QB; JKFF CUT(.J(J), .K(K), .CLK(CLK), .Q(Q), .QB(QB)); initial begin $dumpfile("JKFF.vcd"); $dumpvars(1, TESTBENCH); CLK <= 0; J <= 0; K <= 0; #10 CLK <= 1; #50 CLK <= 0; #40 // 保持 J <= 1; K <= 0; #10 CLK <= 1; #50 CLK <= 0; #40 // セット J <= 0; K <= 0; #10 CLK <= 1; #50 CLK <= 0; #40 // 保持 J <= 0; K <= 1; #10 CLK <= 1; #50 CLK <= 0; #40 // リセット J <= 0; K <= 0; #10 CLK <= 1; #50 CLK <= 0; #40 // 保持 J <= 1; K <= 1; #10 CLK <= 1; #50 CLK <= 0; #50 // 反転 CLK <= 1; #50 CLK <= 0; #50 // 反転 CLK <= 1; #50 CLK <= 0; #50 // 反転 /* 通常、JK値と クロックは同時に変化させない */ $finish; end endmodule |
難波 一輝 (助教・伊藤・北神・難波研究室)
工学部1号棟4階409号室、内線3255、043-290-3255、namba@ieee.org