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?
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
fn main() -> Machine {
// 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
}
More examples
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
fn main() -> Machine {
// 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)
4: ldidp 28657;
// ------------------
// get a single character to register ch
7: getchar;
// push register ch to stack (4 bytes)
8: pushch;
// pop character to register b
9: popb;
// pop the other 2 bytes
10: stackdealloc 2;
// put 49 (ascii for '1') in register L
13: pushi 0;
15: pushi 49;
17: popl;
// compare registers L and b
18: cmplb;
// push 30 (input == '1' logic)
19: pushi 0;
21: pushi 30;
// pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
23: zpopep;
// empty the stack
24: stackdealloc 2;
// IF INPUT IS '0' (repeat it)
// fallback to the input == '1' logic, ran without jumps
// write the input value ('0')
27: writechar;
// halt machine
28: Ωtheendisnear;
29: Ωskiptothechase;
// IF INPUT IS '1' (repeat indefinitely)
// write the input value ('1')
30: writechar;
// push 30 (input == '1' logic)
31: pushi 0;
33: pushi 30;
// pop to execution pointer (jump to value on stack)
//
// this repeats the input == '1' logic indefinitely
35: popep;
};
// load machine code
machine.load(&asm, 0);
// run machine until it halts
machine.run();
// return the machine's register A (unused)
machine
}
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() -> Machine {
// 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;
// -----------------
// set L to 99
8: pushi 0;
10: pushi 99;
12: popl;
// set num to 99
13: pushi 0;
15: pushi 0;
17: pushi 0;
19: pushi 99;
21: popnum;
// set B to 1
22: pushi 0;
24: pushi 1;
26: popb;
27: Ωsetpaperclipproduction true;
// WORK
29: writeline 110; // wall
33: writeline 140; // bottles
35: Ωsetpaperclipproduction false;
37: writeline 158; // take
40: Ωsetpaperclipproduction true;
// jump to fin if L == 1
42: cmplb;
43: pushi 0;
45: pushi 71;
47: zpopep;
48: stackdealloc 2;
// set B to 1
51: pushi 0;
53: pushi 1;
55: popb;
56: subbl; // L -= 1
// set num to L
57: pushi 0;
59: pushi 0;
61: pushl;
62: popnum;
63: writeline 193; // wall_end
// jump back to work
66: pushi 0;
68: pushi 29;
70: popep;
// FIN
71: Ωsetpaperclipproduction false;
73: writeline 224; // no_more
76: writeline 193; // wall_end
79: writeline 233; // No_more
82: writeline 110; // wall
85: writeline 224; // no_more
88: writeline 140; // bottles
91: writeline 242; // store
// set num to 99
94: pushi 0;
96: pushi 0;
98: pushi 0;
100: pushi 99;
102: popnum;
103: Ωsetpaperclipproduction true;
105: writeline 193; // wall_end
// halt machine
108: Ωtheendisnear;
109: Ωskiptothechase;
// wall (30 bytes)
110: data b"bottles of beer on the wall, \0";
// bottles (18 bytes)
140: data b"bottles of beer.\n\0";
// take (35 bytes)
158: data b"Take one down and pass it around, \0";
// wall end (31 bytes)
193: data b"bottles of beer on the wall.\n\n\0";
// no more (9 bytes)
224: data b"no more \0";
// No more (9 bytes)
233: data b"No more \0";
// store
242: data b"Go to the store and buy some more, \0";
};
// load machine code
machine.load(&asm, 0);
// run machine until it halts
machine.run();
// return the machine's register A (unused)
machine
}
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?
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
fn main() -> Machine {
// 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
}
More examples
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
fn main() -> Machine {
// 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)
4: ldidp 28657;
// ------------------
// get a single character to register ch
7: getchar;
// push register ch to stack (4 bytes)
8: pushch;
// pop character to register b
9: popb;
// pop the other 2 bytes
10: stackdealloc 2;
// put 49 (ascii for '1') in register L
13: pushi 0;
15: pushi 49;
17: popl;
// compare registers L and b
18: cmplb;
// push 30 (input == '1' logic)
19: pushi 0;
21: pushi 30;
// pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
23: zpopep;
// empty the stack
24: stackdealloc 2;
// IF INPUT IS '0' (repeat it)
// fallback to the input == '1' logic, ran without jumps
// write the input value ('0')
27: writechar;
// halt machine
28: Ωtheendisnear;
29: Ωskiptothechase;
// IF INPUT IS '1' (repeat indefinitely)
// write the input value ('1')
30: writechar;
// push 30 (input == '1' logic)
31: pushi 0;
33: pushi 30;
// pop to execution pointer (jump to value on stack)
//
// this repeats the input == '1' logic indefinitely
35: popep;
};
// load machine code
machine.load(&asm, 0);
// run machine until it halts
machine.run();
// return the machine's register A (unused)
machine
}
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() -> Machine {
// 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;
// -----------------
// set L to 99
8: pushi 0;
10: pushi 99;
12: popl;
// set num to 99
13: pushi 0;
15: pushi 0;
17: pushi 0;
19: pushi 99;
21: popnum;
// set B to 1
22: pushi 0;
24: pushi 1;
26: popb;
27: Ωsetpaperclipproduction true;
// WORK
29: writeline 110; // wall
33: writeline 140; // bottles
35: Ωsetpaperclipproduction false;
37: writeline 158; // take
40: Ωsetpaperclipproduction true;
// jump to fin if L == 1
42: cmplb;
43: pushi 0;
45: pushi 71;
47: zpopep;
48: stackdealloc 2;
// set B to 1
51: pushi 0;
53: pushi 1;
55: popb;
56: subbl; // L -= 1
// set num to L
57: pushi 0;
59: pushi 0;
61: pushl;
62: popnum;
63: writeline 193; // wall_end
// jump back to work
66: pushi 0;
68: pushi 29;
70: popep;
// FIN
71: Ωsetpaperclipproduction false;
73: writeline 224; // no_more
76: writeline 193; // wall_end
79: writeline 233; // No_more
82: writeline 110; // wall
85: writeline 224; // no_more
88: writeline 140; // bottles
91: writeline 242; // store
// set num to 99
94: pushi 0;
96: pushi 0;
98: pushi 0;
100: pushi 99;
102: popnum;
103: Ωsetpaperclipproduction true;
105: writeline 193; // wall_end
// halt machine
108: Ωtheendisnear;
109: Ωskiptothechase;
// wall (30 bytes)
110: data b"bottles of beer on the wall, \0";
// bottles (18 bytes)
140: data b"bottles of beer.\n\0";
// take (35 bytes)
158: data b"Take one down and pass it around, \0";
// wall end (31 bytes)
193: data b"bottles of beer on the wall.\n\n\0";
// no more (9 bytes)
224: data b"no more \0";
// No more (9 bytes)
233: data b"No more \0";
// store
242: data b"Go to the store and buy some more, \0";
};
// load machine code
machine.load(&asm, 0);
// run machine until it halts
machine.run();
// return the machine's register A (unused)
machine
}