计算机组成原理_2_ALU

ALU:逻辑算术单元

1 实验要求

在ALU类中实现2个方法,具体如下

1.计算两个32位二进制整数补码真值的和

 public DataType add(DataType src, DataType dest)

2.计算两个32位二进制整数补码真值的差,dest表示被减数,src表示减数(即计算dest - src)

 public DataType sub(DataType src, DataType dest) 

3.在ALU类中实现实现整数的二进制乘法(要求使用布斯乘法实现)。
输入和输出均为32位二进制补码,计算结果直接截取低32位作为最终输出

 public DataType mul(DataType src, DataType dest)

2 实验攻略

2.1 代码实现要求

有些同学可能注意到,将传入的参数通过transformer转化为int,再通过整数的加减运算后,将结果重新转化为DataType即可轻松完成实验。在此,我们明确禁止各位采用这种方法来完成本次实验。

2.2 数据封装

从本次实验开始,我们采用统一的类DataType来封装32位的二进制数,包括二进制补码整数、NBCD码与IEEE754浮点数。核心数据结构如下

package util;

import java.util.Collections;

public class DataType {

    private final byte[] data = new byte[4];
// 下面代码不需要考虑,只需要知道是32位2进制数的一个包装类即可
    public DataType(String dataStr) {
        // 目前是大端实现,高位字节存放在低地址
        int length = dataStr.length();
        if (length == 8 || length == 16 || length == 32) {
            dataStr = String.join("", Collections.nCopies(32 - length, "0")) + dataStr;
            for (int i = 0; i < 32; i++) {
                char temp = dataStr.charAt(i);
                if (temp == '0' || temp == '1') {
                    data[i / 8] |= ((dataStr.charAt(i) - '0') << (7 - i % 8));
                } else {
                    throw new NumberFormatException("Illegal dataStr: " + dataStr);
                }
            }
        } else {
            throw new NumberFormatException("Illegal dataStr: " + dataStr);
        }
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            stringBuilder.append(Transformer.intToBinary(String.valueOf(data[i])).substring(24));
        }
        return stringBuilder.toString();
    }

}

采用这样的数据封装将保证DataType类中存放的一定是32位二进制数,并且有利于ALU等运算模块与其他模块的整合。为了方便编码,我们为DataType类提供了构造函数与toString函数,便于DataType对象与String对象之间的转化,具体可阅读DataType类源码。

3实现

3.0 取反加一操作

加一操作,额外使用jinWei 来代表加1 操作,再通过四个if-else 使得逻辑非常的清晰

    public static String reverse(String str) {
        char[] ansArr = new char[str.length()];
        for (int i = 0; i < ansArr.length; i++) {
            ansArr[i] = str.charAt(i) == '0' ? '1' : '0';
        }
        return new String(ansArr);
    }

    public static String oneAdder(String str) {
        char[] ansArr = new char[str.length()];
        int jinWei = 1;
        for (int i = 31; i >= 0; i--) {
            if (str.charAt(i) == '0' && jinWei == 1) {
                ansArr[i] = '1';
                jinWei = 0;
            } else if (str.charAt(i) == '0' && jinWei == 0) {
                ansArr[i] = '0';
            } else if (str.charAt(i) == '1' && jinWei == 1) {
                ansArr[i] = '0';
            } else if (str.charAt(i) == '1' && jinWei == 0) {
                ansArr[i] = '1';
            }
        }
        return new String(ansArr);
    }

3.1 32位补码加法

3.1.1 代码实现

