计组机试盘点

2023年12月7日 作者 ScotI_Blog

programming07

实验要求是分别实现实模式、分段式、段页式三种内存的地址转换与数据加载功能

资料核心点:

实模式和保护模式都是CPU的工作模式的一种。

实模式出现于早期8088CPU时期。当时由于CPU的性能有限,一共只有 20 位地址线(所以地址空间只有1MB),以及一些 16 位的寄存器。为了能够通过这些 16 位的寄存器去构成 20 位的主存地址,通常需要用两个寄存器,第一个寄存器表示基址,第二个寄存器表示偏移量。那么两个 16 位的值如何组合成一个 20位的地址呢?实模式采用的方式是把基址先向左移 4 位,然后再与偏移量相加。即:

物理地址 = 基址 << 4 + 偏移量

而在本实验中,

logicAddr 48= 16位段寄存器 + 32offset,计算公式为:①(16-bits段寄存器左移4+ offset的低16-bits) = 20-bits物理地址 ②高位补032-bits
@return 32-bits实模式线性地址

因为物理地址只有20位,所以只要偏移量有效的低20位即可,为了最后是32位注意使用inttobinary转换可以自动补齐至32位

分段过程实现将逻辑地址转换为线性地址,分页过程再实现将线性地址转换为物理地址。

段选择符和段寄存器

段选择符存放在段寄存器中,共有 6 个段寄存器: CS、SS、DS、ES、FS和GS。其中,CS是代码段寄存器,指向程序代码所在的段。SS是栈段寄存器,指向栈区所在的段。DS是数据段寄存器,指向程序的全局静态数据区所在的段。其他 3 个段寄存器可以指向任意的数据段。

段描述符

段描述符是一种数据结构,实际上就是分段方式下的段表项。一个段描述符占用 8 个字节,其一般格式如下图所示,包括 32 位的基地址(Base)、 20 位的限界(SegLimit)和一些属性位。属性位比较多,我们只介绍属性位G。

属性位G表示粒度大小。G=1说明段以页(4KB)为基本单位,G=0则段以字节为基本单位。由于界限为20 位,所以当G=0时,最大的段为1B * 2^20 = 1MB。当G=1时,最大的段为4KB * 2^20 = 4GB。

Programming 05 cache

package memory.cache;

import memory.Memory;
import memory.cache.cacheReplacementStrategy.ReplacementStrategy;
import util.Transformer;
import java.util.Arrays;

/**
 * 高速缓存抽象类
 */
public class Cache {

    public static final boolean isAvailable = true; // 默认启用Cache

    public static final int CACHE_SIZE_B = 32 * 1024; // 32 KB 总大小

    public static final int LINE_SIZE_B = 64; // 64 B 行大小

    private final CacheLine[] cache = new CacheLine[CACHE_SIZE_B / LINE_SIZE_B];

    private int SETS;   // 组数

    private int setSize;    // 每组行数

    // 单例模式
    private static final Cache cacheInstance = new Cache();

    private Cache() {
        for (int i = 0; i < cache.length; i++) {
            cache[i] = new CacheLine();
        }
    }

    public static Cache getCache() {
        return cacheInstance;
    }

    private ReplacementStrategy replacementStrategy;    // 替换策略

    public static boolean isWriteBack;   // 写策略

    /**
     * 读取[pAddr, pAddr + len)范围内的连续数据,可能包含多个数据块的内容
     *
     * @param pAddr 数据起始点(32位物理地址 = 26位块号 + 6位块内地址)
     * @param len   待读数据的字节数
     * @return 读取出的数据,以char数组的形式返回
     */
    public byte[] read(String pAddr, int len) {
        byte[] data = new byte[len];
        int addr = Integer.parseInt(Transformer.binaryToInt("0" + pAddr));
        int upperBound = addr + len;
        int index = 0;
        while (addr < upperBound) {
            int nextSegLen = LINE_SIZE_B - (addr % LINE_SIZE_B);
            if (addr + nextSegLen >= upperBound) {
                nextSegLen = upperBound - addr;
            }//get the length of the next segment
            //if exceed the upper bound, then set the length to the rest of the data
            int rowNO = fetch(Transformer.intToBinary(String.valueOf(addr)));
            byte[] cache_data = cache[rowNO].getData();
            int i = 0;
            while (i < nextSegLen) {
                data[index] = cache_data[addr % LINE_SIZE_B + i];
                index++;
                i++;
            }
            addr += nextSegLen;
        }
        return data;
    }

    /**
     * 向cache中写入[pAddr, pAddr + len)范围内的连续数据,可能包含多个数据块的内容
     *
     * @param pAddr 数据起始点(32位物理地址 = 26位块号 + 6位块内地址)
     * @param len   待写数据的字节数
     * @param data  待写数据
     */
    public void write(String pAddr, int len, byte[] data) {
        int addr = Integer.parseInt(Transformer.binaryToInt("0" + pAddr));
        int upperBound = addr + len;
        int index = 0;
        while (addr < upperBound) {
            int nextSegLen = LINE_SIZE_B - (addr % LINE_SIZE_B);
            if (addr + nextSegLen >= upperBound) {
                nextSegLen = upperBound - addr;
            }
            int rowNO = fetch(Transformer.intToBinary(String.valueOf(addr)));
            byte[] cache_data = cache[rowNO].getData();
            int i = 0;
            while (i < nextSegLen) {
                cache_data[addr % LINE_SIZE_B + i] = data[index];
                index++;
                i++;
            }
            //TODO but done
            //write the data according to the write strategy
            //1. write through
            if(!isWriteBack){
                //dirty bit is always 0
                //write the data to memory
                Memory.getMemory().write(pAddr, len, data);
                //update the cache and using strategy
                addTimeStamp();
                update(rowNO, getTag(pAddr), cache_data);
                setTimeStamp(rowNO);
            }
            else{
                //get the dirty bit
                cache[rowNO].dirty = true;
                //update the cache and using strategy
                addTimeStamp();
                update(rowNO, getTag(pAddr), cache_data);
                setTimeStamp(rowNO);
            }

            addr += nextSegLen;
        }
    }

