指令集

指令集架构(Instruction Set Architecture, ISA)是软硬件之间的契约 contract;它定义软件能够看到与使用的硬件行为。设计 ISA 时,需要考虑:programmability(程序是否容易表达?)、implementability(是否容易在硬件上实现?)与 compatibility(是否能长期有效兼容?)。

执行模型与并行

ISA 的两种执行模型(execution model):冯诺依曼模型 Von Neumann 与数据流模型 dataflow。

Von Neumann 模型维护一个 PC,根据顺序不断推进程序执行。而 dataflow 模型把程序建模成一张依赖图,其中的节点只要数据准备好就能触发操作。相比 Von Neumann,dataflow 显式地暴露出程序的并行机会。

Von Neumann 的指令格式通常是 [opcode] [src reg1] [src reg2] [dst reg],指令 X 在指令 X+1 之前完成。而 dataflow 的指令格式通常是 [opcode] [dst ins1] [dst ins2],每次挑选一个或多个准备完毕的指令 fire 即可。

dataflow 模型暴露的显式并行机会是有代价的。

  • 同一指令的迭代运行(如 for-loop),需要通过 ordering 或 tagging 等机制防止并发打乱顺序。
  • 运行中的程序更难暂停 => 可能使 debugging 异常痛苦!
  • ...

现代处理器(e.g., ooo core)结合了两种思路,对外使用 Von Neumann ISA,对内则在有限窗口内使用 dataflow 按依赖调度。

此外,ISA 还可以从语义上表达并行。

  • 标量指令(scalar instruction):无并行,寄存器的数据类型是标量
  • 向量指令(vector instruction):需要硬件实现数据级并行(DLP),可表示 single instruction over multiple data(SIMD),寄存器的数据类型是宽向量
  • VLIW(very-long instruction word):需要硬件实现指令级并行(ILP),把可并行的指令放进一个指令包,寄存器的数据类型是标量

向量指令与 VLIW 对编译器的要求都很高。

操作数模型

操作数模型(operand model)规定了如何保存中间结果的语义。

课上介绍了以下几种:

memory-only 模型:直接操作存储。add B,C,A => mem[A]=mem[B]+mem[C]。不实用。

accumulator 模型:相当于是一个单元素存储。

code
load  B => ACC = mem[B]
add   C => ACC = ACC + mem[C]
store A => mem[A] = ACC

栈模型:有一个隐式的栈顶。

code
push B => stk[TOS++] = mem[B]
push C => stk[TOS++] = mem[C]
add    => stk[TOS++] = stk[--TOS] + stk[--TOS]
pop A  => mem[A] = stk[--TOS]

通用寄存器(general-purpose register):提供多个可用的 accumulator。e.g., x86。

GPR with only load-store:有通用寄存器,并且只能通过 load 与 store 与存储交互。e.g., MIPS。

操作数模型的衡量标准:静态代码的长短、存储访问流量的大小、CPI。

寻址

寻址(memory addressing)规定了如何访问计算地址的语义。

注意虚拟地址与物理地址的转换。

控制流

指令编码

RISC v.s. CISC