···11+# This file is automatically @generated by Cargo.
22+# It is not intended for manual editing.
33+version = 3
44+55+[[package]]
66+name = "um"
77+version = "0.1.0"
···11+fn main() {
22+ let mut program = Vec::new();
33+ for arg in std::env::args().skip(1) {
44+ let p = std::fs::read(arg).unwrap();
55+ program.extend_from_slice(&p);
66+ }
77+88+ Um::from_bytes(program)
99+ .stdout(std::io::stdout())
1010+ .stdin(std::io::stdin())
1111+ .run();
1212+}
1313+1414+type Platter = u32;
1515+type Register = u8;
1616+1717+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1818+enum Op {
1919+ ConditionalMove {
2020+ a: Register,
2121+ b: Register,
2222+ c: Register,
2323+ },
2424+ ArrayIndex {
2525+ a: Register,
2626+ b: Register,
2727+ c: Register,
2828+ },
2929+ ArrayAmendment {
3030+ a: Register,
3131+ b: Register,
3232+ c: Register,
3333+ },
3434+ Addition {
3535+ a: Register,
3636+ b: Register,
3737+ c: Register,
3838+ },
3939+ Multiplication {
4040+ a: Register,
4141+ b: Register,
4242+ c: Register,
4343+ },
4444+ Division {
4545+ a: Register,
4646+ b: Register,
4747+ c: Register,
4848+ },
4949+ NotAnd {
5050+ a: Register,
5151+ b: Register,
5252+ c: Register,
5353+ },
5454+ Halt,
5555+ Allocation {
5656+ b: Register,
5757+ c: Register,
5858+ },
5959+ Abandonment {
6060+ c: Register,
6161+ },
6262+ Output {
6363+ c: Register,
6464+ },
6565+ Input {
6666+ c: Register,
6767+ },
6868+ LoadProgram {
6969+ b: Register,
7070+ c: Register,
7171+ },
7272+ Orthography {
7373+ a: Register,
7474+ value: u32,
7575+ },
7676+}
7777+7878+impl From<Platter> for Op {
7979+ fn from(value: Platter) -> Self {
8080+ let a = ((value >> 6) & 0x07) as Register;
8181+ let b = ((value >> 3) & 0x07) as Register;
8282+ let c = ((value >> 0) & 0x07) as Register;
8383+8484+ match value & 0xf0000000 {
8585+ 0x00000000 => Self::ConditionalMove { a, b, c },
8686+ 0x10000000 => Self::ArrayIndex { a, b, c },
8787+ 0x20000000 => Self::ArrayAmendment { a, b, c },
8888+ 0x30000000 => Self::Addition { a, b, c },
8989+ 0x40000000 => Self::Multiplication { a, b, c },
9090+ 0x50000000 => Self::Division { a, b, c },
9191+ 0x60000000 => Self::NotAnd { a, b, c },
9292+ 0x70000000 => Self::Halt,
9393+ 0x80000000 => Self::Allocation { b, c },
9494+ 0x90000000 => Self::Abandonment { c },
9595+ 0xa0000000 => Self::Output { c },
9696+ 0xb0000000 => Self::Input { c },
9797+ 0xc0000000 => Self::LoadProgram { b, c },
9898+ 0xd0000000 => {
9999+ let a = ((value >> 25) & 0x07) as Register;
100100+ let value = value & 0x01ffffff;
101101+ Self::Orthography { a, value }
102102+ }
103103+ _ => Self::Halt,
104104+ }
105105+ }
106106+}
107107+108108+fn decode_ops(ops: &[Platter]) -> Vec<Op> {
109109+ ops.iter().map(|encoded| Op::from(*encoded)).collect()
110110+}
111111+112112+#[derive(Default)]
113113+pub struct Um {
114114+ program_counter: Platter,
115115+ registers: [Platter; 8],
116116+ memory: Vec<Vec<Platter>>,
117117+ #[cfg(feature = "reclaim-memory")]
118118+ free_blocks: Vec<Platter>,
119119+ ops: Vec<Op>,
120120+ stdin: Option<Box<dyn std::io::Read>>,
121121+ stdout: Option<Box<dyn std::io::Write>>,
122122+}
123123+124124+impl Um {
125125+ /// Construct a new Universal Machine with the specified program.
126126+ pub fn new(program: Vec<Platter>) -> Self {
127127+ let ops = decode_ops(&program);
128128+ Self {
129129+ memory: vec![program],
130130+ ops,
131131+ ..Default::default()
132132+ }
133133+ }
134134+135135+ /// Construct a new Universal Machine from a program represented in bytes.
136136+ pub fn from_bytes(program: impl AsRef<[u8]>) -> Self {
137137+ let bytes = program.as_ref();
138138+ let mut program = Vec::with_capacity(bytes.len().div_ceil(size_of::<Platter>()));
139139+ for word in bytes.chunks(size_of::<Platter>()) {
140140+ let value = Platter::from_be_bytes(match word {
141141+ [a, b, c, d] => [*a, *b, *c, *d],
142142+ [a, b, c] => [*a, *b, *c, 0],
143143+ [a, b] => [*a, *b, 0, 0],
144144+ [a] => [*a, 0, 0, 0],
145145+ _ => unreachable!(),
146146+ });
147147+ program.push(value);
148148+ }
149149+150150+ Self::new(program)
151151+ }
152152+153153+ /// Sets the output for the univeral machine.
154154+ pub fn stdout(mut self, stdout: impl std::io::Write + 'static) -> Self {
155155+ self.stdout.replace(Box::new(stdout));
156156+ self
157157+ }
158158+159159+ /// Sets the input for the universal machine.
160160+ pub fn stdin(mut self, stdin: impl std::io::Read + 'static) -> Self {
161161+ self.stdin.replace(Box::new(stdin));
162162+ self
163163+ }
164164+165165+ /// Begins the spin-cycle of the universal machine.
166166+ pub fn run(mut self) {
167167+ loop {
168168+ match self.ops[self.program_counter as usize] {
169169+ // Operator #0. Conditional Move.
170170+ //
171171+ // The register A receives the value in register B,
172172+ // unless the register C contains 0.
173173+ Op::ConditionalMove { a, b, c } => {
174174+ if self.load_register(c) != 0 {
175175+ self.save_register(a, self.load_register(b));
176176+ }
177177+ }
178178+179179+ // Operator #1: Array Index.
180180+ //
181181+ // The register A receives the value stored at offset
182182+ // in register C in the array identified by B.
183183+ Op::ArrayIndex { a, b, c } => {
184184+ let block = self.load_register(b);
185185+ let offset = self.load_register(c);
186186+ self.save_register(a, self.load_memory(block, offset));
187187+ }
188188+189189+ // Operator #2. Array Amendment.
190190+ //
191191+ // The array identified by A is amended at the offset
192192+ // in register B to store the value in register C.
193193+ Op::ArrayAmendment { a, b, c } => {
194194+ let block = self.load_register(a);
195195+ let offset = self.load_register(b);
196196+ let value = self.load_register(c);
197197+ self.store_memory(block, offset, value);
198198+ }
199199+200200+ // Operator #3. Addition.
201201+ //
202202+ // The register A receives the value in register B plus
203203+ // the value in register C, modulo 2^32.
204204+ Op::Addition { a, b, c } => {
205205+ self.save_register(
206206+ a,
207207+ self.load_register(b).wrapping_add(self.load_register(c)),
208208+ );
209209+ }
210210+211211+ // Operator #4. Multiplication.
212212+ //
213213+ // The register A receives the value in register B times
214214+ // the value in register C, modulo 2^32.
215215+ Op::Multiplication { a, b, c } => {
216216+ self.save_register(
217217+ a,
218218+ self.load_register(b).wrapping_mul(self.load_register(c)),
219219+ );
220220+ }
221221+222222+ // Operator #5. Division.
223223+ //
224224+ // The register A receives the value in register B
225225+ // divided by the value in register C, if any, where
226226+ // each quantity is treated as an unsigned 32 bit number.
227227+ Op::Division { a, b, c } => {
228228+ self.save_register(
229229+ a,
230230+ self.load_register(b).wrapping_div(self.load_register(c)),
231231+ );
232232+ }
233233+234234+ // Operator #6. Not-And.
235235+ //
236236+ // Each bit in the register A receives the 1 bit if
237237+ // either register B or register C has a 0 bit in that
238238+ // position. Otherwise the bit in register A receives
239239+ // the 0 bit.
240240+ Op::NotAnd { a, b, c } => {
241241+ self.save_register(a, !(self.load_register(b) & self.load_register(c)));
242242+ }
243243+244244+ // Operator #7. Halt.
245245+ //
246246+ // The universal machine stops computation.
247247+ Op::Halt => break,
248248+249249+ // Operator #8. Allocation.
250250+ //
251251+ // A new array is created with a capacity of platters
252252+ // commensurate to the value in the register C. This
253253+ // new array is initialized entirely with platters
254254+ // holding the value 0. A bit pattern not consisting of
255255+ // exclusively the 0 bit, and that identifies no other
256256+ // active allocated array, is placed in the B register.
257257+ Op::Allocation { b, c } => {
258258+ let length = self.load_register(c);
259259+ let index = self.allocate_memory(length);
260260+ self.save_register(b, index);
261261+ }
262262+263263+ // Operator #9. Abandonment.
264264+ //
265265+ // The array identified by the register C is abandoned.
266266+ // Future allocations may then reuse that identifier.
267267+ Op::Abandonment { c } => {
268268+ let block = self.load_register(c);
269269+ self.free_memory(block);
270270+ }
271271+272272+ // Operator #10. Output.
273273+ //
274274+ // The value in the register C is displayed on the console
275275+ // immediately. Only values between and including 0 and 255
276276+ // are allowed.
277277+ Op::Output { c } => {
278278+ let value = self.load_register(c);
279279+ if let Some(stdout) = self.stdout.as_mut() {
280280+ let buffer = [(value & 0xff) as u8];
281281+ stdout.write_all(&buffer).unwrap();
282282+ }
283283+ }
284284+285285+ // Operator #11. Input.
286286+ //
287287+ // The universal machine waits for input on the console.
288288+ // When input arrives, the register C is loaded with the
289289+ // input, which must be between and including 0 and 255.
290290+ // If the end of input has been signaled, then the
291291+ // register C is endowed with a uniform value pattern
292292+ // where every place is pregnant with the 1 bit.
293293+ Op::Input { c } => {
294294+ if let Some(stdin) = self.stdin.as_mut() {
295295+ let mut buffer = vec![0];
296296+ match stdin.read_exact(&mut buffer) {
297297+ Ok(()) => self.save_register(c, buffer[0] as u32),
298298+ Err(_) => self.save_register(c, 0xff),
299299+ }
300300+ } else {
301301+ self.save_register(c, 0xff);
302302+ }
303303+ }
304304+305305+ // Operator #12. Load Program.
306306+ //
307307+ // The array identified by the B register is duplicated
308308+ // and the duplicate shall replace the '0' array,
309309+ // regardless of size. The execution finger is placed
310310+ // to indicate the platter of this array that is
311311+ // described by the offset given in C, where the value
312312+ // 0 denotes the first platter, 1 the second, et
313313+ // cetera.
314314+ //
315315+ // The '0' array shall be the most sublime choice for
316316+ // loading, and shall be handled with the utmost
317317+ // velocity.
318318+ Op::LoadProgram { b, c } => {
319319+ let block = self.load_register(b);
320320+321321+ // Source array is always copied to array[0], but there
322322+ // is no point copying array[0] to array[0].
323323+ if block != 0 {
324324+ let duplicated = self.duplicate_memory(block);
325325+ let ops = decode_ops(&duplicated);
326326+ self.ops = ops;
327327+ }
328328+329329+ self.program_counter = self.load_register(c);
330330+ continue;
331331+ }
332332+333333+ // Operator #13. Orthography.
334334+ //
335335+ // The value indicated is loaded into the register A
336336+ // forthwith.
337337+ Op::Orthography { a, value } => {
338338+ self.save_register(a, value);
339339+ }
340340+ }
341341+342342+ self.program_counter += 1;
343343+ }
344344+ }
345345+346346+ /// Loads the value from the specified register.
347347+ fn load_register(&self, index: Register) -> Platter {
348348+ debug_assert!(index < 8, "register index out of bounds");
349349+ self.registers[index as usize]
350350+ }
351351+352352+ /// Saves a value to the specified register.
353353+ fn save_register(&mut self, index: Register, value: Platter) {
354354+ debug_assert!(index < 8, "register index out of bounds");
355355+ self.registers[index as usize] = value;
356356+ }
357357+358358+ fn load_memory(&self, block: Platter, offset: Platter) -> Platter {
359359+ debug_assert!((block as usize) < self.memory.len());
360360+ debug_assert!((offset as usize) < self.memory[block as usize].len());
361361+ self.memory[block as usize][offset as usize]
362362+ }
363363+364364+ fn store_memory(&mut self, block: Platter, offset: Platter, value: Platter) {
365365+ debug_assert!((block as usize) < self.memory.len());
366366+ debug_assert!((offset as usize) < self.memory[block as usize].len());
367367+ self.memory[block as usize][offset as usize] = value;
368368+ }
369369+370370+ fn duplicate_memory(&mut self, block: Platter) -> &[Platter] {
371371+ debug_assert!((block as usize) < self.memory.len());
372372+ self.memory[0] = self.memory[block as usize].clone();
373373+ &self.memory[0]
374374+ }
375375+376376+ #[cfg(not(feature = "reclaim-memory"))]
377377+ fn allocate_memory(&mut self, length: Platter) -> Platter {
378378+ self.memory.push(vec![0; length as usize]);
379379+ (self.memory.len() - 1) as Platter
380380+ }
381381+382382+ #[cfg(feature = "reclaim-memory")]
383383+ fn allocate_memory(&mut self, length: Platter) -> Platter {
384384+ if let Some(index) = self.free_blocks.pop() {
385385+ self.memory[index as usize] = vec![0; length as usize];
386386+ index as Platter
387387+ } else {
388388+ self.memory.push(vec![0; length as usize]);
389389+ (self.memory.len() - 1) as Platter
390390+ }
391391+ }
392392+393393+ fn free_memory(&mut self, block: Platter) {
394394+ debug_assert!((block as usize) < self.memory.len());
395395+ #[cfg(feature = "reclaim-memory")]
396396+ {
397397+ self.free_blocks.push(block);
398398+ self.memory[block as usize] = vec![];
399399+ }
400400+ }
401401+}