为做好的CPU写一个编译器
本文最后更新于 990 天前,其中的信息可能已经有所发展或是发生改变。

上一篇记录了一次CPU的制作过程:如何制作一个简易16位CPU – LovelyCat的小站

于是我又试着写了一个编译器来实现真正的可编程,下面只展示一些核心代码。

由于编程语言语法简单,编译器的逻辑也很简单,无数if for套上去就是了

此编译器逐行读取代码,因此一行只能有一条指令。

语法

结构:指令 参数1, 参数2, 参数3…

例如:MOV R0, 1 ALU ADD, R1 = R0 + R1

核心代码

枚举

指令代码枚举类

public enum Code {
    LOAD("0001",2, 8,ParamType.Register, ParamType.ADDR),
    STORE("0010",2, 8,ParamType.Register, ParamType.ADDR),
    MOV("0011",2, 8,ParamType.Register, ParamType.VALUE),
    ALU("0100",4, 4,ParamType.VALUE, ParamType.Register, ParamType.Register, ParamType.Register),
    HALT("0101",1, 1,ParamType.VALUE),
    JUMP_A("0110",1, 12,ParamType.VALUE),
    JUMP_S("0111",1, 12,ParamType.VALUE),
    JUMP_GT("1000",5, 6,ParamType.VALUE, ParamType.Register, ParamType.Register, ParamType.BOOLEAN, ParamType.BOOLEAN),
    JUMP_LT("1001",5, 6,ParamType.VALUE, ParamType.Register, ParamType.Register, ParamType.BOOLEAN, ParamType.BOOLEAN),
    JUMP_EQ("1010",5, 6,ParamType.VALUE, ParamType.Register, ParamType.Register, ParamType.BOOLEAN, ParamType.BOOLEAN);

    public String code;
    public int paramsLength;
    public ParamType[] paramTypes;
    public int vLength;
    Code(String code, int paramsLength, int vLength, ParamType... paramTypes) {
        this.code = code;
        this.paramsLength = paramsLength;
        this.vLength = vLength;
        this.paramTypes = paramTypes;
    }
}

paramsLength是参数的个数,vLength是某参数的最大长度,code为4位指令。

同样可以为ALUCode创建一个枚举

ALU操作枚举

public enum ALUMode {
    ADD("0001"),
    SUB("0010");

    public String code;
    ALUMode(String code) {
        this.code = code;
    }
}

参数类型枚举

public enum ParamType {
    Register,
    ADDR,
    VALUE,
    BOOLEAN
}

数据检查与操作

初步检查参数是否合法

// 检查参数是否合法 合法返回空 不合法返回信息                                                                                          
public static String checkParamType(ParamType paramType, String value) {                                           
    switch (paramType) {                                                                                           
        case Register:                                                                                             
            if (regNameToADDR(value).equals("-2")) return String.format("未知寄存器 %s {%s}", value, value);            
            break;                                                                                                 
        case BOOLEAN:                                                                                              
            if (value.length() != 1 || !isOnly2B(value)) return String.format("布尔值只能为0或1");                        
            break;                                                                                                 
    }                                                                                                              
    return "";                                                                                                     
}                                                                                                                  

检查参数长度

public static String GreatThanMaxLength(Code code, String v) {                                                             
    return code.vLength < v.length() ? String.format("参数长度(%s)过长 最长应为 %s {%s}", v.length(), code.vLength, v) : "";         
}                                                                                                                          

位拓展器

// 位拓展                                                                            
public static String extend(String origin, int to, int mode) {                    
    String ss = "";                                                               
    String add = "";                                                              
    switch (mode) {                                                               
        case 0:                                                                   
            add = "0";                                                            
            break;                                                                
        case 1:                                                                   
            add = "1";                                                            
            break;                                                                
    }                                                                             
    for (int i=0;i<to - origin.length();i++) {                                    
        ss += add;                                                                
    }                                                                             
    return ss + origin;                                                           
}                                                                                 

// 十进制整数转二进制并拓展位                                                                        
public static String intTo2BAndExtend(String num, int extendTo, int extendMode) {       
    return extend(Integer.toBinaryString(Integer.parseInt(num)),extendTo, extendMode);  
}                                                                                       

比较整数与指定位宽的二进制的大小

若isADDR为真则将vB转换成二进制再与a比较

// 比较 十进制数与指定位数的二进制数的大小 例如 a=9 bits=4 isADDR = true 则9 < 1111                                                                                     
public static String to2BAndGreatThan(String a, int bits, boolean isADDR) {                                                                       
    String extendedvB = extend("1", bits, 1);                                                                                                     
    long vB = Long.parseLong(extendedvB);                                                                                                         
    long vB10 = Long.parseLong(String.valueOf(vB), 2);                                                                                            
    return Long.parseLong(a) > (isADDR ? vB : vB10) ? String.format("%s 数值太大 最大应为 %s(%s) [%s > %s] {%s}", a, extendedvB, vB10, a, vB10, a) : "";  
}                                                                                                                                                 
                                                                                                                                                

