Javascript 实现的RISC-V模拟器,可用于在线模拟器搭建

使用方法(示例):

let state = new RVState(256);

state.load(code); //code里不允许空行

// while(condition){

state.step(); //单步执行

// }

let ra = state.reg[1]; //获取寄存器的值

let v = state.ram[0]; //获取内存的值(按字存取)

let pc = state.pc; //获取pc的值

有错误的话欢迎指出。

由于本人不太擅长前端(尤其是美化),所以没有做出完整的网页(其实做了,太丑不放)。如果有人给这个代码做出了前端界面并且发布在网站上,请告诉我,让我欣赏一下~

/**
 * RISCV32 Simulator
 * @author Wenhan Zhang
 * "offset(register)" is not supported.
 * lw a0, -100(s0) -> lw a0, s0, -100
 * sw a0, -100(s0) -> sw a0, s0, -100
 * jalr zero, 0(ra) -> jalr zero, ra, 0
 */

const RVInstructionOp = {
    add: 0,
    sub: 1,
    mul: 2,
    div: 3,
    sll: 4,
    srl: 5,
    sra: 6,
    slt: 7,
    sltu: 8,
    and: 9,
    or: 10,
    xor: 11,
    addi: 12,
    muli: 13,
    divi: 14,
    slli: 15,
    srli: 16,
    srai: 17,
    slti: 18,
    sltiu: 19,
    andi: 20,
    ori: 21,
    xori: 22,
    lb: 23,
    lh: 24,
    lw: 25,
    lbu: 26,
    lhu: 27,
    sb: 28,
    sh: 29,
    sw: 30,
    lui: 31,
    auipc: 32,
    jal : 33,
    jalr : 34,
    beq : 35,
    bne : 36,
    blt : 37,
    bge : 38,
    bltu : 39,
    bgeu : 40
}

const RVInstructionOpType = {
    add: 0,
    sub: 0,
    mul: 0,
    div: 0,
    sll: 0,
    srl: 0,
    sra: 0,
    slt: 0,
    sltu: 0,
    and: 0,
    or: 0,
    xor: 0,
    addi: 1,
    muli: 1,
    divi: 1,
    slli: 1,
    srli: 1,
    srai: 1,
    slti: 1,
    sltiu: 1,
    andi: 1,
    ori: 1,
    xori: 1,
    lb: 1,
    lh: 1,
    lw: 1,
    lbu: 1,
    lhu: 1,
    sb: 2,
    sh: 2,
    sw: 2,
    lui: 3,
    auipc: 3,
    jal : 4,
    jalr : 1,
    beq : 5,
    bne : 5,
    blt : 5,
    bge : 5,
    bltu : 5,
    bgeu : 5
}

const RVRegister = {
    zero:0,
    ra:1,
    sp:2,
    gp:3,
    tp:4,
    t0:5,
    t1:6,
    t2:7,
    s0:8,
    s1:9,
    a0:10,
    a1:11,
    a2:12,
    a3:13,
    a4:14,
    a5:15,
    a6:16,
    a7:17,
    s2:18,
    s3:19,
    s4:20,
    s5:21,
    s6:22,
    s7:23,
    s8:24,
    s9:25,
    s10:26,
    s11:27,
    t3:28,
    t4:29,
    t5:30,
    t6:31,
    x0:0,
    x1:1,
    x2:2,
    x3:3,
    x4:4,
    x5:5,
    x6:6,
    x7:7,
    x8:8,
    x9:9,
    x10:10,
    x11:11,
    x12:12,
    x13:13,
    x14:14,
    x15:15,
    x16:16,
    x17:17,
    x18:18,
    x19:19,
    x20:20,
    x21:21,
    x22:22,
    x23:23,
    x24:24,
    x25:25,
    x26:26,
    x27:27,
    x28:28,
    x29:29,
    x30:30,
    x31:31
}

