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)
machine
Fields§
§reg_a: u8
register a (used as the machine’s exit code)
reg_b: i16
register b
reg_L: u16
register L
reg_f: f64
register f
reg_ch: char
register ch (ch is one letter in Czech, therefore it’s valid)
reg_ř: [i8; 37]
register ř
reg_ß: ConstantSizeString
register ß
reg_Ω: Ω
register Ω
num_reg: i32
number 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: u16
execution pointer
reg_dp: u16
dot pointer (has to point to a .
character. if it doesn’t, then IO operation attempts are cancelled and the flag is set)
flag: bool
overflow/error flag
debug_mode: bool
debug mode
halted: bool
whether the machine is halted (can’t run anymore and is finished)
memory: Box<[u8; 65535]>
memory (should be 65K)
stack: Stack
stack 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}