构造ROM HEX

在Logisim里面我用的是地址位宽和数据位宽都为16的ROM/RAM。

因此从Logisim导出的ROM HEX文件中有16列4096行,刚好是65536个数据。

// 构造可以被Logisim ROM读取的文本                                                                              
StringBuilder resultHEXROM = new StringBuilder();                                                     
resultHEXROM.append("v3.0 hex words addressed\n");                                                    
int codeIndex = 0;                                                                                    
int maxLines = 4096;                                                                                  
int maxColumns = 16;                                                                                  
for (int lineIndex=0;lineIndex<maxLines;lineIndex++) {                                                
    StringBuilder lineStr = new StringBuilder(" ");                                                   
    for (int columnIndex=0;columnIndex<maxColumns;columnIndex++,codeIndex++)                          
        lineStr.append(codeIndex > result6.size() - 1 ? "0000" : result6.get(codeIndex)).append(" "); 
    String lineHex = Integer.toHexString(lineIndex * 16);                                             
    String resultLine = extend(lineHex, 4, 0) + ":" + lineStr;                                        
    resultHEXROM.append(resultLine).append("\n");                                                     
}

主要判断逻辑

String preCode = code.code;                                                                                                                                                   
switch (code) {                                                                                                                                                               
    case ALU:                                                                                                                                                                 
        preCode += ALUMode.valueOf(params[0]).code + regNameToADDR(params[1]) + regNameToADDR(params[2]) +regNameToADDR(params[3]) + "00";                                    
        break;                                                                                                                                                                
    case MOV:                                                                                                                                                                 
        errorMsg = GreatThanMaxLength(code, params[1]);                                                                                                                       
        if (!errorMsg.equals("")) break;                                                                                                                                      
        String movValue = intTo2BAndExtend(params[1], 8, 0);                                                                                                                  
        errorMsg = to2BAndGreatThan(params[1], 8, paramTypes[1] == ParamType.ADDR);                                                                                           
        preCode += regNameToADDR(params[0]) + "00" + movValue;                                                                                                                
        break;                                                                                                                                                                
    case HALT:                                                                                                                                                                
        String haltValue = params[0];                                                                                                                                         
        errorMsg = GreatThanMaxLength(code, haltValue);                                                                                                                       
        if (!errorMsg.equals("")) break;                                                                                                                                      
        errorMsg = to2BAndGreatThan(haltValue, 12,paramTypes[0] == ParamType.ADDR);                                                                                           
        preCode += extend(params[0], 12, 0);                                                                                                                                  
        break;                                                                                                                                                                
    case LOAD:                                                                                                                                                                
    case STORE:                                                                                                                                                               
        String loadValue = params[1];                                                                                                                                         
        errorMsg = GreatThanMaxLength(code, loadValue);                                                                                                                       
        if (!errorMsg.equals("")) break;                                                                                                                                      
        errorMsg = to2BAndGreatThan(loadValue, 8,paramTypes[1] == ParamType.ADDR);                                                                                            
        preCode += regNameToADDR(params[0]) + "00" + loadValue;                                                                                                               
        break;                                                                                                                                                                
    case JUMP_A:                                                                                                                                                              
    case JUMP_S:                                                                                                                                                              
        String jump_aValue = params[0];                                                                                                                                       
        errorMsg = GreatThanMaxLength(code, jump_aValue);                                                                                                                     
        if (!errorMsg.equals("")) break;                                                                                                                                      
        errorMsg = to2BAndGreatThan(jump_aValue, 12,paramTypes[0] == ParamType.ADDR);                                                                                         
        preCode += intTo2BAndExtend(jump_aValue,12,0);                                                                                                                        
        break;                                                                                                                                                                
    case JUMP_EQ:                                                                                                                                                             
    case JUMP_GT:                                                                                                                                                             
    case JUMP_LT:                                                                                                                                                             
        String jump_eqValue = params[0];                                                                                                                                      
        errorMsg = GreatThanMaxLength(code, jump_eqValue);                                                                                                                    
        if (!errorMsg.equals("")) break;                                                                                                                                      
        errorMsg = to2BAndGreatThan(jump_eqValue, 6,paramTypes[0] == ParamType.ADDR);                                                                                         
        preCode += intTo2BAndExtend(jump_eqValue,6,0) + regNameToADDR(params[1]) + regNameToADDR(params[2]) + params[3] + params[4];                                          
        break;                                                                                                                                                                
}                                                                                                                                                                             
result2.add(preCode);                                                                                                                                                         

编程测试

这次的代码用的是上一期演示的指令。

最后

到目前为止,整个项目就已经很完整了,有可以执行指令的CPU和编译器,现在可以轻松地编写出自制CPU可以运行的程序了。

未经允许禁止转载本站内容,经允许转载后请严格遵守CC-BY-NC-ND知识共享协议4.0,代码部分则采用GPL v3.0协议
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