CPUをPythonで作ろう


## 【第0章】準備と目的：Pythonで論理回路を模倣する意義

本章では、なぜPythonを用いて論理回路を模倣するのか、その教育的・工学的意義を明確にします。

* **デジタル回路設計の直観的理解**
  Pythonによる論理回路の模倣は、物理的な回路設計の背後にあるブール代数の仕組みを明示的に視覚化し、理解を助けます。特に、回路の「状態」や「伝播」をステップごとに追えるため、電気回路に不慣れな学習者にも直感的な理解を提供します。

* **教育的なシミュレーション環境としての活用**
  仮想的にゲート・加算器・ALU・命令セットなどを構築することで、抽象的な論理概念を具体的に動作確認できる教材になります。ハードウェア設計・組込みシステム・機械学習ハードウェアの導入として有効です。

* **ブール代数とビット演算の復習**
  Pythonの`&`, `|`, `^`, `~`, `<<`, `>>`演算子を通して、論理ゲート操作とビット操作の原理（AND, OR, NOT, XOR, シフト）を実践的に学べます。

* **バイナリと10進数の変換・表記**
  `bin()`, `int()`, `format()` などを活用して、計算結果の2進数表現や桁合わせ（zfill）なども学びます。これは後の命令フォーマット処理にも直結します。

---

## 【第1章】基本論理ゲートの実装

この章では、論理演算の基本構成要素であるゲートを関数として定義し、構造的に理解を深めます。

* **1.1 単体ゲートの定義（AND, OR, NOT）**
  各ゲートは1ビット演算として関数化され、2入力/1出力の構造がどのように作用するかを可視化します。

* **1.2 複合ゲート（NAND, NOR, XOR）**
  基本ゲートを組み合わせて複雑な論理を構成する手法を学びます。例えば、`NAND`は`NOT(AND(a, b))`として定義可能です。

* **1.3 真理値表の生成と表示**
  `itertools.product([0, 1], repeat=2)`により、すべての入力組合せに対する出力（真理値表）を動的に生成し、テーブル形式で表示します。

* **1.4 ゲートの構成的合成**
  XORの構成例（`(A OR B) AND (NOT (A AND B))`など）や、NOTゲートだけでNANDを構成する演習を通じて、論理回路の構成原理に触れます。

---

## 【第2章】1ビット加算器の設計

本章では、加算器の基本構造を論理ゲートの観点から定義し、より複雑な演算回路の構築へと進めます。

* **2.1 半加算器（Half Adder）**
  `Sum = A XOR B`、`Carry = A AND B` の構成を明示し、最小単位の演算ブロックを定義します。

* **2.2 全加算器（Full Adder）**
  2つのHalf Adder + ORゲートによって、`A + B + Carry_in`を計算するブロックを構成します。

* **2.3 真理値表による検証**
  入力3ビットのすべての組合せ（2³ = 8通り）に対して、SumとCarry\_outが正しく計算されるかをテストして確認します。

---

## 【第3章】8ビットリップルキャリー加算器

本章では、1ビットのFull Adderを8つ直列化し、桁上がりの伝播を含む演算を実装します。

* **3.1 Full Adderの直列化**
  最下位ビット（LSB）から上位ビット（MSB）へ、キャリーを伝播させるRipple Carry構造を形成します。

* **3.2 整数のビット列への変換**
  `format(n, '08b')`を用いて8ビットの2進数表現に変換し、逆順に走査します。

* **3.3 桁上がりの伝播と検出**
  最終のCarry\_outをCarry Flag（CF）として格納し、演算結果のオーバーフロー監視に利用します。

* **3.4 オーバーフローフラグ（Overflow Flag: OF）の実装**
  加算元AとBの符号が同じで、結果の符号が異なる場合にOFを1とします（符号ビット逆転による符号付き演算エラーの検出）。

---

## 【第4章】ALU（算術論理演算装置）の設計

ALUはCPUの中核であり、様々な演算を統合的に処理する装置です。

* **4.1 演算機能の統合**
  `ADD`, `SUB`（2の補数方式による減算）、`AND`, `OR`, `XOR`などを1つの`alu()`関数に統合します。

* **4.2 op\_codeによる演算分岐**
  `if`文または`dict`マップを用いて、op='ADD'などの文字列で演算を選択します。

