最近在看RISC-V v1手册的中文译版,在第一章里面讲到ISA可以分为模块化的和增量化的,还举了很生动的例子来比喻两者
后来读胡伟武老师的《计算机体系结构》,里面从指令对于数据的使用方法的角度对ISA进行了分类,感觉很有意思
- 堆栈型(零地址指令)
- 操作数在栈顶,运算指令不用指定操作数
- 累加器型(单地址指令)
- 累加器是隐含操作数,指令中指定另一个操作数,结果写回累加器
- 寄存器型(每个操作数都由指令显式指定)
- 寄存器-存储器型
- 操作数是寄存器或内存地址
- 寄存器-寄存器型
- 操作数都是寄存器
- 寄存器-存储器型
只看文字肯定不好理解,不如直接看一个指令例子
堆栈型 | 累加器型 | 寄存器-存储器型 | 寄存器-寄存器型 |
---|---|---|---|
PUSH A PUSH B ADD POP C |
LOAD A ADD B STORE C |
LOAD R1, A ADD R1, B STORE C, R1 |
LOAD R1, A LOAD R2, B ADD R3, R1, R2 STORE C, R3 |
~~PUSH和POP都是对堆栈的操作,本应不该有后面的参数;~~PUSH A指的是把A从内存中取出来,然后压入堆栈;如果没有后面的参数A,那么压谁呢?
解释:PUSH A
把A从内存中取出来,压入堆栈;PUSH B
把B从内存中取出来,压入堆栈;ADD
把栈顶的两个数弹出,作为加法器的输入,并把输出压回栈;POP C
把栈顶的数弹出,存入内存单元C中
指令的隐含操作数是累加器
解释:LOAD A
把内存单元A存入累加器;ADD B
把累加器的值与内存单元B的值相加,并把结果写回累加器;STORE C
把累加器的值存入内存单元C
一个操作数是寄存器,一个操作数是内存地址
解释:LOAD R1, A
把内存单元A的值存入寄存器R1;ADD R1, B
把内存单元B的值和寄存器R1的值相加,并把结果写回R1;STORE C, R1
把寄存器R1的值存入内存单元C
两个操作数都是寄存器
解释:LOAD R1, A
把内存单元A的值存入寄存器R1;LOAD R2, B
把内存单元B的值存入寄存器R2;ADD R3, R1, R2
把寄存器R1和寄存器R2做加法,把结果写入寄存器R3;STORE C, R3
把寄存器R3写到内存单元C
可以从代码量和与内存交换的数据量两个方面来看
// 代码片段
A = B - C
D = A - C
B = D + A
注:假设,操作码占用8位,内存地址和操作数都是16位,寄存器型ISA有16个通用寄存器
堆栈型 | 累加器型 | 寄存器-存储器型 | 寄存器-寄存器型 | |
---|---|---|---|---|
汇编代码 | PUSH B PUSH C SUB POP A PUSH A PUSH C SUB POP D PUSH D PUSH A ADD POP B |
LOAD C NEG ADD B STORE A LOAD C NEG ADD A STORE D ADD A STORE B |
LOAD R1, B SUB R1, C STORE R1, A SUB R1, C STORE R1, D ADD R1, A STORE R1, B |
LOAD R1, B LOAD R2, C SUB R3, R1, R2 STORE R3, A SUB R4, R3, R2 STORE R4, D ADD R5, R4, R3 STORE R5, B |
代码量 | 12·1+9·2=30 | 10·1+8·2=26 | 7·1+7·2+7·1=28 | 8·1+5·2+5·1+3·2=29 |
与内存交换的数据量 | 30+9·2=48 | 26+8·2=42 | 28+7·2=42 | 29+5·2=39 |
结论:在代码量方面,累加器型ISA更优;在与内存交换的数据量方面,寄存器-寄存器型ISA更优
补充:因为指令必须是byte的整数倍。所以LOAD R1, B中的R1要占8bit;ADD R5, R4, R3中的R5和R4占8bit,R3占8bit