summaryrefslogtreecommitdiff
path: root/src/instructions.rs
blob: ed264f980952eda19ea7e138b832675f8281308f (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
use once_cell::sync::Lazy;

static INSTRUCTIONS: Lazy<[Option<OpcodeHandler>; 32]> = Lazy::new(|| {
    let mut instructions = std::array::from_fn(|_i| None);

    instructions
});

use crate::{
    consts::Word,
    core::{Core, InstructionResult},
    decode::Instruction,
};

type Runner = fn(&mut Core, Instruction) -> InstructionResult;

#[derive(Clone, Copy)]
struct InstructionHandler {
    runner: Runner,
}

struct OpcodeHandler {
    handler: Option<InstructionHandler>,
    splitter: Option<Splitter>,
}

pub fn find_runner(instruction: Instruction) -> Option<Runner> {
    let opcode_handler = &INSTRUCTIONS[instruction.opcode_noncompressed() as usize];
    match opcode_handler {
        Some(h) => h.find_runner(instruction),
        None => None,
    }
}

impl OpcodeHandler {
    fn find_runner(&self, instruction: Instruction) -> Option<Runner> {
        if let Some(splitter) = &self.splitter {
            splitter.find_runner(instruction)
        } else {
            self.handler.map(|h| h.runner)
        }
    }
}

enum Splitter {
    Funct3Splitter(Box<[Option<OpcodeHandler>; 8]>),
    GeneralSplitter(Box<[GeneralSplitterEntry]>),
}

impl Splitter {
    fn find_runner(&self, instruction: Instruction) -> Option<Runner> {
        match self {
            Splitter::Funct3Splitter(f3s) => f3s[instruction.funct3() as usize]
                .as_ref()
                .and_then(|h| h.find_runner(instruction)),
            Splitter::GeneralSplitter(entries) => {
                for entry in entries {
                    if instruction.0 & entry.mask == entry.value {
                        return Some(entry.handler.runner);
                    }
                }

                None
            }
        }
    }
}

struct GeneralSplitterEntry {
    mask: Word,
    value: Word,
    handler: InstructionHandler,
}