* **4.3 フラグの導出**

  * **ZF (Zero Flag)**: 結果が0なら1
  * **CF (Carry Flag)**: 8ビットを超える桁上がり
  * **NF (Negative Flag)**: 結果が負なら1（符号付き演算結果）

---

## 【第5章】レジスタ・メモリ・命令セット

この章では、CPUの記憶装置と命令体系を定義します。

* **5.1 レジスタ構造**
  A（汎用レジスタ）、B（演算用）、PC（プログラムカウンタ）、FLAG（ZF, CF, NF）を辞書またはクラスで定義します。

* **5.2 メモリ構造**
  256バイトの配列（`list`）を使用して、命令・データの格納を行います。

* **5.3 命令セットとフォーマット（8ビット固定長）**
  上位4ビット：命令コード（opcode）、下位4ビット：オペランド（レジスタまたはアドレス）として構成。

  * `LOAD A, addr`: 0001aaaa
  * `STORE A, addr`: 0010aaaa
  * `ADD B`: 0011bbbb
  * `SUB B`: 0100bbbb
  * `JMP addr`: 0101aaaa
  * `JZ addr`: 0110aaaa

---

## 【第6章】8ビットCPUの統合と実行環境

本章では、定義したCPUコンポーネントを統合し、命令の逐次実行を可能にする環境を構築します。

* **6.1 命令のデコードと実行ループ**
  命令のフェッチ → デコード → 実行 を順に行う処理ループを実装します。`PC`が指すメモリアドレスから命令を取得し、オペコードを基に対応する処理を実行します。

* **6.2 シミュレータの実装（CPUクラス）**
  全体をCPUクラスで管理し、レジスタとメモリを持ち、命令セットに基づく演算処理を行う構造とします。

* **6.3 デバッグ用のログ出力・ステップ実行**
  各命令実行時に、PC、レジスタ、メモリの状態を出力することで、動作確認・デバッグを容易にします。

* **6.4 サンプルプログラムの作成と実行**
  `LOAD`, `ADD`, `STORE`, `JMP`, `JZ` を組み合わせて、簡単な加算・ジャンプ・条件分岐のロジックを確認します。

---