对于加法操作,可以直接进行x+y+jinWei 的操作,而不需要分正负号

    /**
     * 返回两个二进制整数的和
     * dest + src
     *
     * @param src  32-bits
     * @param dest 32-bits
     * @return 32-bits
     */
    public DataType add(DataType src, DataType dest) {
        char[] ansArr = new char[32];
        Arrays.fill(ansArr, '0');
        char[] srcArr = src.toString().toCharArray();
        char[] destArr = dest.toString().toCharArray();
        boolean jinWei = false;
        String ans;
        for (int i = 31; i >= 0; i--) {
            if (srcArr[i] == '0' && destArr[i] == '0') {
                ansArr[i] = jinWei ? '1' : '0';
                jinWei = false;
            } else if (srcArr[i] == '1' && destArr[i] == '1') {
                ansArr[i] = jinWei ? '1' : '0';
                jinWei = true;
            } else {
                ansArr[i] = jinWei ? '0' : '1';
//                    jinWei状态不变
            }
        }
        ans = new String(ansArr);
        return new DataType(ans);
        /**
         * 加法直接进行加减,不需要管正负号
         */
    }
3.1.2 测试用例
package cpu.alu;

import org.junit.Test;
import util.DataType;
import util.Transformer;

import java.util.Random;

import static org.junit.Assert.assertEquals;

public class ALUAddTest {

    private final ALU alu = new ALU();
    private DataType src;
    private DataType dest;
    private DataType result;

    @Test
    public void AddTest1() {
        src = new DataType("10000000000000000000000000000000");
        dest = new DataType("00000000000000000000000000000100");
        result = alu.add(src, dest);
        assertEquals("00000000000000000000000000001000", result.toString());
    }

    @Test
    public void AddTest2() {
        src = new DataType("10000000000000000000000000000000");
        dest = new DataType("00000000000000000000000000000100");
        result = alu.add(src, dest);
        assertEquals("00000000000000000000000000001000", result.toString());
    }

    @Test
    public void mulTest() {
        for (int i = 0; i < 100000; i++) {
            Random random = new Random();
            int x = random.nextInt(999999999);
            int y = random.nextInt(999999999);
            src = new DataType(Transformer.intToBinary(String.valueOf(x)));
            dest = new DataType(Transformer.intToBinary(String.valueOf(y)));
            result = alu.add(src, dest);
            assertEquals(Transformer.intToBinary(String.valueOf(x + y)), result.toString());
        }
    }
}

3.2 32位补码减法

3.2.1 代码实现
  • 对于减法,只需要将被减数取反加1即可,这样子就能够得到对应的相反数的补码,从而实现由减法变为加法。
  • 在x86中,减法是dest-src
    /**
     * 返回两个二进制整数的差
     * dest - src
     */
    public DataType sub(DataType src, DataType dest) {
        /**
         * 减法直接把src取反加1即可,变为加法
         */
        return add(dest, new DataType(oneAdder(reverse(src.toString()))));
    }
3.2.2 测试用例
package cpu.alu;

import org.junit.Test;
import util.DataType;
import util.Transformer;

import static org.junit.Assert.assertEquals;

public class ALUSubTest {

    private final ALU alu = new ALU();
    private DataType src;
    private DataType dest;
    private DataType result;

    @Test
    public void SubTest0() {
        src = new DataType("00000000000000000000000000000001");   //2147483647
        dest = new DataType("10000000000000000000000000000001"); // -1
        result = alu.sub(src, dest); // -2147483648
        assertEquals("10000000000000000000000000000000", result.toString());
    }

    @Test
    public void SubTest1() {
        src = new DataType("01111111111111111111111111111111");   //2147483647
        dest = new DataType("11111111111111111111111111111111"); // -1
        result = alu.sub(src, dest);
        assertEquals("10000000000000000000000000000000", result.toString());
    }

    @Test
    public void SubTest2() {
        src = new DataType("11111111111111111111111111111000"); // -7
        dest = new DataType("00000000000000000000000000000111"); // 7
        result = alu.sub(dest, src); //-14
        assertEquals("11111111111111111111111111110001", result.toString());
    }

    @Test
    public void SubTest3() {
        src = new DataType("00000000000000000000000000000000");
        dest = new DataType("10000000000000000000000000000000");
        result = alu.sub(dest, src);
        assertEquals("10000000000000000000000000000000", result.toString());
    }

