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 21 .run(); 22 22 } 23 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 + 24 50 #[derive(Default)] 25 51 pub struct Um<'a> { 26 52 program_counter: Platter, ··· 275 301 /// Loads the value from the specified register. 276 302 fn load_register(&self, index: Parameter) -> Platter { 277 303 assert!(index < 8, "register index out of bounds"); 278 - self.registers[index as usize] 304 + self.registers[index.into_index()] 279 305 } 280 306 281 307 /// Saves a value to the specified register. 282 308 fn save_register(&mut self, index: Parameter, value: Platter) { 283 309 assert!(index < 8, "register index out of bounds"); 284 - self.registers[index as usize] = value; 310 + self.registers[index.into_index()] = value; 285 311 } 286 312 287 313 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] 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] 293 318 } 294 319 295 320 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; 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 301 325 } 302 326 303 327 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(); 328 + let block = block.into_index(); 329 + assert!(block < self.memory.len()); 330 + self.memory[0] = self.memory[block].clone(); 306 331 &self.memory[0] 307 332 } 308 333 309 334 #[cfg(not(feature = "reclaim-memory"))] 310 335 fn allocate_memory(&mut self, length: Platter) -> Platter { 311 - self.memory.push(Self::new_block(length as usize)); 336 + self.memory.push(Self::new_block(length.into_index())); 312 337 (self.memory.len() - 1) as Platter 313 338 } 314 339 315 340 #[cfg(feature = "reclaim-memory")] 316 341 fn allocate_memory(&mut self, length: Platter) -> Platter { 317 342 if let Some(index) = self.free_blocks.pop() { 318 - self.memory[index as usize] = Self::new_block(length as usize); 343 + self.memory[index.into_index()] = Self::new_block(length.into_index()); 319 344 index as Platter 320 345 } else { 321 - self.memory.push(Self::new_block(length as usize)); 346 + self.memory.push(Self::new_block(length.into_index())); 322 347 (self.memory.len() - 1) as Platter 323 348 } 324 349 } 325 350 326 351 fn free_memory(&mut self, block: Platter) { 327 - assert!((block as usize) < self.memory.len()); 352 + assert!(block.into_index() < self.memory.len()); 328 353 #[cfg(feature = "reclaim-memory")] 329 354 { 330 355 self.free_blocks.push(block); 331 - self.memory[block as usize] = Self::new_block(0); 356 + self.memory[block.into_index()] = Self::new_block(0); 332 357 } 333 358 } 334 359 ··· 337 362 fn panic(&self) -> ! { 338 363 panic!( 339 364 "universal machine failure: instruction: {:08x}, program_counter: {:08x}, registers: {:08x?}", 340 - self.memory[0][self.program_counter as usize], self.program_counter, self.registers 365 + self.memory[0][self.program_counter.into_index()], self.program_counter, self.registers 341 366 ) 342 367 } 343 368