-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexec.c
More file actions
323 lines (301 loc) · 9.31 KB
/
Copy pathexec.c
File metadata and controls
323 lines (301 loc) · 9.31 KB
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*!
* \file exec.c
* \brief Exécution d'une instruction.
*/
#include "exec.h"
#include "error.h"
#include <stdio.h>
//! Met à jour cc (code condition) selon la valeur de reg.
/*!
* \param pmach machine en cours d'exécution
* \param reg numéro de registre
*/
void refresh_cc(Machine *pmach, unsigned int reg)
{
if (reg < 0)
pmach->_cc = CC_N;
else if (reg > 0)
pmach->_cc = CC_P;
else
pmach->_cc = CC_Z;
}
//! Vérifie que le Stack Pointer (SP) ne dépasse pas la zone dédiée à la pile.
//! Il ne faut pas par exemple qu'avec des branchements successifs, on efface les données existantes.
/*!
* \param pmach machine en cours d'exécution
* \param addr adresse de l'instruction
*/
void check_stack(Machine *pmach, unsigned addr)
{
if (pmach->_sp < pmach->_dataend || pmach->_sp >= pmach->_datasize)
error(ERR_SEGSTACK,addr);
}
//! Vérifie que l'instruction n'est pas immédiate.
/*!
* \param instr instruction en cours
* \param addr adresse de l'instruction
*/
void check_immediate(Instruction instr, unsigned addr)
{
if (instr.instr_generic._immediate)
error(ERR_IMMEDIATE,addr);
}
//! Vérifie si la condition de branchement est respectée.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
*/
bool allowed_condition(Machine *pmach, Instruction instr, unsigned addr)
{
switch (instr.instr_generic._regcond) {
case NC: // Pas de condition
return true;
case EQ: // Egal à 0
return (pmach->_cc == CC_Z);
case NE: // Different de zero
return (pmach->_cc != CC_Z);
case GT: // Strictement positif
return (pmach->_cc == CC_P);
case GE: // Positif ou nul
return (pmach->_cc == CC_P || pmach->_cc == CC_Z);
case LT: // Strictement négatif
return (pmach->_cc == CC_N);
case LE: // Négatif ou nul
return (pmach->_cc == CC_N || pmach->_cc == CC_Z);
default:
error(ERR_CONDITION, addr);
}
}
//! Récupère l'adresse réelle, à partir d'un adressage indexé ou absolu.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
*/
unsigned int get_address(Machine *pmach, Instruction instr)
{
if (instr.instr_generic._indexed) {
return pmach->_registers[instr.instr_indexed._rindex] + instr.instr_indexed._offset;
}
return instr.instr_absolute._address;
}
//! Vérifie qu'il n'y a pas d'erreur de segmentation sur le tableau des données.
/*!
* \param pmach machine en cours d'exécution
* \param data_addr adresse réelle
* \param addr adresse de l'instruction en cours
*/
void check_data_addr(Machine *pmach, unsigned int data_addr, unsigned addr)
{
if (data_addr > pmach->_datasize)
error(ERR_SEGDATA, addr);
}
//! Décode et exécute l'instruction LOAD.
//! LOAD accepte l'adressage immédiat, absolu et indexé pour la source.
//! Il faut indiquer un registre de destination.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool load(Machine *pmach, Instruction instr, unsigned addr)
{
if (instr.instr_generic._immediate) { // Si I = 1 : Immediat
pmach->_registers[instr.instr_generic._regcond] = instr.instr_immediate._value;
} else {
unsigned int address = get_address(pmach, instr);
check_data_addr(pmach, address, addr);
pmach->_registers[instr.instr_generic._regcond] = pmach->_data[address];
}
refresh_cc(pmach, pmach->_registers[instr.instr_generic._regcond]);
return true;
}
//! Décode et exécute l'instruction STORE.
//! STORE accepte l'adressage absolu et indexé pour la destination.
//! Il faut indiquer un registre pour la source.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool store(Machine *pmach, Instruction instr, unsigned addr)
{
check_immediate(instr, addr);
unsigned int address = get_address(pmach, instr);
check_data_addr(pmach, address, addr);
pmach->_data[address] = pmach->_registers[instr.instr_generic._regcond];
return true;
}
//! Décode et exécute l'instruction ADD.
//! ADD accepte l'adressage immédiat, absolu et indexé pour la source.
//! Il faut indiquer un registre pour la destination.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool add(Machine *pmach, Instruction instr, unsigned addr)
{
if (instr.instr_generic._immediate) { // Immediat
pmach->_registers[instr.instr_generic._regcond] += instr.instr_immediate._value;
} else {
unsigned int address = get_address(pmach, instr);
check_data_addr(pmach, address, addr);
pmach->_registers[instr.instr_generic._regcond] += pmach->_data[address];
}
refresh_cc(pmach,pmach->_registers[instr.instr_generic._regcond]);
return true;
}
//! Décode et exécute l'instruction SUB.
//! SUB accepte l'adressage immédiat, absolu et indexé pour la source.
//! Il faut indiquer un registre pour la destination.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool sub(Machine *pmach, Instruction instr,unsigned addr)
{
if (instr.instr_generic._immediate) { // Immediat
pmach->_registers[instr.instr_generic._regcond] -= instr.instr_immediate._value;
} else {
unsigned int address = get_address(pmach, instr);
check_data_addr(pmach, address, addr);
pmach->_registers[instr.instr_generic._regcond] -= pmach->_data[address];
}
refresh_cc(pmach,pmach->_registers[instr.instr_generic._regcond]);
return true;
}
//! Décode et exécute l'instruction BRANCH.
//! BRANCH accepte l'adressage absolu et indexé pour l'adresse de l'instruction à exécuter.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool branch(Machine *pmach, Instruction instr, unsigned addr)
{
check_immediate(instr, addr);
if (allowed_condition(pmach, instr, addr)) {
unsigned int address = get_address(pmach, instr);
pmach->_pc = address;
}
return true;
}
//! Décode et exécute l'instruction CALL.
//! CALL accepte l'adressage absolu et indexé pour l'adresse du sous-programme.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool call(Machine *pmach, Instruction instr, unsigned addr)
{
check_immediate(instr, addr);
check_stack(pmach, addr);
if (allowed_condition(pmach, instr, addr)) {
pmach->_data[pmach->_sp--] = pmach->_pc;
unsigned int address = get_address(pmach, instr);
pmach->_pc = address;
}
return true;
}
//! Décode et exécute l'instruction RET.
//! RET est employé seul.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool ret(Machine *pmach, Instruction instr, unsigned addr) {
++pmach->_sp;
check_stack(pmach, addr);
pmach->_pc = pmach->_data[pmach->_sp];
return true;
}
//! Décode et exécute l'instruction PUSH.
//! PUSH supporte l'immédiat, l'adressage indexé et absolu.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool push(Machine *pmach, Instruction instr, unsigned addr)
{
check_stack(pmach, addr);
if (instr.instr_generic._immediate) { // Immediat
pmach->_data[pmach->_sp--] = instr.instr_immediate._value;
} else {
unsigned int address = get_address(pmach, instr);
check_data_addr(pmach, address, addr);
pmach->_data[pmach->_sp--] = pmach->_data[address];
}
return true;
}
//! Décode et exécute l'instruction POP.
//! POP ne supporte pas les valeurs immédiates mais doit indiquer une adresse (absolue ou indexée).
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours
*/
bool pop(Machine *pmach, Instruction instr, unsigned addr)
{
check_immediate(instr,addr);
unsigned int address = get_address(pmach, instr);
check_data_addr(pmach, address, addr);
++pmach->_sp;
check_stack(pmach, addr);
pmach->_data[address] = pmach->_data[pmach->_sp];
return true;
}
//! Décode et exécute une instruction.
/*!
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
*/
bool decode_execute(Machine *pmach, Instruction instr)
{
unsigned addr = pmach->_pc - 1;
switch (instr.instr_generic._cop) {
case LOAD:
return load(pmach, instr, addr);
case STORE:
return store(pmach, instr, addr);
case ADD:
return add(pmach, instr, addr);
case SUB:
return sub(pmach, instr, addr);
case BRANCH:
return branch(pmach, instr, addr);
case CALL:
return call(pmach, instr, addr);
case RET:
return ret(pmach, instr, addr);
case PUSH:
return push(pmach, instr, addr);
case POP:
return pop(pmach, instr, addr);
case HALT:
warning(WARN_HALT, addr);
return false;
case NOP:
return true;
case ILLOP:
error(ERR_ILLEGAL, addr);
default:
error(ERR_UNKNOWN, addr);
}
}
//! Affiche la trace d'une instruction.
/*!
* \param msg message à afficher
* \param pmach machine en cours d'exécution
* \param instr instruction en cours
* \param addr adresse de l'instruction en cours d'exécution
*/
void trace(const char *msg, Machine *pmach, Instruction instr, unsigned addr)
{
printf("TRACE: %s: 0x%04x: ",msg, addr);
print_instruction(instr, addr);
printf("\n");
}