use once_cell::sync::Lazy; static INSTRUCTIONS: Lazy<[Option; 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) -> Result<(), InstructionResult>; #[derive(Clone, Copy)] struct InstructionHandler { runner: Runner, } struct OpcodeHandler { handler: Option, splitter: Option, } pub fn find_runner(instruction: Instruction) -> Option { 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 { if let Some(splitter) = &self.splitter { splitter.find_runner(instruction) } else { self.handler.map(|h| h.runner) } } } enum Splitter { Funct3Splitter(Box<[Option; 8]>), GeneralSplitter(Box<[GeneralSplitterEntry]>), } impl Splitter { fn find_runner(&self, instruction: Instruction) -> Option { 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, }