```python
# Program Name: logic_circuit_simulation.py  
# Creation Date: 20250607  
# Overview: Simulate basic logic gates and binary-decimal conversion using Python  
# Usage: Run in Python environment to explore digital logic operations and thresholding  

# -------------------- Install Required Libraries --------------------
# Python標準ライブラリのみを使用するため追加インストール不要 / No external libraries required

# -------------------- Parameters / 中央管理パラメータ --------------------
# 論理演算テスト用の入力値 / Input values for logic operations
A = 1
B = 0
threshold = 0.5  # 閾値 / Threshold value for binary decision

# -------------------- Logic Gate Functions / 論理ゲート関数定義 --------------------
def AND(a, b):
    return a & b  # AND演算（両方1のときのみ1） / Bitwise AND

def OR(a, b):
    return a | b  # OR演算（どちらか1なら1） / Bitwise OR

def NOT(a):
    return 1 - a  # NOT演算（1なら0, 0なら1） / Bitwise NOT (binary inversion)

def XOR(a, b):
    return a ^ b  # XOR演算（異なれば1） / Bitwise XOR

def shift_left(val, n):
    return val << n  # 左シフト（2のn乗倍） / Left shift by n bits

def shift_right(val, n):
    return val >> n  # 右シフト（2のn乗除算） / Right shift by n bits

# -------------------- Binary-Decimal Conversion / バイナリ⇔10進変換 --------------------
def decimal_to_binary(n):
    return bin(n)  # 10進数から2進数への変換 / Convert decimal to binary string

def binary_to_decimal(b):
    return int(b, 2)  # 2進数文字列から10進数への変換 / Convert binary string to decimal

def format_binary(n, width=4):
    return format(n, f'0{width}b')  # 0埋めバイナリ表記 / Zero-padded binary string

# -------------------- Thresholding Example / 閾値処理の例（機械学習的） --------------------
def thresholding(x, th):
    return 1 if x > th else 0  # 閾値を超えたら1、以下なら0 / Return binary decision based on threshold

# -------------------- Plotting Logic Outputs / 論理演算の可視化 --------------------
import matplotlib.pyplot as plt

def plot_logic_gate_results():
    # 入力値の全組み合わせを準備 / Prepare all input combinations
    inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
    and_vals = [AND(a, b) for a, b in inputs]
    or_vals = [OR(a, b) for a, b in inputs]
    xor_vals = [XOR(a, b) for a, b in inputs]

    x_labels = [f'{a},{b}' for a, b in inputs]
    x_pos = range(len(inputs))

    # グラフ描画 / Plot logic gate results
    plt.figure()
    plt.plot(x_pos, and_vals, marker='o', label='AND')
    plt.plot(x_pos, or_vals, marker='s', label='OR')
    plt.plot(x_pos, xor_vals, marker='^', label='XOR')
    plt.xticks(x_pos, x_labels)
    plt.xlabel("Input (A,B)")
    plt.ylabel("Output")
    plt.title("Logic Gate Outputs")
    plt.legend()
    plt.grid(True)
    plt.show()

# -------------------- Main Execution / メイン処理 --------------------
if __name__ == "__main__":
    print(f"AND({A}, {B}) = {AND(A, B)}")
    print(f"OR({A}, {B}) = {OR(A, B)}")
    print(f"NOT({A}) = {NOT(A)}")
    print(f"XOR({A}, {B}) = {XOR(A, B)}")

    print(f"Shift Left A << 1: {shift_left(A, 1)}")
    print(f"Shift Right A >> 1: {shift_right(A, 1)}")

    dec_val = 5
    bin_val = '101'
    print(f"Decimal to Binary ({dec_val}): {decimal_to_binary(dec_val)}")
    print(f"Binary to Decimal ('{bin_val}'): {binary_to_decimal(bin_val)}")
    print(f"Formatted Binary (5): {format_binary(5)}")

    print(f"Thresholding(0.6, 0.5): {thresholding(0.6, threshold)}")
    print(f"Thresholding(0.3, 0.5): {thresholding(0.3, threshold)}")

    plot_logic_gate_results()


```

```python
# Program Name: ripple_carry_adder_8bit.py  
# Creation Date: 20250607  
# Overview: Simulate 1-bit Half Adder, Full Adder, and 8-bit Ripple Carry Adder with flags  
# Usage: Run this Python script to verify bitwise addition and carry/overflow detection  

# -------------------- Import Required Library --------------------
# No external libraries required

# -------------------- Logic Gate Definitions / 論理ゲート定義 --------------------
def XOR(a, b):
    return a ^ b  # 排他的論理和 / Exclusive OR

def AND(a, b):
    return a & b  # 論理積 / Logical AND

def OR(a, b):
    return a | b  # 論理和 / Logical OR

# -------------------- 2.1 Half Adder / 半加算器 --------------------
# 入力：a, b（1ビット）→ 出力：sum_bit, carry
def half_adder(a, b):
    sum_bit = XOR(a, b)
    carry = AND(a, b)
    return sum_bit, carry

# -------------------- 2.2 Full Adder / 全加算器 --------------------
# Half Adderを2個用いてSumとCarryを構成 / Use two Half Adders + OR
def full_adder(a, b, carry_in):
    sum1, carry1 = half_adder(a, b)
    sum2, carry2 = half_adder(sum1, carry_in)
    carry_out = OR(carry1, carry2)
    return sum2, carry_out

# -------------------- 2.3 Truth Table Verification / 真理値表の検証 --------------------
def test_full_adder():
    print("A B Cin | Sum Cout")
    for a in [0, 1]:
        for b in [0, 1]:
            for cin in [0, 1]:
                s, c = full_adder(a, b, cin)
                print(f"{a} {b}  {cin}   |  {s}   {c}")

# -------------------- 3.1〜3.4 Ripple Carry Adder --------------------
def ripple_carry_adder_8bit(a_int, b_int):
    # 3.2 整数を8ビットの文字列に変換（0埋め） / Convert to 8-bit binary string
    a_bin = format(a_int, '08b')
    b_bin = format(b_int, '08b')

    result_bits = []
    carry = 0

    # 3.1 Full Adderを8ビット直列化 / Cascade 8 full adders
    for i in range(7, -1, -1):  # LSBからMSBへ / Least to Most Significant Bit
        a_bit = int(a_bin[i])
        b_bit = int(b_bin[i])
        sum_bit, carry = full_adder(a_bit, b_bit, carry)
        result_bits.insert(0, str(sum_bit))

    result_bin = ''.join(result_bits)
    result_int = int(result_bin, 2)

    # 3.3 桁上がり検出（最終キャリービット）/ Final carry
    carry_flag = carry  # CF: キャリーフラグ / Carry Flag

    # 3.4 オーバーフローフラグ検出（MSBの変化）/ Overflow Flag
    msb_a = int(a_bin[0])
    msb_b = int(b_bin[0])
    msb_r = int(result_bin[0])
    overflow_flag = (msb_a == msb_b) and (msb_a != msb_r)  # OF: 同符号加算で符号反転

    return {
        "A_int": a_int,
        "B_int": b_int,
        "A_bin": a_bin,
        "B_bin": b_bin,
        "Result_bin": result_bin,
        "Result_int": result_int,
        "CarryFlag_CF": carry_flag,
        "OverflowFlag_OF": overflow_flag
    }

# -------------------- Main Execution / メイン処理 --------------------
if __name__ == "__main__":
    print("=== Full Adder Truth Table ===")
    test_full_adder()

    print("\n=== 8-bit Ripple Carry Adder Test ===")
    A = 100      # 8ビット整数A / 8-bit integer A
    B = 200      # 8ビット整数B / 8-bit integer B
    result = ripple_carry_adder_8bit(A, B)
    
    for key, val in result.items():
        print(f"{key}: {val}")


```

