diff --git a/Cargo.lock b/Cargo.lock index bb7ba3e..ee3da81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,9 +17,16 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "rvem" version = "0.1.0" dependencies = [ "memmap2", + "once_cell", ] diff --git a/Cargo.toml b/Cargo.toml index f844555..1bb7d29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] memmap2 = "0.9.8" +once_cell = "1.21.3" diff --git a/src/instructions.rs b/src/instructions.rs new file mode 100644 index 0000000..9f3a544 --- /dev/null +++ b/src/instructions.rs @@ -0,0 +1,69 @@ +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, decode::Instruction}; + +type Runner = fn(&mut Core, Instruction) -> Result<(), ()>; + +#[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, +} diff --git a/src/lib.rs b/src/lib.rs index 4020af3..3cc8c0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ mod consts; pub mod core; mod decode; +mod instructions; pub mod mem;