class RVInstruction {
    constructor(op, argstr) {
        let rd = 0;
        let rs1 = 0;
        let rs2 = 0;

        let imm = 0;
        let label = "";

        let args = null;
        switch (RVInstructionOpType[op]) {
            case 0:
                args = argstr.split(",");
                rd = RVRegister[args[0]];
                rs1 = RVRegister[args[1]];
                rs2 = RVRegister[args[2]];
                break;
            case 1:
                args = argstr.split(",");
                rd = RVRegister[args[0]];
                rs1 = RVRegister[args[1]];
                imm = parseInt(args[2]);
                break;
            case 2:
                args = argstr.split(",");
                rs2 = RVRegister[args[0]];
                rs1 = RVRegister[args[1]];
                imm = parseInt(args[2]);
                break;
            case 3:
                args = argstr.split(",");
                rd = RVRegister[args[0]];
                imm = parseInt(args[1]);
                break;
            case 4:
                args = argstr.split(",");
                rd = RVRegister[args[0]];
                label = args[1];
                break;
            case 5:
                args = argstr.split(",");
                rs1 = RVRegister[args[0]];
                rs1 = RVRegister[args[1]];
                label = args[2];
                break;
        }

        this.rd = rd;
        this.rs1 = rs1;
        this.rs2 = rs2;
        this.imm = imm;
        this.label = label;
        this.op = RVInstructionOp[op];
        this.text = op + " " + argstr;
        console.log(this.op);
    }
};