```python
# Program Name: cpu_simulator_8bit.py
# Creation Date: 20250607
# Overview: Simulate an 8-bit CPU with registers, memory, and instruction set
# Usage: Run this script to test fetch-decode-execute loop with simple programs

# -------------------- CPU Constants --------------------
MEMORY_SIZE = 256  # メモリサイズ（256バイト）/ 256-byte memory

# 命令コード（上位4ビット）/ Instruction opcodes
OP_LOAD  = 0b0001
OP_STORE = 0b0010
OP_ADD   = 0b0011
OP_SUB   = 0b0100
OP_JMP   = 0b0101
OP_JZ    = 0b0110

# -------------------- CPU Class --------------------
class CPU:
    def __init__(self):
        # 5.1 レジスタ初期化 / Initialize Registers
        self.registers = {
            'A': 0,
            'B': 0,
            'PC': 0,
            'FLAG': {'ZF': 0, 'CF': 0, 'NF': 0}
        }
        # 5.2 メモリ初期化 / Initialize Memory
        self.memory = [0] * MEMORY_SIZE

    # 6.1 命令のデコードと実行 / Instruction decoding and execution
    def fetch_decode_execute(self):
        while self.registers['PC'] < MEMORY_SIZE:
            instr = self.memory[self.registers['PC']]
            opcode = (instr & 0b11110000) >> 4
            operand = instr & 0b00001111

            self.log_state(instr)

            if opcode == OP_LOAD:
                self.registers['A'] = self.memory[operand]
            elif opcode == OP_STORE:
                self.memory[operand] = self.registers['A']
            elif opcode == OP_ADD:
                result = self.registers['A'] + self.registers['B']
                self.registers['A'] = result & 0xFF
                self.registers['FLAG']['CF'] = 1 if result > 0xFF else 0
                self.registers['FLAG']['ZF'] = 1 if self.registers['A'] == 0 else 0
            elif opcode == OP_SUB:
                result = self.registers['A'] - self.registers['B']
                self.registers['A'] = result & 0xFF
                self.registers['FLAG']['NF'] = 1 if result < 0 else 0
                self.registers['FLAG']['ZF'] = 1 if self.registers['A'] == 0 else 0
            elif opcode == OP_JMP:
                self.registers['PC'] = operand
                continue
            elif opcode == OP_JZ:
                if self.registers['FLAG']['ZF'] == 1:
                    self.registers['PC'] = operand
                    continue
            else:
                print(f"Unknown opcode: {opcode:04b}")
                break

            self.registers['PC'] += 1

    # 6.3 デバッグ用ログ出力 / Debug logging
    def log_state(self, instr):
        pc = self.registers['PC']
        print(f"PC: {pc:02X}, Instruction: {instr:08b}, A: {self.registers['A']:02X}, B: {self.registers['B']:02X}, FLAGS: {self.registers['FLAG']}")

    # 6.4 プログラムのロード / Load program into memory
    def load_program(self, program):
        for i, val in enumerate(program):
            self.memory[i] = val

# -------------------- サンプルプログラム --------------------
# メモリ0x0Aに値5を格納、AにロードしてBと加算、その結果を0x0Fに格納
program = [
    0b00011010,  # LOAD A, addr=0x0A
    0b00110000,  # ADD B
    0b00101111,  # STORE A, addr=0x0F
    0b01010000   # JMP 0x00（ループ）
]

# メモリ初期化：アドレス0x0Aに5を格納 / Initialize memory data
cpu = CPU()
cpu.memory[0x0A] = 5
cpu.registers['B'] = 10
cpu.load_program(program)

# -------------------- 実行開始 / Run CPU --------------------
cpu.fetch_decode_execute()


```

