---
# System prepended metadata

title: 手搓 CPU - 未來無限可期

---

# 手搓 CPU - 未來無限可期
微算機專題，用電子元件自製 CPU，並結合 pic18 的應用。
題目：微處理器創新整合應用
[實體 DEMO]：12/18
[上傳書面報告]：12/21

## 架構：
控制單元、IO 單元、ALU、Register、Memory、指令集、Program counter
以 8bit 為 word

### pic18f4520：
作為我們與 CPU 互動的介面，有一顆負責將指令燒錄進 Program Memory，或者作為直譯器，以 UART 操作 CPU（超他媽炫砲）
另一顆則負責用我們專門設計的 register，與 CPU 互動

### 實際空間分配

![截圖 2026-01-22 下午5.11.48](https://hackmd.io/_uploads/B1eycwk8We.png)

### Register
以 DFF 實現
提供 8 個 Reg
Reg[0] 是 0x00
Reg[1] 實作特殊功能用，暫且保留（如 BANK）
Reg[2:5] 單純 register
Reg[6] 對 CPU 來說 Read Only，由外部決定
Reg[7] 其值專門給外部讀取

|WriteToReg|CP|IN|D|Q|
|------|------|------|------|------|
|0|-|X|X|$Q_{n-1}$|
|1|↑|X|IN|D|

控制是否要發出正緣訊號給 DFF

##### latch-based clock gating

### ALU：

8 bit input

提供運算：
|id|name|實作方式|包含指令|
|------|------|------|------|
|0|A and B|||
|1|A xor B|||
|2|not A|||
|3|A or B|||
|4|A add B|||
|5|A sub B|(not B) add A with carry|NEG (0 - B)|
|6|lrotate A|||
|7|rrotate A|||

### PC(Program counter)
找到 instruction 的位置並從 program memory 抓進 instruction register
jump 等指令會賦值 pc = x，或者一般執行時 pc += 1

### Data Memory
#### sram(program memory 用):
- 兩個
    - 第一個：RD為I/O，RB為地址線
    - 第二個：RC0~5、RE 1, 2(6, 7的位置)為I/O，RB為地址線
- RC6, 7是RX, TX要用來debug所以先不用
- ~~RA 要調設定好麻煩~~
#### IO 問題
如何確保寫的時候能將 B 寫進去，而讀的時候 B 能不影響 output?
把 SN74HC245N 當 tri-state buffer 控制 IO 要不要吃輸入
平時要把 CS 設定好，需要用時再開啟
以 74HC74 做微狀態機
要保證：
CPU 給對的訊號在 CS 打開前
在沒有連續 LOAD/STORE 前應該都做得到？
- 非 LOAD/STORE
    1. SRAM_CS = 0
- LOAD：
    - STATE 0：
    SRAM_CS = 1         ; 關閉 SRAM
    CPU_OE = 1          ; CPU 停止輸出
    - STATE 1：
    SRAM_OE = 0         ; SRAM 驅動資料線
    SRAM_CS = 0         ; 開啟 SRAM
- STORE
    - STATE 0：
    SRAM_CS = 1         ; 關閉 SRAM
    SRAM_OE = 1         ; SRAM 不驅動資料線
    - STATE 1：
    CPU_OE = 1          ; CPU 開始輸出
    SRAM_CS = 0         ; 開啟 SRAM

### pipeline：
範例（by 祭祖簡報）：
![截圖 2025-11-30 凌晨3.52.39](https://hackmd.io/_uploads/ryDGyC_W-x.png)

我們的 4 stage pipeline 結構：
![截圖 2025-12-20 晚上8.19.22](https://hackmd.io/_uploads/S1cLEz4XZx.png)

由於我們使用 Bank 而不是 offset 來支援 data memory 的存取，所以 ex 和 mem 可以平行的在同一 stage 處理，也降低了硬體設計的複雜度。

#### 各階段要往後送的資料：
| 階段 | 內容 | Register 需求 |
| --- | --- | --- |
| IF / ID  | 指令本身（Instruction）：<br>下一階段需要知道指令是什麼，才能解碼。<br>PC（Program Counter）：<br>用於計算 branch/jump 目標或更新<br>|3 個|
| ID / EX&MEM  |A, B 兩個的數值，對 ALU 是兩個運算元。對 MEM 來說 B 是 addr 的目標，A 是低 8 位元的 addrs。<br>A 與 B 的 id，讓 Forwarding 判斷是否要跟 EX&MEM/WB 取值。<br>target id：<br>WB 階段要知道要寫回哪個暫存器，也讓 Forwarding 知道能否使用。<br>B_src：<br>B是否來自 register，若不是則不能 Forwarding（A 一定來自 register 所以不需要）<br>ALU control：<br>（做什麼運算）。<br>MemRead / MemWrite：<br>是否讀寫記憶體<br>RegWrite：<br>是否要寫回暫存器<br>PC：<br>用於 EX 階段做 branch 計算。|6~8 個|
| EX&MEM / WB |result：<br>LOAD -> Memory 讀的資料。<br>算數 -> ALU 結果。<br>RegWrite：<br>WB 是否寫回暫存器。<br>target id：<br>WB 回哪。|2 個|

#### Forwarding：
ALU 要看他的 input 是否是後面 EX&MEM 的結果，要確保他們是要 Write Back 的。
![截圖 2025-12-02 凌晨3.54.52](https://hackmd.io/_uploads/Bk25zOsWbe.png)
if (EX&MEM/WB.RegWrite && A.rs == EX&MEM/WB.rd && A_is_reg) ALU_INPUT = EX&MEM/WB.data
else ALU_INPUT = ID/EX.A.data

#### Hazard detection：
如果 Branch 會發生，要將原本做的事清理乾淨（前兩個 STAGE 的控制訊號必須清 0）
實作方式：ID/EX&M 控制訊號設為全 0，IF/ID 的指令給一組沒實際作用的

### 指令集：
#### 硬體端

如果是 IMM 類型指令，其 imm 在 Ex/MEM 階段一定是 B
如果是 REG 類型指令，reg_1 為 A，reg_2 為 B
如果有 MEM 操作，mem_addr 必定是 B
如果是 條件分支（B2），由 A 與 B 比較，硬體會另外實作 PC+offset

指令 decoder 概念圖
|類型|opcode|rd|A|B|offset|
|-|-|-|-|-|-|
|IMM|00xxx[0-4]|5~7|Reg[5-7]|8~F|-|
|REG|01xxx,xx[0-4,8-9]|5~7|Reg[A-C]|Reg[D-F]|-|
|LOADI|10000[0-4]|5~7|-|8~F|-|
|STOREI|10001[0-4]|-|Reg[5-7]|8~F|-|
|LOAD|10010[0-4]|5~7|-|Reg[D-F]|-|
|STORE|10011[0-4]|-|Reg[5-7]|Reg[D-F]|-|
|B1|10100xxx[0-7]|-|-|-|8~F|
|B2|11X[0-1,F]|-|Reg[5-7]|Reg[2-4]|sign_ex(8-E)|

|IF/ID|值|大小（bit）|
|-|-|-|
|instruction|`instruction`|16|
|PC|`PC`|8|

|ID/EX&MEM|值|大小（bit）|產生單元|進度|
|-|-|-|-|-|
|isBranch|`Conditional_Branch \| Unconditional_Branch`|1|Control|存在|
|Unconditional_Branch|`101`|1|IF/ID|存在|
|Conditional_Branch|`11`|1|IF/ID|存在|
|Conditional_Branch_Type|`[F]`|1|IF/ID|存在|
|offset|`[8,E]+(Conditional_Branch&[E] \| !Conditional_Branch&[F])`|8|Sign_ex|正確|
|NEW_PC|`PC + offset`|8|PC_adder|正確|
|is_WB|`[0]`|1|IF/ID|存在|
|WB_rd|`[5~7]`|3|IF/ID|存在|
|MemRead|`1x0x0`|1|Control|存在|
|MemWrite|`1x0x1`|1|Control|存在|
|ALU_op|`[2~4]`|3|IF/ID|存在|
|A_isreg|`true`|1|-|存在|
|B_isreg|`(x1 \| 10x1)`|1|Control|存在|
|A_regid|`(01)&[A-C] \| (1\|0)&[5-7]`|3+1|Control|存在|
|B_regid|`(11)&[2-4]\|(0\|0)&[D-F]`|3+1|Control|存在|
|A_value|`Reg[A_regid]`|8|register|可存在|
|B_value|`((!b_isreg)&[8~F])\|:(b_isreg&Reg[b_regid]`|8|register/imm MUX|可存在|

|EX&MEM/WB|值|大小（bit）|
|-|-|-|
|is_WB|`[0]`|1|
|WB_rd|`[5~7]`|3|
|WB_VALUE|`WB_VALUE`|8|
|WB_rd(8bit)|WB_rd|8|

共同前綴：00
| 指令 | 說明 | opcode | type |
|------|------|------|------|
| ANDI,breg_rd,imm | `Reg[reg_rd] &= imm` |000|IMM|
| XORI,reg_rd,imm | `Reg[reg_rd] ^= imm` |001|IMM|
| ORI,reg_rd,imm | `Reg[reg_rd] \|= imm` |011|IMM|
| ADDI,reg_rd,imm | `Reg[reg_rd] += imm` |100|IMM|
| SUBI,reg_rd,imm | `Reg[reg_rd] -= imm` |101|IMM|

共同前綴：01
| 指令 | 說明 | opcode | type |
|------|------|------|------|
| NOT,reg_rd,reg | `Reg[reg_rd] = !Reg[reg]` |010|IMM|
| LROTATE,reg_rd,reg | `Reg[reg_rd] = Reg[reg]<<1` |110|IMM|
| RROTATE,reg_rd,reg | `Reg[reg_rd] = Reg[reg]>>1` |111|IMM|
| AND,reg_rd,reg_1,reg_2 | `Reg[reg_rd] = Reg[reg_1]&Reg[reg_2]` |000|REG|
| XOR,reg_rd,reg_1,reg_2 | `Reg[reg_rd] = Reg[reg_1]^Reg[reg_2]` |001|REG|
| OR,reg_rd,reg_1,reg_2 | `Reg[reg_rd] = Reg[reg_1]\|Reg[reg_2]` |011|REG|
| ADD,reg_rd,reg_1,reg_2 | `Reg[reg_rd] = Reg[reg_1]+Reg[reg_2]` |100|REG|
| SUB,reg_rd,reg_1,reg_2 | `Reg[reg_rd] = Reg[reg_1]-Reg[reg_2]` |101|REG|

共同前綴：10
| 指令 | 說明 | opcode | type |
|------|------|------|------|
| LOADI,reg_rd,imm_mem | `Reg[reg_rd] = Mem[bank,imm_mem]` |000|LOADI|
| STOREI,reg,imm_mem | `Mem[bank,imm_mem] = Reg[reg]` |001|STOREI|
| LOAD,reg,reg_mem | `Reg[reg_rd] = Mem[bank,Reg[reg_mem]]` |010|LOAD|
| STORE,reg,reg_mem | `Mem[bank,Reg[reg_mem]] = Reg[reg]` |011|STORE|
| JUMP,imm| `PC += imm` |100|B1|

共同前綴：11
| 指令 | 說明 | opcode | type |
|------|------|------|------|
| JUMP-IF-EQ,reg_1,reg_2,imm2| `if(Reg[reg_1] == Reg[reg_2]) PC += imm2` |0|B2|
| JUMP-IF-LESS,reg_1,reg_2,imm2| `if(Reg[reg_1] < Reg[reg_2]) PC += imm2` |1|B2|
> 可以用來實作 jump-if-zero、jump-if-greater 等

指令長度
opcode：5
reg_addr：3
imm：8
imm2：7

### 時序上會有問題的部分？
Program Memery 的讀取
Data Memory 的讀寫
Register 的讀 (WriteBack) 寫(ID)

統一有 clock1 與 clock2
clock2 = !clock1

clock 上緣觸發 register 將對的值設定好
clock 下緣觸發 register 的寫入 clock
$clock_i$ = clock nor ($write_i$ or $!is\_reg$)

### 工作頻率：
還未算最長 delay 路徑

### 元件：

74HC00 NAND
![截圖 2025-11-30 清晨5.38.47](https://hackmd.io/_uploads/HJreuJK-Zl.png)

74HC02 NOR
![image](https://hackmd.io/_uploads/SJpcGbGWbx.png)

74HC04 NOT
![截圖 2025-12-15 下午2.46.36](https://hackmd.io/_uploads/H1eJJV6fWe.png)

74HC08 AND
![截圖 2025-12-13 下午1.33.05](https://hackmd.io/_uploads/SyDj9dqfZl.png)

74HC32 OR
![截圖 2025-12-13 下午2.07.26](https://hackmd.io/_uploads/SJ1nGY5M-l.png)

74HC86 XOR
![截圖 2025-12-17 凌晨1.06.00](https://hackmd.io/_uploads/S1BYWfyXbg.png)

74HC573 latch
![截圖 2025-12-14 晚上9.43.27](https://hackmd.io/_uploads/BkobyShG-g.png)

![image](https://hackmd.io/_uploads/rkkAj9bZWe.png)

74HC574 DFF
![截圖 2025-12-13 下午2.43.17](https://hackmd.io/_uploads/By8GjFqGZx.png)

![截圖 2025-11-30 凌晨2.13.49](https://hackmd.io/_uploads/BJnkuh_bbe.png)

[74HC139](https://www.ti.com/lit/ds/symlink/sn74hc139-q1.pdf?ts=1763995453072&ref_url=https%253A%252F%252Fwww.google.com%252F) 
![截圖 2025-11-25 凌晨2.14.40](https://hackmd.io/_uploads/H1a5xXz--l.png)
![截圖 2025-11-25 凌晨2.15.03](https://hackmd.io/_uploads/S1EhemGbZx.png)

HM628128 Sram
![截圖 2025-11-30 晚上9.39.39](https://hackmd.io/_uploads/HkLXFpKZbg.png)
![截圖 2025-11-30 晚上9.40.07](https://hackmd.io/_uploads/rJBrF6K-Wg.png)

74HC74 D-Trigger

74HC245
![截圖 2025-12-11 下午5.20.17](https://hackmd.io/_uploads/S1C0nb_GWg.png)
![截圖 2025-12-11 下午5.20.45](https://hackmd.io/_uploads/rytxaWOG-x.png)

74HC283 adder
![截圖 2025-12-15 晚上7.35.09](https://hackmd.io/_uploads/BkZtGupfZe.png)

### 有用的網站
[畫方塊圖](https://app.diagrams.net/)
[元件圖](https://app.ultralibrarian.com/)

## 專題工作順序：
[專題大綱提案繳交]：11/20
[實體 DEMO]：12/18
[上傳書面報告]：12/21

![截圖 2025-11-02 凌晨1.16.22](https://hackmd.io/_uploads/rJKKl6Q1bg.png)
