perilus.rs (3129B)
1 use bounded_integer::BoundedU32; 2 use std::{io, path::PathBuf, slice}; 3 4 unsafe extern "C" { 5 fn perilus_init(); 6 fn perilus_eval(); 7 fn perilus_drop(); 8 fn perilus_increment_time(); 9 fn perilus_set_clock(new_clock: u32); 10 fn perilus_get_pc() -> u32; 11 fn perilus_set_pc(new_pc: u32); 12 fn perilus_set_reset(new_reset: u32); 13 fn perilus_get_control_unit_state() -> u32; 14 fn perilus_get_register_file() -> *const u32; 15 fn perilus_set_register(reg: u32, value: u32); 16 fn perilus_get_memory() -> *const u32; 17 fn perilus_set_memory(address: u32, value: u32); 18 } 19 20 pub(crate) type Register = BoundedU32<0, 31>; 21 pub(crate) type MemoryIndex = BoundedU32<0, { Perilus::MEMORY_SIZE_WORDS as u32 }>; 22 23 pub(crate) struct Perilus; 24 25 impl Perilus { 26 const NUM_REGISTERS: usize = 32; 27 const MEMORY_SIZE_WORDS: usize = 1_048_576; 28 29 pub(crate) fn init() -> Perilus { 30 unsafe { perilus_init() }; 31 Perilus 32 } 33 pub(crate) fn pulse_clock(&self) { 34 unsafe { 35 perilus_set_clock(0); 36 perilus_eval(); 37 perilus_increment_time(); 38 perilus_set_clock(1); 39 perilus_eval(); 40 perilus_increment_time(); 41 } 42 } 43 pub(crate) fn reset(&self) { 44 unsafe { 45 perilus_set_reset(1); 46 self.pulse_clock(); 47 perilus_set_reset(0); 48 } 49 } 50 pub(crate) fn get_pc(&self) -> u32 { 51 unsafe { perilus_get_pc() } 52 } 53 pub(crate) fn set_pc(&self, new_pc: u32) { 54 unsafe { perilus_set_pc(new_pc) }; 55 } 56 pub(crate) fn get_control_unit_state(&self) -> u32 { 57 unsafe { perilus_get_control_unit_state() } 58 } 59 pub(crate) fn get_registers(&self) -> &'static [u32] { 60 unsafe { slice::from_raw_parts(perilus_get_register_file(), Perilus::NUM_REGISTERS) } 61 } 62 pub(crate) fn set_register(&self, register: Register, value: u32) { 63 unsafe { perilus_set_register(register.get(), value) }; 64 } 65 pub(crate) fn get_memory(&self) -> &'static [u32] { 66 unsafe { slice::from_raw_parts(perilus_get_memory(), Perilus::MEMORY_SIZE_WORDS) } 67 } 68 pub(crate) fn set_memory(&self, address: u32, value: u32) { 69 unsafe { perilus_set_memory(address, value) }; 70 } 71 pub(crate) fn load_file(&self, file: PathBuf) -> io::Result<()> { 72 let bytes = std::fs::read(file)?; 73 if bytes.len() > Self::MEMORY_SIZE_WORDS * 4 { 74 return Err(io::Error::new( 75 io::ErrorKind::InvalidInput, 76 "Provided file is too large to fit in simulated memory", 77 )); 78 } 79 for (address_bytes, value) in bytes.iter().enumerate() { 80 let address_words = address_bytes / 4; 81 let shift = (address_bytes % 4) * 8; 82 let current = self.get_memory()[address_words]; 83 let mask = !(0xffu32 << shift); 84 let new = (current & mask) | ((*value as u32) << shift); 85 self.set_memory(address_words as u32, new); 86 } 87 Ok(()) 88 } 89 } 90 91 impl Drop for Perilus { 92 fn drop(&mut self) { 93 unsafe { perilus_drop() }; 94 } 95 }