```python

# Program Name: ripple_carry_adder_8bit.py
# Creation Date: 20250607
# Overview: 8-bit ripple carry adder simulation with carry and overflow flag detection
# Usage: Execute in a Python environment to simulate 8-bit addition with flags

# -------------------- Install Required Libraries --------------------
# ※標準ライブラリのみ使用（追加インストール不要）

# -------------------- Parameters / 中央管理パラメータ --------------------
BIT_WIDTH = 8  # ビット幅（8ビット）/ Bit width (8-bit)

# -------------------- Functions / 関数定義 --------------------

# Full Adder（1ビットの全加算器）/ 1-bit Full Adder
def full_adder(a: int, b: int, carry_in: int) -> tuple:
    """
    1ビットの加算処理を行う / Perform 1-bit addition
    :param a: 入力ビットA / Input bit A
    :param b: 入力ビットB / Input bit B
    :param carry_in: 繰り上がり入力 / Carry-in
    :return: (Sumビット, Carry-out)
    """
    sum_bit = a ^ b ^ carry_in  # XORによる合計ビット計算 / XOR for sum
    carry_out = (a & b) | (b & carry_in) | (a & carry_in)  # 繰り上がり計算 / Carry out
    return sum_bit, carry_out

# 8ビットのリップルキャリー加算器 / 8-bit Ripple Carry Adder
def ripple_carry_adder_8bit(a_int: int, b_int: int) -> dict:
    """
    8ビットの整数を加算し、CarryとOverflowを計算 / Add 8-bit integers and calculate flags
    :param a_int: 整数A（0〜255）/ Input A (0–255)
    :param b_int: 整数B（0〜255）/ Input B (0–255)
    :return: 加算結果とフラグの辞書 / Result dict with flags
    """
    # 2進数へ変換し、逆順（LSBが先頭）に変換 / Convert to reversed binary string
    a_bin = format(a_int, f'0{BIT_WIDTH}b')[::-1]
    b_bin = format(b_int, f'0{BIT_WIDTH}b')[::-1]

    result_bits = []  # 加算結果のビット列 / Result bit list
    carry = 0         # 初期キャリー / Initial carry
    for i in range(BIT_WIDTH):
        a_bit = int(a_bin[i])
        b_bit = int(b_bin[i])
        sum_bit, carry = full_adder(a_bit, b_bit, carry)
        result_bits.append(str(sum_bit))  # ビットを文字列として追加 / Append bit as string

    # 加算結果を10進数へ / Convert result bits to integer
    result_bin = ''.join(result_bits[::-1])  # MSBからLSBへ整列 / Reverse to MSB first
    result_int = int(result_bin, 2)

    # フラグ判定 / Flag detection
    carry_flag = carry  # 最終キャリー / Final carry out
    sign_a = int(a_bin[-1])  # Aの符号ビット（MSB）/ Sign bit of A
    sign_b = int(b_bin[-1])  # Bの符号ビット（MSB）/ Sign bit of B
    sign_r = int(result_bin[0])  # 結果の符号ビット / Sign bit of result

    overflow_flag = 1 if (sign_a == sign_b and sign_r != sign_a) else 0  # 符号オーバーフロー / Signed overflow

    return {
        'A_bin': a_bin[::-1],
        'B_bin': b_bin[::-1],
        'Result_bin': result_bin,
        'Result_int': result_int,
        'CarryFlag (CF)': carry_flag,
        'OverflowFlag (OF)': overflow_flag
    }

# -------------------- Example / 実行例 --------------------
# A = 120, B = 100 を加算 / Add A=120 and B=100
result = ripple_carry_adder_8bit(120, 100)
for key, value in result.items():
    print(f'{key}: {value}')

```


