分享免费的编程资源和教程

网站首页 > 技术教程 正文

计算机组成原理(7): Beta ALU指令(ALU Instructions)

goqiw 2025-03-14 16:53:39 技术教程 14 ℃ 0 评论

ALU指令有三种类型:

  • 计算指令:对寄存器值进行数学或逻辑计算
  • 加载和存储指令:在寄存器和主存之间移动数据
  • 分支指令:改变PC值

Bata ISA的所有指令等长(32位,占用主存里的一个字,4字节),与可变长度指令相比

  • 优点:简化控制逻辑单元的解码过程,易于计算下一个PC值
  • 缺点:编码长度更长(固定长度编码)。

下面分别介绍三种类型的指令。

变量和变量的计算指令

其中:

  • OPCOD是操作代码,6bits。这意味着最多有64()种运算
  • 是目的寄存器的代码,5bits。用于存储计算结果
  • 是源操作数所在寄存器的代码,各占5bits。用于指定参与运算的数值

有效代码一种是21位,却要占32位的1个字。所以说编码的长度更长。内存利用率不高。

以加法运算为例

其指令格式为

  • OPCODE=10000代表的是加法,为了方便起见,编码为ADD
  • =00011的含义是内部寄存器 ,编码为R3
  • =00001的含义是内部寄存器 ,编码为R1
  • =00010的含义是内部寄存器 ,编码为R2

最终该条指令的16进制表达为0x80611000。这样人理解起来非常困难。所以我们最好用功能表达,这样可读性强,如下:ADD(r1,r2,r3)

实际上在CPU内部就是:

实际电路上发生了:

  • 操作数选择器的控制信号为
  • 目的寄存器选择器的控制信号为
  • 程序计数器寄存器 PCPC+4。

如下图:

通过上图,我们可以看到,RISC指令集的优点之一就是:指令解码不需要太多的逻辑来控制数据路径。

满足该格式的指令

  • 算术:ADD、SUB、DIV
  • 比较:CMPEQ、CMPLT、CMPLE
  • 逻辑:AND、OR、XOR、XNOR
  • 移位:SHL、SHR、SAR

变量和常量的计算指令

很多程序会经常使用小常量(如1,-1,0 等)。这样就对ISA设计师提出了一个功能请求:允许小的常量作为ALU指令中的第二个操作数。

因此我们在指令中占用原先使用的5bits,与后面的11位构成了表示常量的16bits。

这样能够表达小常量的值的范围是

其指令格式为:

其中:

  • OPCOD是操作代码,6bits。这意味着最多有64()种运算
  • 是目的寄存器的代码,5bits。用于存储计算结果
  • 是源操作数所在寄存器的代码,占5bits。用于指定参与运算的数值
  • 后11位是小常量

以加法运算为例

其指令格式为:

  • OPCODE=11000代表的是加法,为了方便起见,编码为ADDC
  • =00011的含义是内部寄存器 ,编码为R3
  • =00001的含义是内部寄存器 ,编码为R1
  • 常量=11111111101的含义-3的补码。这里有一个技术细节,小常量-3是11bits。

最好用功能表达,这样可读性强,如下:ADDC(r1,-3,r3)

实际上在CPU内部就是:

这里有一个技术细节,小常量-3是16bits。数据路径的硬件如何从-3的16位表现形式转换到32位表现形式?

硬件需要执行的操作是“符号扩展”,将16位小常量的最高位复制16次形成32位的高半部分。这样与小常量就构成了32位小常量。硬件上可以做到无需额外的逻辑门就能实现符号扩展。

实际电路上发生了:

  • 操作数选择器的控制信号为,小常量控制信号bsel=1
  • 目的寄存器选择器的控制信号为
  • 程序计数器寄存器 PCPC+4。

如下图:

需要注意的是,如果一个常量太大,无法用16位正确表达,那么我们需要以32位的形式将它存储在主存中,像使用变量一样,使用时将其加载到寄存器中。

满足该格式的指令

  • 算术:ADDC、SUBC、DIVC
  • 比较:CMPEQC、CMPLTC、CMPLEC
  • 逻辑:ANDC、ORC、XORC、XNORC
  • 移位:SHLC、SHRC、SARC

内存访问指令(Memory Access)

由于Beta ISA是加载-存储架构,所以加载和存储是访问内存值的唯一方法。

格式如下:

加载:从主内存读取数据到寄存器

存储:从寄存器写回主存

为了访问内存,CPU需要产生内存地址,式中:Mem[Reg[ra]+sext(const)] 是内存地址,计算可以用ADDC指令完成。

  1. 如果使用常量地址,可以指定R31作为,这是因为R31寄存器恒为0,和一个16位的带符号的相加,可以将16位扩展位32位。
  2. 如果就是寄存器的值作为内存地址,可以指定常量为0

使用LD和ST指令

上面是使用小常量的地址的用法,对于大常量可用LDRSTR指令。

分支指令(Branches)

可以用分支指令实现循环、条件、过程、调用等功能。格式如下:

offset 偏移量

这里的分支使用的是PC相对地址,也就是说分支目标的地址是相对于分支的下一个指令的地址而言的。offset=0表示分支的下一个指令,offset=-1表示分支本身。

  • 向后分支(backward branch):offset为负值,经常在循环结束的分支处使用,用于回到循环的开头
  • 向前分支(forward branch):offset为正值,在if条件判断中需要向前跳过一些步骤时使用

示例,实现阶乘

用C语言编程,代码如下:

int a= 1;
int b= N;
do {
     a = a*b;
     b = b-1;
} while (b != 0)

假定r1=N,则用指令实现如下:

  ADDC(r31,1,r0)  //r0=1
L:MUL(r0,r1,r0)   //r0=r0*r1
  SUBC(r1,1,r1)   //r1=r1-1
  BNE(r1,L,r31)   //if r1!=0 run MUL next,r31=0
                         //at this point,r0=N!

跳转指令(Jumps)

分支指令可以将控制传递给由常数计算得的目标位置,JMP指令则可以将控制传递给预先计算好的地址。格式如下:


所谓CPU设计,就是设计出硬件电路满足各项指令要求的运算和操作。而指令是跟ISA密切相关的。

所以在CPU的设计中,首先要搞清楚指令集架构ISA。这里所用的Beta ISA是32位的,以此为例介绍CPU的设计。但设计方法和逻辑是通用的。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表