tags: [数电] type: note source_type: reconstructed created: 2026-08-18 updated: 2026-08-18 aliases:
[!note] 对象层 学完这篇,你能判断:
- PC 计数器、指令寄存器、控制器各管什么、怎么协作;
- 一条指令 = 操作码(opcode) + 操作数(addr/立即数),并读懂完整指令集表;
- 冯诺依曼单内存如何在两个时钟周期内"取指→执行";
- 总线有哪些线、CPU 如何用 11 位地址"地址映射"区分内存/磁盘/终端;
- 引导程序(iRom → 硬盘 → 内存)为什么需要多级加载。
本篇是 [[10-从零搭建计算机(上)-组成与算力|数电 10(上)]] 的续篇,建议先读上篇。
用生活理解:控制器是"发号施令的调度员"(用查找表把 opcode 翻译成一排开关信号);PC 计数器是"翻页的书签"(每页读完自动 +1,jmp 直接翻到指定页);指令寄存器是"当前这一页的内容";总线是"邮箱系统"(地址=写给谁,数据=内容,ld/str=收信还是寄信)。引导程序则是"开机时快递员":CPU 出厂只认 iRom 这张小纸条,小纸条先去硬盘取一段"小队",小队再把主程序全部搬进内存开工。
一台可编程计算机 = PC(决定取哪条指令)+ 指令寄存器(暂存指令)+ 控制器(把指令翻译成控制信号)+ ALU/寄存器(算)+ 一块共享内存(冯诺依曼单内存,指令=opcode+操作数)+ 总线(互连 I/O);启动靠多级引导(iRom→硬盘引导区→内存→主程序)。
| opname | opcode | 操作 |
|---|---|---|
| halt | 00000 | 停止时钟 |
| ld_a | 00001 | 数据 RAM 的内容 → 寄存器 A |
| add | 00010 | 数据 RAM 内容 + A → A |
| sub | 00011 | A − 数据 RAM 内容 → A |
| or | 00100 | A | 数据 RAM → A |
| and | 00101 | A & 数据 RAM → A |
| str | 00110 | A → 数据 RAM 指定地址 |
| jmp | 00111 | 无条件跳转指定地址 |
| je | 01000 | 相等时跳转(依赖比较寄存器) |
| ld_ia | 01001 | 立即数 → A |
| add_ia | 01010 | 立即数 + A → A |
| sub_ia | 01011 | A − 立即数 → A |
| or_ia | 01100 | A | 立即数 → A |
| and_ia | 01101 | A & 立即数 → A |
操作数(addr/立即数)两种含义:
ld_a 7里的 7 可能是"数据 RAM 地址",也可能是"立即数 7"——用两套指令区分(末尾带_ia= immediate 立即数)。这就是"操作码 + 操作数"机指格式,也是所有汇编的雏形。
| 阶段 | state | RAM 地址取什么 | 做什么 |
|---|---|---|---|
| 取指令 | 0 | 指令地址 | 把指令读入指令寄存器 |
| 执行指令 | 1 | 数据地址 | 读数据、按指令运算/跳转 |
state 只在 0/1 之间切换 → 用一个 D 触发器实现;一条指令 = 两个时钟周期。
| 线 | 类型 | 作用 |
|---|---|---|
| A | 地址总线 | 传输寻址地址 |
| ld / str | 控制总线 | 表明"读"还是"写" |
| Din / Dout | 数据总线 | 传输数据 |
| CPU 寻址范围 | 设备 |
|---|---|
0b000 00000000 ~ 0b000 11111111 |
iRom(CPU 内置只读区,0~255) |
0b001 00000000 ~ 0b001 11111111 |
内存(外部扩展 RAM,256~511) |
0b010 00000000 ~ 0b010 11111111 |
磁盘(外部扩展 ROM,可持久化,512~767) |
0b011 00000000 |
终端(向此地址写低 8bit ASCII 即显示,768) |
CPU 上电 → 执行 iRom(只读、不可改)
→ iRom 引导:把硬盘前 32 条(引导区)拷贝到内存头 32 条
→ 跳转内存执行"引导程序"
→ 引导程序把硬盘自定义程序全部拷贝到内存
→ 跳转主程序执行
sel 控制信号就是指令本身(上篇 2.3)。_ia 后缀 = 立即数参与运算;否则按"数据 RAM 地址"处理。cmp_b x 先比较,jne/je 再跳)。ld/en_i 控制信号在电路层面"让路"。| 易混点 A | 易混点 B | 关键区别 |
|---|---|---|
| 数据 RAM | 指令 RAM | 存"要算的数" vs 存"ALU 控制信号";合并后靠"取指/执行两个阶段"区分 |
| 操作数=地址 | 操作数=立即数 | ld_a 7:7 可能是地址也可能是数;立即数指令多 _ia 后缀 |
| 冯诺依曼(单内存) | 哈佛(双内存) | 单内存一条数据线=指令+数据二选一(需两阶段);双内存可并行取指取数 |
| RAM | EEPROM | RAM 掉电丢、仅程序写;EEPROM 可预编辑/持久化(课件用它当硬盘) |
| jmp | je | 无条件跳转;比较寄存器相等才跳(配合 cmp_b) |
| 引导区(32 条) | 主程序 | 引导区只负责"搬运+跳转"的短程序,不是最终业务代码 |
0. ld_ia 0 / 1. ld_ib 1 / 2. jmp 5 / 3. add 0 / 4. add_ib 1 / 5. cmp_b 101 / 6. jne 3 / 7. save_a 16 / 8. halt 做什么?
> 答:0 到 100 求和——A 从 0 累加 B(=1 递增到 101),B≠101 则跳回第 3 条继续加,相等后把 A 存入内存 16 号地址并停止。add 0 编码为 0b00101?(提示 opcode=00010,操作数 0)
> 答:操作码 00010 + 11 位操作数 0000000000 → 0b0001000000000000(具体位宽以课件烧录格式为准,重点是"opcode+操作数"拼成一条 16 位指令)。save_a 0b011 00000000 的效果?
> 答:把寄存器 A 的低 8 位写到终端(0b011 前缀命中终端模块)→ 终端按 ASCII 显示一个字符。给计算单元接一块 EEPROM 当数据存储后,需要一个"逐条取数"的地址产生器:寄存器存地址 + 加法器恒 +1 + 时钟上升沿写回 → 输出 0,1,2,3…(这就是上篇 6.7 计算单元的延伸)。
halt 信号:换成真实震荡时钟后 PC 会 0,1,2,3,0,1,2,3… 反复执行 → 用比较器判断 PC==3,经与门暂停时钟输出终止程序。
想要 13+45-27-6:加一块 EEPROM 存 ALU 的 sel 序列(00 加、00 加、01 减、01 减),地址也接 PC → ALU 的 sel 控制信号 = 指令,这块 EEPROM 就是"指令存储"。于是计算机有了两块 RAM:数据 RAM + 指令 RAM。
双 RAM 不符合"一块内存编程"的直觉 → 合并成一块。但单内存一个时钟周期无法既传指令又传数据 → 把每条指令拆成两个时钟周期:
指令格式定型:操作码(opcode) + 操作数(addr),存进 RAM 的一个单元(如 ld_a → 0b00001 0000000100)。PC 扩成 11 位以匹配新寻址。
把每条指令的 opcode 对应到"每个开关该置 0 还是 1"——用 Digital 的查找表(LUT)直接实现:输入 5 位 opcode,输出 halt/ld/str/jmp/je/en_pc/en_a/sel_a/sel_b/sel_alu 等一排控制信号。
控制器本质上是一张 真值表/查表器——这是 FPGA 用 LUT 实现逻辑的底层原理,也和 [[07-半导体存储器|数电 07 用 ROM 实现组合逻辑]] 完全同源。
en_i 控制)——于是指令集扩出一整套 _ia 指令;ld_ib/add_ib 等指令)就能做多变量运算(x86 汇编里的 r8~r15 就是这套思想的放大版)。没有编译器也能"翻译-烧录-运行":
mov/add/cmp/jne/ret);ld_ia/add_ib/jmp/cmp_b/jne/save_a/halt…);把 CPU 的 A/str/ld/Dout/Din 五根线引出来接到外部设备 → 这五根线就是总线。问题:多个外部设备,Din 数据源冲突(会短路)→ 用 ld 和 en_i 控制信号决定"谁让路"。
地址映射方案:11 位地址 = 高 3 位设备编号 + 低 8 位设备内地址(见 2.4 表)。CPU 内部 RAM 电路限制只响应 0b000 前缀;内存模块响应 0b001(介质用 RAM,上电后由程序改写);磁盘模块响应 0b010(介质用 EEPROM 持久化);终端模块响应 0b011(en 有效时,时钟上升沿把低 8bit ASCII 显示出来)。最终 CPU 通过总线连接内存、硬盘、终端三台外部设备(图见 6.6)。
三块存储各司其职:iRom(CPU 内置只读)、内存(不可持久)、硬盘(持久)。上电先执行 iRom,而 iRom 代码是写死的 → 它的作用是"搬运":
为什么分两级?程序长度不定,iRom 一次只能搬固定长度 → 先搬一小段"引导程序",再由引导程序自由搬运,兼顾通用与效率。这就是真实 x86 的 MBR/GRUB 与单片机 bootloader 的思想原型(课件用它解释了"开机如何把硬盘里的程序送进内存")。
| 芯片 | 功能 | 用途 |
|---|---|---|
| 与/或/非门(SN74LVC1G08 等单门) | 基本逻辑 | 组合电路(本课 03) |
| 74HC245 | 8 位双向总线缓冲器/驱动器 | 总线增强驱动、隔离(DIP-20) |
| 74HC138 | 3-8 译码器 | 地址译码产生片选(DIP-16,见 04) |
| DS1302 | 实时时钟 RTC | 掉电走时(需电池),I2C/单线协议 |
买芯片三件套:看原理图、看封装(决定 PCB 焊盘)、查数据手册(决定引脚/参数/时序)。课件给每颗芯片附了立创商城购买链接与手册 PDF——动手项目选型的第一课。
来源:尚硅谷《从零搭建计算机》第 3 章(内存/控制器/立即数/B寄存器/合并RAM)+ 第 4 章(汇编/总线/地址映射)+ 第 5 章(引导程序)+ 第 6 章(常用芯片);关联 [[冯诺依曼体系结构]] 维基页