perilus

git clone https://git.bradleygannon.com/perilus.git
Log | Files | Refs | Submodules | README

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 }