// Copyright (C) 2025 Thom Hayward. // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation, version 3. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . // use crate::reg::Register; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Operation { /// Operator #0. Conditional Move. /// /// The register A receives the value in register B, /// unless the register C contains 0. ConditionalMove { a: Register, b: Register, c: Register, }, /// Operator #1: Array Index. /// /// The register A receives the value stored at offset /// in register C in the array identified by B. ArrayIndex { a: Register, b: Register, c: Register, }, /// Operator #2. Array Amendment. /// /// The array identified by A is amended at the offset /// in register B to store the value in register C. ArrayAmendment { a: Register, b: Register, c: Register, }, /// Operator #3. Addition. /// /// The register A receives the value in register B plus /// the value in register C, modulo 2^32. Addition { a: Register, b: Register, c: Register, }, /// Operator #4. Multiplication. /// /// The register A receives the value in register B times /// the value in register C, modulo 2^32. Multiplication { a: Register, b: Register, c: Register, }, /// Operator #5. Division. /// /// The register A receives the value in register B /// divided by the value in register C, if any, where /// each quantity is treated as an unsigned 32 bit number. Division { a: Register, b: Register, c: Register, }, /// Operator #6. Not-And. /// /// Each bit in the register A receives the 1 bit if /// either register B or register C has a 0 bit in that /// position. Otherwise the bit in register A receives /// the 0 bit. NotAnd { a: Register, b: Register, c: Register, }, /// Operator #7. Halt. /// /// The universal machine stops computation. Halt, /// Operator #8. Allocation. /// /// A new array is created with a capacity of platters /// commensurate to the value in the register C. This /// new array is initialized entirely with platters /// holding the value 0. A bit pattern not consisting of /// exclusively the 0 bit, and that identifies no other /// active allocated array, is placed in the B register. Allocation { b: Register, c: Register, }, /// Operator #9. Abandonment. /// /// The array identified by the register C is abandoned. /// Future allocations may then reuse that identifier. Abandonment { c: Register, }, /// Operator #10. Output. /// /// The value in the register C is displayed on the console /// immediately. Only values between and including 0 and 255 /// are allowed. Output { c: Register, }, /// Operator #11. Input. /// /// The universal machine waits for input on the console. /// When input arrives, the register C is loaded with the /// input, which must be between and including 0 and 255. /// If the end of input has been signaled, then the /// register C is endowed with a uniform value pattern /// where every place is pregnant with the 1 bit. Input { c: Register, }, /// Operator #12. Load Program. /// /// The array identified by the B register is duplicated /// and the duplicate shall replace the '0' array, /// regardless of size. The execution finger is placed /// to indicate the platter of this array that is /// described by the offset given in C, where the value /// 0 denotes the first platter, 1 the second, et /// cetera. /// /// The '0' array shall be the most sublime choice for /// loading, and shall be handled with the utmost /// velocity. LoadProgram { b: Register, c: Register, }, /// Operator #13. Orthography. /// /// The value indicated is loaded into the register A /// forthwith. Orthography { a: Register, value: u32, }, IllegalInstruction, } impl From for Operation { fn from(value: u32) -> Self { let a = Register::from_u8(((value >> 6) & 0x07) as u8); let b = Register::from_u8(((value >> 3) & 0x07) as u8); let c = Register::from_u8((value & 0x07) as u8); match value & 0xf0000000 { 0x00000000 => Self::ConditionalMove { a, b, c }, 0x10000000 => Self::ArrayIndex { a, b, c }, 0x20000000 => Self::ArrayAmendment { a, b, c }, 0x30000000 => Self::Addition { a, b, c }, 0x40000000 => Self::Multiplication { a, b, c }, 0x50000000 => Self::Division { a, b, c }, 0x60000000 => Self::NotAnd { a, b, c }, 0x70000000 => Self::Halt, 0x80000000 => Self::Allocation { b, c }, 0x90000000 => Self::Abandonment { c }, 0xa0000000 => Self::Output { c }, 0xb0000000 => Self::Input { c }, 0xc0000000 => Self::LoadProgram { b, c }, 0xd0000000 => { let a = Register::from_u8(((value >> 25) & 0x07) as u8); let value = value & 0x01ffffff; Self::Orthography { a, value } } _ => Self::IllegalInstruction, } } } pub fn decode(ops: &[u32]) -> Vec { ops.iter() .map(|&encoded| Operation::from(encoded)) .collect() }