-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexecute.c
340 lines (286 loc) · 11.8 KB
/
execute.c
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
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/*
* File: execute.c
* Description: Contains the execution logic for instructions in the XM-23p Emulator. It performs arithmetic and logical operations and updates the processor status word (PSW) accordingly.
* Author: Abdulla Sadoun
*
* - Date: 26/06/2024
*
*/
#include "xm23p.h"
void execute(int instructionnumber){ // execute function
/*
function to execute the instruction
- it calls appropriate function to execute the instruction based on
the internal instruction number
- it updates the registers and PSW flags
- it updates the HexString and Binary files for the registers
- it prints out the execution details
*/
unsigned short Temp_Destination, Temp_src_buffer; // temporary destination variable for swapping/replacing etc.
if(instructionnumber >= ADD && instructionnumber <= BIS && rcbuff == SET && instructionnumber != CMP){ // Constant is taken from the register
Temp_src_buffer = RegistersValue[srcbuff]; // set the source buffer to the temporary source buffer
RegistersValue[srcbuff] = handleConstant(srcbuff); // handle the constant value
}
switch(instructionnumber) { // opcode cases
case BL: // branch and link
printf("BL: offset:%d\n", offsetbuff); // debug printf
bl(); //
break;
case BEQBZ: // Branch if equal
printf("BEQ/BZ: offset:%d\n", offsetbuff); // debug printf
beqbz();
break;
case BNEBNZ: // Branch if not equal
printf("BNE/BNZ: offset:%d\n", offsetbuff); // debug printf
bnebnz();
break;
case BCBHS: // Branch if carry
printf("BC/BHS: offset:%d\n", offsetbuff); // debug printf
bcbhs();
break;
case BNCBLO: // Branch if not carry
printf("BNV/BLO: offset:%d\n", offsetbuff); // debug printf
bncblo();
break;
case BN: // Branch if negative
printf("BN: offset:%d\n", offsetbuff); // debug printf
bn();
break;
case BGE: // Branch if greater than or equal
printf("BGE: offset:%d\n", offsetbuff); // debug printf
bge();
break;
case BLT: // Branch if less than
printf("BLT: offset:%d\n", offsetbuff); // debug printf
blt();
break;
case BRA: // Branch always
printf("BRA: offset:%d\n", offsetbuff); // debug printf
bra();
break;
case ADD: // add registers
printf("ADD: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf); // debug printf
add(); // DST = DST + SRC/CON
break;
case ADDC: // add registers with carry
printf("ADDC: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf); // debug printf
addc(); // DST = DST + (SRC/CON + Carry)
break;
case SUB: // subtract registers
printf("SUB: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
sub(); // DST = DST + (-SRC/CON + 1)
break;
case SUBC: // subtract registers with carry
printf("SUBC: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
subc(); // DST = DST + (-SRC/CON + 1 + Carry)
break;
case DADD: // add registers (decimals)
printf("DADD: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
dadd(); // DST = DST + SRC/CON
break;
case CMP: // compare registers
printf("CMP: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
cmp(); // DST - SRC/CON
break;
case XOR: // exclusive OR registers
printf("XOR: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
xor(); // DST = DST ^ SRC/CON
break;
case AND: // AND registers
printf("AND: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
and(); // DST = DST & SRC/CON
break;
case OR: // OR registers
printf("OR: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
or(); // DST = DST | SRC/CON
break;
case BIT: // BIT test
printf("BIT: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
bit(); // DST & SRC/CON
break;
case BIC: // bit clear
printf("BIC: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
bic(); // DST = DST & ~(SRC/CON)
break;
case BIS: // bit set
printf("BIS: RC=%d, WB=%d, SRC=%d, DST=%d\n", rcbuff, wbbuff, srcbuff, dstbuff); // debug printf
bis(); // DST = DST | (1 << SRC/CON)
break;
case MOV: // move registers
printf("MOV: WB=%d, SRC=%d, DST=%d\n", wbbuff, srcbuff, dstbuff); // debug printf (no need for r/c)
mov(); // DST = SRC/CON
break;
case SWAP: // swap registers
printf("SWAP: SRC=%d, DST=%d\n", srcbuff, dstbuff); // debug printf
swap(); // DST = SRC
break;
case SRA: // shift right arithmetic
printf("SRA: WB=%d, DST=%d\n", wbbuff, dstbuff);
sra(); // DST = DST >> 1
break;
case RRC: // rotate right through carry
printf("RRC: WB=%d, DST=%d\n", wbbuff, dstbuff);
rrc(); // DST = DST >> 1 + Carry
break;
case SWPB: // swap bytes
printf("SWPB: DST=%d Result: %04X\n", dstbuff, RegistersValue[dstbuff]);
swpb(); // DST = ((DST & 0xFF) << 8) | ((DST >> 8) & 0xFF)
break;
case SXT: // sign extend
sxt(); // DST = (DST & 0x80) ? 0xFF00 | DST : DST
printf("SXT: DST=%d Result: %04X\n", dstbuff, RegistersValue[dstbuff]);
break;
case SETPRI: // not yet implemented
printf("SETPRI: \n");
break;
case SVC: // not yet implemented
printf("SVC: \n");
break;
case SETCC: // set psw flags
printf("SETCC: \n");
setcc(); // set the PSW flags
break;
case CLRCC: // clear psw flags
printf("CLRCC: \n");
clrcc(); // clear the PSW flags
break;
case CEX: // conditional execution
cex(); // set the cex condition
printf("CEX: Cond:%04X TC:%d FC:%d ", condition_prefix_buff, tcountbuff, fcountbuff);
printf("%s\n", cex_condition ? "TRUE" : "FALSE");
break;
case LD: // load content to register
printf("LD: PRPO:%d DEC:%d INC:%d WB:%d SRC:%d DST:%d\n", prpobuff, decbuff, incbuff, wbbuff, srcbuff, dstbuff); // debug printf
ld(); // DST = DMEM[SRC plus addressing]
break;
case ST: // store content from register to DMEM
printf("ST: PRPO:%d DEC:%d INC:%d WB:%d SRC:%d DST:%d\n", prpobuff, decbuff, incbuff, wbbuff, srcbuff, dstbuff); // debug printf
st(); // DMEM[DST plus addressing] = SRC
break;
case MOVL: // move low bits
printf("MOVL: dst:%d bits:%d\n", dstbuff, bitsbuff); // debug printf
movl(); // DST = SRC/CON
break;
case MOVLZ: // move low bits and zero rest
printf("MOVLZ: dst:%d bits:%d\n", dstbuff, bitsbuff);
movlz(); // DST = SRC/CON
break;
case MOVLS: // move low bits and set high
printf("MOVLS: dst:%d bits:%d\n", dstbuff, bitsbuff);
movls(); // DST = SRC/CON
break;
case MOVH: // move high bits
printf("MOVH: dst:%d bits:%d\n", dstbuff, bitsbuff);
movh(); // DST = SRC/CON
break;
case LDR: // load from memory to register with offset
printf("LDR: offset:%d wb:%d src:%d dst:%d\n", offsetbuff, wbbuff, srcbuff, dstbuff); // debug printf
ldr(); // DST = mem[SRC + sign-extended 7-bit offset]
break;
case STR: // store from register to memory with offset
printf("STR: offset:%d wb:%d src:%d dst:%d\n", offsetbuff, wbbuff, srcbuff, dstbuff); // debug printf
str(); // mem[DST + sign-extended 7-bit offset] = SRC
break;
case Error: // error
printf("Error: \n"); // return error message
break;
default:
printf("instruction execution code not recognized\n");
break;
}
if(instructionnumber >= ADD && instructionnumber <= BIS && rcbuff == SET && instructionnumber != CMP){ // Constant is taken from the register
RegistersValue[srcbuff] = Temp_src_buffer; // set the source buffer to the temporary source buffer after constant was used
}
for(int i = 0; i < 8; i++ ){ // update register binary content
ChangedRegistersValue(RegistersValue[i], i);
}
return;
}
unsigned short handleConstant(int src) {
/*
function to handle constant values
- works when RC bit is set
- returns the constant value
- for the appropriate register no. (src)
*/
switch (src) {
case R0: return 0;
case R1: return 1;
case R2: return 2;
case R3: return 4;
case R4: return 8;
case R5: return 16;
case R6: return 32;
case R7: return -1;
default:
printf("Error: Invalid register/constant value\n");
return 0;
}
}
/*
void cex(){
/*
function to handle conditional execution
- it sets the cex_condition based on the condition prefix
- it sets the TC and FC values to know number of instructions to execute
*
// enum for the cex conditions prefix cases
enum{EQ, NE, CSHS, CCLO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, TR, FL}; // enum
// inspect the psw based on condition prefix
switch (condition_prefix_buff) {
case EQ: // Equal / Zero
cex_condition = (PSW.z == SET) ? TRUE : FALSE; // Z flag is set
break;
case NE: // Not Equal
cex_condition = (PSW.z == CLEAR) ? TRUE : FALSE; // Z flag is clear
break;
case CSHS: // Carry Set / Unsigned Higher or Same
cex_condition = (PSW.c == SET) ? TRUE : FALSE; // C flag is set
break;
case CCLO: // Carry Clear / Unsigned Lower
cex_condition = (PSW.c == CLEAR) ? TRUE : FALSE; // C flag is clear
break;
case MI: // Minus / Negative
cex_condition = (PSW.n == SET) ? TRUE : FALSE; // N flag is set
break;
case PL: // Plus / Positive or Zero
cex_condition = (PSW.n == CLEAR) ? TRUE : FALSE; // N flag is clear
break;
case VS: // Overflow Set
cex_condition = (PSW.v == SET) ? TRUE : FALSE; // V flag is set
break;
case VC: // No Overflow
cex_condition = (PSW.v == CLEAR) ? TRUE : FALSE; // V flag is clear
break;
case HI: // Unsigned Higher
cex_condition = (PSW.c == SET && PSW.z == CLEAR) ? TRUE : FALSE; // C set and Z clear
break;
case LS: // Unsigned Lower or Same
cex_condition = (PSW.c == CLEAR || PSW.z == SET) ? TRUE : FALSE; // C clear or Z set
break;
case GE: // Greater or Equal (Signed)
cex_condition = (PSW.n == PSW.v) ? TRUE : FALSE; // N equal to V
break;
case LT: // Less Than (Signed)
cex_condition = (PSW.n != PSW.v) ? TRUE : FALSE; // N not equal to V
break;
case GT: // Greater Than (Signed)
cex_condition = (PSW.z == CLEAR && PSW.n == PSW.v) ? TRUE : FALSE; // Z clear and N equal to V
break;
case LE: // Less Than or Equal (Signed)
cex_condition = (PSW.z == SET || PSW.n != PSW.v) ? TRUE : FALSE; // Z set or N not equal to V
break;
case TR: // Always True
cex_condition = TRUE; // Always execute
break;
case FL: // Always False
cex_condition = FALSE; // Never execute
break;
default:
printf("Error: Invalid condition prefix\n");
break;
}
TC = tcountbuff;
FC = fcountbuff;
return;
}*/