-
Notifications
You must be signed in to change notification settings - Fork 0
/
instructions.h
174 lines (128 loc) · 8.51 KB
/
instructions.h
1
2
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// instruction function helpers
static inline void zvm_set_value(zvm_program_t* self, uint64_t type, uint64_t data, uint64_t value) { // set object (based on type and data) to value
switch (type) {
case ZED_OPERAND_16_TYPE_REGISTER: self->state.registers[data] = value; break;
case ZED_OPERAND_16_TYPE_ADDRESS_64: *(uint64_t*) (intptr_t) self->state.registers[data] = value; break;
case ZED_OPERAND_16_TYPE_ADDRESS_8: *(uint8_t *) (intptr_t) self->state.registers[data] = value; break;
}
}
static inline uint64_t zvm_get_value(zvm_program_t* self, uint64_t type, uint64_t data) { // get object (based on type and data) and return value
switch (type) {
case ZED_OPERAND_16_TYPE_REGISTER: return self->state.registers[data];
case ZED_OPERAND_16_TYPE_CONSTANT: return data;
case ZED_OPERAND_16_TYPE_ADDRESS_64: return *(uint64_t*) (intptr_t) self->state.registers[data];
case ZED_OPERAND_16_TYPE_ADDRESS_8: return (uint64_t) *(uint8_t *) (intptr_t) self->state.registers[data]; // zero extended by default
case ZED_OPERAND_16_TYPE_KFUNC_INDEX: return data < ZVM_KFUNC_COUNT ? (uint64_t) (intptr_t) zvm_kfunc_pointers[data] : 0;
case ZED_OPERAND_16_TYPE_POSITION_INDEX: return (uint64_t) self->positions[data];
case ZED_OPERAND_16_TYPE_DATA_INDEX: return (uint64_t) (intptr_t) (self->rom + self->data_section_elements[data].data_offset);
default: return 0;
}
}
static inline uint64_t zvm_get_value_sext(zvm_program_t* self, uint64_t type, uint64_t data) { // sign-extend if operand type is 8-bit address
if (type == ZED_OPERAND_16_TYPE_ADDRESS_8) {
return (uint64_t) *(int8_t*) (intptr_t) self->state.registers[data];
}
return zvm_get_value(self, type, data);
}
// instruction functions
static void zvm_mov(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source);
}
static void zvm_red(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, 1 - !source);
}
static void zvm_inv(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, ~source);
}
static void zvm_jmp(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t position = zvm_get_value(self, instruction->operand1_type, instruction->operand1_data);
self->state.registers[ZED_REGISTER_IP] = position;
}
static void zvm_cal(zvm_program_t* self, zvm_instruction_t* instruction) {
zvm_kfunc_t kfunc = (zvm_kfunc_t) (intptr_t) zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
uint64_t retval = kfunc(self,
self->state.registers[ZED_REGISTER_A0],
self->state.registers[ZED_REGISTER_A1],
self->state.registers[ZED_REGISTER_A2],
self->state.registers[ZED_REGISTER_A3]
);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, retval);
}
static void zvm_cpe(zvm_program_t* self, zvm_instruction_t* instruction) {
int64_t source_a = zvm_get_value_sext(self, instruction->operand1_type, instruction->operand1_data);
int64_t source_b = zvm_get_value_sext(self, instruction->operand2_type, instruction->operand2_data);
self->state.registers[ZED_REGISTER_F2] = (uint64_t) source_a > (uint64_t) source_b;
uint64_t comparison = source_a - source_b; // shouldn't really matter if this stuff is signed or not
uint8_t sign = comparison >> 63;
self->state.registers[ZED_REGISTER_F1] = sign;
self->state.registers[ZED_REGISTER_F3] = (uint64_t) source_a >> 63 != sign;
self->state.registers[ZED_REGISTER_F0] = !comparison;
uint64_t source_e = zvm_get_value(self, instruction->operand3_type, instruction->operand3_data); // important that this go AFTER comparison
if (!source_e) { // skip next instruction
zvm_instruction_t dummy_instruction;
zvm_next_instruction(self, &dummy_instruction);
}
}
static void zvm_add(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source_a = zvm_get_value_sext(self, instruction->operand2_type, instruction->operand2_data);
uint64_t source_b = zvm_get_value_sext(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a + source_b);
}
static void zvm_sub(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source_a = zvm_get_value_sext(self, instruction->operand2_type, instruction->operand2_data);
uint64_t source_b = zvm_get_value_sext(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a - source_b);
}
static void zvm_mul(zvm_program_t* self, zvm_instruction_t* instruction) {
int64_t source_a = (int64_t) zvm_get_value_sext(self, instruction->operand2_type, instruction->operand2_data);
int64_t source_b = (int64_t) zvm_get_value_sext(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a * source_b);
}
static void zvm_div(zvm_program_t* self, zvm_instruction_t* instruction) {
int64_t source_a = (int64_t) zvm_get_value_sext(self, instruction->operand2_type, instruction->operand2_data);
int64_t source_b = (int64_t) zvm_get_value_sext(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a / source_b);
self->state.registers[ZED_REGISTER_F3] = source_a % source_b;
}
static void zvm_sel(zvm_program_t* self, zvm_instruction_t* instruction) {
// ignore for now, not exactly sure i really want this instruction
}
static void zvm_and(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source_a = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
uint64_t source_b = zvm_get_value(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a & source_b);
}
static void zvm_or(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source_a = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
uint64_t source_b = zvm_get_value(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a | source_b);
}
static void zvm_xor(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source_a = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
uint64_t source_b = zvm_get_value(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source_a ^ source_b);
}
static void zvm_shl(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
uint64_t shift = zvm_get_value(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source << shift);
}
static void zvm_shr(zvm_program_t* self, zvm_instruction_t* instruction) {
uint64_t source = zvm_get_value(self, instruction->operand2_type, instruction->operand2_data);
uint64_t shift = zvm_get_value(self, instruction->operand3_type, instruction->operand3_data);
zvm_set_value(self, instruction->operand1_type, instruction->operand1_data, source >> shift);
}
typedef void (*zvm_ofunc_t) (zvm_program_t* self, zvm_instruction_t* instruction); // technically should be called 'zvm_ofunc_pointer_t' but whatever
zvm_ofunc_t zvm_operations[ZED_OPERATION_COUNT] = { // list of all operation function pointers for fast indexing
(zvm_ofunc_t) zvm_mov,
(zvm_ofunc_t) zvm_red, (zvm_ofunc_t) zvm_inv,
(zvm_ofunc_t) zvm_jmp, (zvm_ofunc_t) zvm_cal,
(zvm_ofunc_t) zvm_cpe,
(zvm_ofunc_t) zvm_add, (zvm_ofunc_t) zvm_sub, (zvm_ofunc_t) zvm_mul, (zvm_ofunc_t) zvm_div,
(zvm_ofunc_t) zvm_sel,
(zvm_ofunc_t) zvm_and, (zvm_ofunc_t) zvm_or, (zvm_ofunc_t) zvm_xor,
(zvm_ofunc_t) zvm_shl, (zvm_ofunc_t) zvm_shr,
};