Implementation of the UM-32 "Universal Machine" as described by the Cult of the Bound Variable
at main 6.2 kB view raw
1// Copyright (C) 2025 Thom Hayward. 2// 3// This program is free software: you can redistribute it and/or modify it under 4// the terms of the GNU General Public License as published by the Free Software 5// Foundation, version 3. 6// 7// This program is distributed in the hope that it will be useful, but WITHOUT 8// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10// details. 11// 12// You should have received a copy of the GNU General Public License along with 13// this program. If not, see <https://www.gnu.org/licenses/>. 14// 15use crate::reg::Register; 16 17#[derive(Clone, Copy, Debug, PartialEq, Eq)] 18pub enum Operation { 19 /// Operator #0. Conditional Move. 20 /// 21 /// The register A receives the value in register B, 22 /// unless the register C contains 0. 23 ConditionalMove { 24 a: Register, 25 b: Register, 26 c: Register, 27 }, 28 /// Operator #1: Array Index. 29 /// 30 /// The register A receives the value stored at offset 31 /// in register C in the array identified by B. 32 ArrayIndex { 33 a: Register, 34 b: Register, 35 c: Register, 36 }, 37 /// Operator #2. Array Amendment. 38 /// 39 /// The array identified by A is amended at the offset 40 /// in register B to store the value in register C. 41 ArrayAmendment { 42 a: Register, 43 b: Register, 44 c: Register, 45 }, 46 /// Operator #3. Addition. 47 /// 48 /// The register A receives the value in register B plus 49 /// the value in register C, modulo 2^32. 50 Addition { 51 a: Register, 52 b: Register, 53 c: Register, 54 }, 55 /// Operator #4. Multiplication. 56 /// 57 /// The register A receives the value in register B times 58 /// the value in register C, modulo 2^32. 59 Multiplication { 60 a: Register, 61 b: Register, 62 c: Register, 63 }, 64 /// Operator #5. Division. 65 /// 66 /// The register A receives the value in register B 67 /// divided by the value in register C, if any, where 68 /// each quantity is treated as an unsigned 32 bit number. 69 Division { 70 a: Register, 71 b: Register, 72 c: Register, 73 }, 74 /// Operator #6. Not-And. 75 /// 76 /// Each bit in the register A receives the 1 bit if 77 /// either register B or register C has a 0 bit in that 78 /// position. Otherwise the bit in register A receives 79 /// the 0 bit. 80 NotAnd { 81 a: Register, 82 b: Register, 83 c: Register, 84 }, 85 /// Operator #7. Halt. 86 /// 87 /// The universal machine stops computation. 88 Halt, 89 /// Operator #8. Allocation. 90 /// 91 /// A new array is created with a capacity of platters 92 /// commensurate to the value in the register C. This 93 /// new array is initialized entirely with platters 94 /// holding the value 0. A bit pattern not consisting of 95 /// exclusively the 0 bit, and that identifies no other 96 /// active allocated array, is placed in the B register. 97 Allocation { 98 b: Register, 99 c: Register, 100 }, 101 /// Operator #9. Abandonment. 102 /// 103 /// The array identified by the register C is abandoned. 104 /// Future allocations may then reuse that identifier. 105 Abandonment { 106 c: Register, 107 }, 108 /// Operator #10. Output. 109 /// 110 /// The value in the register C is displayed on the console 111 /// immediately. Only values between and including 0 and 255 112 /// are allowed. 113 Output { 114 c: Register, 115 }, 116 /// Operator #11. Input. 117 /// 118 /// The universal machine waits for input on the console. 119 /// When input arrives, the register C is loaded with the 120 /// input, which must be between and including 0 and 255. 121 /// If the end of input has been signaled, then the 122 /// register C is endowed with a uniform value pattern 123 /// where every place is pregnant with the 1 bit. 124 Input { 125 c: Register, 126 }, 127 /// Operator #12. Load Program. 128 /// 129 /// The array identified by the B register is duplicated 130 /// and the duplicate shall replace the '0' array, 131 /// regardless of size. The execution finger is placed 132 /// to indicate the platter of this array that is 133 /// described by the offset given in C, where the value 134 /// 0 denotes the first platter, 1 the second, et 135 /// cetera. 136 /// 137 /// The '0' array shall be the most sublime choice for 138 /// loading, and shall be handled with the utmost 139 /// velocity. 140 LoadProgram { 141 b: Register, 142 c: Register, 143 }, 144 /// Operator #13. Orthography. 145 /// 146 /// The value indicated is loaded into the register A 147 /// forthwith. 148 Orthography { 149 a: Register, 150 value: u32, 151 }, 152 IllegalInstruction, 153} 154 155impl From<u32> for Operation { 156 fn from(value: u32) -> Self { 157 let a = Register::from_u8(((value >> 6) & 0x07) as u8); 158 let b = Register::from_u8(((value >> 3) & 0x07) as u8); 159 let c = Register::from_u8((value & 0x07) as u8); 160 match value & 0xf0000000 { 161 0x00000000 => Self::ConditionalMove { a, b, c }, 162 0x10000000 => Self::ArrayIndex { a, b, c }, 163 0x20000000 => Self::ArrayAmendment { a, b, c }, 164 0x30000000 => Self::Addition { a, b, c }, 165 0x40000000 => Self::Multiplication { a, b, c }, 166 0x50000000 => Self::Division { a, b, c }, 167 0x60000000 => Self::NotAnd { a, b, c }, 168 0x70000000 => Self::Halt, 169 0x80000000 => Self::Allocation { b, c }, 170 0x90000000 => Self::Abandonment { c }, 171 0xa0000000 => Self::Output { c }, 172 0xb0000000 => Self::Input { c }, 173 0xc0000000 => Self::LoadProgram { b, c }, 174 0xd0000000 => { 175 let a = Register::from_u8(((value >> 25) & 0x07) as u8); 176 let value = value & 0x01ffffff; 177 Self::Orthography { a, value } 178 } 179 _ => Self::IllegalInstruction, 180 } 181 } 182} 183 184pub fn decode(ops: &[u32]) -> Vec<Operation> { 185 ops.iter() 186 .map(|&encoded| Operation::from(encoded)) 187 .collect() 188}