ComputerFromScratch
Building a computer from scratch using Logisim. Starting from basic logic gates, this project progressively constructs an Arithmetic Logic Unit (ALU) and aims to eventually create a simple CPU. Follow along as each component is designed, tested, and integrated—truly from zero to a functioning computer.
Install / Use
/learn @build-with-zou/ComputerFromScratchREADME
#ComputerFromScratch
从零开始搭建的 8 位 CPU 项目
欢迎来到我的数字电路学习项目!本项目使用 Logisim 仿真软件,从最基础的晶体管和门电路开始,一步步搭建了一个完整的、可编程的 8 位 CPU(中央处理器)。整个过程中,我坚持“自底向上、全自制”的原则,所有模块(包括与门、或门、加法器、寄存器、程序计数器、指令寄存器、控制器等)均由底层门电路手工搭建,最终成功让这个 CPU 能够自动执行存储在 ROM 中的程序。
⚠️ 关于 ROM 实现的说明
本项目最初尝试完全自底向上地构建 ROM,计划使用 256 选 1 的多路选择器(由 16 选 1 选择器树形级联而成)来模拟 256×8 位的存储阵列。然而,由于 Logisim 仿真软件的性能限制,这种大规模的门级电路在实际仿真中会出现严重卡顿,导致无法正常工作。因此,为了确保项目的可用性,最终采用了 Logisim 内置的 ROM 元件,其内部原理(地址译码 + 存储阵列)与自制方案完全一致。
理论上,完全可以使用 16 选 1 选择器级联实现 256 选 1 的 ROM,且这一过程在理解上非常有价值。 如果您有兴趣或找到了优化仿真性能的方法(例如通过减少元件数量、调整仿真参数等),非常欢迎提交 Pull Request 来改进本项目的实现,或者分享您的优化经验!
这个 README 文档将详细介绍项目的背景、结构、模块功能、使用方法以及扩展方向,希望能为同样对计算机底层原理感兴趣的朋友提供参考。
一、项目简介
本项目实现了一个 8 位 CPU,采用经典的冯·诺依曼架构,具备以下特性:
- 数据总线宽度:8 位
- 地址总线宽度:8 位(可寻址 256 个存储单元)
- 指令集:16 条指令,包括算术运算、逻辑运算、移位、比较、数据传输和程序控制
- 核心部件:
- ALU(算术逻辑单元):支持 16 种运算
- 累加器(ACC):8 位寄存器,直接放在了顶层模块CPU中,存放 ALU 的操作数和结果
- 程序计数器(PC):8 位寄存器,可自增、可加载跳转地址
- 指令存储器(ROM):256 × 8 位,存放用户程序
- 指令寄存器(IR):8 位寄存器,暂存当前指令
整个 CPU 由用户亲手搭建的门电路和触发器构成,不依赖 Logisim 内置的高级元件(仅 ROM 使用了内置元件以简化仿真,但其原理已由用户理解)。
二、设计目标
- 理解计算机底层工作原理:从晶体管到门电路,从组合逻辑到时序逻辑,最终构建出一个能运行程序的计算机系统。
- 模块化与层次化:每个功能单元封装为独立的子电路,便于调试和复用。
- 可编程性:CPU 能够自动执行存储在 ROM 中的指令序列,支持循环和条件跳转。
- 贴近真实硬件:虽然采用仿真软件,但所有电路结构均参考真实 CMOS 设计(如传输门、D 触发器、异步复位等),力求原理一致。
三、开发环境
- 软件:Logisim 2.7.1 或更高版本(推荐 Logisim-evolution,界面更友好)
- 平台:Windows / macOS / Linux(需安装 Java 运行环境)
- 项目文件:所有电路保存在一个
.circ文件中,通过内部文件夹分类管理。
四、项目结构
项目在 Logisim 中采用单文件多电路的方式,按功能模块创建了以下文件夹(电路列表中的分类):
📁 00_Gates
├── AND (与门,由晶体管搭建)
├── OR (或门)
├── NOT (非门)
├── XOR (异或门)
├── NAND (与非门)
├── NOR (或非门)
├── 2to1单刀双掷 (用来解决RST的首尾相接导致的报错问题)
├── 8位或门 (字面意思)
├── 4位与门 (字面意思)
├── 8位2to1单刀双掷 (字面意思)
└── 传输门 (由 NMOS 和 PMOS 构成的双向开关)
📁 01_算术单元
├── 半加器
├── 全加器
├── 4位加法器
├── 8位加法器 (行波进位结构)
├── 8位减法器 (补码加法实现)
├── 取补器
├── 递增器 (A+1)
└── 递减器 (A-1)
📁 02_逻辑单元
├── 8位与门阵列
├── 8位或门阵列
├── 8位异或门阵列
└── 8位非门
📁 03_移位单元
├── 逻辑左移
├── 逻辑右移
└── 算术右移
📁 04_比较单元
├── 相等比较
├── 无符号小于
└── 无符号大于
📁 05_选择器
├── 2选1选择器
├── 4选1选择器
├── 16选1选择器
├── 8位16选1选择器
└── 8位输入带宽的8位16选1选择器
📁 06_译码器
└── 4-16译码器(4位输入OP)
📁 08_时序电路
├── SR锁存器(或非门版)(使用了logisim自带的或非门,后续所有的锁存器都用的是D锁存器)
├── D锁存器(电平触发)
├── D触发器(主从结构,边沿触发)
├── 8位寄存器(带使能和异步复位)
├── 程序计数器PC(8位,可自增、可加载)
├── 传输门 (利用晶体管实现)
├── 递增器1(一个尝试做储存+计算的文件,后来没有出现在CPU中)
├── 反向输出D锁存器 (字面意思,输出和输入相反)
└── 正在搭建的ROM+IR (PC + ROM + IR)
📁 07_顶层模块
├── ALU_8bit (完整的算术逻辑单元)
└── CPU 整合后的中央处理器)
每个模块均可独立测试,最终在 CPU 电路中完成全部连接。
五、核心模块详解
5.1 算术逻辑单元(ALU)
- 功能:支持 16 种运算,由 16 选 1 多路选择器选择结果输出。
- 输入:
A[7:0]:第一个操作数B[7:0]:第二个操作数OP[3:0]:操作码
- 输出:
Y[7:0]:运算结果
- 支持的操作(操作码与功能对应):
| 操作码 | 功能名称 | 描述 | |--------|----------|------| | 0000 | 加法 (ADD) | A + B | | 0001 | 减法 (SUB) | A - B | | 0010 | 递增 (INC) | A + 1 | | 0011 | 递减 (DEC) | A - 1 | | 0100 | 按位与 (AND) | A & B | | 0101 | 按位或 (OR) | A | B | | 0110 | 按位异或 (XOR) | A ^ B | | 0111 | 按位取反 (NOT) | ~A | | 1000 | 逻辑左移 (LSL) | A << 1 | | 1001 | 逻辑右移 (LSR) | A >> 1 | | 1010 | 算术右移 (ASR) | A >>> 1 | | 1011 | 相等比较 (CMPEQ) | 若 A == B 输出全1,否则全0 | | 1100 | 无符号小于 (CMPLTU) | 若 A < B 输出全1,否则全0 | | 1101 | 无符号大于 (CMPGTU) | 若 A > B 输出全1,否则全0 | | 1110 | 直通 B (PASSA) | 输出 B(用于 LOAD 指令)| | 1111 | 清零 (CLR) | 输出全 0 |
5.2 累加器(ACC) (没有单独模块,仅出现在CPU中)
- 功能:8 位寄存器,存放 ALU 的操作数和结果。
- 输入:
D[7:0]:来自 ALU 的结果CLK:时钟(下降沿触发)WE:写使能(由控制器控制)RST:异步复位(高有效)
- 输出:
Q[7:0],送往 ALU 的 A 输入端。
5.3 程序计数器(PC)
- 功能:8 位寄存器,指向下一条指令的地址。每个时钟周期自动加 1,遇到跳转指令时可加载新地址。
- 输入:
CLK:时钟(下降沿触发)WE:写使能(通常接高电平)(在最后的实现中为了方便我直接接了电源,但留有接口可以接入信号)RST:复位JumpAddr[7:0]:跳转地址(来自指令的低 4 位经零扩展)PC_src:选择信号(0 = PC+1,1 = JumpAddr)
- 输出:
Q[7:0],送往 ROM 的地址输入端。
5.4 指令存储器(ROM)
- 功能:存放用户程序,地址 8 位,数据 8 位。采用 Logisim 内置 ROM 元件,通过十六进制编辑器填入指令。
- 输入:
A[7:0](来自 PC) - 输出:
D[7:0](指令码),送往指令寄存器。
5.5 指令寄存器(IR)
- 功能:暂存当前执行的指令,保证在整个执行周期内指令码稳定。
- 输入:
D[7:0]:来自 ROMCLK:时钟(上升沿触发)WE:写使能(调试时可常高)RST:复位
- 输出:
Q[7:0],高 4 位送控制器和 ALU 操作码,低 4 位扩展后输入回PC。
5.6 控制器
- 功能:根据指令的高 4 位产生控制信号。
- 输入:
Op[3:0](来自 IR 的高 4 位) - 输出:
PC_src:当指令为 JUMP(操作码 1101)时为 1,否则为 0ACC_we:当指令不是 JUMP 时为 1,否则为 0(即ACC_we = NOT PC_src)
- 实现方式:用一个 4 输入与门检测
Op == 1101,与门输出直接作为PC_src,再经非门得到ACC_we。
5.7 时钟与复位
- 时钟:采用手动按钮或连续脉冲。为简化调试,使用手动时钟按钮产生上升沿和下降沿。
- 复位:所有寄存器(PC、IR、ACC)的复位端连在一起,由一个输入接口控制。
六、指令集与编码
指令长度为 8 位,格式为 [操作码(4位)] [立即数/地址(4位)]。
| 操作码 | 指令名 | 功能说明 | 低 4 位含义 | |--------|--------|----------|-------------| | 0000 | ADD | ACC = ACC + 立即数 | 立即数 | | 0001 | SUB | ACC = ACC - 立即数 | 立即数 | | 0010 | INC | ACC = ACC + 1 | 忽略(填0) | | 0011 | DEC | ACC = ACC - 1 | 忽略 | | 0100 | AND | ACC = ACC & 立即数 | 立即数 | | 0101 | OR | ACC = ACC | 立即数 | 立即数 | | 0110 | XOR | ACC = ACC ^ 立即数 | 立即数 | | 0111 | NOT | ACC = ~ACC | 忽略 | | 1000 | LSL | ACC = ACC << 1 | 忽略 | | 1001 | LSR | ACC = ACC >> 1 | 忽略 | | 1010 | ASR | ACC = ACC >>> 1 | 忽略 | | 1011 | CMPEQ | 若 ACC == 立即数,输出全1,否则全0 | 立即数 | | 1100 | CMPLTU | 若 ACC < 立即数,输出全1,否则全0 | 立即数 | | 1101 | JUMP | PC = 立即数(零扩展为 8 位地址) | 跳转地址 | | 1110 | LOAD | ACC = 立即数(直通 B) | 立即数 | | 1111 | CLR | ACC = 0 | 忽略 |
七、如何使用
7.1 打开项目
- 下载并安装 Logisim(建议使用 Logisim-evolution)。
- 打开项目文件
CPU.circ(或你保存的顶层电路)。
7.2 编写程序并写入 ROM
- 双击打开 ROM 元件(位于 CPU 电路中)。
- 在弹出的十六进制编辑器中,按地址填入你需要的指令(十六进制数)。例如测试程序:
00: E1 (LOAD 1) 01: 02 (ADD 2) 02: 03 (ADD 3) 03: D3 (JUMP 3) 其余地址填 00 - 关闭编辑器,内容自动保存。
7.3 仿真运行
- 使用 复位按钮(RST)将所有寄存器清零(按下后释放)。
- 使用 手动时钟按钮 逐步产生脉冲:
- 先按一下产生上升沿(IR 锁存指令)
- 再按一下产生下降沿(PC 更新,ACC 写入结果)
- 重复以上步骤,观察累加器和 PC 的输出 LED 变化。
- 也可以使用连续时钟源,但建议先用单步调试确认功能。
- 需要说明的一点,由于仿真软件的算力限制,在打开大型文件(如顶层的CPU)时可能回在
RST后依然保持报错,此时可以先重置导入每一个库,然后重置模拟器,如果还是不行,重新打开文件,一般可以解决问题。
7.4 观察结果
- 累加器(ACC)的 8 位输出接有 8 个 LED,可直接看到当前数值。
- 程序计数器(PC)的输出也可接 LED 观察当前指令地址。
- 如果希望看到更多细节,可以用探针(Probe)检测任意信号线。
八、示例程序及运行结果
8.1 简单加法程序
| 地址 | 指令 | 说明 | |------|------|------| | 0x00 | E1 | LOAD 1 → ACC = 1 | | 0x01 | 02 | ADD 2 → ACC = 3 | | 0x02 | 03 | ADD 3 → ACC = 6 | | 0x03 | D3 | JUMP 3 → 死循环 |
执行过程(假设复位后 ACC=0):
- 第 1 周期:ACC = 1
- 第 2 周期:ACC = 3
- 第 3 周期:ACC = 6
- 之后 ACC 保持 6,PC 在地址 3 循环。
8.2 多功能测试程序(覆盖所有指令)
这是目前ROM中存储的内容,用来检验CPU具有正常功能
使用者也可以自己改变
| 地址 | 指令 | 说明 | 执行后 ACC(十进制) | |------|------|------|----------------------| | 0x00 | E1 | LOAD 1 | 1 | | 0x01 | 02 | ADD 2 | 3 | | 0x02 | 13 | SUB 3 | 0 | | 0x03 | 42 | AND 2 | 0 | | 0x04 | 51 | OR 1 | 1 | | 0x05 | 60 | XOR 0 | 1 | | 0x06 | 70 | NOT | 254 | | 0x07 | 20 | INC | 255 | | 0x08 | 30 | DEC | 254 | | 0x09 | 80 | LSL | 252 | | 0x0A | 90 | LSR | 126 | | 0x0B | A0 | ASR | 63 | | 0x0C | B5 | CMPEQ 5 | 0(全0) | | 0x0D | C3 | CMPLTU 3 | 255(全1) | | 0x0E | F0 | CLR | 0 | | 0x0F | D0 | JUMP 0 | 0(跳回开始) |
运行该程序可验证所有指令的正确性。
九、未来扩展
这个 CPU 已经具备了完整的功能,但仍有大量扩展空间:
- 增加数据存储器(RAM):实现
LOAD和STORE指令,使 CPU 能处理更多变量。 - 扩展指令格式:改为 16 位指令(8 位操作码 + 8 位立即数/地址),支持更大地址空间和更多指令。
- 增加通用寄存器组:从单累加器扩展为多个寄存器(如 8 个),提升编程灵活性。
- 实现条件跳转:利用比较指令的结果,实现
BEQ、BLT等条件跳转。 - 添加输入输出端口:通过专用指令读写外部设备,如开关、LED、七段数码管。
- 流水线设计:将取指、译码、执行阶段重叠,提高性能。
- 中断处理:引入中断机制,响应外部事件。
- 汇编器:编写一个简单的汇编器,将助记符转换为机器码,方便编程。
十、许可证与致谢
本项目为个人学习记录,采用 MIT 许可证,欢迎任何人自由使用、修改和分享。如果你基于本项目做出了有趣的东西,欢迎告知我,一起交流。
感谢 Logisim 开发团队提供了如此优秀的教学仿真软件。感谢所有在网上分享数字电路知识的老师和朋友,你们的教程给了我无数启发。
作者:一位热爱底层的大一学生
日期:2026年3月
联系方式:可通过 GitHub Issues 或邮件联系 build.with.me@gmail.com
希望这个项目能帮助更多同学理解计算机是如何工作的。如果你有任何问题或建议,欢迎随时交流!
Security Score
Audited on Mar 19, 2026
