从1位到64位:深入解析算术逻辑单元(ALU)设计与RISC-V指令实现
从1位到64位:深入解析算术逻辑单元(ALU)设计与RISC-V指令实现
算数逻辑单元(Arithmetic Logic Unit,ALU)是处理器的核心部分,负责对操作数进行算术和逻辑运算。本文将对ALU的内部构造及其工作原理进行深度剖析,并提供ALU的Verilog代码,方便大家学习。
1-Bit ALU
我们从零开始,循序渐进,从1位逐渐过渡到64位的ALU。
逻辑运算
1位的逻辑运算很简单,AND和OR运算如下图所示:
a和b分别接入到与门和或门,然后再通过选择器,选择输出的结果(Result)。
Result = (a·b)·(!Operation)+(a+b)·Operation
算术运算
一位全加法器的框图抽象如下:
可以得出:
CarryOut = (a+b)·CarryIn + a·b
Sum = a ^ b ^ CarryIn
^为异或
于是有下图:
Sum同理,我们就不详细说明了
64-bit ALU
级联
1位的ALU通过简单的级联,如同串行进位加法器一样,就可以形成64位的ALU,如下:
功能扩展
- Sub
在计算机中,补码计算
因为A + !A = -1
所以 A - B = A + (! B )+ 1
因而做减法则需要对减数取反相加,然后再加1,这里刚好可以对输入进位置位
- Nor
! ( a + b ) = ! a · !b
- Slt
在RISC-V架构中,需要支持slt指令的硬件连接
slt : set less than;
slt指令结果与rs1, rs2的大小有关
如果rs1 < rs2, 则结果的非最低位为0,最低位为1(set)
如果rs1>=rs2, 则结果的非最低位为0,最低为为0(reset)
要判断a和b的大小,我们可以前面减法的基础上,进行判断
如果a < b, a - b <0; 那么输出结果为负,对应的符号位为1;
反之,结果为非负,对应的符号位位0
这里很有意思的巧合就是,结果的符号位刚好满足slt的操作要求
因而,我们可以将最高符号位,连接回最低位
- Zero
在RISC-V架构指令架构中,除了加减还有逻辑运算之外,我们还需要支持决策指令,如beq
beq r1, r2, THEN
如果r1 = r2, 跳转到THEN语句
否则,执行接下来的指令
那么该如何判断r1 = r2呢?
我们可以使用减法
(a - b = 0)<=> a = b
那么可以有Zero信号
Zero = !(Result63 + Result62 +Result61+…Result1 + Result 0)
只用当所有的位的结果都相等(Resulti = 0, i=0,1,…63),即
Result63 + Result62 +Result61+…Result1 + Result0=0
Zero才为高
每次进行减法判断的时候,CarryIn会被置1,同时B会被取反(通过Binvert选择器选择),因而我们可以将CarryIn和Binvert简化为一个控制信号Bnegate。
同时我们加入Overflow(溢出)检测
指令字段
那么ALU是如何与指令相连接起来的呢?
答案就藏在指令的指令的字段里面,我们在深入剖析RISC-V指令:类型、编解码与工作原理中有提到指令可以分成很多有效字段,它们决定了指令的类型和操作。
处理器在读取指令时,因为不同指令的操作和操作对象不一样,因而在操作的时候,处理器的控制单元会对funct段进行编码,与控制信号建立联系。控制信号对应的操作与ALU进行的功能如下:
funct字段和控制信号的具体联系和原因,不是本篇文章的重点,我们后面会提到。
代码
// ALU模块
module ALU(
input [3:0] ALUctrl,
input [63:0] A,
input [63:0] B,
output reg [63:0] ALUOut,
output Zero
);
assign Zero = (ALUOut == 0); // 零标志生成
always @(*) begin // 使用组合逻辑敏感列表
case (ALUctrl)
4'b0000: ALUOut = A & B; // AND
4'b0001: ALUOut = A | B; // OR
4'b0010: ALUOut = A + B; // ADD
4'b0110: ALUOut = A - B; // SUB
4'b0111: ALUOut = (A < B) ? 64'd1 : 64'd0; // SLT
4'b1100: ALUOut = ~(A | B); // NOR
default: ALUOut = 64'd0; // 默认安全值
endcase
end
endmodule
// 修改后的ALU控制模块
module ALUControl(
input [1:0] ALUOp,
input [5:0] FuncCode,
output reg [3:0] ALUCtrl
);
//整个RSIC-V 有很多类型的指令,此处只做一些常见的指令的编码;
always @(*) begin
case (ALUOp)
2'b00: ALUCtrl = 4'b0010; // 加法(用于lw/sw/addi)
2'b01: ALUCtrl = 4'b0110; // 减法(用于beq)
2'b10: begin // R-type指令
case (FuncCode)
6'b10_0000: ALUCtrl = 4'b0010; // ADD
6'b10_0010: ALUCtrl = 4'b0110; // SUB
6'b10_0100: ALUCtrl = 4'b0000; // AND
6'b10_0101: ALUCtrl = 4'b0001; // OR
6'b10_0111: ALUCtrl = 4'b1100; // NOR
6'b10_1010: ALUCtrl = 4'b0111; // SLT
default: ALUCtrl = 4'b1111; // 未知操作
endcase
end
default: ALUCtrl = 4'b1111; // 异常操作码处理
endcase
end
endmodule