指令集
指令集架构(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 模型:相当于是一个单元素存储。
load B => ACC = mem[B]
add C => ACC = ACC + mem[C]
store A => mem[A] = ACC
栈模型:有一个隐式的栈顶。
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)规定了如何访问计算地址的语义。
注意虚拟地址与物理地址的转换。