• Rocket core ALU


    https://mp.weixin.qq.com/s/C6Twva47PDyUev-BLhKLug

     

    简单介绍ALU的实现。

     

     

    1. object ALU

     

    ALU对象中定义了ALU要使用的一些常量和辅助方法。

     

    1) 常量

     

    a. SIZE_ALU_FN: 表示ALU操作类型的占用的宽度为4位;

     

    需要注意的是,这个位数只是用来表示操作类型,而不是指令中的宽度。

    比如ADDI指令中的func3域只占用3位,并且与SLTI/SLTU的值相同:

    而FN_ADD/FN_SLT/FN_SLTI占用4位,并且有不同的值:

     

    b. FN_ADD: 相加;

    c. FN_SL: 左移;

    d. FN_SR: 右移;

    e. FN_SEQ: 相等时置位;

    f. FN_SNE: 不相等时置位;

    g. FN_SLT: 小于时置位;

    h. FN_SGE: 大于等于时置位;

    i. FN_SLTU: 小于(作为无符号数进行比较)时置位;

    j. FN_SGEU: 大于等于(作为无符号数进行比较)时置位;

    k. FN_XOR: 异或;

    l. FN_OR: 按位或;

    m. FN_AND: 按位与;

    n. FN_SUB: 相减;

    o. FN_SRA: arithmetic right shift,带符号右移;

    p. 乘除法相关的类型:

    在规范中描述如下:

     

    2) 辅助方法

     

    定义对操作类型进行判断的辅助方法:

    其中:

    a. isMulFN:判断是否乘法操作;

    b. isSub:判断是否减法;

    c. isCmp:判断是否比较操作;

    d. cmpUnsigned:判断是否无符号数相比较;

    e. cmpInverted:判断是否基本判断的相反判断,比如相等是基本判断,不等是相反判断:

    f. cmpEq:是否相等判断;

     

    2. class ALU

     

    用于实现ALU的逻辑:

     

    1) io

     

    定义ALU模块的IO接口:

    其中:

    a. dw:数据宽度;

    b. fn:功能类型;

    c. in2:第二个操作数;

    d. in1:第一个操作数;

    e. out:输出结果;

    f. adder_out:加法器输出;

    g. cmp_out:比较结果输出;

     

    2) ADD/SUB

     

    实现ADD/SUB指令:

    其中:

    a. 根据操作类型是否是减法,确定io.in2是否需要取反;

    b. 如果不是减法,则in2_inv等于io.in2,而io.adder_out是相加的结果;

    c. 如果是减法,则使用取反加一的方法进行计算;

     

    3) SLT/SLTU

     

    实现SLT/SLTU操作的逻辑:

    A. 首先,判断符号位是否相同,如果相同,则取决于io.adder_out的符号位。

    此时io.adder_out中是什么呢?

    从SLT/SLTU的定义可以看出:

    其第3位都是1,也就是isSub为真:

    所以,io.adder_out中的值为io.in1-in.in2的差值;

    进而:

    a. 如果差值为负数,其符号位为1,表明io.in1 < io.in2;

    b. 如果差值非负数,其符号位为0,表明io.in1 >= io.in2;

     

    B. 其次,如果io.in1和io.in2的符号位不同,则需要区分是否要把二者看做无符号数进行比较。

    a. 如果按照无符号数进行比较,在二者符号不同的前提下,如果io.in2的符号位为1,则io.in2较大,less than为真;

    b. 如果按照有符号数进行比较,在二者符号不同的前提下,如果io.in1的符号位为1,则io.in2较大,less than为真;

     

    C. 先不考虑cmpEq,io.cmp_out := cmpInverted ^ slt,表示是否要把比较结果取反。

    如果cmpInverted为1,则取反;为0,则不取反。

     

    D. cmpEq的定义为:

    表示cmd小于8,即:

    可以看到slt/sltu都是大于8,所以cmpEq对slt指令的比较结果不影响。

     

    小于8的操作类型里面,意义为比较的操作类型为:SEQ/SNE。其实现为:

    a. 当io.fn为SEQ/SNE时,in1_xor_in2 = in1 ^ in2;

    b. in1_xor_in2为0,表示in1和in2中的各个比特都相同,也就是二者相等;

    c. 根据cmpInverted的值,决定判断结果是否需要取反;

     

    E. 这里把cmpEq和slt混合在一起的原因,是为了复用cmpInverted的判断逻辑。

     

    4) SLL/SRL/SRA

     

    实现SLL/SRL/SRA操作:

    A. shamt是shift amount的缩写,意指移位的数量;

    B. 当xLen == 32时,移动的位数shamt最多为32位,所以取io.in2的低5位;被移位的数据为io.in1;

    C. 当xLen != 32时,要求xLen必须是64,否则不支持。然后对io.in1进行补位处理:

    a. SLL/SRL/SRA中只有SRA的值大于8,其对应的isSub为真:

    如果是SL/SR,则可能用于补位的数据为32个0;

    如果是SRA,则可能用于补位的数据取决于io.in1的符号位,如果其符号位是1,则补位32个1,如果其符号位为0,则补位32个0:

    b. 如果io.dw为64位,则说明io.in1是64位的,不需要补位;如果不是,则需要使用shin_hi_32补位:

    c. 如果操作的数据宽度为32位,则移位的最大位数为32位,忽略io.in2的第5位;如果操作的数据宽度为64位,则需要使用io.in2的第5位来确定移位的位数:

    d. 返回移位数量和补位后的待移位数:

     

    D. 使用Reverse把左移操作转变为右移操作:

    a. 如果是右移操作,则不需要改变shin_r;

    b. 如果不是右移操作,即是SLL操作,把shin_r逆序;

     

    E. 把shin作为有符号数,向右移位,而后取移位结果的低xLen位:

    其中:

    a. asSInt把待移位数转变为SInt类型,调用其右移方法;有符号数的右移会补符号位;

    b. Cat(isSub(io.fn) & shin(xLen-1), shin)用于为shin添加一个正确的符号位:

    a) 如果不是SRA,则isSub为0,添加符号位0,对应逻辑移位应该以0补位;

    b) 如果是SRA,则取决于shin的符号位,再补一个符号位不改变其值;

    可以看到引入这段逻辑,不是为了b),而是为了a)。

     

    在a)中,isSub(io.fn) & shin(xLen-1)的结果是0,如果shin的符号位是0,则补位没有意义。可见这里补0是为了修正shin的符号位为1的情况。

    在操作类型(io.fn)为SLL/SRL的情况下,这里有如下可能:

    a.a. xLen == 32,io.fn == SRL,io.in1为负数;

    a.b. xLen == 32,io.fn == SLL,io.in1最低位为1;

    a.c. xLen == 64,io.dw == 64,io.fn == SRL,io.in1为负数;

    a.d. xLen == 64,io.dw == 64,io.fn == SRL,io.in1最低位为1;

     

    F. shout_r逆序之后为左移的结果:

     

    G. 根据操作类型计算移位结果:

    其中:

    a. 如果操作类型为SR/SRA,则使用shout_r;

    b. 如果操作类型为SL,则使用shout_l;

     

    5) AND/OR/XOR

     

    实现AND/OR/XOR操作:

    其中:

    a. 如果操作为XOR,则使用in1_xor_in2 = in1 ^ in2;

    b. 如果操作为AND,则使用in1 & in2;

    c. 如果操作为OR,则结果位(in1 ^ in2) | (in1 & in2);(只有一个1的位,加上有两个1的位);

     

    6) 根据操作类型,决定shift_logic的取值:

    因为操作类型同时只能去一个值,所以shift_logic的值,是从slt/logic/shout中选择一个。

     

    7) 根据是否加减法操作,决定输出adder_out还是shift_logic:

     

    8) 结果从io.out输出:

     

    9) 根据xLen及操作的数据宽度,决定是否需要对结果进行补位:

     

  • 相关阅读:
    screenHeight和windowHeight的区别
    背景图及首次引导加载图片会闪烁、图片预加载
    项目模板
    后端返回一段字符串模板,前端如何解析?
    echarts 饼图label显示指定数据
    html2canvas页面生成图片并添加水印
    js 面试题总结
    如何快速绘制任意角度的扇形?
    纯HTML+CSS 拉窗帘效果
    常用regex正则表达式
  • 原文地址:https://www.cnblogs.com/wjcdx/p/16041079.html
Copyright © 2020-2023  润新知