Pythonで作る8ビットCPUエミュレータ入門 

 
## ～ALU・バス・I/O・命令セットを一から構築～

このプロジェクトでは、Pythonを使ってシンプルな8ビットCPUのエミュレータを実装します。ALU、バス、I/Oデバイス、命令セットなど、CPUを構成する各要素を自作し、最終的には簡単なプログラムを実行させます。

---

##  構成概要

このエミュレータは以下の構成要素で構成されています：

- **ALU（算術論理演算器）**：加算、減算、論理演算などを処理
- **バス（Bus）**：レジスタやI/Oとのデータのやりとり
- **レジスタ（Register）**：汎用レジスタAとB
- **I/Oデバイス（IODevice）**：出力処理
- **CPU（中央処理装置）**：命令の実行・管理

---

##  Pythonコード






```python
# 8-bit CPU Emulator with ALU, Bus, I/O, and Instruction Set
# 8ビットCPUエミュレータ（ALU、バス、I/O、命令セットを含む）

class ALU:
    def __init__(self):
        self.result = 0          # 演算結果 / Result of ALU operation
        self.zero_flag = False  # ゼロフラグ / Zero flag

    def operate(self, op, a, b):
        # 各種演算を実行 / Perform operations based on opcode
        if op == "ADD":
            self.result = (a + b) & 0xFF  # 8ビット加算 / 8-bit addition
        elif op == "SUB":
            self.result = (a - b) & 0xFF  # 8ビット減算 / 8-bit subtraction
        elif op == "AND":
            self.result = a & b           # 論理積 / Bitwise AND
        elif op == "OR":
            self.result = a | b           # 論理和 / Bitwise OR
        elif op == "MUL":
            self.result = (a * b) & 0xFF  # 8ビット乗算 / 8-bit multiplication
        elif op == "CMP":
            self.result = 0
            self.zero_flag = (a == b)    # 比較結果（等しいならZF=1）/ Set zero flag if equal
            return None
        self.zero_flag = (self.result == 0)  # 結果が0ならZF=1 / Update zero flag
        return self.result

    def get_zero_flag(self):
        return self.zero_flag  # ZFを返す / Return zero flag


class Bus:
    def __init__(self):
        self.data = 0  # バス上のデータ / Data on the bus

    def write(self, value):
        self.data = value & 0xFF  # 8ビットに制限 / Limit to 8-bit

    def read(self):
        return self.data  # データ読み出し / Read data


class IODevice:
    def __init__(self):
        self.output = []  # 出力データの履歴 / History of outputs

    def write(self, value):
        self.output.append(value)
        print(f"[I/O] Output Device Received: {value}")  # 出力表示 / Show output


class Register:
    def __init__(self):
        self.value = 0  # レジスタの値 / Value of the register

    def load(self, val):
        self.value = val & 0xFF  # 8ビット制限 / Limit to 8-bit

    def read(self):
        return self.value  # 値の読み出し / Read value


class CPU:
    def __init__(self):
        # レジスタ、PC、メモリなどの初期化 / Initialize registers, PC, memory, etc.
        self.regA = Register()
        self.regB = Register()
        self.PC = 0
        self.memory = [0] * 256  # 256バイトメモリ / 256-byte memory
        self.alu = ALU()
        self.bus = Bus()
        self.io = IODevice()
        self.halt = False

    def load_program(self, program):
        self.memory[:len(program)] = program  # プログラムのロード / Load program into memory

    def fetch(self):
        instr = self.memory[self.PC]  # 命令の取得 / Fetch instruction
        self.PC += 1
        return instr

    def execute(self, instr):
        # 命令のデコードと実行 / Decode and execute instruction
        if instr == 0x01:  # LOAD A, imm
            val = self.fetch()
            self.regA.load(val)
        elif instr == 0x02:  # LOAD B, imm
            val = self.fetch()
            self.regB.load(val)
        elif instr == 0x03:  # ADD A, B
            result = self.alu.operate("ADD", self.regA.read(), self.regB.read())
            self.regA.load(result)
        elif instr == 0x04:  # MUL A, B
            result = self.alu.operate("MUL", self.regA.read(), self.regB.read())
            self.regA.load(result)
        elif instr == 0x05:  # CMP A, B
            self.alu.operate("CMP", self.regA.read(), self.regB.read())
        elif instr == 0x06:  # OUT A
            self.io.write(self.regA.read())
        elif instr == 0x07:  # MOV A to Bus
            self.bus.write(self.regA.read())
        elif instr == 0x08:  # MOV Bus to B
            self.regB.load(self.bus.read())
        elif instr == 0x09:  # SUB A, B
            result = self.alu.operate("SUB", self.regA.read(), self.regB.read())
            self.regA.load(result)
        elif instr == 0x0A:  # AND A, B
            result = self.alu.operate("AND", self.regA.read(), self.regB.read())
            self.regA.load(result)
        elif instr == 0x0B:  # OR A, B
            result = self.alu.operate("OR", self.regA.read(), self.regB.read())
            self.regA.load(result)
        elif instr == 0xFF:  # HALT
            self.halt = True  # プログラム終了 / Stop the program

        # 現在の状態を表示 / Display current CPU state
        print(f"PC: {self.PC-1}, A: {self.regA.read()}, B: {self.regB.read()}, Bus: {self.bus.read()}, ZF: {self.alu.get_zero_flag()}")

    def run(self):
        # 命令を連続的に実行 / Run until HALT instruction
        while not self.halt:
            instr = self.fetch()
            self.execute(instr)


# サンプルプログラム：A=7, B=3, A=A*B → Aをバス経由でBにコピー → Aを出力 → 比較 → AND → OR → 停止
# Sample Program: A=7, B=3, A=A*B → Copy A to B via Bus → Output A → Compare → AND → OR → HALT
program = [
    0x01, 0x07,  # LOAD A, 7
    0x02, 0x03,  # LOAD B, 3
    0x04,        # MUL A, B
    0x07,        # MOV A to Bus
    0x08,        # MOV Bus to B
    0x06,        # OUT A
    0x05,        # CMP A, B
    0x0A,        # AND A, B
    0x0B,        # OR A, B
    0xFF         # HALT
]

# CPU実行 / Execute CPU
cpu = CPU()
cpu.load_program(program)
cpu.run()
```

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/301d644b-db0d-4726-baae-2d1ea1e1bf17.png)