```python
# Program Name: cpu_memory_instructionset.py
# Creation Date: 20250607
# Overview: Define 8-bit CPU registers, memory, and instruction set format
# Usage: Execute in Python to simulate CPU architecture components and opcode format

# -------------------- Install Required Libraries --------------------
# ※標準ライブラリのみ使用 / No additional installation required

# -------------------- Parameters / 中央管理パラメータ --------------------
MEMORY_SIZE = 256  # メモリサイズ（バイト）/ Memory size (bytes)

# -------------------- Register Class / レジスタクラス定義 --------------------
class Registers:
    def __init__(self):
        self.A = 0             # 汎用レジスタA / General-purpose register A
        self.B = 0             # 汎用レジスタB / General-purpose register B
        self.PC = 0            # プログラムカウンタ / Program Counter
        self.FLAG = {          # フラグレジスタ / Flag register
            'ZF': 0,           # Zero Flag（結果が0）/ Zero result
            'CF': 0,           # Carry Flag（桁上がり）/ Carry occurred
            'NF': 0            # Negative Flag（負値）/ Negative result
        }

    def __str__(self):
        return f"PC={self.PC}, A={self.A}, B={self.B}, FLAGS={self.FLAG}"

# -------------------- Memory Initialization / メモリ初期化 --------------------
memory = [0] * MEMORY_SIZE  # 256バイトの空メモリ / 256-byte empty memory

# -------------------- Instruction Encoding / 命令エンコード関数 --------------------
def encode_instruction(opcode: int, operand: int) -> int:
    """
    命令とオペランドをエンコード / Encode opcode and operand into 8-bit instruction
    :param opcode: 上位4ビットの命令コード / 4-bit opcode
    :param operand: 下位4ビットのアドレスやレジスタ番号 / 4-bit operand
    :return: 8ビット命令整数値 / 8-bit instruction as integer
    """
    return ((opcode & 0b1111) << 4) | (operand & 0b1111)

# -------------------- Instruction Set Mapping / 命令セット定義 --------------------
INSTRUCTION_SET = {
    'LOAD':  0b0001,  # レジスタAにメモリ値を読み込み / LOAD A, addr
    'STORE': 0b0010,  # レジスタAの値をメモリに保存 / STORE A, addr
    'ADD':   0b0011,  # Bの値をAに加算 / ADD B
    'SUB':   0b0100,  # Bの値をAから減算 / SUB B
    'JMP':   0b0101,  # アドレスへジャンプ / JMP addr
    'JZ':    0b0110   # ZFが1ならジャンプ / JZ addr
}

# -------------------- Example Program / サンプル命令列 --------------------
# 命令例：A ← mem[15], A ← A + B, mem[20] ← A
program = [
    encode_instruction(INSTRUCTION_SET['LOAD'], 15),   # LOAD A, 15
    encode_instruction(INSTRUCTION_SET['ADD'], 0),     # ADD B (operand not used)
    encode_instruction(INSTRUCTION_SET['STORE'], 20),  # STORE A, 20
]

# メモリにプログラムを書き込む / Load program into memory
for i, instr in enumerate(program):
    memory[i] = instr

# デバッグ出力 / Debug output
print("=== Memory Dump (0–10) ===")
for i in range(10):
    print(f"Addr {i:03}: {format(memory[i], '08b')}")

print("\n=== Registers Initial State ===")
cpu = Registers()
print(cpu)


```


