mirror of
https://github.com/PiMaker/rvc.git
synced 2024-11-10 06:00:07 +00:00
64e2d0b45c
passes all RV32IM tests (run './test.sh all') instructions.txt is extracted from takahirox/riscv-rust
1683 lines
40 KiB
Plaintext
1683 lines
40 KiB
Plaintext
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
|
|
},
|