rvc/instructions.txt

1683 lines
40 KiB
Plaintext
Raw Normal View History

Instruction {
mask: 0xfe00707f,
data: 0x00000033,
name: "ADD",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_add(cpu.x[f.rs2]));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00000013,
name: "ADDI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_add(f.imm));
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0x0000707f,
data: 0x0000001b,
name: "ADDIW",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.x[f.rs1].wrapping_add(f.imm) as i32 as i64;
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0x0000003b,
name: "ADDW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.x[f.rs1].wrapping_add(cpu.x[f.rs2]) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0000302f,
name: "AMOADD.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2].wrapping_add(tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0000202f,
name: "AMOADD.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2].wrapping_add(tmp) as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x6000302f,
name: "AMOAND.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] & tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x6000202f,
name: "AMOAND.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] & tmp) as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0xe000302f,
name: "AMOMAXU.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data,
Err(e) => return Err(e)
};
let max = match cpu.x[f.rs2] as u64 >= tmp {
true => cpu.x[f.rs2] as u64,
false => tmp
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, max) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0xe000202f,
name: "AMOMAXU.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data,
Err(e) => return Err(e)
};
let max = match cpu.x[f.rs2] as u32 >= tmp {
true => cpu.x[f.rs2] as u32,
false => tmp
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, max) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x4000302f,
name: "AMOOR.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] | tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x4000202f,
name: "AMOOR.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] | tmp) as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0800302f,
name: "AMOSWAP.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0800202f,
name: "AMOSWAP.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x00007033,
name: "AND",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] & cpu.x[f.rs2]);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00007013,
name: "ANDI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] & f.imm);
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0x0000007f,
data: 0x00000017,
name: "AUIPC",
operation: |cpu, word, address| {
let f = parse_format_u(word);
cpu.x[f.rd] = cpu.sign_extend(address.wrapping_add(f.imm) as i64);
Ok(())
},
disassemble: dump_format_u
},
Instruction {
mask: 0x0000707f,
data: 0x00000063,
name: "BEQ",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) == cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00005063,
name: "BGE",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) >= cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00007063,
name: "BGEU",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.unsigned_data(cpu.x[f.rs1]) >= cpu.unsigned_data(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00004063,
name: "BLT",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) < cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00006063,
name: "BLTU",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.unsigned_data(cpu.x[f.rs1]) < cpu.unsigned_data(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00001063,
name: "BNE",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) != cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00003073,
name: "CSRRC",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
let tmp = cpu.x[f.rs];
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, (cpu.x[f.rd] & !tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00007073,
name: "CSRRCI",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, (cpu.x[f.rd] & !(f.rs as i64)) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00002073,
name: "CSRRS",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
let tmp = cpu.x[f.rs];
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, cpu.unsigned_data(cpu.x[f.rd] | tmp)) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00006073,
name: "CSRRSI",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, cpu.unsigned_data(cpu.x[f.rd] | (f.rs as i64))) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00001073,
name: "CSRRW",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
let tmp = cpu.x[f.rs];
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, cpu.unsigned_data(tmp)) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00005073,
name: "CSRRWI",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, f.rs as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0xfe00707f,
data: 0x02004033,
name: "DIV",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1];
let divisor = cpu.x[f.rs2];
if divisor == 0 {
cpu.x[f.rd] = -1;
} else if dividend == cpu.most_negative() && divisor == -1 {
cpu.x[f.rd] = dividend;
} else {
cpu.x[f.rd] = cpu.sign_extend(dividend.wrapping_div(divisor))
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02005033,
name: "DIVU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.unsigned_data(cpu.x[f.rs1]);
let divisor = cpu.unsigned_data(cpu.x[f.rs2]);
if divisor == 0 {
cpu.x[f.rd] = -1;
} else {
cpu.x[f.rd] = cpu.sign_extend(dividend.wrapping_div(divisor) as i64)
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200503b,
name: "DIVUW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.unsigned_data(cpu.x[f.rs1]) as u32;
let divisor = cpu.unsigned_data(cpu.x[f.rs2]) as u32;
if divisor == 0 {
cpu.x[f.rd] = -1;
} else {
cpu.x[f.rd] = dividend.wrapping_div(divisor) as i32 as i64
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200403b,
name: "DIVW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1] as i32;
let divisor = cpu.x[f.rs2] as i32;
if divisor == 0 {
cpu.x[f.rd] = -1;
} else if dividend == std::i32::MIN && divisor == -1 {
cpu.x[f.rd] = dividend as i32 as i64;
} else {
cpu.x[f.rd] = dividend.wrapping_div(divisor) as i32 as i64
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xffffffff,
data: 0x00100073,
name: "EBREAK",
operation: |_cpu, _word, _address| {
// @TODO: Implement
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xffffffff,
data: 0x00000073,
name: "ECALL",
operation: |cpu, _word, address| {
let exception_type = match cpu.privilege_mode {
PrivilegeMode::User => TrapType::EnvironmentCallFromUMode,
PrivilegeMode::Supervisor => TrapType::EnvironmentCallFromSMode,
PrivilegeMode::Machine => TrapType::EnvironmentCallFromMMode,
PrivilegeMode::Reserved => panic!("Unknown Privilege mode")
};
return Err(Trap {
trap_type: exception_type,
value: address
});
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00007f,
data: 0x02000053,
name: "FADD.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.f[f.rs1] + cpu.f[f.rs2];
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xd2200053,
name: "FCVT.D.L",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.x[f.rs1] as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0x42000053,
name: "FCVT.D.S",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// Is this implementation correct?
cpu.f[f.rd] = f32::from_bits(cpu.f[f.rs1].to_bits() as u32) as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xd2000053,
name: "FCVT.D.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.x[f.rs1] as i32 as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xd2100053,
name: "FCVT.D.WU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.x[f.rs1] as u32 as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0x40100053,
name: "FCVT.S.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// Is this implementation correct?
cpu.f[f.rd] = cpu.f[f.rs1] as f32 as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xc2000053,
name: "FCVT.W.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// Is this implementation correct?
cpu.x[f.rd] = cpu.f[f.rs1] as u32 as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00007f,
data: 0x1a000053,
name: "FDIV.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.f[f.rs1];
let divisor = cpu.f[f.rs2];
// Is this implementation correct?
if divisor == 0.0 {
cpu.f[f.rd] = std::f64::INFINITY;
cpu.set_fcsr_dz();
} else if divisor == -0.0 {
cpu.f[f.rd] = std::f64::NEG_INFINITY;
cpu.set_fcsr_dz();
} else {
cpu.f[f.rd] = dividend / divisor;
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x0000000f,
name: "FENCE",
operation: |_cpu, _word, _address| {
// Do nothing?
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0x0000707f,
data: 0x0000100f,
name: "FENCE.I",
operation: |_cpu, _word, _address| {
// Do nothing?
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0xa2002053,
name: "FEQ.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.f[f.rs1] == cpu.f[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0x0000707f,
data: 0x00003007,
name: "FLD",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.f[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => f64::from_bits(data),
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0xa2000053,
name: "FLE.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.f[f.rs1] <= cpu.f[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0xa2001053,
name: "FLT.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.f[f.rs1] < cpu.f[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002007,
name: "FLW",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.f[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => f64::from_bits(data as i32 as i64 as u64),
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0600007f,
data: 0x02000043,
name: "FMADD.D",
operation: |cpu, word, _address| {
// @TODO: Update fcsr if needed?
let f = parse_format_r2(word);
cpu.f[f.rd] = cpu.f[f.rs1] * cpu.f[f.rs2] + cpu.f[f.rs3];
Ok(())
},
disassemble: dump_format_r2
},
Instruction {
mask: 0xfe00007f,
data: 0x12000053,
name: "FMUL.D",
operation: |cpu, word, _address| {
// @TODO: Update fcsr if needed?
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.f[f.rs1] * cpu.f[f.rs2];
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xf2000053,
name: "FMV.D.X",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = f64::from_bits(cpu.x[f.rs1] as u64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xe2000053,
name: "FMV.X.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.f[f.rs1].to_bits() as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xe0000053,
name: "FMV.X.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.f[f.rs1].to_bits() as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xf0000053,
name: "FMV.W.X",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = f64::from_bits(cpu.x[f.rs1] as u32 as u64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0600007f,
data: 0x0200004b,
name: "FNMSUB.D",
operation: |cpu, word, _address| {
let f = parse_format_r2(word);
cpu.f[f.rd] = -(cpu.f[f.rs1] * cpu.f[f.rs2]) + cpu.f[f.rs3];
Ok(())
},
disassemble: dump_format_r2
},
Instruction {
mask: 0x0000707f,
data: 0x00003027,
name: "FSD",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.f[f.rs2].to_bits())
},
disassemble: dump_format_s
},
Instruction {
mask: 0xfe00707f,
data: 0x22000053,
name: "FSGNJ.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let rs1_bits = cpu.f[f.rs1].to_bits();
let rs2_bits = cpu.f[f.rs2].to_bits();
let sign_bit = rs2_bits & 0x8000000000000000;
cpu.f[f.rd] = f64::from_bits(sign_bit | (rs1_bits & 0x7fffffffffffffff));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x22002053,
name: "FSGNJX.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let rs1_bits = cpu.f[f.rs1].to_bits();
let rs2_bits = cpu.f[f.rs2].to_bits();
let sign_bit = (rs1_bits ^ rs2_bits) & 0x8000000000000000;
cpu.f[f.rd] = f64::from_bits(sign_bit | (rs1_bits & 0x7fffffffffffffff));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00007f,
data: 0x0a000053,
name: "FSUB.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// @TODO: Update fcsr if needed?
cpu.f[f.rd] = cpu.f[f.rs1] - cpu.f[f.rs2];
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002027,
name: "FSW",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.f[f.rs2].to_bits() as u32)
},
disassemble: dump_format_s
},
Instruction {
mask: 0x0000007f,
data: 0x0000006f,
name: "JAL",
operation: |cpu, word, address| {
let f = parse_format_j(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.pc as i64);
cpu.pc = address.wrapping_add(f.imm);
Ok(())
},
disassemble: dump_format_j
},
Instruction {
mask: 0x0000707f,
data: 0x00000067,
name: "JALR",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
let tmp = cpu.sign_extend(cpu.pc as i64);
cpu.pc = (cpu.x[f.rs1] as u64).wrapping_add(f.imm as u64);
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: |cpu, word, _address, evaluate| {
let f = parse_format_i(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{:x}({}", f.imm, get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(")");
s
}
},
Instruction {
mask: 0x0000707f,
data: 0x00000003,
name: "LB",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i8 as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00004003,
name: "LBU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00003003,
name: "LD",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00001003,
name: "LH",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_halfword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i16 as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00005003,
name: "LHU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_halfword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0xf9f0707f,
data: 0x1000302f,
name: "LR.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// @TODO: Implement properly
cpu.x[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => {
cpu.is_reservation_set = true;
cpu.reservation = cpu.x[f.rs1] as u64; // Is virtual address ok?
data as i64
},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf9f0707f,
data: 0x1000202f,
name: "LR.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// @TODO: Implement properly
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => {
cpu.is_reservation_set = true;
cpu.reservation = cpu.x[f.rs1] as u64; // Is virtual address ok?
data as i32 as i64
},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000007f,
data: 0x00000037,
name: "LUI",
operation: |cpu, word, _address| {
let f = parse_format_u(word);
cpu.x[f.rd] = f.imm as i64;
Ok(())
},
disassemble: dump_format_u
},
Instruction {
mask: 0x0000707f,
data: 0x00002003,
name: "LW",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00006003,
name: "LWU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0xfe00707f,
data: 0x02000033,
name: "MUL",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_mul(cpu.x[f.rs2]));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02001033,
name: "MULH",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.xlen {
Xlen::Bit32 => {
cpu.sign_extend((cpu.x[f.rs1] * cpu.x[f.rs2]) >> 32)
},
Xlen::Bit64 => {
((cpu.x[f.rs1] as i128) * (cpu.x[f.rs2] as i128) >> 64) as i64
}
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02003033,
name: "MULHU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.xlen {
Xlen::Bit32 => {
cpu.sign_extend((((cpu.x[f.rs1] as u32 as u64) * (cpu.x[f.rs2] as u32 as u64)) >> 32) as i64)
},
Xlen::Bit64 => {
((cpu.x[f.rs1] as u64 as u128).wrapping_mul(cpu.x[f.rs2] as u64 as u128) >> 64) as i64
}
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02002033,
name: "MULHSU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.xlen {
Xlen::Bit32 => {
cpu.sign_extend(((cpu.x[f.rs1] as i64).wrapping_mul(cpu.x[f.rs2] as u32 as i64) >> 32) as i64)
},
Xlen::Bit64 => {
((cpu.x[f.rs1] as u128).wrapping_mul(cpu.x[f.rs2] as u64 as u128) >> 64) as i64
}
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200003b,
name: "MULW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend((cpu.x[f.rs1] as i32).wrapping_mul(cpu.x[f.rs2] as i32) as i64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xffffffff,
data: 0x30200073,
name: "MRET",
operation: |cpu, _word, _address| {
cpu.pc = match cpu.read_csr(CSR_MEPC_ADDRESS) {
Ok(data) => data,
Err(e) => return Err(e)
};
let status = cpu.read_csr_raw(CSR_MSTATUS_ADDRESS);
let mpie = (status >> 7) & 1;
let mpp = (status >> 11) & 0x3;
let mprv = match get_privilege_mode(mpp) {
PrivilegeMode::Machine => (status >> 17) & 1,
_ => 0
};
// Override MIE[3] with MPIE[7], set MPIE[7] to 1, set MPP[12:11] to 0
// and override MPRV[17]
let new_status = (status & !0x21888) | (mprv << 17) | (mpie << 3) | (1 << 7);
cpu.write_csr_raw(CSR_MSTATUS_ADDRESS, new_status);
cpu.privilege_mode = match mpp {
0 => PrivilegeMode::User,
1 => PrivilegeMode::Supervisor,
3 => PrivilegeMode::Machine,
_ => panic!() // Shouldn't happen
};
cpu.mmu.update_privilege_mode(cpu.privilege_mode.clone());
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0x00006033,
name: "OR",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] | cpu.x[f.rs2]);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00006013,
name: "ORI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] | f.imm);
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0x02006033,
name: "REM",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1];
let divisor = cpu.x[f.rs2];
if divisor == 0 {
cpu.x[f.rd] = dividend;
} else if dividend == cpu.most_negative() && divisor == -1 {
cpu.x[f.rd] = 0;
} else {
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_rem(cpu.x[f.rs2]));
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02007033,
name: "REMU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.unsigned_data(cpu.x[f.rs1]);
let divisor = cpu.unsigned_data(cpu.x[f.rs2]);
cpu.x[f.rd] = match divisor {
0 => cpu.sign_extend(dividend as i64),
_ => cpu.sign_extend(dividend.wrapping_rem(divisor) as i64)
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200703b,
name: "REMUW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1] as u32;
let divisor = cpu.x[f.rs2] as u32;
cpu.x[f.rd] = match divisor {
0 => dividend as i32 as i64,
_ => dividend.wrapping_rem(divisor) as i32 as i64
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200603b,
name: "REMW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1] as i32;
let divisor = cpu.x[f.rs2] as i32;
if divisor == 0 {
cpu.x[f.rd] = dividend as i64;
} else if dividend == std::i32::MIN && divisor == -1 {
cpu.x[f.rd] = 0;
} else {
cpu.x[f.rd] = dividend.wrapping_rem(divisor) as i64;
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00000023,
name: "SB",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u8)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xf800707f,
data: 0x1800302f,
name: "SC.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// @TODO: Implement properly
cpu.x[f.rd] = match cpu.is_reservation_set && cpu.reservation == (cpu.x[f.rs1] as u64) {
true => match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u64) {
Ok(()) => {
cpu.is_reservation_set = false;
0
},
Err(e) => return Err(e)
},
false => 1
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x1800202f,
name: "SC.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
// @TODO: Implement properly
cpu.x[f.rd] = match cpu.is_reservation_set && cpu.reservation == (cpu.x[f.rs1] as u64) {
true => match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u32) {
Ok(()) => {
cpu.is_reservation_set = false;
0
},
Err(e) => return Err(e)
},
false => 1
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00003023,
name: "SD",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u64)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xfe007fff,
data: 0x12000073,
name: "SFENCE.VMA",
operation: |_cpu, _word, _address| {
// Do nothing?
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0x0000707f,
data: 0x00001023,
name: "SH",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_halfword(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u16)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xfe00707f,
data: 0x00001033,
name: "SLL",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_shl(cpu.x[f.rs2] as u32));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x00001013,
name: "SLLI",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] << shamt);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0000101b,
name: "SLLIW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let shamt = f.rs2 as u32;
cpu.x[f.rd] = (cpu.x[f.rs1] << shamt) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0000103b,
name: "SLLW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = (cpu.x[f.rs1] as u32).wrapping_shl(cpu.x[f.rs2] as u32) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x00002033,
name: "SLT",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.x[f.rs1] < cpu.x[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002013,
name: "SLTI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.x[f.rs1] < f.imm {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0x0000707f,
data: 0x00003013,
name: "SLTIU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.unsigned_data(cpu.x[f.rs1]) < cpu.unsigned_data(f.imm) {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0x00003033,
name: "SLTU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.unsigned_data(cpu.x[f.rs1]) < cpu.unsigned_data(cpu.x[f.rs2]) {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x40005033,
name: "SRA",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_shr(cpu.x[f.rs2] as u32));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x40005013,
name: "SRAI",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] >> shamt);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x4000501b,
name: "SRAIW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let shamt = ((word >> 20) & 0x1f) as u32;
cpu.x[f.rd] = ((cpu.x[f.rs1] as i32) >> shamt) as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x4000503b,
name: "SRAW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = (cpu.x[f.rs1] as i32).wrapping_shr(cpu.x[f.rs2] as u32) as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xffffffff,
data: 0x10200073,
name: "SRET",
operation: |cpu, _word, _address| {
// @TODO: Throw error if higher privilege return instruction is executed
cpu.pc = match cpu.read_csr(CSR_SEPC_ADDRESS) {
Ok(data) => data,
Err(e) => return Err(e)
};
let status = cpu.read_csr_raw(CSR_SSTATUS_ADDRESS);
let spie = (status >> 5) & 1;
let spp = (status >> 8) & 1;
let mprv = match get_privilege_mode(spp) {
PrivilegeMode::Machine => (status >> 17) & 1,
_ => 0
};
// Override SIE[1] with SPIE[5], set SPIE[5] to 1, set SPP[8] to 0,
// and override MPRV[17]
let new_status = (status & !0x20122) | (mprv << 17) | (spie << 1) | (1 << 5);
cpu.write_csr_raw(CSR_SSTATUS_ADDRESS, new_status);
cpu.privilege_mode = match spp {
0 => PrivilegeMode::User,
1 => PrivilegeMode::Supervisor,
_ => panic!() // Shouldn't happen
};
cpu.mmu.update_privilege_mode(cpu.privilege_mode.clone());
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0x00005033,
name: "SRL",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.unsigned_data(cpu.x[f.rs1]).wrapping_shr(cpu.x[f.rs2] as u32) as i64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x00005013,
name: "SRLI",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = cpu.sign_extend((cpu.unsigned_data(cpu.x[f.rs1]) >> shamt) as i64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x0000501b,
name: "SRLIW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = ((cpu.x[f.rs1] as u32) >> shamt) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0000503b,
name: "SRLW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = (cpu.x[f.rs1] as u32).wrapping_shr(cpu.x[f.rs2] as u32) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x40000033,
name: "SUB",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_sub(cpu.x[f.rs2]));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x4000003b,
name: "SUBW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.x[f.rs1].wrapping_sub(cpu.x[f.rs2]) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002023,
name: "SW",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u32)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xffffffff,
data: 0x00200073,
name: "URET",
operation: |_cpu, _word, _address| {
// @TODO: Implement
panic!("URET instruction is not implemented yet.");
},
disassemble: dump_empty
},
Instruction {
mask: 0xffffffff,
data: 0x10500073,
name: "WFI",
operation: |cpu, _word, _address| {
cpu.wfi = true;
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0x00004033,
name: "XOR",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] ^ cpu.x[f.rs2]);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00004013,
name: "XORI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] ^ f.imm);
Ok(())
},
disassemble: dump_format_i
},