174 lines
6.4 KiB
Rust
174 lines
6.4 KiB
Rust
// Copyright (c) 2025 taitep
|
|
// SPDX-License-Identifier: BSD-2-Clause
|
|
//
|
|
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
|
|
// See LICENSE file in the project root for full license text.
|
|
|
|
#[macro_use]
|
|
mod macros;
|
|
|
|
mod rva;
|
|
mod rvi;
|
|
mod rvm;
|
|
|
|
use crate::{
|
|
core::Core,
|
|
decode::Instruction,
|
|
exceptions::{
|
|
Exception,
|
|
ExceptionType::{self, IllegalInstruction},
|
|
},
|
|
};
|
|
|
|
fn illegal(instr: Instruction) -> Result<(), Exception> {
|
|
Err(Exception {
|
|
type_: IllegalInstruction,
|
|
value: instr.0 as u64,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), Exception> {
|
|
match instr.opcode_noncompressed() {
|
|
0b01100 => match (instr.funct3(), instr.funct7()) {
|
|
// OP
|
|
(0b000, 0b0000000) => rvi::add(core, instr),
|
|
(0b000, 0b0100000) => rvi::sub(core, instr),
|
|
(0b010, 0b0000000) => rvi::slt(core, instr),
|
|
(0b011, 0b0000000) => rvi::sltu(core, instr),
|
|
(0b001, 0b0000000) => rvi::sll(core, instr),
|
|
(0b101, 0b0000000) => rvi::srl(core, instr),
|
|
(0b101, 0b0100000) => rvi::sra(core, instr),
|
|
(0b111, 0b0000000) => rvi::and(core, instr),
|
|
(0b100, 0b0000000) => rvi::xor(core, instr),
|
|
(0b110, 0b0000000) => rvi::or(core, instr),
|
|
// rvm
|
|
(0b000, 0b0000001) => rvm::mul(core, instr),
|
|
(0b001, 0b0000001) => rvm::mulh(core, instr),
|
|
(0b010, 0b0000001) => rvm::mulhsu(core, instr),
|
|
(0b011, 0b0000001) => rvm::mulhu(core, instr),
|
|
(0b100, 0b0000001) => rvm::div(core, instr),
|
|
(0b101, 0b0000001) => rvm::divu(core, instr),
|
|
(0b110, 0b0000001) => rvm::rem(core, instr),
|
|
(0b111, 0b0000001) => rvm::remu(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b01110 => match (instr.funct3(), instr.funct7()) {
|
|
// OP_32
|
|
(0b000, 0b0000000) => rvi::addw(core, instr),
|
|
(0b000, 0b0100000) => rvi::subw(core, instr),
|
|
(0b001, 0b0000000) => rvi::sllw(core, instr),
|
|
(0b101, 0b0000000) => rvi::srlw(core, instr),
|
|
(0b101, 0b0100000) => rvi::sraw(core, instr),
|
|
// rvm
|
|
(0b000, 0b0000001) => rvm::mulw(core, instr),
|
|
(0b100, 0b0000001) => rvm::divw(core, instr),
|
|
(0b101, 0b0000001) => rvm::divuw(core, instr),
|
|
(0b110, 0b0000001) => rvm::remw(core, instr),
|
|
(0b111, 0b0000001) => rvm::remuw(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b00100 => match instr.funct3() {
|
|
// OP_IMM
|
|
0b000 => rvi::addi(core, instr),
|
|
0b010 => rvi::slti(core, instr),
|
|
0b011 => rvi::sltiu(core, instr),
|
|
0b001 => match instr.funct6() {
|
|
0 => rvi::slli(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b101 => match instr.funct6() {
|
|
0b000000 => rvi::srli(core, instr),
|
|
0b010000 => rvi::srai(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b100 => rvi::xori(core, instr),
|
|
0b110 => rvi::ori(core, instr),
|
|
0b111 => rvi::andi(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b00110 => match instr.funct3() {
|
|
// OP_IMM_32
|
|
0b000 => rvi::addiw(core, instr),
|
|
0b001 => match instr.funct7() {
|
|
0 => rvi::slliw(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b101 => match instr.funct7() {
|
|
0b0000000 => rvi::srliw(core, instr),
|
|
0b0100000 => rvi::sraiw(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
_ => illegal(instr),
|
|
},
|
|
0b01000 => match instr.funct3() {
|
|
// STORE
|
|
0b000 => rvi::sb(core, instr),
|
|
0b001 => rvi::sh(core, instr),
|
|
0b010 => rvi::sw(core, instr),
|
|
0b011 => rvi::sd(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b00000 => match instr.funct3() {
|
|
// LOAD
|
|
0b000 => rvi::lb(core, instr),
|
|
0b100 => rvi::lbu(core, instr),
|
|
0b001 => rvi::lh(core, instr),
|
|
0b101 => rvi::lhu(core, instr),
|
|
0b010 => rvi::lw(core, instr),
|
|
0b110 => rvi::lwu(core, instr),
|
|
0b011 => rvi::ld(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b11000 => match instr.funct3() {
|
|
// BRANCH
|
|
0b000 => rvi::beq(core, instr),
|
|
0b001 => rvi::bne(core, instr),
|
|
0b100 => rvi::blt(core, instr),
|
|
0b101 => rvi::bge(core, instr),
|
|
0b110 => rvi::bltu(core, instr),
|
|
0b111 => rvi::bgeu(core, instr),
|
|
_ => illegal(instr),
|
|
},
|
|
0b01101 => rvi::lui(core, instr),
|
|
0b00101 => rvi::auipc(core, instr),
|
|
0b11011 => rvi::jal(core, instr),
|
|
0b11001 => {
|
|
if instr.funct3() == 0 {
|
|
rvi::jalr(core, instr)
|
|
} else {
|
|
illegal(instr)
|
|
}
|
|
}
|
|
0b00011 => match instr.funct3() {
|
|
// MISC_MEM
|
|
0b000 => {
|
|
// FENCE is just implemented as a SeqCst fence always here
|
|
// I dont yet care about the potential performance issue this may bring
|
|
std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst);
|
|
core.advance_pc();
|
|
Ok(())
|
|
}
|
|
_ => illegal(instr),
|
|
},
|
|
0b11100 => match (instr.funct3(), instr.funct12(), instr.rs1(), instr.rd()) {
|
|
(0b000, 0b000000000000, 0, 0) => {
|
|
// TODO: When privilege modes are added, make the exception raised by ecall
|
|
// depend on privilege mode
|
|
Err(ExceptionType::EnvironmentCallFromMMode.with_no_value())
|
|
}
|
|
(0b000, 0b000000000001, 0, 0) => Err(ExceptionType::Breakpoint.with_no_value()),
|
|
_ => {
|
|
// Temporarily allowing unrecognized instructions here to be able to run
|
|
// the official ISA tests, which perform CSR operations but work just fine
|
|
// without them
|
|
eprintln!("Unrecognized instruction within SYSTEM opcode");
|
|
dbg!(instr);
|
|
core.advance_pc();
|
|
Ok(())
|
|
}
|
|
},
|
|
0b01011 => rva::find_and_exec(instr, core),
|
|
_ => illegal(instr),
|
|
}
|
|
}
|