class RVState {
    constructor(ram_size) {
        this.reg = new Int32Array(32);
        this.ram = new Int32Array(ram_size);
        this.pc = 0;
        this.inst_ram = [];
        this.label_list = {};
    }
    clear(){
        this.inst_ram = [];
        this.label_list = {};
    }
    reset(){
        this.reg.forEach((value, index, array) => {
            this.reg[index] = 0;
        });
        this.ram.forEach((value, index, array) => {
            this.ram[index] = 0;
        });
        this.pc = 0;
    }
    load(text){
        let lines = text.split("\n");
        let line_num = 0;
        lines.forEach((value, index, array) => {
            if(lines[index].indexOf("#")!==-1){
                lines[index] = lines[index].slice(0, lines[index].indexOf("#"));
            }
            if(lines[index].indexOf(":")!==-1){
                let label = lines[index].slice(0, lines[index].indexOf(":"));
                this.label_list[label] = line_num;
            }else{
                lines[index] = lines[index].trim();
                let [op, ...args] = lines[index].split(/\s+/);
                args = args.join("");
                let inst = new RVInstruction(op, args);
                this.inst_ram.push(inst);
                line_num = line_num + 4;
            }
        });
    }
    step(){
        this.exec(this.inst_ram[this.pc/4]);
    }
    exec(inst) {
        let pc_change = false;
        switch (inst.op) {
            case RVInstructionOp.add:
                this.reg[inst.rd] = this.reg[inst.rs1] + this.reg[inst.rs2];
                break;
            case RVInstructionOp.sub:
                this.reg[inst.rd] = this.reg[inst.rs1] - this.reg[inst.rs2];
                break;
            case RVInstructionOp.mul:
                this.reg[inst.rd] = this.reg[inst.rs1] * this.reg[inst.rs2];
                break;
            case RVInstructionOp.div:
                this.reg[inst.rd] = this.reg[inst.rs1] / this.reg[inst.rs2];
                break;
            case RVInstructionOp.sll:
                this.reg[inst.rd] = this.reg[inst.rs1] << this.reg[inst.rs2];
                break;
            case RVInstructionOp.srl:
                this.reg[inst.rd] = this.reg[inst.rs1] >>> this.reg[inst.rs2];
                break;
            case RVInstructionOp.sra:
                this.reg[inst.rd] = this.reg[inst.rs1] >> this.reg[inst.rs2];
                break;
            case RVInstructionOp.slt:
                if (this.reg[inst.rs1] < this.reg[inst.rs2]) {
                    this.reg[inst.rd] = 1;
                } else {
                    this.reg[inst.rd] = 0;
                }
                break;
            case RVInstructionOp.sltu:
                if (this.reg[inst.rs1] > 0 && this.reg[inst.rs1] < this.reg[inst.rs2] < 0) {
                    this.reg[inst.rd] = 1;
                } else if ((this.reg[inst.rs1] & 0x7fffffff) < (this.reg[inst.rs2] & 0x7fffffff)) {
                    this.reg[inst.rd] = 1;
                } else {
                    this.reg[inst.rd] = 0;
                }
                break;
            case RVInstructionOp.and:
                this.reg[inst.rd] = this.reg[inst.rs1] & this.reg[inst.rs2];
                break;
            case RVInstructionOp.or:
                this.reg[inst.rd] = this.reg[inst.rs1] | this.reg[inst.rs2];
                break;
            case RVInstructionOp.xor:
                this.reg[inst.rd] = this.reg[inst.rs1] ^ this.reg[inst.rs2];
                break;
            case RVInstructionOp.add:
                this.reg[inst.rd] = this.reg[inst.rs1] + this.reg[inst.rs2];
                break;
            case RVInstructionOp.sub:
                this.reg[inst.rd] = this.reg[inst.rs1] - this.reg[inst.rs2];
                break;
            case RVInstructionOp.mul:
                this.reg[inst.rd] = this.reg[inst.rs1] * this.reg[inst.rs2];
                break;
            case RVInstructionOp.div:
                this.reg[inst.rd] = this.reg[inst.rs1] / this.reg[inst.rs2];
                break;
            case RVInstructionOp.sll:
                this.reg[inst.rd] = this.reg[inst.rs1] << this.reg[inst.rs2];
                break;
            case RVInstructionOp.srl:
                this.reg[inst.rd] = this.reg[inst.rs1] >>> this.reg[inst.rs2];
                break;
            case RVInstructionOp.sra:
                this.reg[inst.rd] = this.reg[inst.rs1] >> this.reg[inst.rs2];
                break;
            case RVInstructionOp.slt:
                if (this.reg[inst.rs1] < this.reg[inst.rs2]) {
                    this.reg[inst.rd] = 1;
                } else {
                    this.reg[inst.rd] = 0;
                }
                break;
            case RVInstructionOp.sltu:
                if (this.reg[inst.rs1] > 0 && this.reg[inst.rs1] < this.reg[inst.rs2] < 0) {
                    this.reg[inst.rd] = 1;
                } else if ((this.reg[inst.rs1] & 0x7fffffff) < (this.reg[inst.rs2] & 0x7fffffff)) {
                    this.reg[inst.rd] = 1;
                } else {
                    this.reg[inst.rd] = 0;
                }
                break;
            case RVInstructionOp.and:
                this.reg[inst.rd] = this.reg[inst.rs1] & this.reg[inst.rs2];
                break;
            case RVInstructionOp.or:
                this.reg[inst.rd] = this.reg[inst.rs1] | this.reg[inst.rs2];
                break;
            case RVInstructionOp.xor:
                this.reg[inst.rd] = this.reg[inst.rs1] ^ this.reg[inst.rs2];
                break;
            case RVInstructionOp.addi:
                this.reg[inst.rd] = this.reg[inst.rs1] + inst.imm;
                break;
            case RVInstructionOp.muli:
                this.reg[inst.rd] = this.reg[inst.rs1] * inst.imm;
                break;
            case RVInstructionOp.divi:
                this.reg[inst.rd] = this.reg[inst.rs1] / inst.imm;
                break;
            case RVInstructionOp.slli:
                this.reg[inst.rd] = this.reg[inst.rs1] << inst.imm;
                break;
            case RVInstructionOp.srli:
                this.reg[inst.rd] = this.reg[inst.rs1] >>> inst.imm;
                break;
            case RVInstructionOp.srai:
                this.reg[inst.rd] = this.reg[inst.rs1] >> inst.imm;
                break;
            case RVInstructionOp.slti:
                if (this.reg[inst.rs1] < inst.imm) {
                    this.reg[inst.rd] = 1;
                } else {
                    this.reg[inst.rd] = 0;
                }
                break;
            case RVInstructionOp.sltiu:
                if (this.reg[inst.rs1] > 0 && this.reg[inst.rs1] < inst.imm < 0) {
                    this.reg[inst.rd] = 1;
                } else if ((this.reg[inst.rs1] & 0x7fffffff) < (inst.imm & 0x7fffffff)) {
                    this.reg[inst.rd] = 1;
                } else {
                    this.reg[inst.rd] = 0;
                }
                break;
            case RVInstructionOp.andi:
                this.reg[inst.rd] = this.reg[inst.rs1] & inst.imm;
                break;
            case RVInstructionOp.ori:
                this.reg[inst.rd] = this.reg[inst.rs1] | inst.imm;
                break;
            case RVInstructionOp.xori:
                this.reg[inst.rd] = this.reg[inst.rs1] ^ inst.imm;
                break;
            case RVInstructionOp.lb:{
                let offset = inst.imm%4;
                let w = (inst.imm-offset)/4;
                let word = this.ram[this.reg[inst.rs1]+w];
                this.reg[inst.rd] = ((word&(0xff<<(offset*8)))<<(24-offset*8))>>24;
                break;}
            case RVInstructionOp.lh:{
                let offset = inst.imm%2;
                let w = (inst.imm-offset)/2;
                let word = this.ram[this.reg[inst.rs1]+w];
                this.reg[inst.rd] = ((word&(0xffff<<(offset*16)))<<(16-offset*16))>>16;
                break;}
            case RVInstructionOp.lw:
                this.reg[inst.rd] = this.ram[this.reg[inst.rs1]+inst.imm/4];
                break;
            case RVInstructionOp.lbu:{
                let offset = inst.imm%4;
                let w = (inst.imm-offset)/4;
                let word = this.ram[this.reg[inst.rs1]+w];
                this.reg[inst.rd] = ((word&(0xff<<(offset*8)))>>(offset*8))&0xff;
                break;}
            case RVInstructionOp.lhu:{
                let offset = inst.imm%2;
                let w = (inst.imm-offset)/2;
                let word = this.ram[this.reg[inst.rs1]+w];
                this.reg[inst.rd] = ((word&(0xffff<<(offset*16)))>>(offset*16))&0xffff;
                break;}
            case RVInstructionOp.sb:{
                let offset = inst.imm%4;
                let w = (inst.imm-offset)/4;
                let word = this.ram[this.reg[inst.rs1]+w]|(0xff<<(offset*8));
                word = word & ((this.reg[inst.rs2]&0xff)<<(offset*8));
                this.ram[this.reg[inst.rs1]+w] = word;
                break;}
            case RVInstructionOp.sh:{
                let offset = inst.imm%2;
                let w = (inst.imm-offset)/2;
                let word = this.ram[this.reg[inst.rs1]+w]|(0xffff<<(offset*16));
                word = word & ((this.reg[inst.rs2]&0xffff)<<(offset*16));
                this.ram[this.reg[inst.rs1]+w] = word;
                break;}
            case RVInstructionOp.sw:
                this.ram[this.reg[inst.rs1]+inst.imm/4] = this.reg[inst.rs2];
                break;
            case RVInstructionOp.auipc:
                this.reg[inst.rd] = this.pc + inst.imm<<20;
                break;
            case RVInstructionOp.lui:
                this.reg[inst.rd] = inst.imm<<20;
                break;
            case RVInstructionOp.jal:
                this.reg[inst.rd] = this.pc + 4;
                this.pc = this.label_list[inst.label];
                pc_change = true;
                break;
            case RVInstructionOp.jalr:
                this.reg[inst.rd] = this.pc + 4;
                this.pc = this.reg[inst.rs1]+inst.imm;
                pc_change = true;
                break;
            case RVInstructionOp.beq:
                if(this.reg[inst.rs1]==this.reg[inst.rs2]){
                    this.pc = this.label_list[inst.label];
                    pc_change = true;
                }
                break;
            case RVInstructionOp.bne:
                if(this.reg[inst.rs1]!=this.reg[inst.rs2]){
                    this.pc = this.label_list[inst.label];
                    pc_change = true;
                }
                break;
            case RVInstructionOp.blt:
                if(this.reg[inst.rs1]<this.reg[inst.rs2]){
                    this.pc = this.label_list[inst.label];
                    pc_change = true;
                }
                break;
            case RVInstructionOp.bge:
                if(this.reg[inst.rs1]>=this.reg[inst.rs2]){
                    this.pc = this.label_list[inst.label];
                    pc_change = true;
                }
                break;
            case RVInstructionOp.bltu:
                if((this.reg[inst.rs1]>0&&this.reg[inst.rs1]<0)||(this.reg[inst.rs1]<this.reg[inst.rs2])){
                    this.pc = this.label_list[inst.label];
                    pc_change = true;
                }
                break;
            case RVInstructionOp.bgeu:
                if(!((this.reg[inst.rs1]>0&&this.reg[inst.rs1]<0)||(this.reg[inst.rs1]<this.reg[inst.rs2]))){
                    this.pc = this.label_list[inst.label];
                    pc_change = true;
                }
                break;
        }
        if(!pc_change){
            this.pc = this.pc + 4;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值