    /**
    * 从32位物理地址(26位块号 + 6位块内地址)获取目标数据的tag
     * 首先将32位物理地址转换为26位,然后将其前面补0至32位
    * @param pAddr 32位物理地址
    * @return 数据的tag
    *
     */
    public char[] getTag(String pAddr) {
        int tagSize = 26 - (int) (Math.log(SETS) / Math.log(2));
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 26 - tagSize; i++) {
            builder.append("0");
        }
        builder.append(pAddr.substring(0, tagSize));
        return builder.toString().toCharArray();
    }

    /**
     * 查询{@link Cache#cache}表以确认包含pAddr的数据块是否在cache内
     * 如果目标数据块不在Cache内,则将其从内存加载到Cache
     *
     * @param pAddr 数据起始点(32位物理地址 = 26位块号 + 6位块内地址)
     * @return 数据块在Cache中的对应行号
     */
    private int fetch(String pAddr) {
        //TODO but done
        int blockNO = getBlockNO(pAddr);
        int rowNO = map(blockNO);
        int start = (blockNO%SETS)*setSize;
        int last = start + setSize;
        //get the tag
        char[] tag = getTag(pAddr);
        //if didn't hit
        if(rowNO == -1){
            //get the data from memory(pAddr is 26 bits but the address in memory is 32 bits)
            byte[] data = Memory.getMemory().read(pAddr.substring(0,26)+"000000", LINE_SIZE_B);
            int availableRow = -1;
            //find an available row
            for(int i = start; i < last; i++){
                if(!cache[i].validBit){
                    availableRow = i;
                    break;
                }
            }
            //if there is an available row
            if(availableRow != -1){
                //update the cache
                addTimeStamp();
                update(availableRow, tag, data);
                //update the strategy
                setTimeStamp(availableRow);
                rowNO = availableRow;
            }
            else{
                //if there is no available row
                //replace the row
                int replace = replacementStrategy.replace(start, last, tag, data);
                if(cache[replace].dirty){
                    //if the dirty bit is 1
                    //write the data to memory
                    Memory.getMemory().write(pAddr.substring(0,26)+"000000", LINE_SIZE_B, cache[replace].getData());
                    cache[replace].dirty = false;
                }
                //update the cache
                addTimeStamp();
                update(replace, tag, data);
                setTimeStamp(replace);
                return replace;
            }

        }
        else {
            //if hit
            //update the strategy
            replacementStrategy.hit(rowNO);
            return rowNO;
        }
        return rowNO;
    }

    public String getpAddr(int rowNO) {
//        System.out.println(getBlockNO("00000000000000000000000001000000"));
//        rowNO = setSize * blocknum + blockAddr
        int n = 0;
        while (Math.pow(2, n) != SETS) {
            n += 1;
        }
        String tag = String.valueOf(this.cache[rowNO].tag).substring(n, 26);
        int blocknum = rowNO / setSize;
        String block = Transformer.intToBinary("0" + blocknum).substring(32 - n, 32);
        String blockAddr = Transformer.intToBinary("0" + (rowNO - setSize * blocknum)).substring(26, 32);

        return tag + block + blockAddr;

    }


    /**
     * 根据目标数据内存地址前26位的int表示,进行映射
     *
     * @param blockNO 数据在内存中的块号
     * @return 返回cache中所对应的行,-1表示未命中
     */
    private int map(int blockNO) {
        //TODO but done
        //search for the rowNO
        int start = (blockNO%SETS)*setSize;
        int last = start + setSize;
        for(int i = start; i < last; i++){
            if(cache[i].validBit){
                if(Integer.parseInt(Transformer.binaryToInt(String.valueOf(cache[i].getTag()))) == blockNO/SETS){
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 更新cache
     *
     * @param rowNO 需要更新的cache行号
     * @param tag   待更新数据的Tag
     * @param input 待更新的数据
     */
    public void update(int rowNO, char[] tag, byte[] input) {
        //TODO but done
        //update the cache
        cache[rowNO].tag = tag;
        cache[rowNO].data = input;
        cache[rowNO].validBit = true;
        //cache[rowNO].dirty = true;
        //replacementStrategy.hit(rowNO);
    }


    /**
     * 从32位物理地址(26位块号 + 6位块内地址)获取目标数据在内存中对应的块号
     *
     * @param pAddr 32位物理地址
     * @return 数据在内存中的块号
     */
    private int getBlockNO(String pAddr) {
        return Integer.parseInt(Transformer.binaryToInt("0" + pAddr.substring(0, 26)));
    }

    public void setDirty(int rowNO){
        cache[rowNO].dirty = false;
    }
    /**
     * 该方法会被用于测试,请勿修改
     * 使用策略模式,设置cache的替换策略
     *
     * @param replacementStrategy 替换策略
     */
    public void setReplacementStrategy(ReplacementStrategy replacementStrategy) {
        this.replacementStrategy = replacementStrategy;
    }

    /**
     * 该方法会被用于测试,请勿修改
     *
     * @param SETS 组数
     */
    public void setSETS(int SETS) {
        this.SETS = SETS;
    }

    /**
     * 该方法会被用于测试,请勿修改
     *
     * @param setSize 每组行数
     */
    public void setSetSize(int setSize) {
        this.setSize = setSize;
    }

    /**
     * 告知Cache某个连续地址范围内的数据发生了修改,缓存失效
     * 该方法仅在memory类中使用,请勿修改
     *
     * @param pAddr 发生变化的数据段的起始地址
     * @param len   数据段长度
     */
    public void invalid(String pAddr, int len) {
        int from = getBlockNO(pAddr);
        int to = getBlockNO(Transformer.intToBinary(String.valueOf(Integer.parseInt(Transformer.binaryToInt("0" + pAddr)) + len - 1)));

        for (int blockNO = from; blockNO <= to; blockNO++) {
            int rowNO = map(blockNO);
            if (rowNO != -1) {
                cache[rowNO].validBit = false;
            }
        }
    }

    /**
     * 清除Cache全部缓存
     * 该方法会被用于测试,请勿修改
     */
    public void clear() {
        for (CacheLine line : cache) {
            if (line != null) {
                line.validBit = false;
                line.dirty = false;
                line.timeStamp = 0L;
                line.visited = 0;
            }
        }
    }

    /**
     * 输入行号和对应的预期值,判断Cache当前状态是否符合预期
     * 这个方法仅用于测试,请勿修改
     *
     * @param lineNOs     行号
     * @param validations 有效值
     * @param tags        tag
     * @return 判断结果
     */
    public boolean checkStatus(int[] lineNOs, boolean[] validations, char[][] tags) {
        if (lineNOs.length != validations.length || validations.length != tags.length) {
            return false;
        }
        for (int i = 0; i < lineNOs.length; i++) {
            CacheLine line = cache[lineNOs[i]];
            if (line.validBit != validations[i]) {
                return false;
            }
            if (!Arrays.equals(line.getTag(), tags[i])) {
                System.out.println(Arrays.toString(line.getTag()));
                System.out.println(Arrays.toString(tags[i]));
                return false;
            }
        }
        return true;
    }

    // 获取有效位
    public boolean isValid(int rowNO){
        return cache[rowNO].validBit;
    }

    // 获取脏位
    public boolean isDirty(int rowNO){
        return cache[rowNO].dirty;
    }

    // LFU算法增加访问次数
    public void addVisited(int rowNO){
        cache[rowNO].visited++;
    }

    // 获取访问次数
    public int getVisited(int rowNO){
        return cache[rowNO].visited;
    }

    // 用于LRU算法,重置时间戳
    public void setTimeStamp(int rowNO){
        cache[rowNO].timeStamp = 0L;
    }

    //增加时间戳
    public void addTimeStamp(){
        for(int i = 0; i < cache.length; i++){
            if(cache[i].validBit)
            {
                cache[i].timeStamp++;
            }
        }
    }

    //用于FIFO算法,重置时间戳
    public void setTimeStampFIFO(int rowNo){
        cache[rowNo].timeStamp = 1L;
        if((rowNo+1)%setSize == 0){
            cache[rowNo+1-setSize].timeStamp = 0L;
        }else{
            cache[rowNo+1].timeStamp = 0L;
        }
    }

    // 获取时间戳
    public long getTimeStamp(int rowNO){
        return cache[rowNO].timeStamp;
    }

    // 获取该行数据
    public byte[] getData(int rowNO){
        return cache[rowNO].data;
    }

    /**
     * Cache行,每行长度为(1+22+{@link Cache#LINE_SIZE_B})
     */
    private static class CacheLine {

        // 有效位,标记该条数据是否有效
        boolean validBit = false;

        // 脏位,标记该条数据是否被修改
        boolean dirty = false;

        // 用于LFU算法,记录该条cache使用次数
        int visited = 0;

        // 用于LRU和FIFO算法,记录该条数据时间戳
        Long timeStamp = 0L;

        // 标记,占位长度为26位,有效长度取决于映射策略:
        // 直接映射: 17 位
        // 全关联映射: 26 位
        // (2^n)-路组关联映射: 26-(9-n) 位
        // 注意,tag在物理地址中用高位表示,如:直接映射(32位)=tag(17位)+行号(9位)+块内地址(6位),
        // 那么对于值为0b1111的tag应该表示为00000000000000000000001111,其中低12位为有效长度
        char[] tag = new char[26];

        // 数据
        byte[] data = new byte[LINE_SIZE_B];

        byte[] getData() {
            return this.data;
        }

        char[] getTag() {
            return this.tag;
        }

    }
}
package cpu.mmu;

import memory.Memory;
import memory.cache.Cache;
import memory.tlb.TLB;
import util.Transformer;

/**
 * MMU内存管理单元抽象类
 * 接收一个48-bits的逻辑地址,并最终将其转换成32-bits的物理地址
 * Memory.SEGMENT和Memory.PAGE标志用于表示是否开启分段和分页。
 * 实际上在机器里从实模式进入保护模式后分段一定会保持开启(即使实模式也会使用段寄存器),因此一共只要实现三种模式的内存管理即可:实模式、只有分段、段页式
 * 所有模式的物理地址都采用32-bits,实模式的物理地址高位补0
 */

public class MMU {

    private static final MMU mmuInstance = new MMU();

    private MMU() {
    }

    public static MMU getMMU() {
        return mmuInstance;
    }

    private final Memory memory = Memory.getMemory();

    private final Cache cache = Cache.getCache();

    private final TLB tlb = TLB.getTLB();

    /**
     * 读取数据
     *
     * @param logicAddr 48-bits逻辑地址
     * @param length    读取数据的长度
     * @return 内存中的数据
     */
    public byte[] read(String logicAddr, int length) {
        String physicalAddr = addressTranslation(logicAddr, length);
        if(Cache.isAvailable){
            return cache.read(physicalAddr, length);
        }
        return memory.read(physicalAddr, length);
    }

    /**
     * 写数据
     *
     * @param logicAddr 48-bits逻辑地址
     * @param length    读取数据的长度
     */
    public void write(String logicAddr, int length, byte[] data) {
        String physicalAddr = addressTranslation(logicAddr, length);
        if(Cache.isAvailable){
            cache.write(physicalAddr, length, data);
            return;
        }
        memory.write(physicalAddr, length, data);
    }

    /**
     * 地址转换
     *
     * @param logicAddr 48-bits逻辑地址
     * @param length    读取数据的长度
     * @return 32-bits物理地址
     */
    private String addressTranslation(String logicAddr, int length) {
        String linearAddr;      // 32位线性地址
        String physicalAddr;    // 32位物理地址
        if (!Memory.SEGMENT) {
            // 实模式:线性地址等于物理地址
            linearAddr = toRealLinearAddr(logicAddr);
            memory.real_load(linearAddr, length);  // 从磁盘中加载到内存
            physicalAddr = linearAddr;
        } else {
            // 分段模式
            int segIndex = getSegIndex(logicAddr);
            if (!memory.isValidSegDes(segIndex)) {
                // 缺段中断,该段不在内存中,内存从磁盘加载该段索引的数据
                memory.seg_load(segIndex);
            }
            linearAddr = toSegLinearAddr(logicAddr);
            // 权限检查
            int start = Integer.parseInt(Transformer.binaryToInt(linearAddr));
            int base = chars2int(memory.getBaseOfSegDes(segIndex));
            long limit = chars2int(memory.getLimitOfSegDes(segIndex));
            if (memory.isGranularitySegDes(segIndex)) {
                limit = (limit + 1) * Memory.PAGE_SIZE_B - 1;
            }
            if ((start < base) || (start + length > base + limit)) {
                throw new SecurityException("Segmentation Fault");
            }
            if (!Memory.PAGE) {
                // 分段模式:线性地址等于物理地址
                physicalAddr = linearAddr;
            } else {
                // 段页式
                int startvPageNo = Integer.parseInt(Transformer.binaryToInt(linearAddr.substring(0, 20)));   // 高20位表示虚拟页号
                int offset = Integer.parseInt(Transformer.binaryToInt(linearAddr.substring(20, 32)));         // 低12位的页内偏移
                int pages = (length - offset + Memory.PAGE_SIZE_B - 1) / Memory.PAGE_SIZE_B;
                if (offset > 0) pages++;
                int endvPageNo = startvPageNo + pages - 1;
                for (int i = startvPageNo; i <= endvPageNo; i++) {
                    if(TLB.isAvailable){
                        if(!tlb.isValidPage(i)){
                            // 缺页中断,该页不在内存中,内存从磁盘加载该页的数据
                            memory.page_load(i);
                            tlb.write(i);
                        }
                    }
                    if (!memory.isValidPage(i)) {
                        // 缺页中断,该页不在内存中,内存从磁盘加载该页的数据
                        memory.page_load(i);
                    }
                }
                physicalAddr = toPagePhysicalAddr(linearAddr);
            }
        }
        return physicalAddr;
    }

    /**
     * 实模式下的逻辑地址转线性地址
     *
     * @param logicAddr 48位 = 16位段寄存器 + 32位offset,计算公式为:①(16-bits段寄存器左移4位 + offset的低16-bits) = 20-bits物理地址 ②高位补0到32-bits
     * @return 32-bits实模式线性地址
     */
    private String toRealLinearAddr(String logicAddr) {
        return Transformer.intToBinary(""+(Integer.valueOf(logicAddr.substring(0, 16)+"0000",2)+Integer.valueOf("0000"+logicAddr.substring(48-16),2)));
    }

    private String add(char[] base, String offsetStr) {
        char[] offset = offsetStr.toCharArray();
        StringBuilder res = new StringBuilder();
        char carry = '0';
        for (int i = base.length - 1; i >= 0; i--) {
            res.append((carry - '0') ^ (base[i] - '0') ^ (offset[i] - '0'));
            carry = (char) (((carry - '0') & (base[i] - '0')) | ((carry - '0') & (offset[i] - '0')) | ((base[i] - '0') & (offset[i] - '0')) + '0');
        }
        int t = res.length();
        for (int i = 0; i < 32 - t; i++) {
            res.append("0");
        }
        return res.reverse().toString();
    }

    /**
     * 分段模式下的逻辑地址转线性地址
     *
     * @param logicAddr 48位 = 16位段选择符(高13位index选择段表项) + 32位段内偏移
     * @return 32-bits 线性地址
     */
    private String toSegLinearAddr(String logicAddr) {
        String offset = logicAddr.substring(16, 48);
        int segIndex = Integer.parseInt(Transformer.binaryToInt(logicAddr.substring(0, 13)));   // 段描述符索引
        char[] segBase = memory.getBaseOfSegDes(segIndex);               // 内存基址base 32位
        return add(segBase, offset);
    }

    /**
     * 段页式下的线性地址转物理地址
     *
     * @param linearAddr 32位
     * @return 32-bits 物理地址
     */
    private String toPagePhysicalAddr(String linearAddr) {
        String offset = linearAddr.substring(20);
        int vPageNo = Integer.parseInt(Transformer.binaryToInt("000000000000"+linearAddr.substring(0,20)));
        return TLB.isAvailable ? (new String(tlb.getFrameOfPage(vPageNo)) + offset) : (String.valueOf(memory.getFrameOfPage(vPageNo)) + offset);
    }

    /**
     * 根据逻辑地址找到对应的段索引
     *
     * @param logicAddr 逻辑地址
     * @return 整数表示的段索引
     */
    private int getSegIndex(String logicAddr) {
        String indexStr = logicAddr.substring(0, 13);
        return Integer.parseInt(Transformer.binaryToInt(indexStr));   // 段描述符索引
    }

    private int chars2int(char[] chars) {
        return Integer.parseInt(Transformer.binaryToInt(String.valueOf(chars)));
    }

    public void clear() {
        memory.clear();
        if (Cache.isAvailable) {
            cache.clear();
        }
        if (TLB.isAvailable) {
            tlb.clear();
        }
    }

}

Programming 03 Integer Add & Sub

package cpu.alu;

import util.DataType;
import util.Transformer;


/**
 * Arithmetic Logic Unit
 * ALU封装类
 */
public class ALU {
    /**
     * 返回两个二进制整数的乘积(结果低位截取后32位)
     * dest * src
     *Put multiplicand in BR and multiplier in QR
     * and then the algorithm works as per the following conditions :
     * 1. If Qn and Qn+1 are same i.e. 00 or 11 perform arithmetic shift by 1 bit.
     * 2. If Qn Qn+1 = 01 do A= A + BR and perform arithmetic shift by 1 bit.
     * 3. If Qn Qn+1 = 10 do A= A – BR and perform arithmetic shift by 1 bit.
     * @param src  32-bits
     * @param dest 32-bits
     * @return 32-bits
     */
    public DataType mul(DataType src, DataType dest) {
        //Booth Algorithm
        String srcStr = src.toString();
        String desStr = dest.toString();
        StringBuilder srcStrBuilder = new StringBuilder("00000000000000000000000000000000");
        srcStrBuilder.append(srcStr);
        srcStrBuilder.append("0");//to fill the first
        int len=srcStrBuilder.length();//should be 65
        for(int i=0;i<32;i++){
            if(srcStrBuilder.charAt(len-1)=='0'&&srcStrBuilder.charAt(len-2)=='1'){
                srcStrBuilder.replace(0,32,sub(desStr,srcStrBuilder.substring(0,32)));
            }
            else if(srcStrBuilder.charAt(len-1)=='1'&&srcStrBuilder.charAt(len-2)=='0'){
                srcStrBuilder.replace(0,32,add(srcStrBuilder.substring(0,32),desStr));
            }
            srcStrBuilder.insert(0,srcStrBuilder.charAt(0));
            srcStrBuilder.deleteCharAt(len);
        }
        return new DataType(srcStrBuilder.substring(32,64));
    }

    static DataType remainderReg = new DataType("00000000000000000000000000000000");

    /**
     * 返回两个二进制整数的除法结果
     * dest ÷ src
     *
     * @param src  32-bits
     * @param dest 32-bits
     * @return 32-bits
     */
    public DataType div(DataType src, DataType dest) {
        String srcStr = src.toString();
        String desStr = dest.toString();
        String retu="";
        StringBuilder ans=new StringBuilder("00000000000000000000000000000000");
        if(srcStr.equals(ans.toString())){
            throw new ArithmeticException("Divisor cannot be 0");
        }
        if(desStr.equals(ans.toString())){
            return dest;
        }
        int flag=0;
        if(srcStr.charAt(0)==desStr.charAt(0)){
            flag=0;
            if(srcStr.charAt(0)=='1'){
                srcStr=not(srcStr);
                desStr=not(desStr);
            }
        }
        else{
            flag=1;
            if(srcStr.charAt(0)=='1'){
                srcStr=not(srcStr);
            }
            else {
                desStr=not(desStr);
            }
        }
        ans.append(desStr);
        int len=ans.length();
        String temp="";
        for(int i=1;i<=32;i++){
            temp=sub(srcStr,ans.substring(i,i+32));
            if(temp.charAt(0)=='0'){
                ans.replace(i,i+32,temp);
                retu+="1";
            }
            else{
                retu+="0";
            }
        }
        if(flag==1){
            retu=not(retu);
        }
        remainderReg=new DataType(ans.substring(32,64));
        if(dest.toString().charAt(0)=='1')
            remainderReg=new DataType(not(ans.substring(32,64)));
        return new DataType(retu);
    }
    public static void main(String[] args){
        ALU alu=new ALU();
        DataType src = new DataType(intToBinary("10"));
        DataType dest = new DataType(intToBinary("-25"));
        String ans=alu.div(src,dest).toString();
        System.out.println(binaryToInt(remainderReg.toString()));
        System.out.println(binaryToInt(ans));
    }
    public String add(String src, String dest) {
        int c=0;
        int s1,d1;
        String s = src.toString();
        String d = dest.toString();
        StringBuilder ans = new StringBuilder();
        for(int i=s.length()-1;i>=0;i--){
            s1 = s.charAt(i) - '0';
            d1 = d.charAt(i) - '0';
            ans.append(c ^ s1 ^ d1);
            c = (s1 & d1) | (c & d1) | (s1 & c);
        }
        return ans.reverse().toString();
    }
    /*
    sub: dest - src
     */
    public String sub(String srcStr, String destStr) {
        return add(destStr, not(srcStr));
    }
    public String not(String srcStr){
        String ans = "";
        for(int i = 0;i < 32;i++){
            if(srcStr.charAt(i) == '0'){
                ans = ans + '1';
            }
            else{
                ans = ans + '0';
            }
        }
        return add(ans,"00000000000000000000000000000001");
    }
    public static String intToBinary(String numStr) {
        return BinarytoComplement(DecimaltoBinary(numStr,true));
    }

    public static String binaryToInt(String binStr) {
        int num=0;
        int len=binStr.length(),result =0;
        for(int i=1;i<=len-1;i++)
        {
            num=binStr.charAt(i)-'0';
            result+=num*Math.pow(2,len-1-i);
        }
        if(binStr.charAt(0)=='1')
            result-=Math.pow(2,len-1);

        return String.valueOf(result);
    }
    public static String BinarytoComplement(String binStr){
        int len=binStr.length();
        StringBuilder result=new StringBuilder();
        if(binStr.charAt(0)=='1'){
            result.append("1");
            for(int i=1;i<len;i++) {
                if (binStr.charAt(i) == '0')
                    result.append("1");
                else
                    result.append("0");
            }
            //System.out.println(result.toString());
            StringBuilder temp=new StringBuilder();
            int i=result.length()-1;
            while(result.charAt(i)=='1'&&i>0){
                temp.append("0");
                i--;
            }
            if(i>0)
                temp.append("1");
            i--;
            for(;i>0;i--){
                temp.append(result.charAt(i));
            }
            temp.append("1");
            return temp.reverse().toString();
        }
        else {
            return binStr;
        }
    }
    public static String DecimaltoBinary(String decimalStr,boolean f){
        StringBuilder result=new StringBuilder();
        int num=Integer.parseInt(decimalStr);
        int flag=0;
        if(num<0){
            num=-num;
            flag=1;
        }
        int len=0;
        while(num>0){
            result.append(num%2);
            num/=2;
            len++;
        }
        while(len<31&&f)
        {
            result.append("0");
            len++;
        }
        if (f)
        {
            if (flag == 1) {
                result.append("1");
            } else
                result.append("0");
        }
        return result.reverse().toString();
    }
}

Programmming 05 cache

package memory.cache;

import memory.Memory;
import memory.cache.cacheReplacementStrategy.ReplacementStrategy;
import util.Transformer;
import java.util.Arrays;

/**
 * 高速缓存抽象类
 */
public class Cache {

    public static final boolean isAvailable = true; // 默认启用Cache

    public static final int CACHE_SIZE_B = 32 * 1024; // 32 KB 总大小

    public static final int LINE_SIZE_B = 64; // 64 B 行大小

    private final CacheLine[] cache = new CacheLine[CACHE_SIZE_B / LINE_SIZE_B];

    private int SETS;   // 组数

    private int setSize;    // 每组行数

    // 单例模式
    private static final Cache cacheInstance = new Cache();

    private Cache() {
        for (int i = 0; i < cache.length; i++) {
            cache[i] = new CacheLine();
        }
    }

    public static Cache getCache() {
        return cacheInstance;
    }

    private ReplacementStrategy replacementStrategy;    // 替换策略

    public static boolean isWriteBack;   // 写策略

    /**
     * 读取[pAddr, pAddr + len)范围内的连续数据,可能包含多个数据块的内容
     *
     * @param pAddr 数据起始点(32位物理地址 = 26位块号 + 6位块内地址)
     * @param len   待读数据的字节数
     * @return 读取出的数据,以char数组的形式返回
     */
    public byte[] read(String pAddr, int len) {
        byte[] data = new byte[len];
        int addr = Integer.parseInt(Transformer.binaryToInt("0" + pAddr));
        int upperBound = addr + len;
        int index = 0;
        while (addr < upperBound) {
            int nextSegLen = LINE_SIZE_B - (addr % LINE_SIZE_B);
            if (addr + nextSegLen >= upperBound) {
                nextSegLen = upperBound - addr;
            }//get the length of the next segment
            //if exceed the upper bound, then set the length to the rest of the data
            int rowNO = fetch(Transformer.intToBinary(String.valueOf(addr)));
            byte[] cache_data = cache[rowNO].getData();
            int i = 0;
            while (i < nextSegLen) {
                data[index] = cache_data[addr % LINE_SIZE_B + i];
                index++;
                i++;
            }
            addr += nextSegLen;
        }
        return data;
    }

    /**
     * 向cache中写入[pAddr, pAddr + len)范围内的连续数据,可能包含多个数据块的内容
     *
     * @param pAddr 数据起始点(32位物理地址 = 26位块号 + 6位块内地址)
     * @param len   待写数据的字节数
     * @param data  待写数据
     */
    public void write(String pAddr, int len, byte[] data) {
        int addr = Integer.parseInt(Transformer.binaryToInt("0" + pAddr));
        int upperBound = addr + len;
        int index = 0;
        while (addr < upperBound) {
            int nextSegLen = LINE_SIZE_B - (addr % LINE_SIZE_B);
            if (addr + nextSegLen >= upperBound) {
                nextSegLen = upperBound - addr;
            }
            int rowNO = fetch(Transformer.intToBinary(String.valueOf(addr)));
            byte[] cache_data = cache[rowNO].getData();
            int i = 0;
            while (i < nextSegLen) {
                cache_data[addr % LINE_SIZE_B + i] = data[index];
                index++;
                i++;
            }
            //TODO but done
            //write the data according to the write strategy
            //1. write through
            if(!isWriteBack){
                //dirty bit is always 0
                //write the data to memory
                Memory.getMemory().write(pAddr, len, data);
                //update the cache and using strategy
                addTimeStamp();
                update(rowNO, getTag(pAddr), cache_data);
                setTimeStamp(rowNO);
            }
            else{
                //get the dirty bit
                cache[rowNO].dirty = true;
                //update the cache and using strategy
                addTimeStamp();
                update(rowNO, getTag(pAddr), cache_data);
                setTimeStamp(rowNO);
            }

            addr += nextSegLen;
        }
    }

    /**
    * 从32位物理地址(26位块号 + 6位块内地址)获取目标数据的tag
     * 首先将32位物理地址转换为26位,然后将其前面补0至32位
    * @param pAddr 32位物理地址
    * @return 数据的tag
    *
     */
    public char[] getTag(String pAddr) {
        int tagSize = 26 - (int) (Math.log(SETS) / Math.log(2));
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 26 - tagSize; i++) {
            builder.append("0");
        }
        builder.append(pAddr.substring(0, tagSize));
        return builder.toString().toCharArray();
    }

    /**
     * 查询{@link Cache#cache}表以确认包含pAddr的数据块是否在cache内
     * 如果目标数据块不在Cache内,则将其从内存加载到Cache
     *
     * @param pAddr 数据起始点(32位物理地址 = 26位块号 + 6位块内地址)
     * @return 数据块在Cache中的对应行号
     */
    private int fetch(String pAddr) {
        //TODO but done
        int blockNO = getBlockNO(pAddr);
        int rowNO = map(blockNO);
        int start = (blockNO%SETS)*setSize;
        int last = start + setSize;
        //get the tag
        char[] tag = getTag(pAddr);
        //if didn't hit
        if(rowNO == -1){
            //get the data from memory(pAddr is 26 bits but the address in memory is 32 bits)
            byte[] data = Memory.getMemory().read(pAddr.substring(0,26)+"000000", LINE_SIZE_B);
            int availableRow = -1;
            //find an available row
            for(int i = start; i < last; i++){
                if(!cache[i].validBit){
                    availableRow = i;
                    break;
                }
            }
            //if there is an available row
            if(availableRow != -1){
                //update the cache
                addTimeStamp();
                update(availableRow, tag, data);
                //update the strategy
                setTimeStamp(availableRow);
                rowNO = availableRow;
            }
            else{
                //if there is no available row
                //replace the row
                int replace = replacementStrategy.replace(start, last, tag, data);
                if(cache[replace].dirty){
                    //if the dirty bit is 1
                    //write the data to memory
                    Memory.getMemory().write(pAddr.substring(0,26)+"000000", LINE_SIZE_B, cache[replace].getData());
                    cache[replace].dirty = false;
                }
                //update the cache
                addTimeStamp();
                update(replace, tag, data);
                setTimeStamp(replace);
                return replace;
            }

        }
        else {
            //if hit
            //update the strategy
            replacementStrategy.hit(rowNO);
            return rowNO;
        }
        return rowNO;
    }

    public String getpAddr(int rowNO) {
//        System.out.println(getBlockNO("00000000000000000000000001000000"));
//        rowNO = setSize * blocknum + blockAddr
        int n = 0;
        while (Math.pow(2, n) != SETS) {
            n += 1;
        }
        String tag = String.valueOf(this.cache[rowNO].tag).substring(n, 26);
        int blocknum = rowNO / setSize;
        String block = Transformer.intToBinary("0" + blocknum).substring(32 - n, 32);
        String blockAddr = Transformer.intToBinary("0" + (rowNO - setSize * blocknum)).substring(26, 32);

        return tag + block + blockAddr;

    }


    /**
     * 根据目标数据内存地址前26位的int表示,进行映射
     *
     * @param blockNO 数据在内存中的块号
     * @return 返回cache中所对应的行,-1表示未命中
     */
    private int map(int blockNO) {
        //TODO but done
        //search for the rowNO
        int start = (blockNO%SETS)*setSize;
        int last = start + setSize;
        for(int i = start; i < last; i++){
            if(cache[i].validBit){
                if(Integer.parseInt(Transformer.binaryToInt(String.valueOf(cache[i].getTag()))) == blockNO/SETS){
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 更新cache
     *
     * @param rowNO 需要更新的cache行号
     * @param tag   待更新数据的Tag
     * @param input 待更新的数据
     */
    public void update(int rowNO, char[] tag, byte[] input) {
        //TODO but done
        //update the cache
        cache[rowNO].tag = tag;
        cache[rowNO].data = input;
        cache[rowNO].validBit = true;
        //cache[rowNO].dirty = true;
        //replacementStrategy.hit(rowNO);
    }


    /**
     * 从32位物理地址(26位块号 + 6位块内地址)获取目标数据在内存中对应的块号
     *
     * @param pAddr 32位物理地址
     * @return 数据在内存中的块号
     */
    private int getBlockNO(String pAddr) {
        return Integer.parseInt(Transformer.binaryToInt("0" + pAddr.substring(0, 26)));
    }

    public void setDirty(int rowNO){
        cache[rowNO].dirty = false;
    }
    /**
     * 该方法会被用于测试,请勿修改
     * 使用策略模式,设置cache的替换策略
     *
     * @param replacementStrategy 替换策略
     */
    public void setReplacementStrategy(ReplacementStrategy replacementStrategy) {
        this.replacementStrategy = replacementStrategy;
    }

    /**
     * 该方法会被用于测试,请勿修改
     *
     * @param SETS 组数
     */
    public void setSETS(int SETS) {
        this.SETS = SETS;
    }

    /**
     * 该方法会被用于测试,请勿修改
     *
     * @param setSize 每组行数
     */
    public void setSetSize(int setSize) {
        this.setSize = setSize;
    }

    /**
     * 告知Cache某个连续地址范围内的数据发生了修改,缓存失效
     * 该方法仅在memory类中使用,请勿修改
     *
     * @param pAddr 发生变化的数据段的起始地址
     * @param len   数据段长度
     */
    public void invalid(String pAddr, int len) {
        int from = getBlockNO(pAddr);
        int to = getBlockNO(Transformer.intToBinary(String.valueOf(Integer.parseInt(Transformer.binaryToInt("0" + pAddr)) + len - 1)));

        for (int blockNO = from; blockNO <= to; blockNO++) {
            int rowNO = map(blockNO);
            if (rowNO != -1) {
                cache[rowNO].validBit = false;
            }
        }
    }

    /**
     * 清除Cache全部缓存
     * 该方法会被用于测试,请勿修改
     */
    public void clear() {
        for (CacheLine line : cache) {
            if (line != null) {
                line.validBit = false;
                line.dirty = false;
                line.timeStamp = 0L;
                line.visited = 0;
            }
        }
    }

    /**
     * 输入行号和对应的预期值,判断Cache当前状态是否符合预期
     * 这个方法仅用于测试,请勿修改
     *
     * @param lineNOs     行号
     * @param validations 有效值
     * @param tags        tag
     * @return 判断结果
     */
    public boolean checkStatus(int[] lineNOs, boolean[] validations, char[][] tags) {
        if (lineNOs.length != validations.length || validations.length != tags.length) {
            return false;
        }
        for (int i = 0; i < lineNOs.length; i++) {
            CacheLine line = cache[lineNOs[i]];
            if (line.validBit != validations[i]) {
                return false;
            }
            if (!Arrays.equals(line.getTag(), tags[i])) {
                System.out.println(Arrays.toString(line.getTag()));
                System.out.println(Arrays.toString(tags[i]));
                return false;
            }
        }
        return true;
    }

    // 获取有效位
    public boolean isValid(int rowNO){
        return cache[rowNO].validBit;
    }

    // 获取脏位
    public boolean isDirty(int rowNO){
        return cache[rowNO].dirty;
    }

    // LFU算法增加访问次数
    public void addVisited(int rowNO){
        cache[rowNO].visited++;
    }

    // 获取访问次数
    public int getVisited(int rowNO){
        return cache[rowNO].visited;
    }

    // 用于LRU算法,重置时间戳
    public void setTimeStamp(int rowNO){
        cache[rowNO].timeStamp = 0L;
    }

    //增加时间戳
    public void addTimeStamp(){
        for(int i = 0; i < cache.length; i++){
            if(cache[i].validBit)
            {
                cache[i].timeStamp++;
            }
        }
    }

    //用于FIFO算法,重置时间戳
    public void setTimeStampFIFO(int rowNo){
        cache[rowNo].timeStamp = 1L;
        if((rowNo+1)%setSize == 0){
            cache[rowNo+1-setSize].timeStamp = 0L;
        }else{
            cache[rowNo+1].timeStamp = 0L;
        }
    }

    // 获取时间戳
    public long getTimeStamp(int rowNO){
        return cache[rowNO].timeStamp;
    }

    // 获取该行数据
    public byte[] getData(int rowNO){
        return cache[rowNO].data;
    }

    /**
     * Cache行,每行长度为(1+22+{@link Cache#LINE_SIZE_B})
     */
    private static class CacheLine {

        // 有效位,标记该条数据是否有效
        boolean validBit = false;

        // 脏位,标记该条数据是否被修改
        boolean dirty = false;

        // 用于LFU算法,记录该条cache使用次数
        int visited = 0;

        // 用于LRU和FIFO算法,记录该条数据时间戳
        Long timeStamp = 0L;

        // 标记,占位长度为26位,有效长度取决于映射策略:
        // 直接映射: 17 位
        // 全关联映射: 26 位
        // (2^n)-路组关联映射: 26-(9-n) 位
        // 注意,tag在物理地址中用高位表示,如:直接映射(32位)=tag(17位)+行号(9位)+块内地址(6位),
        // 那么对于值为0b1111的tag应该表示为00000000000000000000001111,其中低12位为有效长度
        char[] tag = new char[26];

        // 数据
        byte[] data = new byte[LINE_SIZE_B];

        byte[] getData() {
            return this.data;
        }

        char[] getTag() {
            return this.tag;
        }

    }
}

Programming 04 Float add and mul and div

public String floatAddition(String operand1, String operand2, int eLength, int sLength, int gLength) {
            //floatAddition加法的特殊情况,如果有0,答案就是另一个,如果有一个是+Inf结果就是Inf
            if (allZero(operand1.substring(1))) {
                return "0" + operand2;
            }
            if (allZero(operand2.substring(1))) {
                return "0" + operand1;
            }
            //处理阶码,考虑阶码的2种特殊的情况,全0和全1.全0就+1,全1的话,返回本身
            int Xexponent = Integer.valueOf(operand1.substring(1, 1 + eLength), 2);  //注意这里要加上第二个参数2,不然默认十进制转化
            int Yexponent = Integer.valueOf(operand2.substring(1, 1 + eLength), 2);
            if (Xexponent == 0) Xexponent++;  //如果指数是全0,那么指数的真实值为1,因为阶码已经考虑了隐藏位
            if (Yexponent == 0) Yexponent++;
            if (Xexponent == 255) {
                return "0" + operand1;
            }
            if (Yexponent == 255) {
                return "0" + operand2;
            }
            //处理尾数:前面加了1位是规格化的
            StringBuilder Xsig = new StringBuilder(getSignificand(operand1, eLength, sLength));  //get the two significands including the implicit bit
            StringBuilder Ysig = new StringBuilder(getSignificand(operand2, eLength, sLength));
            //加上保护胃,1+23+3=27
            for (int i = 0; i < gLength; i++) {  //add the guard bits
                Xsig.append("0");
                Ysig.append("0");
            }
            //现在Xsig组成为 隐藏位+sLength+保护位
            int exponent = Math.max(Xexponent, Yexponent);  //choose the bigger exponent and right shift the smaller one
            //提取大的然后右移动
            if (Xexponent != Yexponent) {
                if (Xexponent > Yexponent) {
                    Ysig = new StringBuilder(rightShift(Ysig.toString(), Xexponent - Yexponent));
                } else {
                    Xsig = new StringBuilder(rightShift(Xsig.toString(), Yexponent - Xexponent));
                }
            }
            //尾码全部0就可以直接输出了
            if (allZero(Xsig.toString())) {
                return "0" + operand2;
            }
            if (allZero(Ysig.toString())) {
                return "0" + operand1;
            }
            String temp = signedAddition(operand1.charAt(0) + Xsig.toString(), operand2.charAt(0) + Ysig.toString(), Xsig.length());  //需要传入符号。这里直接设置寄存器长度为 Xsig.length() 就可以检测是否溢出,传入参数结构为 符号位+隐藏位+sLength+保护位
            //temp结构为 溢出位+符号位+隐藏位+sLength+保护位
            boolean overflow = temp.charAt(0) != '0';
            char sign = temp.charAt(1);
            String sig = temp.substring(2);  //sig结构为 隐藏位+sLength+保护位
            StringBuilder answer = new StringBuilder();
            //溢出情况
            if (overflow) {
                sig = "1" + sig.substring(0, sig.length() - 1);  //右移一位(不可能要移动两次)
                exponent++;
                if (exponent == maxValue(eLength)) {  //指数上溢
                    answer.append("1").append(sign);
                    answer.append(Integer.toBinaryString(exponent));
                    for (int i = 0; i < sLength; i++) answer.append("0");  //无穷要求阶码全为0
                    return answer.toString();
                }
            }
            if (allZero(sig)) {
                for (int i = 0; i < eLength + sLength + 2; i++) answer.append("0");
                return answer.toString();
            }
            while (sig.charAt(0) != '1' && exponent > 0) {  //规格化
                sig = leftShift(sig, "1");
                exponent--;
            }
            if (exponent == 0) {  //非规格化数
                sig = rightShift(sig, 1);
            }
            StringBuilder ans_exponent = new StringBuilder(Integer.toBinaryString(exponent));
            int len = ans_exponent.length();  //注意要先把长度单独写出来,不能写在循环里面
            for (int i = 0; i < eLength - len; i++) ans_exponent.insert(0, "0");  //补齐到eLength长度
            return "0" + round(sign, ans_exponent.toString(), sig);
        }

Another Version

public DataType add(DataType src, DataType dest) {
        String destStr = dest.toString();
        String srcStr = src.toString();
        if (destStr.matches(IEEE754Float.NaN_Regular) || srcStr.matches(IEEE754Float.NaN_Regular)) {
            return new DataType(IEEE754Float.NaN);
        }
        String cornerCondition = cornerCheck(addCorner, destStr, srcStr);
        if (null != cornerCondition)
            return new DataType(cornerCondition);
        //corner cases
        String exp1 = destStr.substring(1, 9);
        String exp2 = srcStr.substring(1, 9);
        //get the exp value
        int expVal_1 = Integer.valueOf(exp1, 2);
        int expVal_2 = Integer.valueOf(exp2, 2);
        if (expVal_1 == 255)
            return dest;
        if (expVal_2 == 255)
            return src;
        if (destStr.substring(1).equals(IEEE754Float.P_ZERO.substring(1)))
            return src;
        if (srcStr.substring(1).equals(IEEE754Float.P_ZERO.substring(1)))
            return dest;
        //some other corner cases
        String sig1 = "";
        String sig2 = "";
        if (expVal_1 == 0) {
            expVal_1++;
            sig1 += "0";
        } else sig1 += "1";
        if (expVal_2 == 0) {
            expVal_2++;
            sig2 += "0";
        } else sig2 += "1";
        sig1 = sig1 + destStr.substring(9) + "000";
        sig2 = sig2 + srcStr.substring(9) + "000";
        int expVal = Math.max(expVal_1, expVal_2);
        if (expVal_1 > expVal_2) {
            sig2 = rightShift(sig2, expVal - expVal_2);
        } else {
            sig1 = rightShift(sig1, expVal - expVal_1);
        }
        String temp = signedADD(sig1, sig2, destStr.charAt(0), srcStr.charAt(0));
        String sig = temp.substring(1);
        String sign = temp.substring(0, 1);
        expVal++;//因为转换成规格化之后位数+1但实际大小没变动
        while (sig.charAt(0) == '0' && expVal > 0) {
            expVal--;
            sig = sig.substring(1) + '0';
        }
        while (!sig.startsWith("00000000000000000000000000") && expVal < 0) {
            expVal++;
            sig = rightShift(sig, 1);
        }
        if (expVal >= 255)
            return new DataType(sign + "1111111100000000000000000000000");
        if (expVal == 0)
            sig = rightShift(sig, 1);
        String exp = Transformer.intToBinary(String.valueOf(expVal)).substring(32 - 8);
        String round = round(sign.charAt(0), exp, sig);
        return new DataType(round);
    }

    private String signedADD(String sig1, String sig2, char sign1, char sign2) {
        boolean sameSign = sign1 == sign2;
        if (sig1.equals("000000000000000000000000000"))
            return sign2 + sig2;
        if (sig2.equals("000000000000000000000000000"))
            return sign1 + sig1;

        if (sameSign) {
            int intSig1 = Integer.valueOf(sig1, 2);
            int intSig2 = Integer.valueOf(sig2, 2);
            String intToBinary = Transformer.intToBinary(String.valueOf(intSig1 + intSig2));
            String ansSig = intToBinary.substring(32 - 28);
            return sign1 + ansSig;
        } else {
            int intSig1 = Integer.valueOf(sig1, 2);
            int intSig2 = Integer.valueOf(sig2, 2);
            if (sig1.equals(sig2))
                return "00000000000000000000000000000";
            String intToBinary = Transformer.intToBinary(String.valueOf(Math.abs(intSig1 - intSig2)));
            String ansSig = intToBinary.substring(32 - 28);
            return intSig1 > intSig2 ? (sign1 + ansSig) : (sign2 + ansSig);
        }
    }

Another version of div

package cpu.fpu;

import util.DataType;
import util.IEEE754Float;

import java.util.Collections;

import static util.Transformer.oneAdder;
import static util.Transformer.negation;

public class FPU {

    final int eLength = 8;
    final int sLength = 23;
    final int gLength = 3;

    class FLOAT {
        char sign;
        int exp;
        String sig;

        FLOAT(String v) {
            sign = v.charAt(0);
            exp = Integer.parseInt(v.substring(1, 9), 2);
            sig = exp == 0 ? "0" : "1";
            if (exp == 0)
                exp++;
            sig += v.substring(9) + "000";
        }
    }


    private final String[][] addCorner = new String[][]{
            {IEEE754Float.P_ZERO, IEEE754Float.P_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.N_ZERO, IEEE754Float.P_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.P_ZERO, IEEE754Float.N_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.N_ZERO, IEEE754Float.N_ZERO, IEEE754Float.N_ZERO},
            {IEEE754Float.P_INF, IEEE754Float.N_INF, IEEE754Float.NaN},
            {IEEE754Float.N_INF, IEEE754Float.P_INF, IEEE754Float.NaN}
    };

    private final String[][] subCorner = new String[][]{
            {IEEE754Float.P_ZERO, IEEE754Float.P_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.N_ZERO, IEEE754Float.P_ZERO, IEEE754Float.N_ZERO},
            {IEEE754Float.P_ZERO, IEEE754Float.N_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.N_ZERO, IEEE754Float.N_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.P_INF, IEEE754Float.P_INF, IEEE754Float.NaN},
            {IEEE754Float.N_INF, IEEE754Float.N_INF, IEEE754Float.NaN}
    };

    private final String[][] mulCorner = new String[][]{
            {IEEE754Float.P_ZERO, IEEE754Float.N_ZERO, IEEE754Float.N_ZERO},
            {IEEE754Float.N_ZERO, IEEE754Float.P_ZERO, IEEE754Float.N_ZERO},
            {IEEE754Float.P_ZERO, IEEE754Float.P_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.N_ZERO, IEEE754Float.N_ZERO, IEEE754Float.P_ZERO},
            {IEEE754Float.P_ZERO, IEEE754Float.P_INF, IEEE754Float.NaN},
            {IEEE754Float.P_ZERO, IEEE754Float.N_INF, IEEE754Float.NaN},
            {IEEE754Float.N_ZERO, IEEE754Float.P_INF, IEEE754Float.NaN},
            {IEEE754Float.N_ZERO, IEEE754Float.N_INF, IEEE754Float.NaN},
            {IEEE754Float.P_INF, IEEE754Float.P_ZERO, IEEE754Float.NaN},
            {IEEE754Float.P_INF, IEEE754Float.N_ZERO, IEEE754Float.NaN},
            {IEEE754Float.N_INF, IEEE754Float.P_ZERO, IEEE754Float.NaN},
            {IEEE754Float.N_INF, IEEE754Float.N_ZERO, IEEE754Float.NaN}
    };

    private final String[][] divCorner = new String[][]{
            {IEEE754Float.P_ZERO, IEEE754Float.P_ZERO, IEEE754Float.NaN},
            {IEEE754Float.N_ZERO, IEEE754Float.N_ZERO, IEEE754Float.NaN},
            {IEEE754Float.P_ZERO, IEEE754Float.N_ZERO, IEEE754Float.NaN},
            {IEEE754Float.N_ZERO, IEEE754Float.P_ZERO, IEEE754Float.NaN},
            {IEEE754Float.P_INF, IEEE754Float.P_INF, IEEE754Float.NaN},
            {IEEE754Float.N_INF, IEEE754Float.N_INF, IEEE754Float.NaN},
            {IEEE754Float.P_INF, IEEE754Float.N_INF, IEEE754Float.NaN},
            {IEEE754Float.N_INF, IEEE754Float.P_INF, IEEE754Float.NaN},
    };

    //dest + src
    public DataType add(DataType src, DataType dest) {
        String a = src.toString();
        String b = dest.toString();
        if (Corner(a, b, addCorner) != null) {
            return Corner(a, b, addCorner);
        }
        return new DataType(floatAddition(new FLOAT(a), new FLOAT(b)));
    }

    //dest - src
    public DataType sub(DataType src, DataType dest) {
        String a = src.toString();
        String b = dest.toString();
        if (Corner(a, b, subCorner) != null) {
            return Corner(a, b, subCorner);
        }
        a = negation("" + a.charAt(0)) + a.substring(1);
        return new DataType(floatAddition(new FLOAT(a), new FLOAT(b)));
    }

    //dest * src
    public DataType mul(DataType src, DataType dest) {
        String a = src.toString();
        String b = dest.toString();
        if (Corner(a, b, mulCorner) != null) {
            return Corner(a, b, mulCorner);
        }
        return new DataType(floatMul(new FLOAT(a), new FLOAT(b)));
    }

    //dest / src
    public DataType div(DataType src, DataType dest) {
        String a = src.toString();
        String b = dest.toString();
        if (Corner(a, b, divCorner) != null) {
            return Corner(a, b, divCorner);
        }
        boolean sameSign = a.charAt(0) == b.charAt(0);
        if (isZero(b.substring(1))) {
            return sameSign ? new DataType(IEEE754Float.P_ZERO) : new DataType(IEEE754Float.N_ZERO);
        }
        if (isZero(a.substring(1))) throw new ArithmeticException();
        return new DataType(floatDiv(new FLOAT(b), new FLOAT(a)));
    }

    public String floatAddition(FLOAT a, FLOAT b) {
        int exp = Math.max(a.exp, b.exp);
        b.sig = rightShift(b.sig, exp - b.exp);
        a.sig = rightShift(a.sig, exp - a.exp);

        String temp = signedAdder(a.sign + a.sig, b.sign + b.sig);
        boolean overFlow = temp.charAt(0) == '1';
        char sign = temp.charAt(1);
        String sig = temp.substring(2);
        if (overFlow) {
            exp++;
            sig = "1" + sig.substring(0, sig.length() - 1);
        }
        if (exp >= 255) {
            return "" + sign + "11111111" + String.join("", Collections.nCopies(sLength, "0"));
        }
        return NormalTreatment1(sig, exp, sign, sig.length());
    }

    public String floatMul(FLOAT a, FLOAT b) {
        int exp = a.exp + b.exp - 127;
        char sign = (char) ((a.sign - '0') ^ (b.sign - '0') + '0');
        if (a.exp == 255 || b.exp == 255) {
            return "" + sign + "11111111" + String.join("", Collections.nCopies(sLength, "0"));
        }
        String sig = unsignedMul(a.sig, b.sig, a.sig.length());
        //乘积的隐藏位是2位
        exp++;
        return NormalTreatment2(sig, exp, sign, a.sig.length());
    }

    // a / b
    public String floatDiv(FLOAT a, FLOAT b) {
        char sign = (char) ((a.sign - '0') ^ (b.sign - '0') + '0');
        int exp = a.exp - b.exp + 127;
        if (a.exp == 255) {
            return "" + sign + "11111111" + String.join("", Collections.nCopies(sLength, "0"));
        }
        if (b.exp == 255) {
            return "" + sign + "00000000" + String.join("", Collections.nCopies(sLength, "0"));
        }
        String temp = unsignedDiv(a.sig, b.sig, a.sig.length());
        return NormalTreatment2(temp, exp, sign, a.sig.length());
    }


    public String NormalTreatment1(String sig, int exp, char sign, int length) {
        while (sig.charAt(0) != '1' && exp > 0) { //加减乘除均需要
            sig = leftShift(sig, 1);
            exp--;
        }
        if (exp == 0) {
            sig = rightShift(sig, 1);
        }
        if (isZero(sig)) {  //仅在加减中需要注意符号位设为0
            return "" + String.join("", Collections.nCopies(eLength + sLength + 1, "0"));
        }
        String expStr = String.format("%8s", Integer.toBinaryString(exp)).replaceAll(" ", "0");
        return round(sign, expStr, sig);
    }

    public String NormalTreatment2(String sig, int exp, char sign, int length) {
        while (sig.charAt(0) != '1' && exp > 0) { //加减乘除均需要
            sig = leftShift(sig, 1);
            exp--;
        }
        while (!isZero(sig.substring(0, length)) && exp < 0) { //仅在乘除中需要
            sig = rightShift(sig, 1);
            exp++;
        }
        if (exp >= 255) { //乘除中需要
            return "" + sign + "11111111" + String.join("", Collections.nCopies(sLength, "0"));
        }
        if (exp == 0) {
            sig = rightShift(sig, 1);
        }
        if (exp < 0) {  //仅在乘除中需要,注意符号位设为sign
            return "" + sign + String.join("", Collections.nCopies(eLength + sLength, "0"));
        }
        String expStr = String.format("%8s", Integer.toBinaryString(exp)).replaceAll(" ", "0");
        return round(sign, expStr, sig);
    }

    //第一位是符号位的加法
    public String signedAdder(String a, String b) {
        char signA = a.charAt(0);
        char signB = b.charAt(0);
        //对于零情况的特殊判断
        if (isZero(a.substring(1))) return "0" + b;
        if (isZero(b.substring(1))) return "0" + a;
        a = a.substring(1);
        b = b.substring(1);
        if (signA == signB) { //用 temp.charAt(0) 判断是否溢出
            String temp = carry_adder(a, b, 0, a.length());
            return "" + temp.charAt(0) + signA + temp.substring(1);
        } else {
            b = oneAdder(negation(b)).substring(1);
            String temp = carry_adder(a, b, 0, a.length());
            if (temp.charAt(0) == '1') return "0" + signA + temp.substring(1);
            return "0" + negation("" + signA) + oneAdder(negation(temp.substring(1))).substring(1);
        }
    }

    String unsignedMul(String x, String y, int length) {
        String ans = String.join("", Collections.nCopies(length, "0")) + y;
        for (int i = 0; i < length; i++) {
            char carry = '0';
            if (ans.charAt(2 * length - 1) == '1') {
                String temp = carry_adder(x, ans.substring(0, length), 0, length);
                carry = temp.charAt(0);
                ans = temp.substring(1) + ans.substring(length);
            }
            ans = carry + ans.substring(0, 2 * length - 1);
        }
        return ans;
    }

    // x / y
    String unsignedDiv(String x, String y, int length) {
        String Qstr = "";
        x += String.join("", Collections.nCopies(length, "0"));
        String negy = oneAdder(negation(y)).substring(1);
        for (int i = 0; i < length; i++) {
            String temp = carry_adder(x.substring(0, length), negy, 0, length).substring(1);
            if (temp.charAt(0) == '0') {
                x = temp.substring(1) + x.substring(length) + "1";
            } else {
                x = leftShift(x, 1);
            }
        }
        Qstr = x.substring(length);
        return Qstr;
    }

    public String carry_adder(String add1, String add2, int carry, int length) {
        StringBuilder ans = new StringBuilder();
        int x, y;
        for (int i = length - 1; i >= 0; i--) {//顺序是从低位到高位
            x = add1.charAt(i) - '0';
            y = add2.charAt(i) - '0';
            ans.insert(0, x ^ y ^ carry);
            carry = x & carry | y & carry | x & y;
        }
        return "" + carry + ans;
    }

    public boolean isZero(String s) {
        for (char c : s.toCharArray()) {
            if (c != '0') return false;
        }
        return true;
    }

    public String leftShift(String s, int n) {
        StringBuilder res = new StringBuilder(s.substring(n));
        for (int i = 0; i < n; i++) {
            res.append(0);
        }
        return res.toString();
    }

    public DataType Corner(String a, String b, String[][] corner) {
        String check = cornerCheck(corner, a, b);
        if (check != null) return new DataType(check);
        if (a.matches(IEEE754Float.NaN_Regular) || b.matches(IEEE754Float.NaN_Regular)) {
            return new DataType(IEEE754Float.NaN);
        }
        return null;
    }

    private String cornerCheck(String[][] cornerMatrix, String oprA, String oprB) {
        for (String[] matrix : cornerMatrix) {
            if (oprA.equals(matrix[0]) && oprB.equals(matrix[1])) {
                return matrix[2];
            }
        }
        return null;
    }

    private String rightShift(String operand, int n) {
        StringBuilder result = new StringBuilder(operand);  //保证位数不变
        boolean sticky = false;
        for (int i = 0; i < n; i++) {
            sticky = sticky || result.toString().endsWith("1");
            result.insert(0, "0");
            result.deleteCharAt(result.length() - 1);
        }
        if (sticky) {
            result.replace(operand.length() - 1, operand.length(), "1");
        }
        return result.substring(0, operand.length());
    }

    /**
     * 对GRS保护位进行舍入
     *
     * @param sign    符号位
     * @param exp     阶码
     * @param sig_grs 带隐藏位和保护位的尾数
     * @return 舍入后的结果
     */
    private String round(char sign, String exp, String sig_grs) {
        int grs = Integer.parseInt(sig_grs.substring(24, 27), 2);
        if ((sig_grs.substring(27).contains("1")) && (grs % 2 == 0)) {
            grs++;
        }
        String sig = sig_grs.substring(0, 24); // 隐藏位+23位
        if (grs > 4 || (grs == 4 && sig.endsWith("1"))) {
            sig = oneAdder(sig);
            if (sig.charAt(0) == '1') {
                exp = oneAdder(exp).substring(1);
                sig = sig.substring(1);
            }
        }

        if (Integer.parseInt(sig.substring(0, sig.length() - 23), 2) > 1) {
            sig = rightShift(sig, 1);
            exp = oneAdder(exp).substring(1);
        }
        if (exp.equals("11111111")) {
            return sign == '0' ? IEEE754Float.P_INF : IEEE754Float.N_INF;
        }

        return sign + exp + sig.substring(sig.length() - 23);
    }


}
Print Friendly, PDF & Email