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

活动发起人@小虚竹 想对你说:

这是一个以写作博客为目的的创作活动,旨在鼓励大学生博主们挖掘自己的创作潜能,展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴,那么,快来参加吧!我们一起发掘写作的魅力,书写出属于我们的故事。我们诚挚邀请你参加为期14天的创作挑战赛!

提醒:在发布作品前,请将不需要的内容删除。

手把手教你搭建算术逻辑单元

算数逻辑单元, Arithmetic Logic Unit是处理器的核心部分,它负责对操作数进行算术和逻辑运算。本篇文章,将对ALU的内部构造经以及其工作原理经行深度剖析,其实ALU没有你想到这么复杂。此外,我会用提供ALU的Verilog代码,方便大家学习

在这里插入图片描述

1-Bit ALU

我们从零开始,循序渐进,从1bit逐渐过渡到64bit的ALU。

逻辑运算

1 bit的逻辑运算很简单,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,这里刚好可以对输入进位置位

在这里插入图片描述

2. Nor

  ! ( a + b ) =  ! a  ·  !b

在这里插入图片描述

3. 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的操作要求

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

在这里插入图片描述

**4.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经行的功能如下:
在这里插入图片描述

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JINX的诅咒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值