```python
# Program Name: cpu_simulator_8bit.py
# Creation Date: 20250607
# Overview: 8-bit CPU simulation with instruction execution loop and debugging output
# Usage: Execute in Python environment to simulate simple CPU behavior

# -------------------- Parameters --------------------
MEMORY_SIZE = 256  # メモリサイズ / Memory size
INSTRUCTION_SET = {
    'LOAD':  0b0001,
    'STORE': 0b0010,
    'ADD':   0b0011,
    'SUB':   0b0100,
    'JMP':   0b0101,
    'JZ':    0b0110
}

# -------------------- CPUクラス定義 / CPU Class --------------------
class CPU:
    def __init__(self):
        self.registers = {
            'A': 0,         # 汎用レジスタA / General-purpose register A
            'B': 0,         # 汎用レジスタB / General-purpose register B
            'PC': 0,        # プログラムカウンタ / Program Counter
            'FLAG': {       # フラグレジスタ / Flag Register
                'ZF': 0,    # Zero Flag
                'CF': 0,    # Carry Flag
                'NF': 0     # Negative Flag
            }
        }
        self.memory = [0] * MEMORY_SIZE  # メモリ初期化 / Initialize memory

    # 命令実行 / Instruction Execution
    def execute_instruction(self, instr):
        opcode = (instr & 0b11110000) >> 4  # 上位4ビットが命令コード / Extract opcode
        operand = instr & 0b00001111        # 下位4ビットがオペランド / Extract operand

        A = self.registers['A']
        B = self.registers['B']
        PC = self.registers['PC']

        if opcode == INSTRUCTION_SET['LOAD']:
            self.registers['A'] = self.memory[operand]
        elif opcode == INSTRUCTION_SET['STORE']:
            self.memory[operand] = self.registers['A']
        elif opcode == INSTRUCTION_SET['ADD']:
            result = A + B
            self.registers['A'] = result & 0xFF
            self.registers['FLAG']['CF'] = int(result > 0xFF)
            self.registers['FLAG']['ZF'] = int((result & 0xFF) == 0)
            self.registers['FLAG']['NF'] = int((result & 0x80) != 0)
        elif opcode == INSTRUCTION_SET['SUB']:
            result = A - B
            self.registers['A'] = result & 0xFF
            self.registers['FLAG']['CF'] = int(result < 0)
            self.registers['FLAG']['ZF'] = int((result & 0xFF) == 0)
            self.registers['FLAG']['NF'] = int((result & 0x80) != 0)
        elif opcode == INSTRUCTION_SET['JMP']:
            self.registers['PC'] = operand
            return  # 明示的にPC変更後return
        elif opcode == INSTRUCTION_SET['JZ']:
            if self.registers['FLAG']['ZF'] == 1:
                self.registers['PC'] = operand
                return

        # 通常進行：PCを+1 / Increment PC if no jump
        self.registers['PC'] += 1

    # 実行ループ / Run Program Loop
    def run(self, max_cycles=20):
        cycles = 0
        while self.registers['PC'] < MEMORY_SIZE and cycles < max_cycles:
            instr = self.memory[self.registers['PC']]
            print(f"[Cycle {cycles}] PC={self.registers['PC']:03} Instr={format(instr, '08b')}")
            self.execute_instruction(instr)
            print(f" A={self.registers['A']}, B={self.registers['B']}, FLAGS={self.registers['FLAG']}")
            cycles += 1

    # プログラムと初期値のロード / Load Program and Data
    def load_program(self, program, data={}):
        for i, instr in enumerate(program):
            self.memory[i] = instr
        for addr, val in data.items():
            self.memory[addr] = val

# -------------------- サンプルプログラム / Sample Program --------------------
# メモリ[15]に10を格納 → A ← mem[15] → A += B → mem[20] ← A
def encode(opcode, operand):
    return ((opcode & 0xF) << 4) | (operand & 0xF)

program = [
    encode(INSTRUCTION_SET['LOAD'], 15),   # LOAD A, 15
    encode(INSTRUCTION_SET['ADD'], 0),     # ADD B
    encode(INSTRUCTION_SET['STORE'], 20),  # STORE A, 20
    encode(INSTRUCTION_SET['JZ'], 0),      # JZ 0 (終了条件なし、デモ用)
]

cpu = CPU()
cpu.registers['B'] = 5  # レジスタBに初期値5をセット / Set B = 5
cpu.load_program(program, data={15: 10})  # メモリ15に10をセット / Set mem[15] = 10
cpu.run()


```