3 章 順序回路
- 今回は前章まで作成した「組み合わせ回路」と違って「順序回路」を作っていく。フリップフロップ (1 ビットの入力とクロック入力を受け取り、前のタイムポイントでの入力を出力する) は所与のものとして扱う。
- まずは 1 bit レジスタを作成する。1 ビットの入力と load ビットを受け取り、load ビットが 1 の場合値を更新、0 の場合入力は無視される。これもマルチプレキサの
a
に何を代入したらよいのか分からなくて困ったが、例によって 賢そうな人の解答例 を見て、フィードバック入力を取れることを知った。
1
2
3
4
5
6
7
8
CHIP Bit {
IN in, load;
OUT out;
PARTS:
Mux(a=fb, b=in, sel=load, out=out1);
DFF(in=out1, out=out, out=fb);
}
- お次は 16 bit レジスタだが、これは 1 bit レジスタを 16 個並べればよいだけなので簡単。load は 16 ビットではなく 1 ビットなので注意。
- 続いていよいよメモリを作っていく。RAM は先ほどまでにレジスタに渡していた in、load に加え、アドレス入力を受け取りさらに直接アクセスできる必要がある。8 レジスタメモリを作成する場合、まずデマルチプレキサを用いて各レジスタの load ビットを決定し、最後にマルチプレキサを用いてアクセスのあったレジスタの出力を返すようにすればよい。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CHIP RAM8 {
IN in[16], load, address[3];
OUT out[16];
PARTS:
DMux8Way(in=load, sel=address, a=is0, b=is1, c=is2, d=is3, e=is4, f=is5, g=is6, h=is7);
Register(in=in, load=is0, out=out0);
Register(in=in, load=is1, out=out1);
Register(in=in, load=is2, out=out2);
Register(in=in, load=is3, out=out3);
Register(in=in, load=is4, out=out4);
Register(in=in, load=is5, out=out5);
Register(in=in, load=is6, out=out6);
Register(in=in, load=is7, out=out7);
Mux8Way16(a=out0, b=out1, c=out2, d=out3, e=out4, f=out5, g=out6, h=out7, sel=address, out=out);
}
- RAM64 を作る場合は同様に RAM8 を 8 つ並べることになる。
address[0..2]
の 3 bit でどの RAM8 かを指定し、残りaddress[3..5]
の 3 bit を各 RAM8 に与える形にすればよい。RAM のサイズがもっと大きくなっても同様の方針でいける。 - 最後に作るのは 16 bit カウンタである。ここでは実行している命令コードの行数を格納するものを指しており、通常は単に前のタイムポイントでの入力をインクリメントすればよいので
out(t + 1) = out(t) + 1
となる。ここでは、命令コードにジャンプ機能がついている場合も考え、出力を 0 にする reset ビットや load ビットも受け取れるようにしている。
1
2
3
4
5
6
7
8
9
10
11
12
CHIP PC {
IN in[16], load, inc, reset;
OUT out[16];
PARTS:
Inc16(in=fb, out=outinc); // out[t + 1] = out[t] + 1
Mux16(a=fb, b=outinc, sel=inc, out=out1); // inc なら outinc が返る
Mux16(a=out1, b=in, sel=load, out=out2); // load なら in が返る
Mux16(a=out2, b=false, sel=reset, out=out3); // reset なら zero が返る
// ここまで、いずれもあてはまらない場合 out3 には fb が格納されている
Register(in=out3, load=true, out=out, out=fb);
}