R-Sフリップフロップは R=1, S=1 のとき入力は不定となり有効に使うことができない。 J-Kフリップフロップはこれを有効に使うために、 R=1, S=1 のとき入力を反転させるものである。
このJ、Kは最初にこの回路を提唱した人の名前に由来する。
出力を反転させるための回路図を下に示す。
しかし、この回路では、発振が起こるため、このままでは J-Kフリップフロップとしては機能しない。
下の一つの長方形記号で表したJ-K-Tフリップフロップのシミュレーションについて述べる。
二つの入力段のANDゲートの出力を中間変数(中間信号)とする。 そうすると、プログラムは次のようになる。 最初にすべての信号の現在の値を読み込む。 次に、そろぞれの論理式に従って、中間信号、出力信号の値を求め、遅延時間後の値とする。
var o0 = scope.getVal(output[0]); var o1 = scope.getVal(output[1]); var i0 = scope.getVal(input[0]); var i1 = scope.getVal(input[1]); var t0 = scope.getVal(input[2]); var m0 = scope.getVal(mid[0]); // 中間変数 var m1 = scope.getVal(mid[1]); scope.setVal(mid[0], delay, i0 && o1); // AND scope.setVal(mid[1], delay, i1 && o0); scope.setVal(output[0], delay, !((m1 && t0) || o1)); // AND NOR scope.setVal(output[1], delay, !((m0 && t0) || o0));
R-S-Tフリップフロップの入力段にも AND ゲートがある(上のプログラムでは (m1 && t0) および (m0 && t0))。 2入力ANDゲートが2個続いている。 これは3入力ANDゲート1個に置き換えることができる。 この3入力ANDゲートの出力を中間変数にとると論理式は次のように変わる。
scope.setVal(mid[0], delay, i0 && o1 && t0); // 3入力AND scope.setVal(mid[1], delay, i1 && o0 && t0); scope.setVal(output[0], delay, !(m1 || o1)); // NOR scope.setVal(output[1], delay, !(m0 || o0));
プログラムはこのように変更してもよい。 しかし、中間変数をやめて次のようにできるかというと、この場合はできない。
scope.setVal(output[0], delay, !((i0 && o1 && t0) || o1)); // 3入力AND NOR scope.setVal(output[1], delay, !((i1 && o0 && t0) || o0));遅延時間で述べているように、 一見すると同じ信号と見えるものが遅延時間を考えるとそうではなくなる。 output[0]の式には o1 が二つ(output[1]の式には o0 が二つ)含まれる。 この式では当然この二つを全く同じものとして扱うことになる。 しかし、実際の回路ではそうではない。 最初の o1 は2入力ANDゲート2個または3入力ANDゲート1個を経てNORゲートの入力となっている。 もう一方の o1 は、何らゲートを通さず、直接 NORゲートの入力となっている。 すなわち、前者のo1の方が後者よりも遅延時間が短い。
中間変数を設けた場合、二つのo1には遅延時間分のずれが生じる。
この遅延時間が意味を持っており、このANDゲートの遅延時間を0とすると、発振が止まらなくなる。 遅延時間は通常は害になるが、それが有効に働くケースもあるということである。
次の回路に示すように、R-S-Tフリップフロップを直列接続し、 後方のフリップフロップには反転したクロックを与えると、J-Kフリップフロップとして動作する。
マスタースレーブR-S-Tフリップフロップと同様に、状態の変化はクロックの立下りで起きる。
下の一つの長方形記号で表したJ-Kフリップフロップのシミュレーションについて述べる。
この場合、前段のANDゲートの出力と前段のR-S-Tフリップフロップの出力を中間変数とする。 プログラムの骨子を下に示す。
scope.setVal(mid[0], delayGate, i0 && o1); // 前段AND scope.setVal(mid[1], delayGate, i1 && o0); scope.setVal(mid[2], delay, !((m0 && t0) || m3)); // 前段R-S-T FF scope.setVal(mid[3], delay, !((m1 && t0) || m2)); scope.setVal(output[0], delay, !((m2 && !t0) || o1)); // 後段R-S-T FF scope.setVal(output[1], delay, !((m3 && !t0) || o0));