问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

从1位到64位:深入解析算术逻辑单元(ALU)设计与RISC-V指令实现

创作时间:
作者:
@小白创作中心

从1位到64位:深入解析算术逻辑单元(ALU)设计与RISC-V指令实现

引用
CSDN
1.
https://blog.csdn.net/JInx299/article/details/145851947

算数逻辑单元(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,如下:

功能扩展

  1. Sub

在计算机中,补码计算

因为A + !A = -1

所以 A - B = A + (! B )+ 1

因而做减法则需要对减数取反相加,然后再加1,这里刚好可以对输入进位置位

  1. Nor
! ( a + b ) =  ! a  ·  !b
  1. 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的操作要求

因而,我们可以将最高符号位,连接回最低位

  1. 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
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号