···3344#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum Operation {
66+ /// Operator #0. Conditional Move.
77+ ///
88+ /// The register A receives the value in register B,
99+ /// unless the register C contains 0.
610 ConditionalMove {
711 a: Parameter,
812 b: Parameter,
913 c: Parameter,
1014 },
1515+ /// Operator #1: Array Index.
1616+ ///
1717+ /// The register A receives the value stored at offset
1818+ /// in register C in the array identified by B.
1119 ArrayIndex {
1220 a: Parameter,
1321 b: Parameter,
1422 c: Parameter,
1523 },
2424+ /// Operator #2. Array Amendment.
2525+ ///
2626+ /// The array identified by A is amended at the offset
2727+ /// in register B to store the value in register C.
1628 ArrayAmendment {
1729 a: Parameter,
1830 b: Parameter,
1931 c: Parameter,
2032 },
3333+ /// Operator #3. Addition.
3434+ ///
3535+ /// The register A receives the value in register B plus
3636+ /// the value in register C, modulo 2^32.
2137 Addition {
2238 a: Parameter,
2339 b: Parameter,
2440 c: Parameter,
2541 },
4242+ /// Operator #4. Multiplication.
4343+ ///
4444+ /// The register A receives the value in register B times
4545+ /// the value in register C, modulo 2^32.
2646 Multiplication {
2747 a: Parameter,
2848 b: Parameter,
2949 c: Parameter,
3050 },
5151+ /// Operator #5. Division.
5252+ ///
5353+ /// The register A receives the value in register B
5454+ /// divided by the value in register C, if any, where
5555+ /// each quantity is treated as an unsigned 32 bit number.
3156 Division {
3257 a: Parameter,
3358 b: Parameter,
3459 c: Parameter,
3560 },
6161+ /// Operator #6. Not-And.
6262+ ///
6363+ /// Each bit in the register A receives the 1 bit if
6464+ /// either register B or register C has a 0 bit in that
6565+ /// position. Otherwise the bit in register A receives
6666+ /// the 0 bit.
3667 NotAnd {
3768 a: Parameter,
3869 b: Parameter,
3970 c: Parameter,
4071 },
7272+ /// Operator #7. Halt.
7373+ ///
7474+ /// The universal machine stops computation.
4175 Halt,
7676+ /// Operator #8. Allocation.
7777+ ///
7878+ /// A new array is created with a capacity of platters
7979+ /// commensurate to the value in the register C. This
8080+ /// new array is initialized entirely with platters
8181+ /// holding the value 0. A bit pattern not consisting of
8282+ /// exclusively the 0 bit, and that identifies no other
8383+ /// active allocated array, is placed in the B register.
4284 Allocation {
4385 b: Parameter,
4486 c: Parameter,
4587 },
8888+ /// Operator #9. Abandonment.
8989+ ///
9090+ /// The array identified by the register C is abandoned.
9191+ /// Future allocations may then reuse that identifier.
4692 Abandonment {
4793 c: Parameter,
4894 },
9595+ /// Operator #10. Output.
9696+ ///
9797+ /// The value in the register C is displayed on the console
9898+ /// immediately. Only values between and including 0 and 255
9999+ /// are allowed.
49100 Output {
50101 c: Parameter,
51102 },
103103+ /// Operator #11. Input.
104104+ ///
105105+ /// The universal machine waits for input on the console.
106106+ /// When input arrives, the register C is loaded with the
107107+ /// input, which must be between and including 0 and 255.
108108+ /// If the end of input has been signaled, then the
109109+ /// register C is endowed with a uniform value pattern
110110+ /// where every place is pregnant with the 1 bit.
52111 Input {
53112 c: Parameter,
54113 },
114114+ /// Operator #12. Load Program.
115115+ ///
116116+ /// The array identified by the B register is duplicated
117117+ /// and the duplicate shall replace the '0' array,
118118+ /// regardless of size. The execution finger is placed
119119+ /// to indicate the platter of this array that is
120120+ /// described by the offset given in C, where the value
121121+ /// 0 denotes the first platter, 1 the second, et
122122+ /// cetera.
123123+ ///
124124+ /// The '0' array shall be the most sublime choice for
125125+ /// loading, and shall be handled with the utmost
126126+ /// velocity.
55127 LoadProgram {
56128 b: Parameter,
57129 c: Parameter,
58130 },
131131+ /// Operator #13. Orthography.
132132+ ///
133133+ /// The value indicated is loaded into the register A
134134+ /// forthwith.
59135 Orthography {
60136 a: Parameter,
61137 value: u32,
+109-179
src/main.rs
···109109110110 loop {
111111 match self.ops[self.program_counter as usize] {
112112- // Operator #0. Conditional Move.
113113- //
114114- // The register A receives the value in register B,
115115- // unless the register C contains 0.
116116- Operation::ConditionalMove { a, b, c } => {
117117- if self.load_register(c) != 0 {
118118- self.save_register(a, self.load_register(b));
119119- }
120120- }
121121-122122- // Operator #1: Array Index.
123123- //
124124- // The register A receives the value stored at offset
125125- // in register C in the array identified by B.
126126- Operation::ArrayIndex { a, b, c } => {
127127- let block = self.load_register(b);
128128- let offset = self.load_register(c);
129129- self.save_register(a, self.load_memory(block, offset));
130130- }
131131-132132- // Operator #2. Array Amendment.
133133- //
134134- // The array identified by A is amended at the offset
135135- // in register B to store the value in register C.
136136- Operation::ArrayAmendment { a, b, c } => {
137137- let block = self.load_register(a);
138138- let offset = self.load_register(b);
139139- let value = self.load_register(c);
140140- self.store_memory(block, offset, value);
141141- }
142142-143143- // Operator #3. Addition.
144144- //
145145- // The register A receives the value in register B plus
146146- // the value in register C, modulo 2^32.
147147- Operation::Addition { a, b, c } => {
148148- self.save_register(
149149- a,
150150- self.load_register(b).wrapping_add(self.load_register(c)),
151151- );
152152- }
153153-154154- // Operator #4. Multiplication.
155155- //
156156- // The register A receives the value in register B times
157157- // the value in register C, modulo 2^32.
158158- Operation::Multiplication { a, b, c } => {
159159- self.save_register(
160160- a,
161161- self.load_register(b).wrapping_mul(self.load_register(c)),
162162- );
163163- }
164164-165165- // Operator #5. Division.
166166- //
167167- // The register A receives the value in register B
168168- // divided by the value in register C, if any, where
169169- // each quantity is treated as an unsigned 32 bit number.
170170- Operation::Division { a, b, c } => {
171171- self.save_register(
172172- a,
173173- self.load_register(b).wrapping_div(self.load_register(c)),
174174- );
175175- }
176176-177177- // Operator #6. Not-And.
178178- //
179179- // Each bit in the register A receives the 1 bit if
180180- // either register B or register C has a 0 bit in that
181181- // position. Otherwise the bit in register A receives
182182- // the 0 bit.
183183- Operation::NotAnd { a, b, c } => {
184184- self.save_register(a, !(self.load_register(b) & self.load_register(c)));
185185- }
186186-187187- // Operator #7. Halt.
188188- //
189189- // The universal machine stops computation.
112112+ Operation::ConditionalMove { a, b, c } => self.conditional_move(a, b, c),
113113+ Operation::ArrayIndex { a, b, c } => self.array_index(a, b, c),
114114+ Operation::ArrayAmendment { a, b, c } => self.array_amendment(a, b, c),
115115+ Operation::Addition { a, b, c } => self.addition(a, b, c),
116116+ Operation::Multiplication { a, b, c } => self.multiplication(a, b, c),
117117+ Operation::Division { a, b, c } => self.division(a, b, c),
118118+ Operation::NotAnd { a, b, c } => self.not_and(a, b, c),
190119 Operation::Halt => break,
191191-192192- // Operator #8. Allocation.
193193- //
194194- // A new array is created with a capacity of platters
195195- // commensurate to the value in the register C. This
196196- // new array is initialized entirely with platters
197197- // holding the value 0. A bit pattern not consisting of
198198- // exclusively the 0 bit, and that identifies no other
199199- // active allocated array, is placed in the B register.
200200- Operation::Allocation { b, c } => {
201201- let length = self.load_register(c);
202202- let index = self.allocate_memory(length);
203203- self.save_register(b, index);
204204- }
205205-206206- // Operator #9. Abandonment.
207207- //
208208- // The array identified by the register C is abandoned.
209209- // Future allocations may then reuse that identifier.
210210- Operation::Abandonment { c } => {
211211- let block = self.load_register(c);
212212- self.free_memory(block);
213213- }
214214-215215- // Operator #10. Output.
216216- //
217217- // The value in the register C is displayed on the console
218218- // immediately. Only values between and including 0 and 255
219219- // are allowed.
220220- Operation::Output { c } => {
221221- let value = self.load_register(c);
222222- if let Some(stdout) = self.stdout.as_mut() {
223223- let buffer = [(value & 0xff) as u8];
224224- stdout.write_all(&buffer).unwrap();
225225- }
226226- }
227227-228228- // Operator #11. Input.
229229- //
230230- // The universal machine waits for input on the console.
231231- // When input arrives, the register C is loaded with the
232232- // input, which must be between and including 0 and 255.
233233- // If the end of input has been signaled, then the
234234- // register C is endowed with a uniform value pattern
235235- // where every place is pregnant with the 1 bit.
236236- Operation::Input { c } => {
237237- if let Some(stdin) = self.stdin.as_mut() {
238238- let mut buffer = vec![0];
239239- match stdin.read_exact(&mut buffer) {
240240- Ok(()) => self.save_register(c, buffer[0] as u32),
241241- Err(_) => self.save_register(c, 0xff),
242242- }
243243- } else {
244244- self.save_register(c, 0xff);
245245- }
246246- }
247247-248248- // Operator #12. Load Program.
249249- //
250250- // The array identified by the B register is duplicated
251251- // and the duplicate shall replace the '0' array,
252252- // regardless of size. The execution finger is placed
253253- // to indicate the platter of this array that is
254254- // described by the offset given in C, where the value
255255- // 0 denotes the first platter, 1 the second, et
256256- // cetera.
257257- //
258258- // The '0' array shall be the most sublime choice for
259259- // loading, and shall be handled with the utmost
260260- // velocity.
120120+ Operation::Allocation { b, c } => self.allocation(b, c),
121121+ Operation::Abandonment { c } => self.abandonment(c),
122122+ Operation::Output { c } => self.output(c),
123123+ Operation::Input { c } => self.input(c),
261124 Operation::LoadProgram { b, c } => {
262262- let block = self.load_register(b);
263263-264264- // Source array is always copied to array[0], but there
265265- // is no point copying array[0] to array[0].
266266- if block != 0 {
267267- let duplicated = self.duplicate_memory(block);
268268- let ops = um::decode_ops(duplicated);
269269- self.ops = ops;
270270- }
271271-272272- self.program_counter = self.load_register(c);
125125+ self.load_program(b, c);
273126 continue;
274127 }
275275-276276- // Operator #13. Orthography.
277277- //
278278- // The value indicated is loaded into the register A
279279- // forthwith.
280280- Operation::Orthography { a, value } => {
281281- self.save_register(a, value);
282282- }
283283-284284- Operation::IllegalInstruction => self.panic(),
128128+ Operation::Orthography { a, value } => self.orthography(a, value),
129129+ Operation::IllegalInstruction => self.illegal_instruction(),
285130 }
286286-287131 self.program_counter += 1;
288132 }
289133···305149 self.registers[index.into_index()] = value;
306150 }
307151152152+ pub fn conditional_move(&mut self, a: Parameter, b: Parameter, c: Parameter) {
153153+ if self.load_register(c) != 0 {
154154+ self.save_register(a, self.load_register(b));
155155+ }
156156+ }
157157+158158+ pub fn array_index(&mut self, a: Parameter, b: Parameter, c: Parameter) {
159159+ let block = self.load_register(b);
160160+ let offset = self.load_register(c);
161161+ self.save_register(a, self.load_memory(block, offset));
162162+ }
163163+164164+ pub fn array_amendment(&mut self, a: Parameter, b: Parameter, c: Parameter) {
165165+ let block = self.load_register(a);
166166+ let offset = self.load_register(b);
167167+ let value = self.load_register(c);
168168+ self.store_memory(block, offset, value);
169169+ }
170170+171171+ pub fn addition(&mut self, a: Parameter, b: Parameter, c: Parameter) {
172172+ self.save_register(a, self.load_register(b).wrapping_add(self.load_register(c)));
173173+ }
174174+175175+ pub fn multiplication(&mut self, a: Parameter, b: Parameter, c: Parameter) {
176176+ self.save_register(a, self.load_register(b).wrapping_mul(self.load_register(c)));
177177+ }
178178+179179+ pub fn division(&mut self, a: Parameter, b: Parameter, c: Parameter) {
180180+ self.save_register(a, self.load_register(b).wrapping_div(self.load_register(c)));
181181+ }
182182+183183+ pub fn not_and(&mut self, a: Parameter, b: Parameter, c: Parameter) {
184184+ self.save_register(a, !(self.load_register(b) & self.load_register(c)));
185185+ }
186186+187187+ pub fn allocation(&mut self, b: Parameter, c: Parameter) {
188188+ let length = self.load_register(c);
189189+ let index = self.allocate_memory(length);
190190+ self.save_register(b, index);
191191+ }
192192+193193+ pub fn abandonment(&mut self, c: Parameter) {
194194+ let block = self.load_register(c);
195195+ self.free_memory(block);
196196+ }
197197+198198+ pub fn output(&mut self, c: Parameter) {
199199+ let value = self.load_register(c);
200200+ if let Some(stdout) = self.stdout.as_mut() {
201201+ let buffer = [(value & 0xff) as u8];
202202+ stdout.write_all(&buffer).unwrap();
203203+ }
204204+ }
205205+206206+ pub fn input(&mut self, c: Parameter) {
207207+ if let Some(stdin) = self.stdin.as_mut() {
208208+ let mut buffer = vec![0];
209209+ match stdin.read_exact(&mut buffer) {
210210+ Ok(()) => self.save_register(c, buffer[0] as u32),
211211+ Err(_) => self.save_register(c, 0xff),
212212+ }
213213+ } else {
214214+ self.save_register(c, 0xff);
215215+ }
216216+ }
217217+218218+ pub fn load_program(&mut self, b: Parameter, c: Parameter) {
219219+ let block = self.load_register(b);
220220+221221+ // Source array is always copied to array[0], but there
222222+ // is no point copying array[0] to array[0].
223223+ if block != 0 {
224224+ let duplicated = self.duplicate_memory(block);
225225+ let ops = um::decode_ops(duplicated);
226226+ self.ops = ops;
227227+ }
228228+229229+ self.program_counter = self.load_register(c);
230230+ }
231231+232232+ pub fn orthography(&mut self, a: Parameter, value: Platter) {
233233+ self.save_register(a, value);
234234+ }
235235+236236+ #[cold]
237237+ #[inline(never)]
238238+ fn illegal_instruction(&self) -> ! {
239239+ panic!(
240240+ "illegal instruction: {:08x}, pc: {:08x}, r: {:08x?}",
241241+ self.memory[0][self.program_counter.into_index()],
242242+ self.program_counter,
243243+ self.registers
244244+ )
245245+ }
246246+308247 fn load_memory(&self, block: Platter, offset: Platter) -> Platter {
309248 let block = block.into_index();
310249 let offset = offset.into_index();
···350289 self.free_blocks.push(block);
351290 self.memory[block.into_index()] = Self::new_block(0);
352291 }
353353- }
354354-355355- #[cold]
356356- #[inline(never)]
357357- fn panic(&self) -> ! {
358358- panic!(
359359- "universal machine failure: instruction: {:08x}, program_counter: {:08x}, registers: {:08x?}",
360360- self.memory[0][self.program_counter.into_index()], self.program_counter, self.registers
361361- )
362292 }
363293364294 fn new_block(len: usize) -> SmallVec<[Platter; SMALLVEC_SIZE]> {