···1+# This file is automatically @generated by Cargo.
2+# It is not intended for manual editing.
3+version = 3
4+5+[[package]]
6+name = "um"
7+version = "0.1.0"
···1+fn main() {
2+ let mut program = Vec::new();
3+ for arg in std::env::args().skip(1) {
4+ let p = std::fs::read(arg).unwrap();
5+ program.extend_from_slice(&p);
6+ }
7+8+ Um::from_bytes(program)
9+ .stdout(std::io::stdout())
10+ .stdin(std::io::stdin())
11+ .run();
12+}
13+14+type Platter = u32;
15+type Register = u8;
16+17+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18+enum Op {
19+ ConditionalMove {
20+ a: Register,
21+ b: Register,
22+ c: Register,
23+ },
24+ ArrayIndex {
25+ a: Register,
26+ b: Register,
27+ c: Register,
28+ },
29+ ArrayAmendment {
30+ a: Register,
31+ b: Register,
32+ c: Register,
33+ },
34+ Addition {
35+ a: Register,
36+ b: Register,
37+ c: Register,
38+ },
39+ Multiplication {
40+ a: Register,
41+ b: Register,
42+ c: Register,
43+ },
44+ Division {
45+ a: Register,
46+ b: Register,
47+ c: Register,
48+ },
49+ NotAnd {
50+ a: Register,
51+ b: Register,
52+ c: Register,
53+ },
54+ Halt,
55+ Allocation {
56+ b: Register,
57+ c: Register,
58+ },
59+ Abandonment {
60+ c: Register,
61+ },
62+ Output {
63+ c: Register,
64+ },
65+ Input {
66+ c: Register,
67+ },
68+ LoadProgram {
69+ b: Register,
70+ c: Register,
71+ },
72+ Orthography {
73+ a: Register,
74+ value: u32,
75+ },
76+}
77+78+impl From<Platter> for Op {
79+ fn from(value: Platter) -> Self {
80+ let a = ((value >> 6) & 0x07) as Register;
81+ let b = ((value >> 3) & 0x07) as Register;
82+ let c = ((value >> 0) & 0x07) as Register;
83+84+ match value & 0xf0000000 {
85+ 0x00000000 => Self::ConditionalMove { a, b, c },
86+ 0x10000000 => Self::ArrayIndex { a, b, c },
87+ 0x20000000 => Self::ArrayAmendment { a, b, c },
88+ 0x30000000 => Self::Addition { a, b, c },
89+ 0x40000000 => Self::Multiplication { a, b, c },
90+ 0x50000000 => Self::Division { a, b, c },
91+ 0x60000000 => Self::NotAnd { a, b, c },
92+ 0x70000000 => Self::Halt,
93+ 0x80000000 => Self::Allocation { b, c },
94+ 0x90000000 => Self::Abandonment { c },
95+ 0xa0000000 => Self::Output { c },
96+ 0xb0000000 => Self::Input { c },
97+ 0xc0000000 => Self::LoadProgram { b, c },
98+ 0xd0000000 => {
99+ let a = ((value >> 25) & 0x07) as Register;
100+ let value = value & 0x01ffffff;
101+ Self::Orthography { a, value }
102+ }
103+ _ => Self::Halt,
104+ }
105+ }
106+}
107+108+fn decode_ops(ops: &[Platter]) -> Vec<Op> {
109+ ops.iter().map(|encoded| Op::from(*encoded)).collect()
110+}
111+112+#[derive(Default)]
113+pub struct Um {
114+ program_counter: Platter,
115+ registers: [Platter; 8],
116+ memory: Vec<Vec<Platter>>,
117+ #[cfg(feature = "reclaim-memory")]
118+ free_blocks: Vec<Platter>,
119+ ops: Vec<Op>,
120+ stdin: Option<Box<dyn std::io::Read>>,
121+ stdout: Option<Box<dyn std::io::Write>>,
122+}
123+124+impl Um {
125+ /// Construct a new Universal Machine with the specified program.
126+ pub fn new(program: Vec<Platter>) -> Self {
127+ let ops = decode_ops(&program);
128+ Self {
129+ memory: vec![program],
130+ ops,
131+ ..Default::default()
132+ }
133+ }
134+135+ /// Construct a new Universal Machine from a program represented in bytes.
136+ pub fn from_bytes(program: impl AsRef<[u8]>) -> Self {
137+ let bytes = program.as_ref();
138+ let mut program = Vec::with_capacity(bytes.len().div_ceil(size_of::<Platter>()));
139+ for word in bytes.chunks(size_of::<Platter>()) {
140+ let value = Platter::from_be_bytes(match word {
141+ [a, b, c, d] => [*a, *b, *c, *d],
142+ [a, b, c] => [*a, *b, *c, 0],
143+ [a, b] => [*a, *b, 0, 0],
144+ [a] => [*a, 0, 0, 0],
145+ _ => unreachable!(),
146+ });
147+ program.push(value);
148+ }
149+150+ Self::new(program)
151+ }
152+153+ /// Sets the output for the univeral machine.
154+ pub fn stdout(mut self, stdout: impl std::io::Write + 'static) -> Self {
155+ self.stdout.replace(Box::new(stdout));
156+ self
157+ }
158+159+ /// Sets the input for the universal machine.
160+ pub fn stdin(mut self, stdin: impl std::io::Read + 'static) -> Self {
161+ self.stdin.replace(Box::new(stdin));
162+ self
163+ }
164+165+ /// Begins the spin-cycle of the universal machine.
166+ pub fn run(mut self) {
167+ loop {
168+ match self.ops[self.program_counter as usize] {
169+ // Operator #0. Conditional Move.
170+ //
171+ // The register A receives the value in register B,
172+ // unless the register C contains 0.
173+ Op::ConditionalMove { a, b, c } => {
174+ if self.load_register(c) != 0 {
175+ self.save_register(a, self.load_register(b));
176+ }
177+ }
178+179+ // Operator #1: Array Index.
180+ //
181+ // The register A receives the value stored at offset
182+ // in register C in the array identified by B.
183+ Op::ArrayIndex { a, b, c } => {
184+ let block = self.load_register(b);
185+ let offset = self.load_register(c);
186+ self.save_register(a, self.load_memory(block, offset));
187+ }
188+189+ // Operator #2. Array Amendment.
190+ //
191+ // The array identified by A is amended at the offset
192+ // in register B to store the value in register C.
193+ Op::ArrayAmendment { a, b, c } => {
194+ let block = self.load_register(a);
195+ let offset = self.load_register(b);
196+ let value = self.load_register(c);
197+ self.store_memory(block, offset, value);
198+ }
199+200+ // Operator #3. Addition.
201+ //
202+ // The register A receives the value in register B plus
203+ // the value in register C, modulo 2^32.
204+ Op::Addition { a, b, c } => {
205+ self.save_register(
206+ a,
207+ self.load_register(b).wrapping_add(self.load_register(c)),
208+ );
209+ }
210+211+ // Operator #4. Multiplication.
212+ //
213+ // The register A receives the value in register B times
214+ // the value in register C, modulo 2^32.
215+ Op::Multiplication { a, b, c } => {
216+ self.save_register(
217+ a,
218+ self.load_register(b).wrapping_mul(self.load_register(c)),
219+ );
220+ }
221+222+ // Operator #5. Division.
223+ //
224+ // The register A receives the value in register B
225+ // divided by the value in register C, if any, where
226+ // each quantity is treated as an unsigned 32 bit number.
227+ Op::Division { a, b, c } => {
228+ self.save_register(
229+ a,
230+ self.load_register(b).wrapping_div(self.load_register(c)),
231+ );
232+ }
233+234+ // Operator #6. Not-And.
235+ //
236+ // Each bit in the register A receives the 1 bit if
237+ // either register B or register C has a 0 bit in that
238+ // position. Otherwise the bit in register A receives
239+ // the 0 bit.
240+ Op::NotAnd { a, b, c } => {
241+ self.save_register(a, !(self.load_register(b) & self.load_register(c)));
242+ }
243+244+ // Operator #7. Halt.
245+ //
246+ // The universal machine stops computation.
247+ Op::Halt => break,
248+249+ // Operator #8. Allocation.
250+ //
251+ // A new array is created with a capacity of platters
252+ // commensurate to the value in the register C. This
253+ // new array is initialized entirely with platters
254+ // holding the value 0. A bit pattern not consisting of
255+ // exclusively the 0 bit, and that identifies no other
256+ // active allocated array, is placed in the B register.
257+ Op::Allocation { b, c } => {
258+ let length = self.load_register(c);
259+ let index = self.allocate_memory(length);
260+ self.save_register(b, index);
261+ }
262+263+ // Operator #9. Abandonment.
264+ //
265+ // The array identified by the register C is abandoned.
266+ // Future allocations may then reuse that identifier.
267+ Op::Abandonment { c } => {
268+ let block = self.load_register(c);
269+ self.free_memory(block);
270+ }
271+272+ // Operator #10. Output.
273+ //
274+ // The value in the register C is displayed on the console
275+ // immediately. Only values between and including 0 and 255
276+ // are allowed.
277+ Op::Output { c } => {
278+ let value = self.load_register(c);
279+ if let Some(stdout) = self.stdout.as_mut() {
280+ let buffer = [(value & 0xff) as u8];
281+ stdout.write_all(&buffer).unwrap();
282+ }
283+ }
284+285+ // Operator #11. Input.
286+ //
287+ // The universal machine waits for input on the console.
288+ // When input arrives, the register C is loaded with the
289+ // input, which must be between and including 0 and 255.
290+ // If the end of input has been signaled, then the
291+ // register C is endowed with a uniform value pattern
292+ // where every place is pregnant with the 1 bit.
293+ Op::Input { c } => {
294+ if let Some(stdin) = self.stdin.as_mut() {
295+ let mut buffer = vec![0];
296+ match stdin.read_exact(&mut buffer) {
297+ Ok(()) => self.save_register(c, buffer[0] as u32),
298+ Err(_) => self.save_register(c, 0xff),
299+ }
300+ } else {
301+ self.save_register(c, 0xff);
302+ }
303+ }
304+305+ // Operator #12. Load Program.
306+ //
307+ // The array identified by the B register is duplicated
308+ // and the duplicate shall replace the '0' array,
309+ // regardless of size. The execution finger is placed
310+ // to indicate the platter of this array that is
311+ // described by the offset given in C, where the value
312+ // 0 denotes the first platter, 1 the second, et
313+ // cetera.
314+ //
315+ // The '0' array shall be the most sublime choice for
316+ // loading, and shall be handled with the utmost
317+ // velocity.
318+ Op::LoadProgram { b, c } => {
319+ let block = self.load_register(b);
320+321+ // Source array is always copied to array[0], but there
322+ // is no point copying array[0] to array[0].
323+ if block != 0 {
324+ let duplicated = self.duplicate_memory(block);
325+ let ops = decode_ops(&duplicated);
326+ self.ops = ops;
327+ }
328+329+ self.program_counter = self.load_register(c);
330+ continue;
331+ }
332+333+ // Operator #13. Orthography.
334+ //
335+ // The value indicated is loaded into the register A
336+ // forthwith.
337+ Op::Orthography { a, value } => {
338+ self.save_register(a, value);
339+ }
340+ }
341+342+ self.program_counter += 1;
343+ }
344+ }
345+346+ /// Loads the value from the specified register.
347+ fn load_register(&self, index: Register) -> Platter {
348+ debug_assert!(index < 8, "register index out of bounds");
349+ self.registers[index as usize]
350+ }
351+352+ /// Saves a value to the specified register.
353+ fn save_register(&mut self, index: Register, value: Platter) {
354+ debug_assert!(index < 8, "register index out of bounds");
355+ self.registers[index as usize] = value;
356+ }
357+358+ fn load_memory(&self, block: Platter, offset: Platter) -> Platter {
359+ debug_assert!((block as usize) < self.memory.len());
360+ debug_assert!((offset as usize) < self.memory[block as usize].len());
361+ self.memory[block as usize][offset as usize]
362+ }
363+364+ fn store_memory(&mut self, block: Platter, offset: Platter, value: Platter) {
365+ debug_assert!((block as usize) < self.memory.len());
366+ debug_assert!((offset as usize) < self.memory[block as usize].len());
367+ self.memory[block as usize][offset as usize] = value;
368+ }
369+370+ fn duplicate_memory(&mut self, block: Platter) -> &[Platter] {
371+ debug_assert!((block as usize) < self.memory.len());
372+ self.memory[0] = self.memory[block as usize].clone();
373+ &self.memory[0]
374+ }
375+376+ #[cfg(not(feature = "reclaim-memory"))]
377+ fn allocate_memory(&mut self, length: Platter) -> Platter {
378+ self.memory.push(vec![0; length as usize]);
379+ (self.memory.len() - 1) as Platter
380+ }
381+382+ #[cfg(feature = "reclaim-memory")]
383+ fn allocate_memory(&mut self, length: Platter) -> Platter {
384+ if let Some(index) = self.free_blocks.pop() {
385+ self.memory[index as usize] = vec![0; length as usize];
386+ index as Platter
387+ } else {
388+ self.memory.push(vec![0; length as usize]);
389+ (self.memory.len() - 1) as Platter
390+ }
391+ }
392+393+ fn free_memory(&mut self, block: Platter) {
394+ debug_assert!((block as usize) < self.memory.len());
395+ #[cfg(feature = "reclaim-memory")]
396+ {
397+ self.free_blocks.push(block);
398+ self.memory[block as usize] = vec![];
399+ }
400+ }
401+}