
フリップフロップをPythonで実装する|回路が"記憶"を持つしくみ
2026-09-17 ・ 実践
加算器のような組合せ回路は「入力→出力」を計算するだけで、記憶を持ちません。でもコンピュータには値を覚える仕組みが要ります。それが フリップフロップ。1ビットの記憶素子をPythonで実装し、CPUのレジスタへ繋げます。
組合せ回路と順序回路の違い
組合せ回路
- 入力だけで出力が決まる
- 記憶を持たない
- 加算器・デコーダ
- その瞬間の計算
順序回路
- 過去の状態も影響
- 記憶を持つ
- フリップフロップ・カウンタ
- クロックで刻む
準備
Python標準機能だけ。
① D フリップフロップを実装
最もよく使う「D型」は、クロックの立ち上がりの瞬間に入力Dを取り込み、次まで保持します。
class DFlipFlop:
def __init__(self):
self.q = 0 # 記憶している値
def clock(self, d):
# クロックの立ち上がりで D を取り込む
self.q = d
return self.q
ff = DFlipFlop()
print(ff.clock(1)) # 1 を記憶
print(ff.q) # クロックが来なくても 1 を保持
print(ff.clock(0)) # 0 を記憶
入力が変わっても、次のクロックが来るまで値を保持します。これが「記憶」です。
② 4ビットレジスタを作る
フリップフロップを4つ束ねると、4ビットの値を保持するレジスタになります。
class Register:
def __init__(self, width=4):
self.ffs = [DFlipFlop() for _ in range(width)]
def load(self, value):
for i, ff in enumerate(self.ffs):
ff.clock((value >> i) & 1) # 各ビットを各FFへ
def read(self):
return sum(ff.q << i for i, ff in enumerate(self.ffs))
reg = Register(4)
reg.load(13)
print("保持している値:", reg.read()) # 13
CPUのレジスタはこの塊。計算の途中結果を覚えておくために、フリップフロップが大量に使われています。
③ カウンタ:記憶+演算で"数える"
記憶(レジスタ)に加算器を組み合わせると、クロックごとに1増えるカウンタになります。
class Counter:
def __init__(self, width=4):
self.reg = Register(width)
self.max = (1 << width) - 1
def tick(self):
v = (self.reg.read() + 1) & self.max # +1して桁あふれは巡回
self.reg.load(v)
return v
c = Counter(4)
print([c.tick() for _ in range(6)]) # [1, 2, 3, 4, 5, 6]
クロックごとに数が増える——時計やプログラムカウンタ(次に実行する命令の番地)の基本です。
クロックが『心臓の鼓動』
順序回路はクロック信号に同期して動きます。CPUの「〇GHz」は、このクロックが1秒に何十億回打つかを表す。クロックごとに、フリップフロップが一斉に新しい値を取り込んで計算が進みます。
まとめ
- フリップフロップは1ビットを記憶する順序回路の基本素子
- D型はクロックの立ち上がりで入力を取り込み保持する
- 束ねるとレジスタ、加算器と組むとカウンタになる
- クロックに同期して動くのが順序回路。CPUの動作周波数の正体
もう少し詳しく(背景と理論)
フリップフロップは1ビットを保持する順序回路の基本素子で、組合せ回路(記憶を持たない)と対をなします。クロックのエッジで入力を取り込むエッジトリガ型が同期設計の主役です1。正しく動くには、クロックエッジ前後で入力を安定させるセットアップ時間とホールド時間を守る必要があり、これを破ると出力が中間電位で不定になるメタスタビリティが起こります2。特に非同期な信号を取り込むときはメタスタビリティが避けられず、複数段のフリップフロップ(同期化器)で確率的に安定させます3。クロック周波数の上限は、この順序回路のタイミング制約(最長経路の遅延+セットアップ時間)で決まります。
次の一歩 🌸
組合せ回路の4ビット加算器、状態を扱う有限状態機械、論理の基礎は論理回路のしくみへどうぞ。