1mod alu32;
2mod alu64;
3mod call;
4mod endian;
5mod helpers;
6mod jump;
7mod load;
8mod store;
9#[cfg(test)]
10mod test_utils;
11
12#[cfg(test)]
13pub use test_utils::{MockVm, make_test_instruction};
14use {
15 crate::{errors::ExecutionError, instruction::Instruction, opcode::Opcode},
16 alu32::{execute_alu32_imm, execute_alu32_reg, execute_neg32},
17 alu64::{execute_alu64_imm, execute_alu64_reg, execute_neg64},
18 load::{execute_lddw, execute_ldxb, execute_ldxdw, execute_ldxh, execute_ldxw},
19 store::{
20 execute_stb, execute_stdw, execute_sth, execute_stw, execute_stxb, execute_stxdw,
21 execute_stxh, execute_stxw,
22 },
23};
24pub use {
25 call::{execute_call_immediate, execute_call_register, execute_exit},
26 endian::execute_endian,
27 jump::{execute_jump, execute_jump_immediate, execute_jump_register},
28};
29
30pub type ExecutionResult<T> = Result<T, ExecutionError>;
31
32pub trait Vm {
33 fn get_register(&self, reg: usize) -> u64;
34 fn set_register(&mut self, reg: usize, value: u64);
35
36 fn get_pc(&self) -> usize;
37 fn set_pc(&mut self, pc: usize);
38 fn advance_pc(&mut self) {
39 self.set_pc(self.get_pc() + 1);
40 }
41
42 fn read_u8(&self, addr: u64) -> ExecutionResult<u8>;
43 fn read_u16(&self, addr: u64) -> ExecutionResult<u16>;
44 fn read_u32(&self, addr: u64) -> ExecutionResult<u32>;
45 fn read_u64(&self, addr: u64) -> ExecutionResult<u64>;
46
47 fn write_u8(&mut self, addr: u64, value: u8) -> ExecutionResult<()>;
48 fn write_u16(&mut self, addr: u64, value: u16) -> ExecutionResult<()>;
49 fn write_u32(&mut self, addr: u64, value: u32) -> ExecutionResult<()>;
50 fn write_u64(&mut self, addr: u64, value: u64) -> ExecutionResult<()>;
51
52 fn get_call_depth(&self) -> usize;
53 fn max_call_depth(&self) -> usize;
54 fn push_frame(
55 &mut self,
56 return_pc: usize,
57 saved_registers: [u64; 4],
58 saved_frame_pointer: u64,
59 ) -> ExecutionResult<()>;
60 fn pop_frame(&mut self) -> Option<(usize, [u64; 4], u64)>;
61
62 fn halt(&mut self, exit_code: u64);
63
64 fn get_stack_frame_size(&self) -> u64;
65
66 fn handle_syscall(&mut self, name: &str) -> ExecutionResult<u64>;
67}
68
69pub fn execute_binary_immediate(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
70 match inst.opcode {
71 Opcode::Add64Imm
72 | Opcode::Sub64Imm
73 | Opcode::Mul64Imm
74 | Opcode::Div64Imm
75 | Opcode::Or64Imm
76 | Opcode::And64Imm
77 | Opcode::Lsh64Imm
78 | Opcode::Rsh64Imm
79 | Opcode::Mod64Imm
80 | Opcode::Xor64Imm
81 | Opcode::Mov64Imm
82 | Opcode::Arsh64Imm => execute_alu64_imm(vm, inst),
83 Opcode::Add32Imm
84 | Opcode::Sub32Imm
85 | Opcode::Mul32Imm
86 | Opcode::Div32Imm
87 | Opcode::Or32Imm
88 | Opcode::And32Imm
89 | Opcode::Lsh32Imm
90 | Opcode::Rsh32Imm
91 | Opcode::Mod32Imm
92 | Opcode::Xor32Imm
93 | Opcode::Mov32Imm
94 | Opcode::Arsh32Imm => execute_alu32_imm(vm, inst),
95 _ => Err(ExecutionError::InvalidInstruction),
96 }
97}
98
99pub fn execute_binary_register(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
100 match inst.opcode {
101 Opcode::Add64Reg
102 | Opcode::Sub64Reg
103 | Opcode::Mul64Reg
104 | Opcode::Div64Reg
105 | Opcode::Or64Reg
106 | Opcode::And64Reg
107 | Opcode::Lsh64Reg
108 | Opcode::Rsh64Reg
109 | Opcode::Mod64Reg
110 | Opcode::Xor64Reg
111 | Opcode::Mov64Reg
112 | Opcode::Arsh64Reg => execute_alu64_reg(vm, inst),
113 Opcode::Add32Reg
114 | Opcode::Sub32Reg
115 | Opcode::Mul32Reg
116 | Opcode::Div32Reg
117 | Opcode::Or32Reg
118 | Opcode::And32Reg
119 | Opcode::Lsh32Reg
120 | Opcode::Rsh32Reg
121 | Opcode::Mod32Reg
122 | Opcode::Xor32Reg
123 | Opcode::Mov32Reg
124 | Opcode::Arsh32Reg => execute_alu32_reg(vm, inst),
125 _ => Err(ExecutionError::InvalidInstruction),
126 }
127}
128
129pub fn execute_unary(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
130 match inst.opcode {
131 Opcode::Neg64 => execute_neg64(vm, inst),
132 Opcode::Neg32 => execute_neg32(vm, inst),
133 _ => Err(ExecutionError::InvalidInstruction),
134 }
135}
136
137pub fn execute_load_immediate(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
138 execute_lddw(vm, inst)
139}
140
141pub fn execute_load_memory(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
142 match inst.opcode {
143 Opcode::Ldxb => execute_ldxb(vm, inst),
144 Opcode::Ldxh => execute_ldxh(vm, inst),
145 Opcode::Ldxw => execute_ldxw(vm, inst),
146 Opcode::Ldxdw => execute_ldxdw(vm, inst),
147 _ => Err(ExecutionError::InvalidInstruction),
148 }
149}
150
151pub fn execute_store_immediate(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
152 match inst.opcode {
153 Opcode::Stb => execute_stb(vm, inst),
154 Opcode::Sth => execute_sth(vm, inst),
155 Opcode::Stw => execute_stw(vm, inst),
156 Opcode::Stdw => execute_stdw(vm, inst),
157 _ => Err(ExecutionError::InvalidInstruction),
158 }
159}
160
161pub fn execute_store_register(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
162 match inst.opcode {
163 Opcode::Stxb => execute_stxb(vm, inst),
164 Opcode::Stxh => execute_stxh(vm, inst),
165 Opcode::Stxw => execute_stxw(vm, inst),
166 Opcode::Stxdw => execute_stxdw(vm, inst),
167 _ => Err(ExecutionError::InvalidInstruction),
168 }
169}