D Flip-Flop (DFF) シミュレーションと加算器（Half Adder / Full Adder）の実装

### D Flip-Flop (DFF) シミュレーションと加算器（Half Adder / Full Adder）の実装

このコードでは、まず **D Flip-Flop (DFF)** の動作をシミュレーションして、次に **Half Adder** と **Full Adder** を Python で実装して、その結果を出力します。

---

#### 1. **D Flip-Flop (DFF) のシミュレーション**

D Flip-Flop は、クロック信号（Clock）に同期して入力信号（D）をラッチする記憶素子です。クロック信号の立ち上がりエッジで、入力信号 `D` の値が出力 `Q` に保存されます。コードでは、1Hzのサイン波をD入力として、クロック信号を50%デューティ比で生成し、DFFの動作をシミュレーションしています。

```python
# シミュレーション時間の設定
time = np.arange(0, 10, 0.0001)  # 0から10まで0.0001刻み

# 一定幅のクロック信号の生成（50%デューティ比）
clock_period = 0.0001  # クロック周期
clock = np.array([(t % clock_period) < (clock_period / 2) for t in time]).astype(int)

# D入力の生成（サイン波 -1 から 1）
D = np.sin(2 * np.pi * 1 * time)  # 1Hzのサイン波

# DFFの出力Qの計算
Q = np.zeros_like(time)
Q_prev = 0  # 初期値
for i in range(1, len(time)):
    if clock[i-1] == 0 and clock[i] == 1:  # 立ち上がりエッジでラッチ
        Q_prev = D[i]
    Q[i] = Q_prev

# プロット
fig, axs = plt.subplots(3, 1, figsize=(10, 8), sharex=True)

axs[0].plot(time, D, linestyle='dashed', color='blue')
axs[0].set_ylabel('D Input (Sin Wave)')
axs[0].grid()

axs[1].step(time, clock, where='post', linestyle='dotted', color='green')
axs[1].set_ylabel('Clock Signal')
axs[1].grid()

axs[2].plot(time, Q, color='red')
axs[2].set_ylabel('Q Output')
axs[2].set_xlabel('Time')
axs[2].grid()

fig.suptitle('D Flip-Flop (DFF) Simulation')
plt.show()
```

#### 解説：
- **D入力 (D)** は、1Hzのサイン波として定義されます。この入力信号は、`0` から `1` までの範囲で波動的に変化します。
- **クロック信号 (Clock)** は、`0` と `1` が交互に現れる周期的な信号で、デューティ比50%の矩形波です。
- **DFFの出力 (Q)** は、立ち上がりエッジで入力 `D` の値を保持します。クロックが `0` から `1` に変わるタイミングで、`D` の値が `Q` に伝わります。

結果として、`Q` はクロック信号に同期してDの値を保持する動作を示します。

---

#### 2. **Half Adder と Full Adder の実装**

次に、加算器（Half Adder と Full Adder）の動作を確認します。

##### **Half Adder**
Half Adderは2つのビットを加算する最小の加算器です。出力として、合計 (Sum) とキャリー (Carry) を提供します。

```python
# Half Adder function
def half_adder(A, B):
    sum_bit = A ^ B  # Sum = A XOR B
    carry_bit = A & B  # Carry = A AND B
    return sum_bit, carry_bit
```

##### **Full Adder**
Full Adderは、2つのビットとキャリー入力を加算します。出力として、合計 (Sum) とキャリー出力 (Carry_out) を提供します。

```python
# Full Adder function
def full_adder(A, B, carry_in):
    sum_bit = A ^ B ^ carry_in  # Sum = A XOR B XOR carry_in
    carry_out = (A & B) | (B & carry_in) | (A & carry_in)  # Carry = (A AND B) OR (B AND carry_in) OR (A AND carry_in)
    return sum_bit, carry_out
```

##### 結果を表示
以下のコードでは、すべての入力組み合わせに対してHalf AdderとFull Adderの結果を表示します。

```python
# Print the results for Half Adder
print("Half Adder Results:")
print("A B | Sum Carry")
for A in [0, 1]:
    for B in [0, 1]:
        sum_bit, carry_bit = half_adder(A, B)
        print(f"{A} {B} |  {sum_bit}    {carry_bit}")

print("\n-----------------------------")

# Print the results for Full Adder
print("Full Adder Results:")
print("A B Carry_in | Sum Carry_out")
for A in [0, 1]:
    for B in [0, 1]:
        for carry_in in [0, 1]:
            sum_bit, carry_out = full_adder(A, B, carry_in)
            print(f"{A} {B}     {carry_in}     |  {sum_bit}    {carry_out}")
```

#### **結果：**
- **Half Adder** は、入力 `A` と `B` に対して `Sum` と `Carry` を計算します。
- **Full Adder** は、入力 `A`、`B` に加えて `carry_in`（キャリー入力）も考慮し、結果を表示します。

#### 結果例：
```
Half Adder Results:
A B | Sum Carry
0 0 |  0    0
0 1 |  1    0
1 0 |  1    0
1 1 |  0    1

-----------------------------

Full Adder Results:
A B Carry_in | Sum Carry_out
0 0     0     |  0    0
0 0     1     |  1    0
0 1     0     |  1    0
0 1     1     |  0    1
1 0     0     |  1    0
1 0     1     |  0    1
1 1     0     |  0    1
1 1     1     |  1    1
```

---

#### 結論：
- **D Flip-Flop (DFF)** は、クロック信号に同期して入力 `D` の値をラッチする動作を確認できます。
- **Half Adder** と **Full Adder** は、2ビットまたは3ビットの加算における基本的な論理回路であり、それぞれの入力に対する結果を確認することができます。