Implementation of the UM-32 "Universal Machine" as described by the Cult of the Bound Variable

restrict cast to `usize` to supported architectures

tjh 3377a70d 170d41a4

Changed files
+45 -20
src
+45 -20
src/main.rs
··· 21 .run(); 22 } 23 24 #[derive(Default)] 25 pub struct Um<'a> { 26 program_counter: Platter, ··· 275 /// Loads the value from the specified register. 276 fn load_register(&self, index: Parameter) -> Platter { 277 assert!(index < 8, "register index out of bounds"); 278 - self.registers[index as usize] 279 } 280 281 /// Saves a value to the specified register. 282 fn save_register(&mut self, index: Parameter, value: Platter) { 283 assert!(index < 8, "register index out of bounds"); 284 - self.registers[index as usize] = value; 285 } 286 287 fn load_memory(&self, block: Platter, offset: Platter) -> Platter { 288 - assert!( 289 - (block as usize) < self.memory.len() 290 - && (offset as usize) < self.memory[block as usize].len() 291 - ); 292 - self.memory[block as usize][offset as usize] 293 } 294 295 fn store_memory(&mut self, block: Platter, offset: Platter, value: Platter) { 296 - assert!( 297 - (block as usize) < self.memory.len() 298 - && (offset as usize) < self.memory[block as usize].len() 299 - ); 300 - self.memory[block as usize][offset as usize] = value; 301 } 302 303 fn duplicate_memory(&mut self, block: Platter) -> &[Platter] { 304 - assert!((block as usize) < self.memory.len()); 305 - self.memory[0] = self.memory[block as usize].clone(); 306 &self.memory[0] 307 } 308 309 #[cfg(not(feature = "reclaim-memory"))] 310 fn allocate_memory(&mut self, length: Platter) -> Platter { 311 - self.memory.push(Self::new_block(length as usize)); 312 (self.memory.len() - 1) as Platter 313 } 314 315 #[cfg(feature = "reclaim-memory")] 316 fn allocate_memory(&mut self, length: Platter) -> Platter { 317 if let Some(index) = self.free_blocks.pop() { 318 - self.memory[index as usize] = Self::new_block(length as usize); 319 index as Platter 320 } else { 321 - self.memory.push(Self::new_block(length as usize)); 322 (self.memory.len() - 1) as Platter 323 } 324 } 325 326 fn free_memory(&mut self, block: Platter) { 327 - assert!((block as usize) < self.memory.len()); 328 #[cfg(feature = "reclaim-memory")] 329 { 330 self.free_blocks.push(block); 331 - self.memory[block as usize] = Self::new_block(0); 332 } 333 } 334 ··· 337 fn panic(&self) -> ! { 338 panic!( 339 "universal machine failure: instruction: {:08x}, program_counter: {:08x}, registers: {:08x?}", 340 - self.memory[0][self.program_counter as usize], self.program_counter, self.registers 341 ) 342 } 343
··· 21 .run(); 22 } 23 24 + /// Lossless conversion to `usize`. 25 + /// 26 + /// This should only be implemented on types which can be losslessly 27 + /// cast to a `usize`. 28 + trait IntoIndex: Sized + Copy { 29 + fn into_index(self) -> usize; 30 + } 31 + 32 + macro_rules! impl_into_index { 33 + ($t:ty) => { 34 + impl IntoIndex for $t { 35 + fn into_index(self) -> usize { 36 + self as usize 37 + } 38 + } 39 + }; 40 + } 41 + 42 + #[cfg(target_pointer_width = "16")] 43 + compile_error!("16 bit architectures are unsupported"); 44 + 45 + // usize *may* be 16 bits, so only implement if it is 32 or 64 bits. 46 + #[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))] 47 + impl_into_index!(Platter); 48 + impl_into_index!(Parameter); 49 + 50 #[derive(Default)] 51 pub struct Um<'a> { 52 program_counter: Platter, ··· 301 /// Loads the value from the specified register. 302 fn load_register(&self, index: Parameter) -> Platter { 303 assert!(index < 8, "register index out of bounds"); 304 + self.registers[index.into_index()] 305 } 306 307 /// Saves a value to the specified register. 308 fn save_register(&mut self, index: Parameter, value: Platter) { 309 assert!(index < 8, "register index out of bounds"); 310 + self.registers[index.into_index()] = value; 311 } 312 313 fn load_memory(&self, block: Platter, offset: Platter) -> Platter { 314 + let block = block.into_index(); 315 + let offset = offset.into_index(); 316 + assert!(block < self.memory.len() && offset < self.memory[block].len()); 317 + self.memory[block][offset] 318 } 319 320 fn store_memory(&mut self, block: Platter, offset: Platter, value: Platter) { 321 + let block = block.into_index(); 322 + let offset = offset.into_index(); 323 + assert!(block < self.memory.len() && offset < self.memory[block].len()); 324 + self.memory[block][offset] = value 325 } 326 327 fn duplicate_memory(&mut self, block: Platter) -> &[Platter] { 328 + let block = block.into_index(); 329 + assert!(block < self.memory.len()); 330 + self.memory[0] = self.memory[block].clone(); 331 &self.memory[0] 332 } 333 334 #[cfg(not(feature = "reclaim-memory"))] 335 fn allocate_memory(&mut self, length: Platter) -> Platter { 336 + self.memory.push(Self::new_block(length.into_index())); 337 (self.memory.len() - 1) as Platter 338 } 339 340 #[cfg(feature = "reclaim-memory")] 341 fn allocate_memory(&mut self, length: Platter) -> Platter { 342 if let Some(index) = self.free_blocks.pop() { 343 + self.memory[index.into_index()] = Self::new_block(length.into_index()); 344 index as Platter 345 } else { 346 + self.memory.push(Self::new_block(length.into_index())); 347 (self.memory.len() - 1) as Platter 348 } 349 } 350 351 fn free_memory(&mut self, block: Platter) { 352 + assert!(block.into_index() < self.memory.len()); 353 #[cfg(feature = "reclaim-memory")] 354 { 355 self.free_blocks.push(block); 356 + self.memory[block.into_index()] = Self::new_block(0); 357 } 358 } 359 ··· 362 fn panic(&self) -> ! { 363 panic!( 364 "universal machine failure: instruction: {:08x}, program_counter: {:08x}, registers: {:08x?}", 365 + self.memory[0][self.program_counter.into_index()], self.program_counter, self.registers 366 ) 367 } 368