pub struct Machine {Show 16 fields
pub reg_a: u8,
pub reg_b: i16,
pub reg_L: u16,
pub reg_f: f64,
pub reg_ch: char,
pub reg_ř: [i8; 37],
pub reg_ß: ConstantSizeString,
pub reg_Ω: Ω,
pub num_reg: i32,
pub reg_ep: u16,
pub reg_dp: u16,
pub flag: bool,
pub debug_mode: bool,
pub halted: bool,
pub memory: Box<[u8; 65535]>,
pub stack: Stack,
}Expand description
An esoteric virtual machine.
Create a new machine with [Machine::new] and load
machine code and data to it with Machine::load.
§Examples
// initialize a new machine
let mut machine = Machine::default();
// assembly code for the machine
let asm = esoteric_assembly! {
// initialize dot pointer so that IO operations work
// push a dot character to stack
0: pushi b'.';
// pop to address 28657
2: pop 28657;
// set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
5: ldidp 28657;
// -----------------
// print hello world
8: writeline 13;
// halt machine
11: Ωtheendisnear;
12: Ωskiptothechase;
// hello world text
13: data b"Hello, world!\n\0";
};
// load machine code
machine.load(&asm, 0);
// run machine until it halts
machine.run();
// return the machine's register A (unused)
machineFields§
§reg_a: u8register a (used as the machine’s exit code)
reg_b: i16register b
reg_L: u16register L
reg_f: f64register f
reg_ch: charregister ch (ch is one letter in Czech, therefore it’s valid)
reg_ř: [i8; 37]register ř
reg_ß: ConstantSizeStringregister ß
reg_Ω: Ωregister Ω
num_reg: i32number register (serves as the return value of the main function and
is printed in debug mode if reg_Ω.should_make_infinite_paperclips is true)
reg_ep: u16execution pointer
reg_dp: u16dot pointer (has to point to a . character. if it doesn’t, then IO operation attempts are cancelled and the flag is set)
flag: booloverflow/error flag
debug_mode: booldebug mode
halted: boolwhether the machine is halted (can’t run anymore and is finished)
memory: Box<[u8; 65535]>memory (should be 65K)
stack: Stackstack memory (default is 4K)
Implementations§
Source§impl Machine
impl Machine
Sourcepub fn fetch_byte(&mut self) -> u8
pub fn fetch_byte(&mut self) -> u8
Fetches a byte at [reg_ep] and increments [reg_ep] by 1.
Sourcepub fn fetch_2_bytes(&mut self) -> u16
pub fn fetch_2_bytes(&mut self) -> u16
Fetches 2 bytes at [reg_ep] as a big endian integer
and increments [reg_ep] by 2.
Sourcepub fn fetch_4_bytes(&mut self) -> u32
pub fn fetch_4_bytes(&mut self) -> u32
Fetches 4 bytes at [reg_ep] as a big endian integer
and increments [reg_ep] by 4.
Sourcepub fn fetch_8_bytes(&mut self) -> u64
pub fn fetch_8_bytes(&mut self) -> u64
Fetches 8 bytes at [reg_ep] as a big endian integer
and increments [reg_ep] by 8.
Sourcepub fn fetch_instruction_kind(&mut self) -> Option<InstructionKind>
pub fn fetch_instruction_kind(&mut self) -> Option<InstructionKind>
Fetches a byte and tries to turn it into an InstructionKind.
For more info, read the docs for [fetch_byte].
Sourcepub fn num_debug(&self)
pub fn num_debug(&self)
Prints [num_reg] with a colon and a space after it
if [reg_Ω.should_make_infinite_paperclips] is enabled.
Sourcepub fn fetch_instruction(&mut self) -> Option<Instruction>
pub fn fetch_instruction(&mut self) -> Option<Instruction>
Fetches an instruction from memory,
incrementing [reg_ep] based on the amount of bytes read.
Returns None if the machine is halted.
Sourcepub fn execute_instruction(&mut self, instruction: Instruction)
pub fn execute_instruction(&mut self, instruction: Instruction)
Fetches and executes an instruction.
More info at [fetch_instruction].
Sourcepub fn load_instructions(
&mut self,
instructions: &[Instruction],
offset: u16,
) -> u16
pub fn load_instructions( &mut self, instructions: &[Instruction], offset: u16, ) -> u16
Loads instructions into the machine’s memory at the specified offset.
Returns the amount of bytes written
Sourcepub fn load(&mut self, data: &[DataOrInstruction<'_>], offset: u16) -> u16
pub fn load(&mut self, data: &[DataOrInstruction<'_>], offset: u16) -> u16
Loads data into the machine’s memory at the specified offset.
Returns the amount of bytes written
Examples found in repository?
3fn main() -> Machine {
4 // initialize a new machine
5 let mut machine = Machine::default();
6
7 // assembly code for the machine
8 let asm = esoteric_assembly! {
9 // initialize dot pointer so that IO operations work
10
11 // push a dot character to stack
12 0: pushi b'.';
13 // pop to address 28657
14 2: pop 28657;
15
16 // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17 5: ldidp 28657;
18
19 // -----------------
20
21 // print hello world
22 8: writeline 13;
23
24 // halt machine
25 11: Ωtheendisnear;
26 12: Ωskiptothechase;
27
28 // hello world text
29 13: data b"Hello, world!\n\0";
30 };
31
32 // load machine code
33 machine.load(&asm, 0);
34
35 // run machine until it halts
36 machine.run();
37
38 // return the machine's register A (unused)
39 machine
40}More examples
3fn main() -> Machine {
4 // initialize a new machine
5 let mut machine = Machine::default();
6
7 // assembly code for the machine
8 let asm = esoteric_assembly! {
9 // initialize dot pointer so that IO operations work
10
11 // push a dot character to stack
12 0: pushi b'.';
13 // pop to address 28657
14 2: pop 28657;
15
16 // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17 4: ldidp 28657;
18
19 // ------------------
20
21 // get a single character to register ch
22 7: getchar;
23
24 // push register ch to stack (4 bytes)
25 8: pushch;
26
27 // pop character to register b
28 9: popb;
29
30 // pop the other 2 bytes
31 10: stackdealloc 2;
32
33 // put 49 (ascii for '1') in register L
34 13: pushi 0;
35 15: pushi 49;
36 17: popl;
37
38 // compare registers L and b
39 18: cmplb;
40
41 // push 30 (input == '1' logic)
42 19: pushi 0;
43 21: pushi 30;
44
45 // pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
46 23: zpopep;
47
48 // empty the stack
49 24: stackdealloc 2;
50
51 // IF INPUT IS '0' (repeat it)
52 // fallback to the input == '1' logic, ran without jumps
53
54 // write the input value ('0')
55 27: writechar;
56
57 // halt machine
58 28: Ωtheendisnear;
59 29: Ωskiptothechase;
60
61 // IF INPUT IS '1' (repeat indefinitely)
62
63 // write the input value ('1')
64 30: writechar;
65
66 // push 30 (input == '1' logic)
67 31: pushi 0;
68 33: pushi 30;
69
70 // pop to execution pointer (jump to value on stack)
71 //
72 // this repeats the input == '1' logic indefinitely
73 35: popep;
74
75 };
76
77 // load machine code
78 machine.load(&asm, 0);
79
80 // run machine until it halts
81 machine.run();
82
83 // return the machine's register A (unused)
84 machine
85}3fn main() -> Machine {
4 // initialize a new machine
5 let mut machine = Machine::default();
6
7 // assembly code for the machine
8 let asm = esoteric_assembly! {
9 // initialize dot pointer so that IO operations work
10
11 // push a dot character to stack
12 0: pushi b'.';
13 // pop to address 28657
14 2: pop 28657;
15
16 // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17 5: ldidp 28657;
18
19 // -----------------
20
21
22 // set L to 99
23 8: pushi 0;
24 10: pushi 99;
25 12: popl;
26
27 // set num to 99
28 13: pushi 0;
29 15: pushi 0;
30 17: pushi 0;
31 19: pushi 99;
32 21: popnum;
33
34 // set B to 1
35 22: pushi 0;
36 24: pushi 1;
37 26: popb;
38
39 27: Ωsetpaperclipproduction true;
40
41 // WORK
42 29: writeline 110; // wall
43 33: writeline 140; // bottles
44
45 35: Ωsetpaperclipproduction false;
46
47 37: writeline 158; // take
48
49 40: Ωsetpaperclipproduction true;
50
51 // jump to fin if L == 1
52 42: cmplb;
53 43: pushi 0;
54 45: pushi 71;
55
56 47: zpopep;
57
58 48: stackdealloc 2;
59
60 // set B to 1
61 51: pushi 0;
62 53: pushi 1;
63 55: popb;
64
65 56: subbl; // L -= 1
66
67 // set num to L
68 57: pushi 0;
69 59: pushi 0;
70 61: pushl;
71 62: popnum;
72
73 63: writeline 193; // wall_end
74
75 // jump back to work
76 66: pushi 0;
77 68: pushi 29;
78
79 70: popep;
80
81 // FIN
82 71: Ωsetpaperclipproduction false;
83
84 73: writeline 224; // no_more
85 76: writeline 193; // wall_end
86
87 79: writeline 233; // No_more
88 82: writeline 110; // wall
89 85: writeline 224; // no_more
90 88: writeline 140; // bottles
91
92 91: writeline 242; // store
93
94 // set num to 99
95 94: pushi 0;
96 96: pushi 0;
97 98: pushi 0;
98 100: pushi 99;
99 102: popnum;
100
101 103: Ωsetpaperclipproduction true;
102
103 105: writeline 193; // wall_end
104
105 // halt machine
106 108: Ωtheendisnear;
107 109: Ωskiptothechase;
108
109 // wall (30 bytes)
110 110: data b"bottles of beer on the wall, \0";
111 // bottles (18 bytes)
112 140: data b"bottles of beer.\n\0";
113 // take (35 bytes)
114 158: data b"Take one down and pass it around, \0";
115 // wall end (31 bytes)
116 193: data b"bottles of beer on the wall.\n\n\0";
117
118 // no more (9 bytes)
119 224: data b"no more \0";
120 // No more (9 bytes)
121 233: data b"No more \0";
122
123 // store
124 242: data b"Go to the store and buy some more, \0";
125 };
126
127 // load machine code
128 machine.load(&asm, 0);
129
130 // run machine until it halts
131 machine.run();
132
133 // return the machine's register A (unused)
134 machine
135}Sourcepub fn load_bytes(&mut self, bytes: &[u8], offset: u16) -> Option<u16>
pub fn load_bytes(&mut self, bytes: &[u8], offset: u16) -> Option<u16>
Load bytes into the machine at the specified offset.
Returns the amount of bytes written
Sourcepub fn load_instruction(&mut self, instruction: Instruction, offset: &mut u16)
pub fn load_instruction(&mut self, instruction: Instruction, offset: &mut u16)
Loads a single instruction into memory at the specified offset, mutating it based on the amount of bytes written.
Sourcepub fn run(&mut self) -> u8
pub fn run(&mut self) -> u8
Runs the machine until it halts
via Ωtheendisnear and Ωskiptothechase.
§Panics
Panics if an invalid opcode (instruction) is stumbled upon with an esoteric message and an explaination for demistification.
Examples found in repository?
3fn main() -> Machine {
4 // initialize a new machine
5 let mut machine = Machine::default();
6
7 // assembly code for the machine
8 let asm = esoteric_assembly! {
9 // initialize dot pointer so that IO operations work
10
11 // push a dot character to stack
12 0: pushi b'.';
13 // pop to address 28657
14 2: pop 28657;
15
16 // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17 5: ldidp 28657;
18
19 // -----------------
20
21 // print hello world
22 8: writeline 13;
23
24 // halt machine
25 11: Ωtheendisnear;
26 12: Ωskiptothechase;
27
28 // hello world text
29 13: data b"Hello, world!\n\0";
30 };
31
32 // load machine code
33 machine.load(&asm, 0);
34
35 // run machine until it halts
36 machine.run();
37
38 // return the machine's register A (unused)
39 machine
40}More examples
3fn main() -> Machine {
4 // initialize a new machine
5 let mut machine = Machine::default();
6
7 // assembly code for the machine
8 let asm = esoteric_assembly! {
9 // initialize dot pointer so that IO operations work
10
11 // push a dot character to stack
12 0: pushi b'.';
13 // pop to address 28657
14 2: pop 28657;
15
16 // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17 4: ldidp 28657;
18
19 // ------------------
20
21 // get a single character to register ch
22 7: getchar;
23
24 // push register ch to stack (4 bytes)
25 8: pushch;
26
27 // pop character to register b
28 9: popb;
29
30 // pop the other 2 bytes
31 10: stackdealloc 2;
32
33 // put 49 (ascii for '1') in register L
34 13: pushi 0;
35 15: pushi 49;
36 17: popl;
37
38 // compare registers L and b
39 18: cmplb;
40
41 // push 30 (input == '1' logic)
42 19: pushi 0;
43 21: pushi 30;
44
45 // pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
46 23: zpopep;
47
48 // empty the stack
49 24: stackdealloc 2;
50
51 // IF INPUT IS '0' (repeat it)
52 // fallback to the input == '1' logic, ran without jumps
53
54 // write the input value ('0')
55 27: writechar;
56
57 // halt machine
58 28: Ωtheendisnear;
59 29: Ωskiptothechase;
60
61 // IF INPUT IS '1' (repeat indefinitely)
62
63 // write the input value ('1')
64 30: writechar;
65
66 // push 30 (input == '1' logic)
67 31: pushi 0;
68 33: pushi 30;
69
70 // pop to execution pointer (jump to value on stack)
71 //
72 // this repeats the input == '1' logic indefinitely
73 35: popep;
74
75 };
76
77 // load machine code
78 machine.load(&asm, 0);
79
80 // run machine until it halts
81 machine.run();
82
83 // return the machine's register A (unused)
84 machine
85}3fn main() -> Machine {
4 // initialize a new machine
5 let mut machine = Machine::default();
6
7 // assembly code for the machine
8 let asm = esoteric_assembly! {
9 // initialize dot pointer so that IO operations work
10
11 // push a dot character to stack
12 0: pushi b'.';
13 // pop to address 28657
14 2: pop 28657;
15
16 // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17 5: ldidp 28657;
18
19 // -----------------
20
21
22 // set L to 99
23 8: pushi 0;
24 10: pushi 99;
25 12: popl;
26
27 // set num to 99
28 13: pushi 0;
29 15: pushi 0;
30 17: pushi 0;
31 19: pushi 99;
32 21: popnum;
33
34 // set B to 1
35 22: pushi 0;
36 24: pushi 1;
37 26: popb;
38
39 27: Ωsetpaperclipproduction true;
40
41 // WORK
42 29: writeline 110; // wall
43 33: writeline 140; // bottles
44
45 35: Ωsetpaperclipproduction false;
46
47 37: writeline 158; // take
48
49 40: Ωsetpaperclipproduction true;
50
51 // jump to fin if L == 1
52 42: cmplb;
53 43: pushi 0;
54 45: pushi 71;
55
56 47: zpopep;
57
58 48: stackdealloc 2;
59
60 // set B to 1
61 51: pushi 0;
62 53: pushi 1;
63 55: popb;
64
65 56: subbl; // L -= 1
66
67 // set num to L
68 57: pushi 0;
69 59: pushi 0;
70 61: pushl;
71 62: popnum;
72
73 63: writeline 193; // wall_end
74
75 // jump back to work
76 66: pushi 0;
77 68: pushi 29;
78
79 70: popep;
80
81 // FIN
82 71: Ωsetpaperclipproduction false;
83
84 73: writeline 224; // no_more
85 76: writeline 193; // wall_end
86
87 79: writeline 233; // No_more
88 82: writeline 110; // wall
89 85: writeline 224; // no_more
90 88: writeline 140; // bottles
91
92 91: writeline 242; // store
93
94 // set num to 99
95 94: pushi 0;
96 96: pushi 0;
97 98: pushi 0;
98 100: pushi 99;
99 102: popnum;
100
101 103: Ωsetpaperclipproduction true;
102
103 105: writeline 193; // wall_end
104
105 // halt machine
106 108: Ωtheendisnear;
107 109: Ωskiptothechase;
108
109 // wall (30 bytes)
110 110: data b"bottles of beer on the wall, \0";
111 // bottles (18 bytes)
112 140: data b"bottles of beer.\n\0";
113 // take (35 bytes)
114 158: data b"Take one down and pass it around, \0";
115 // wall end (31 bytes)
116 193: data b"bottles of beer on the wall.\n\n\0";
117
118 // no more (9 bytes)
119 224: data b"no more \0";
120 // No more (9 bytes)
121 233: data b"No more \0";
122
123 // store
124 242: data b"Go to the store and buy some more, \0";
125 };
126
127 // load machine code
128 machine.load(&asm, 0);
129
130 // run machine until it halts
131 machine.run();
132
133 // return the machine's register A (unused)
134 machine
135}