Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

指令系统基础

复习

  1. 第十八章:设计完成了算术逻辑单元(ALU),它可以完成多种运算
  2. 第二十七章:做出了累加器,它是运算部件的雏形
  3. 第二十八章:了解了时序逻辑电路与状态机

TL;DR

  • 硬件电路是“死“的,只能做固定的运算;要让机器做不同的事,就得引入“指令“
  • 一条指令 = 操作码(做什么)+ 操作数(对谁做)
  • 指令按功能分为:数据传送、算术运算、逻辑运算、控制转移
  • 指令格式有定长与变长两种,各有取舍

正文

从电路到指令

  回头看,我们造的电路都很“死“:加法器只会加,减法器只会减。如果想让机器做一件新事,就得重新接一次线,这显然不现实。

  就像钢琴,琴键按下去只能发出固定音高;真正让它能弹奏无数曲子的,是“乐谱“。我们也可以给计算机配一份“乐谱“——一串事先约定好的操作命令,让它照着做。

  这串命令,就叫指令(Instruction)

一条指令长什么样

  一条指令至少要说清两件事:

  1. 做什么?——这部分叫操作码(Opcode),比如“加““减”“跳转”
  2. 对谁做?——这部分叫操作数(Operand),可以是立即数、寄存器编号或内存地址

  举例来说,ADD R1, R2, R3 的意思就是“把 R2 和 R3 相加,结果放进 R1“。其中 ADD 是操作码,R1/R2/R3 是操作数。

  冯·诺依曼体系结构最天才的一点,就是把指令和数据一起放在存储器里。指令不再需要额外接线,而是和普通数据一样被读取、被处理。程序因此变成了可以存储在磁盘上、随时加载的东西。

常见的指令类型

  现实中的指令成百上千,但按功能大致分四类:

  1. 数据传送:搬运数据
    • MOV R1, R2:把 R2 的值复制到 R1
    • LOAD R1, [addr]:从内存读进寄存器
    • STORE [addr], R1:把寄存器写回内存
  2. 算术运算:加减乘除
    • ADDSUBMULDIV
  3. 逻辑运算:与或非、移位
    • ANDORNOTLSL(逻辑左移)等
  4. 控制转移:改变执行顺序
    • JMP:无条件跳转
    • BEQBNEBGT:满足条件才跳转

  前几类靠 ALU 就能完成,第四类则决定了程序能不能“拐弯“。

定长还是变长

  指令在机器里就是一串二进制码,怎么划分这些码,有两种设计:

  • 定长指令:所有指令一样长。译码简单、流水线友好,但可能浪费空间
  • 变长指令:指令长度不一。更省空间、表达能力更强,但译码复杂

  这就像快递盒:统一尺寸好装箱、好分拣,但不一定贴着货物;定制尺寸省材料,但分拣起来麻烦。两种路线各有代表(RISC 偏向定长,CISC 偏向变长),至今仍在竞争。

思考题

  为什么冯·诺依曼体系结构要把“指令“和“数据“放在同一个存储器里?这样做有什么好处,又可能带来什么问题?

小结

知识点

  • 指令与操作码、操作数
  • 存储程序思想
  • 指令的四大类型
  • 定长与变长指令格式

参考资料

  1. Wikipedia(zh):指令集架构:指令集的基本概念
  2. Wikipedia(zh):汇编语言:低级编程语言
  3. Wikipedia(zh):RISC:精简指令集计算机

思考题答案(仅供参考)

  好处:指令像数据一样存在内存里,程序可以被灵活加载、修改,硬件只需一套取指-译码-执行的机制,通用性大大增强。问题:指令和数据混在一起,如果程序出错、跳转到数据区去执行,就会把数据当指令执行,这既是“程序可以自我修改“的灵活之处,也是很多漏洞(如缓冲区溢出攻击)的根源。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