    @Test
    public void SubTest4() {
        src = new DataType("00000000000000000000000000000000");
        dest = new DataType("10000000000000000000000000000001");
        result = alu.sub(dest, src);
        assertEquals("01111111111111111111111111111111", result.toString());
    }

    @Test
    public void SubTest5() {
        src = new DataType("11111010001000011010110101011001"); //-98456231
        dest = new DataType("11111111111111101000000001001001"); //-98231
        result = alu.sub(dest, src);
        assertEquals("11111010001000110010110100010000", result.toString());
    }

    @Test
    public void SubTest6() {
        src = new DataType("11111111111111111111110000101000"); //-984
        dest = new DataType("00000000000000000000000011100111"); //231
        result = alu.sub(dest, src); //-1215 src - dest
        assertEquals("11111111111111111111101101000001", result.toString());
    }

    @Test
    public void SubTest7() {
        src = new DataType("01111111111111111111111111111111"); // 2147483647
        dest = new DataType("10000000000000000000000000000000"); // -2147483648
        result = alu.sub(dest, src);
        assertEquals("11111111111111111111111111111111", result.toString());
    }

    @Test
    public void SubTest8() {
        src = new DataType("01111111111111111111111111111111"); // 2147483647
        dest = new DataType("10000000000000000000000000000001"); // -2147483647
        result = alu.sub(dest, src);
        assertEquals("11111111111111111111111111111110", result.toString());
    }
}

3.3 32位补码加法

参考
布斯算法
其中 P n P_n Pn代表的是存储的乘法结果

3.3.1 代码实现
    public DataType mul(DataType src, DataType dest) {
        char[] srcArr = src.toString().toCharArray();
        char[] destArr = dest.toString().toCharArray();
        char[] ansArr = new char[32];
        char[] retArr = new char[32];
        Arrays.fill(retArr, '0');
        Arrays.fill(ansArr, '0');
        int y0 = 0;
        int y1 = 0;
        for (int i = 31; i >= 0; i--) {
            y1 = destArr[i] - '0';
            if (y1 == 1 && y0 == 0) {
//                进行减法,在部分积上减去 被乘数
                ansArr = sub(src, new DataType(new String(ansArr))).toString().toCharArray();
            } else if (y1 == 0 && y0 == 1) {
                ansArr = add(src, new DataType(new String(ansArr))).toString().toCharArray();
            }
            retArr[i] = ansArr[31];
            ansArr = rightMove(ansArr);
            y0 = y1;
        }
        return new DataType(new String(retArr));
    }

    public char[] rightMove(char[] str) {
        for (int i = str.length - 1; i >= 1; i--) {
            str[i] = str[i - 1];
        }
        return str;
    }

需要注意的是:

  1. 32*32位实际上得到的是64位乘法结果,因此我们需要取低32位作为结果
  2. 在这里,我们分别使用ansArrretArr 两个数组进行存储
  3. 因为实际上计算时,是高32位进行加减操作,因此我们用ansArr进行加减操作
  4. 同时,用retArr来记录低32位,从而得到结果。
3.3.2 测试用例
package cpu.alu;

import org.junit.Test;
import util.DataType;
import util.Transformer;

import static org.junit.Assert.assertEquals;

public class ALUMulTest {

	private final ALU alu = new ALU();
	private DataType src;
	private DataType dest;
	private DataType result;

	@Test
	public void MulTest1() {
//		11111111111111111111111111111101
		src = new DataType("00000000000000000000000000000110");
		dest = new DataType("11111111111111111111111111111101");
		result = alu.mul(src, dest);
		assertEquals("11111111111111111111111111101110", result.toString());
	}
	@Test
	public void MulTest2() {
//		11111111111111111111111111111101
		src = new DataType("00000000000000000000000000000010");
		dest = new DataType("00000000000000000000000000000010");
		result = alu.mul(src, dest);
		assertEquals("00000000000000000000000000000100", result.toString());
	}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值