summaryrefslogtreecommitdiff
path: root/src/instructions.rs
blob: e7b95f191ea04774780f901be2a67288fac900b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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 rvi;

use crate::{
    core::Core,
    decode::Instruction,
    exceptions::ExceptionType::{self, IllegalInstruction},
};

pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), ExceptionType> {
    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),
            _ => Err(IllegalInstruction),
        },
        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),
            _ => Err(IllegalInstruction),
        },
        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),
                _ => Err(IllegalInstruction),
            },
            0b101 => match instr.funct6() {
                0b000000 => rvi::srli(core, instr),
                0b010000 => rvi::srai(core, instr),
                _ => Err(IllegalInstruction),
            },
            0b100 => rvi::xori(core, instr),
            0b110 => rvi::ori(core, instr),
            0b111 => rvi::andi(core, instr),
            _ => Err(IllegalInstruction),
        },
        0b00110 => match instr.funct3() {
            // OP_IMM_32
            0b000 => rvi::addiw(core, instr),
            0b001 => match instr.funct7() {
                0 => rvi::slliw(core, instr),
                _ => Err(IllegalInstruction),
            },
            0b101 => match instr.funct7() {
                0b0000000 => rvi::srliw(core, instr),
                0b0100000 => rvi::sraiw(core, instr),
                _ => Err(IllegalInstruction),
            },
            _ => Err(IllegalInstruction),
        },
        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),
            _ => Err(IllegalInstruction),
        },
        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),
            _ => Err(IllegalInstruction),
        },
        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),
            _ => Err(IllegalInstruction),
        },
        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 {
                Err(IllegalInstruction)
            }
        }
        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);
                Ok(())
            }
            _ => Err(IllegalInstruction),
        },
        _ => Err(IllegalInstruction),
    }
}