
マルチプレクサとデコーダをPythonで作る|信号を"選ぶ・振り分ける"回路
2026-09-18 ・ 実践
CPUやメモリの中では、たくさんの信号から必要な1つを選ぶ、逆に番号から特定の1本を活性化する回路が大活躍します。それが マルチプレクサ(MUX) と デコーダ。地味ですが、データの流れを制御する要です。Pythonで実装します。
準備
Python標準機能だけ。
① マルチプレクサ:複数入力から1つ選ぶ
選択信号(select)で、複数の入力から1つを出力に通します。
def mux2(d0, d1, sel):
# sel=0ならd0、sel=1ならd1を出力
return d1 if sel else d0
def mux4(d, sel):
# d は4入力のリスト、sel は0〜3
return d[sel]
print("mux2:", mux2("A", "B", 0), mux2("A", "B", 1)) # A B
print("mux4:", mux4(["W", "X", "Y", "Z"], 2)) # Y
MUXは「データの分岐点でどの経路を通すか」を切り替えます。CPUが「レジスタAとBのどちらを演算に使うか」を選ぶのもMUXの仕事です。
② デコーダ:番号から1本を立てる
nビットの番号を受け取り、2ⁿ本の出力のうち1本だけを1にします。
def decoder(address, n):
# addressで指定した1本だけ1、他は0
return [1 if i == address else 0 for i in range(2 ** n)]
print("2→4デコーダ address=2:", decoder(2, 2)) # [0, 0, 1, 0]
デコーダはメモリのアドレス選択の中心。「番地5を読め」と言われたら、5番目のメモリセルだけを活性化します。
③ 組み合わせて使う
MUXとデコーダは対になって、「どこから読み、どこへ書くか」を制御します。
memory = ["データ0", "データ1", "データ2", "データ3"]
def read_memory(address):
select = decoder(address, 2) # 番地を1本の選択線に
for i, active in enumerate(select):
if active:
return memory[i]
print("番地2を読む:", read_memory(2)) # データ2
1ビット×たくさん=多ビット
今回は1ビットのMUXですが、実際は8本や64本を束ねて「バス(データの通り道)」ごと切り替えます。同じ選択信号を全ビットに配れば、多ビットの経路をまるごと切り替えられます。
配線が主役の世界
MUXやデコーダが増えると、計算そのものより「信号をどこへ流すか」の配線が回路の大部分を占めます。現代のチップでは、演算よりデータの移動がボトルネックになりがち。だから配置配線の最適化が重要なのです。
まとめ
- マルチプレクサは複数入力から選択信号で1つを選ぶ
- デコーダは番号から1本だけを活性化する(メモリのアドレス選択)
- 両者でデータの読み書き経路を制御する
- 多ビットは同じ選択信号を束ねて経路ごと切り替える
もう少し詳しく(背景と理論)
マルチプレクサ(MUX)とデコーダは、記憶を持たない組合せ回路の代表選手です。MUX は n 本の選択線で 2ⁿ 個の入力から1つを選んで出力する「データの交通整理」、デコーダは n ビットの入力を 2ⁿ 本の「1本だけ有効」な出力に変える「アドレスの展開」を担います1。両者は互いに双対的で、メモリのアドレス選択、バス、ALU の演算選択など至る所で使われます2。理論的に見逃せないのは、MUX は万能素子であること——十分な MUX を組めば任意の論理関数を実装でき、FPGA の LUT(ルックアップテーブル)はまさにこの原理で任意論理を実現しています3。NAND の機能的完全性と並ぶ、「基本部品から万能性が生まれる」好例です。
次の一歩 🌸
論理の基礎は論理回路のしくみ、記憶素子はフリップフロップ、加算器は4ビット加算器へどうぞ。