1 |
53 |
Agner |
/**************************** emulator2.cpp ********************************
|
2 |
|
|
* Author: Agner Fog
|
3 |
|
|
* date created: 2018-02-18
|
4 |
|
|
* Last modified: 2021-02-19
|
5 |
|
|
* Version: 1.11
|
6 |
|
|
* Project: Binary tools for ForwardCom instruction set
|
7 |
|
|
* Description:
|
8 |
|
|
* Emulator: Execution functions for jump instructions
|
9 |
|
|
*
|
10 |
|
|
* Copyright 2018-2021 GNU General Public License http://www.gnu.org/licenses
|
11 |
|
|
*****************************************************************************/
|
12 |
|
|
|
13 |
|
|
#include "stdafx.h"
|
14 |
|
|
|
15 |
|
|
static uint64_t f_jump(CThread * t) {
|
16 |
|
|
// simple self-relative jump
|
17 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
18 |
|
|
t->running = 2; t->returnType = 0; // no return value to save
|
19 |
|
|
return 0;
|
20 |
|
|
}
|
21 |
|
|
|
22 |
|
|
static uint64_t f_call(CThread * t) {
|
23 |
|
|
// simple self-relative call
|
24 |
|
|
t->callStack.push(t->ip); // push return address on call stack
|
25 |
|
|
if (t->callStack.numEntries() > t->callDept) t->callDept = t->callStack.numEntries();
|
26 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
27 |
|
|
t->running = 2; t->returnType = 0; // no return value to save
|
28 |
|
|
return 0;
|
29 |
|
|
}
|
30 |
|
|
|
31 |
|
|
static uint64_t compare_jump_generic(CThread * t) {
|
32 |
|
|
// compare operands, jump on contition
|
33 |
|
|
SNum a = t->parm[1]; // first parameter
|
34 |
|
|
SNum b = t->parm[2]; // second parameter
|
35 |
|
|
uint8_t branch = 0; // jump if 1
|
36 |
|
|
if (t->operandType < 4) {
|
37 |
|
|
// all integer types
|
38 |
|
|
uint64_t sizeMask = dataSizeMask[t->operandType]; // mask for data size
|
39 |
|
|
uint64_t signBit = (sizeMask >> 1) + 1; // sign bit
|
40 |
|
|
a.q &= sizeMask; b.q &= sizeMask; // limit to right number of bits
|
41 |
|
|
// select condition
|
42 |
|
|
switch (t->op & 0xE) { // mask out constant bits and invert bit
|
43 |
|
|
case 0: // jump if equal
|
44 |
|
|
branch = a.q == b.q; break;
|
45 |
|
|
case 2: // jump if signed below
|
46 |
|
|
branch = (a.q ^ signBit) < (b.q ^ signBit); break;
|
47 |
|
|
case 4: // jump if signed above
|
48 |
|
|
branch = (a.q ^ signBit) > (b.q ^ signBit); break;
|
49 |
|
|
case 6: // jump if unsigned below
|
50 |
|
|
branch = a.q < b.q; break;
|
51 |
|
|
case 8: // jump if unsigned above
|
52 |
|
|
branch = a.q > b.q; break;
|
53 |
|
|
default:
|
54 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
55 |
|
|
}
|
56 |
|
|
branch ^= t->op; // invert branch condition if op odd
|
57 |
|
|
}
|
58 |
|
|
else {
|
59 |
|
|
// vector registers
|
60 |
|
|
if (t->operandType != 5 && t->operandType != 6) {
|
61 |
|
|
t->interrupt(INT_WRONG_PARAMETERS); // unsupported operand type
|
62 |
|
|
return 0;
|
63 |
|
|
}
|
64 |
|
|
if ((t->op & 0xFE) == 24) {
|
65 |
|
|
// fp_category test
|
66 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
67 |
|
|
bool mant0; // mantissa is zero
|
68 |
|
|
bool exp0; // exponent is all zeroes
|
69 |
|
|
bool exp1; // exponent is all ones
|
70 |
|
|
bool sign; // sign bit
|
71 |
|
|
if (t->operandType == 5) { // float
|
72 |
|
|
mant0 = (a.i & 0x007FFFFF) == 0; // mantissa is zero
|
73 |
|
|
exp0 = (a.i & 0x7F800000) == 0; // exponent is all zeroes
|
74 |
|
|
exp1 = (a.i & 0x7F800000) == 0x7F800000; // exponent is all ones
|
75 |
|
|
sign = a.i >> 31 != 0; // sign bit
|
76 |
|
|
}
|
77 |
|
|
else { // double
|
78 |
|
|
mant0 = a.q << 12 == 0; // mantissa is zero
|
79 |
|
|
exp0 = a.q << 1 >> 53 == 0; // exponent is all zeroes
|
80 |
|
|
exp1 = a.q << 1 >> 53 == 0xFFFFFFFFFFFFF; // exponent is all ones
|
81 |
|
|
sign = a.q >> 63 != 0; // sign bit
|
82 |
|
|
}
|
83 |
|
|
if (exp1) {
|
84 |
|
|
if (b.b & 1) branch |= !mant0; // NAN
|
85 |
|
|
if (b.b & 0x40) branch |= mant0 && sign; // -INF
|
86 |
|
|
if (b.b & 0x80) branch |= mant0 && !sign; // +INF
|
87 |
|
|
}
|
88 |
|
|
else if (exp0) {
|
89 |
|
|
if (b.b & 2) branch |= uint8_t(mant0); // +/- 0.0
|
90 |
|
|
if (b.b & 4) branch |= !mant0 && sign; // - subnormal
|
91 |
|
|
if (b.b & 8) branch |= !mant0 && !sign; // + subnormal
|
92 |
|
|
}
|
93 |
|
|
else {
|
94 |
|
|
if (b.b & 0x10) branch |= uint8_t(sign); // - normal
|
95 |
|
|
if (b.b & 0x20) branch |= !sign; // + normal
|
96 |
|
|
}
|
97 |
|
|
branch ^= t->op; // invert branch condition if op odd
|
98 |
|
|
}
|
99 |
|
|
else {
|
100 |
|
|
bool unordered;
|
101 |
|
|
uint8_t opj = t->op;
|
102 |
|
|
if (t->operandType == 5) {
|
103 |
|
|
// float
|
104 |
|
|
unordered = isnan_f(a.i) || isnan_f(b.i); // check if unordered
|
105 |
|
|
if (unordered) {
|
106 |
|
|
// a or b is NAN. Don't check the condition. Branch only if unordered version of instruction.
|
107 |
|
|
branch = t->op < 32;
|
108 |
|
|
}
|
109 |
|
|
else {
|
110 |
|
|
if ((opj & 0xE) > 5) {
|
111 |
|
|
// compare absolute values
|
112 |
|
|
a.i &= 0x7FFFFFFF; b.i &= 0x7FFFFFFF;
|
113 |
|
|
opj -= 4;
|
114 |
|
|
}
|
115 |
|
|
// select condition, float
|
116 |
|
|
switch (opj & 0xE) { // mask out bits for ordered/unordered and invert
|
117 |
|
|
case 0: // jump if equal
|
118 |
|
|
branch = a.f == b.f; break;
|
119 |
|
|
case 2: // jump if below
|
120 |
|
|
branch = a.f < b.f; break;
|
121 |
|
|
case 4: // jump if above
|
122 |
|
|
branch = a.f > b.f; break;
|
123 |
|
|
default:
|
124 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
125 |
|
|
}
|
126 |
|
|
branch ^= t->op; // invert branch condition if op odd
|
127 |
|
|
}
|
128 |
|
|
}
|
129 |
|
|
else {
|
130 |
|
|
// double
|
131 |
|
|
unordered = isnan_d(a.q) || isnan_d(b.q); // check if unordered
|
132 |
|
|
if (unordered) {
|
133 |
|
|
// a or b is NAN. Don't check the condition. Branch only if unordered version of instruction.
|
134 |
|
|
branch = t->op < 32;
|
135 |
|
|
}
|
136 |
|
|
else {
|
137 |
|
|
if ((opj & 0xE) > 5) {
|
138 |
|
|
// compare absolute values
|
139 |
|
|
a.q &= 0x7FFFFFFFFFFFFFFF; b.q &= 0x7FFFFFFFFFFFFFFF;
|
140 |
|
|
opj -= 4;
|
141 |
|
|
}
|
142 |
|
|
// select condition, float
|
143 |
|
|
switch (opj & 0xE) { // mask out bits for ordered/unordered and invert
|
144 |
|
|
case 0: // jump if equal
|
145 |
|
|
branch = a.d == b.d; break;
|
146 |
|
|
case 2: // jump if below
|
147 |
|
|
branch = a.d < b.d; break;
|
148 |
|
|
case 4: // jump if above
|
149 |
|
|
branch = a.d > b.d; break;
|
150 |
|
|
default:
|
151 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
152 |
|
|
}
|
153 |
|
|
branch ^= t->op; // invert branch condition if op odd
|
154 |
|
|
}
|
155 |
|
|
}
|
156 |
|
|
}
|
157 |
|
|
}
|
158 |
|
|
if (branch & 1) {
|
159 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
160 |
|
|
t->returnType = 0x2000; // debug output jump taken
|
161 |
|
|
}
|
162 |
|
|
else t->returnType = 0x1000; // debug output jump taken
|
163 |
|
|
if (t->vect) t->vect = 4; // stop vector loop
|
164 |
|
|
t->running = 2; // don't save result
|
165 |
|
|
return 0;
|
166 |
|
|
}
|
167 |
|
|
|
168 |
|
|
|
169 |
|
|
static uint64_t sub_jump_generic(CThread * t) {
|
170 |
|
|
// subtract and jump on some condition
|
171 |
|
|
if (t->operandType > 4) { // floating point types have no add/jump
|
172 |
|
|
// the opcode is used for floating point compare unordered
|
173 |
|
|
return compare_jump_generic(t);
|
174 |
|
|
}
|
175 |
|
|
SNum a = t->parm[1]; // first parameter
|
176 |
|
|
SNum b = t->parm[2]; // second parameter
|
177 |
|
|
SNum result; // result
|
178 |
|
|
int8_t branch = 0; // jump if 1
|
179 |
|
|
int8_t unsignedOverflow = 0; // unsigned overflow detected
|
180 |
|
|
int8_t signedOverflow = 0; // signed overflow detected
|
181 |
|
|
int8_t op1 = t->op >> 1; // operation without toggle bit
|
182 |
|
|
uint64_t sizeMask = dataSizeMask[t->operandType]; // mask for data size
|
183 |
|
|
uint64_t signBit = (sizeMask >> 1) + 1; // sign bit
|
184 |
|
|
result.q = a.q - b.q; // subtract integers
|
185 |
|
|
|
186 |
|
|
// detection of signed overflow
|
187 |
|
|
SNum overfl; // overflow if a and b have opposite sign and result has opposite sign of a
|
188 |
|
|
overfl.q = (a.q ^ b.q) & (a.q ^ result.q);
|
189 |
|
|
signedOverflow = (overfl.q & signBit) != 0;
|
190 |
|
|
// detection of borrow / unsigned overflow required
|
191 |
|
|
unsignedOverflow = (result.q & sizeMask) > (a.q & sizeMask);
|
192 |
|
|
|
193 |
|
|
// detect branch condition
|
194 |
|
|
switch (op1) {
|
195 |
|
|
case 0: // jump if zero
|
196 |
|
|
branch = (result.q & sizeMask) == 0;
|
197 |
|
|
break;
|
198 |
|
|
case 1: // jump if negative
|
199 |
|
|
branch = (result.q & signBit) != 0;
|
200 |
|
|
break;
|
201 |
|
|
case 2: // jump if positive
|
202 |
|
|
branch = (result.q & signBit) == 0 && (result.q & sizeMask) != 0;
|
203 |
|
|
break;
|
204 |
|
|
case 3: // jump if signed overflow
|
205 |
|
|
branch = signedOverflow;
|
206 |
|
|
signedOverflow = unsignedOverflow = 0; // no interrupt for this condition
|
207 |
|
|
break;
|
208 |
|
|
case 4: // jump if borrow (unsigned overflow)
|
209 |
|
|
branch = unsignedOverflow;
|
210 |
|
|
signedOverflow = unsignedOverflow = 0; // no interrupt for this condition
|
211 |
|
|
break;
|
212 |
|
|
default:
|
213 |
|
|
err.submit(ERR_INTERNAL);
|
214 |
|
|
}
|
215 |
|
|
// only integer types in g.p. registers allowed
|
216 |
|
|
if (t->operandType > 3) t->interrupt(INT_WRONG_PARAMETERS);
|
217 |
|
|
// overflow interrupts
|
218 |
|
|
//if (signedOverflow) t->interrupt(INT_OVERFL_SIGN);
|
219 |
|
|
//if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
|
220 |
|
|
|
221 |
|
|
// invert condition if op odd
|
222 |
|
|
branch ^= t->op;
|
223 |
|
|
// conditional branch
|
224 |
|
|
if (branch & 1) {
|
225 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
226 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
227 |
|
|
}
|
228 |
|
|
return result.q; // return result
|
229 |
|
|
}
|
230 |
|
|
|
231 |
|
|
static uint64_t add_jump_generic(CThread * t) {
|
232 |
|
|
// add and jump on some condition
|
233 |
|
|
if (t->operandType > 4) { // floating point types have no add/jump
|
234 |
|
|
// the opcode is used for floating point compare unordered
|
235 |
|
|
return compare_jump_generic(t);
|
236 |
|
|
}
|
237 |
|
|
SNum a = t->parm[1]; // first parameter
|
238 |
|
|
SNum b = t->parm[2]; // second parameter
|
239 |
|
|
SNum result; // result
|
240 |
|
|
int8_t branch = 0; // jump if 1
|
241 |
|
|
int8_t unsignedOverflow = 0; // unsigned overflow detected
|
242 |
|
|
int8_t signedOverflow = 0; // signed overflow detected
|
243 |
|
|
int8_t op1 = t->op >> 1; // operation without toggle bit
|
244 |
|
|
uint64_t sizeMask = dataSizeMask[t->operandType]; // mask for data size
|
245 |
|
|
uint64_t signBit = (sizeMask >> 1) + 1; // sign bit
|
246 |
|
|
|
247 |
|
|
// add integers
|
248 |
|
|
result.q = a.q + b.q;
|
249 |
|
|
// detection of signed overflow required
|
250 |
|
|
SNum overfl; // overflow if a and b have same sign and result has opposite sign of a
|
251 |
|
|
overfl.q = ~(a.q ^ b.q) & (a.q ^ result.q);
|
252 |
|
|
signedOverflow = (overfl.q & signBit) != 0;
|
253 |
|
|
// detection of carry / unsigned overflow required
|
254 |
|
|
unsignedOverflow = (result.q & sizeMask) < (a.q & sizeMask);
|
255 |
|
|
|
256 |
|
|
// detect branch condition
|
257 |
|
|
switch (op1) {
|
258 |
|
|
case 8: // jump if zero
|
259 |
|
|
branch = (result.q & sizeMask) == 0;
|
260 |
|
|
break;
|
261 |
|
|
case 9: // jump if negative
|
262 |
|
|
branch = (result.q & signBit) != 0;
|
263 |
|
|
break;
|
264 |
|
|
case 10: // jump if positive
|
265 |
|
|
branch = (result.q & signBit) == 0 && (result.q & sizeMask) != 0;
|
266 |
|
|
break;
|
267 |
|
|
case 11: // jump if signed overflow
|
268 |
|
|
branch = signedOverflow;
|
269 |
|
|
signedOverflow = unsignedOverflow = 0; // no interrupt for this condition
|
270 |
|
|
break;
|
271 |
|
|
case 12: // jump if borrow (unsigned overflow)
|
272 |
|
|
branch = unsignedOverflow;
|
273 |
|
|
signedOverflow = unsignedOverflow = 0; // no interrupts for these conditions
|
274 |
|
|
break;
|
275 |
|
|
default:
|
276 |
|
|
err.submit(ERR_INTERNAL);
|
277 |
|
|
}
|
278 |
|
|
// only integer types in g.p. registers allowed for add/jump instructions
|
279 |
|
|
if (t->operandType > 3 && op1 < 12) t->interrupt(INT_WRONG_PARAMETERS);
|
280 |
|
|
// overflow interrupts
|
281 |
|
|
//if (signedOverflow) t->interrupt(INT_OVERFL_SIGN);
|
282 |
|
|
//if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
|
283 |
|
|
|
284 |
|
|
// invert condition if op odd
|
285 |
|
|
branch ^= t->op;
|
286 |
|
|
|
287 |
|
|
// conditional branch
|
288 |
|
|
if (branch & 1) {
|
289 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
290 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
291 |
|
|
}
|
292 |
|
|
return result.q; // return result
|
293 |
|
|
}
|
294 |
|
|
/*
|
295 |
|
|
static uint64_t shift_left_jump_zero(CThread * t) {
|
296 |
|
|
// shift left and jump if zero
|
297 |
|
|
SNum a = t->parm[1]; // first parameter
|
298 |
|
|
SNum b = t->parm[2]; // second parameter
|
299 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
300 |
|
|
SNum result; // result
|
301 |
|
|
int8_t branch = 0; // jump if 1
|
302 |
|
|
result.q = 0;
|
303 |
|
|
|
304 |
|
|
switch (t->operandType) {
|
305 |
|
|
case 0: // int8
|
306 |
|
|
if (b.b < 8) result.b = a.b << b.b;
|
307 |
|
|
branch = result.b == 0;
|
308 |
|
|
break;
|
309 |
|
|
case 1: // int16
|
310 |
|
|
if (b.s < 16) result.s = a.s << b.b;
|
311 |
|
|
branch = result.s == 0;
|
312 |
|
|
break;
|
313 |
|
|
case 2: case 5: // int32, float
|
314 |
|
|
if (b.i < 32) result.i = a.i << b.b;
|
315 |
|
|
branch = result.i == 0;
|
316 |
|
|
break;
|
317 |
|
|
case 3: // int64, double
|
318 |
|
|
if (b.q < 64) result.q = a.q << b.b;
|
319 |
|
|
branch = result.q == 0;
|
320 |
|
|
break;
|
321 |
|
|
default:
|
322 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
323 |
|
|
}
|
324 |
|
|
if (t->vect) { // vector registers. make result scalar and stop vector loop
|
325 |
|
|
t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];
|
326 |
|
|
}
|
327 |
|
|
// invert condition if op odd
|
328 |
|
|
branch ^= t->op;
|
329 |
|
|
|
330 |
|
|
// conditional branch
|
331 |
|
|
if (branch & 1) {
|
332 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
333 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
334 |
|
|
}
|
335 |
|
|
return result.q;
|
336 |
|
|
}
|
337 |
|
|
|
338 |
|
|
static uint64_t shift_right_u_jump_zero(CThread * t) {
|
339 |
|
|
// shift right unsigned and jump if zero
|
340 |
|
|
SNum a = t->parm[1]; // first parameter
|
341 |
|
|
SNum b = t->parm[2]; // second parameter
|
342 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
343 |
|
|
SNum result; // result
|
344 |
|
|
int8_t branch = 0; // jump if 1
|
345 |
|
|
result.q = 0;
|
346 |
|
|
|
347 |
|
|
switch (t->operandType) {
|
348 |
|
|
case 0: // int8
|
349 |
|
|
if (b.b < 8) result.b = a.b >> b.b;
|
350 |
|
|
branch = result.b == 0;
|
351 |
|
|
break;
|
352 |
|
|
case 1: // int16
|
353 |
|
|
if (b.s < 16) result.s = a.s >> b.b;
|
354 |
|
|
branch = result.s == 0;
|
355 |
|
|
break;
|
356 |
|
|
case 2: case 5: // int32, float
|
357 |
|
|
if (b.i < 32) result.i = a.i >> b.b;
|
358 |
|
|
branch = result.i == 0;
|
359 |
|
|
break;
|
360 |
|
|
case 3: // int64, double
|
361 |
|
|
if (b.q < 64) result.q = a.q >> b.b;
|
362 |
|
|
branch = result.q == 0;
|
363 |
|
|
break;
|
364 |
|
|
default:
|
365 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
366 |
|
|
}
|
367 |
|
|
if (t->vect) { // vector registers. make result scalar and stop vector loop
|
368 |
|
|
t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];
|
369 |
|
|
}
|
370 |
|
|
// invert condition if op odd
|
371 |
|
|
branch ^= t->op;
|
372 |
|
|
|
373 |
|
|
// conditional branch
|
374 |
|
|
if (branch & 1) {
|
375 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
376 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
377 |
|
|
}
|
378 |
|
|
return result.q;
|
379 |
|
|
}
|
380 |
|
|
|
381 |
|
|
static uint64_t rotate_jump_carry(CThread * t) {
|
382 |
|
|
// rotate left and jump if the last rotated bit is 1
|
383 |
|
|
SNum a = t->parm[1]; // first parameter
|
384 |
|
|
SNum b = t->parm[2]; // second parameter
|
385 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
386 |
|
|
SNum result; // result
|
387 |
|
|
int8_t branch = 0; // jump if 1
|
388 |
|
|
result.q = 0;
|
389 |
|
|
|
390 |
|
|
switch (t->operandType) {
|
391 |
|
|
case 0: // int8
|
392 |
|
|
b.b &= 7;
|
393 |
|
|
result.b = (a.b << b.b) | (a.b >> (8 - b.b));
|
394 |
|
|
branch = b.bs < 0 ? result.b >> 7 : result.b; // most or least significant bit
|
395 |
|
|
break;
|
396 |
|
|
case 1: // int16
|
397 |
|
|
b.b &= 15;
|
398 |
|
|
result.b = (a.s << b.b) | (a.s >> (16 - b.b));
|
399 |
|
|
branch = uint8_t(b.ss < 0 ? result.s >> 15 : result.s); // most or least significant bit
|
400 |
|
|
break;
|
401 |
|
|
case 2: case 5: // int32, float
|
402 |
|
|
b.b &= 31;
|
403 |
|
|
result.i = (a.i << b.b) | (a.i >> (32 - b.b));
|
404 |
|
|
branch = uint8_t(b.is < 0 ? result.i >> 31 : result.i); // most or least significant bit
|
405 |
|
|
break;
|
406 |
|
|
case 3: // int64, double
|
407 |
|
|
b.b &= 63;
|
408 |
|
|
result.q = (a.q << b.b) | (a.q >> (64 - b.b));
|
409 |
|
|
branch = uint8_t(b.qs < 0 ? result.q >> 63 : result.q); // most or least significant bit
|
410 |
|
|
break;
|
411 |
|
|
default:
|
412 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
413 |
|
|
}
|
414 |
|
|
if (t->vect) { // vector registers. make result scalar and stop vector loop
|
415 |
|
|
t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];
|
416 |
|
|
}
|
417 |
|
|
// invert condition if op odd
|
418 |
|
|
branch ^= t->op;
|
419 |
|
|
|
420 |
|
|
// conditional branch
|
421 |
|
|
if (branch & 1) {
|
422 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
423 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
424 |
|
|
}
|
425 |
|
|
return result.q;
|
426 |
|
|
} */
|
427 |
|
|
|
428 |
|
|
static uint64_t and_jump_zero(CThread * t) {
|
429 |
|
|
// bitwise AND, jump if zero
|
430 |
|
|
SNum a = t->parm[1]; // first parameter
|
431 |
|
|
SNum b = t->parm[2]; // second parameter
|
432 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
433 |
|
|
SNum result; // result
|
434 |
|
|
int8_t branch = 0; // jump if 1
|
435 |
|
|
result.q = a.q & b.q; // bitwise AND
|
436 |
|
|
|
437 |
|
|
// branch condition
|
438 |
|
|
switch (t->operandType) {
|
439 |
|
|
case 0: // int8
|
440 |
|
|
branch = result.b == 0; break;
|
441 |
|
|
case 1: // int16
|
442 |
|
|
branch = result.s == 0; break;
|
443 |
|
|
case 2: case 5: // int32, float
|
444 |
|
|
branch = result.i == 0; break;
|
445 |
|
|
case 3: case 6: // int64, double
|
446 |
|
|
branch = result.q == 0; break;
|
447 |
|
|
default:
|
448 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
449 |
|
|
}
|
450 |
|
|
if (t->vect) { // vector registers. make result scalar and stop vector loop
|
451 |
|
|
t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];
|
452 |
|
|
}
|
453 |
|
|
// invert condition if op odd
|
454 |
|
|
branch ^= t->op;
|
455 |
|
|
|
456 |
|
|
// conditional branch
|
457 |
|
|
if (branch & 1) {
|
458 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
459 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
460 |
|
|
}
|
461 |
|
|
return result.q;
|
462 |
|
|
}
|
463 |
|
|
|
464 |
|
|
static uint64_t or_jump_zero(CThread * t) {
|
465 |
|
|
// bitwise OR, jump if zero
|
466 |
|
|
SNum a = t->parm[1]; // first parameter
|
467 |
|
|
SNum b = t->parm[2]; // second parameter
|
468 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
469 |
|
|
SNum result; // result
|
470 |
|
|
int8_t branch = 0; // jump if 1
|
471 |
|
|
result.q = a.q | b.q; // bitwise AND
|
472 |
|
|
|
473 |
|
|
// branch condition
|
474 |
|
|
switch (t->operandType) {
|
475 |
|
|
case 0: // int8
|
476 |
|
|
branch = result.b == 0; break;
|
477 |
|
|
case 1: // int16
|
478 |
|
|
branch = result.s == 0; break;
|
479 |
|
|
case 2: case 5: // int32, float
|
480 |
|
|
branch = result.i == 0; break;
|
481 |
|
|
case 3: case 6: // int64, double
|
482 |
|
|
branch = result.q == 0; break;
|
483 |
|
|
default:
|
484 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
485 |
|
|
}
|
486 |
|
|
if (t->vect) { // vector registers. make result scalar and stop vector loop
|
487 |
|
|
t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];
|
488 |
|
|
}
|
489 |
|
|
// invert condition if op odd
|
490 |
|
|
branch ^= t->op;
|
491 |
|
|
|
492 |
|
|
// conditional branch
|
493 |
|
|
if (branch & 1) {
|
494 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
495 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
496 |
|
|
}
|
497 |
|
|
return result.q;
|
498 |
|
|
}
|
499 |
|
|
|
500 |
|
|
static uint64_t xor_jump_zero(CThread * t) {
|
501 |
|
|
// bitwise XOR, jump if zero
|
502 |
|
|
SNum a = t->parm[1]; // first parameter
|
503 |
|
|
SNum b = t->parm[2]; // second parameter
|
504 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
505 |
|
|
SNum result; // result
|
506 |
|
|
int8_t branch = 0; // jump if 1
|
507 |
|
|
result.q = a.q ^ b.q; // bitwise AND
|
508 |
|
|
|
509 |
|
|
// branch condition
|
510 |
|
|
switch (t->operandType) {
|
511 |
|
|
case 0: // int8
|
512 |
|
|
branch = result.b == 0; break;
|
513 |
|
|
case 1: // int16
|
514 |
|
|
branch = result.s == 0; break;
|
515 |
|
|
case 2: case 5: // int32, float
|
516 |
|
|
branch = result.i == 0; break;
|
517 |
|
|
case 3: case 6: // int64, double
|
518 |
|
|
branch = result.q == 0; break;
|
519 |
|
|
default:
|
520 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
521 |
|
|
}
|
522 |
|
|
if (t->vect) { // vector registers. make result scalar and stop vector loop
|
523 |
|
|
t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];
|
524 |
|
|
}
|
525 |
|
|
// invert condition if op odd
|
526 |
|
|
branch ^= t->op;
|
527 |
|
|
|
528 |
|
|
// conditional branch
|
529 |
|
|
if (branch & 1) {
|
530 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
531 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
532 |
|
|
}
|
533 |
|
|
return result.q;
|
534 |
|
|
}
|
535 |
|
|
|
536 |
|
|
static uint64_t test_bit_jump_true(CThread * t) {
|
537 |
|
|
// test bit number b in a, jump if zero
|
538 |
|
|
// floating point operands are treated as integers with the same size
|
539 |
|
|
SNum a = t->parm[1]; // first parameter
|
540 |
|
|
SNum b = t->parm[2]; // second parameter
|
541 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
542 |
|
|
uint8_t branch = 0; // treat bits out of range as zero
|
543 |
|
|
|
544 |
|
|
// branch condition
|
545 |
|
|
switch (t->operandType) {
|
546 |
|
|
case 0: // int8
|
547 |
|
|
if (b.b < 8) branch = a.b >> b.b;
|
548 |
|
|
break;
|
549 |
|
|
case 1: // int16
|
550 |
|
|
if (b.s < 16) branch = uint8_t(a.s >> b.b);
|
551 |
|
|
break;
|
552 |
|
|
case 2: // int32
|
553 |
|
|
case 5: // float
|
554 |
|
|
if (b.i < 32) branch = uint8_t(a.i >> b.b);
|
555 |
|
|
break;
|
556 |
|
|
case 3: // int64
|
557 |
|
|
case 6: // double
|
558 |
|
|
if (b.q < 64) branch = uint8_t(a.q >> b.b);
|
559 |
|
|
break;
|
560 |
|
|
default:
|
561 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
562 |
|
|
}
|
563 |
|
|
if (t->vect) t->vect = 4; // stop vector loop
|
564 |
|
|
|
565 |
|
|
// invert condition if op odd
|
566 |
|
|
branch ^= t->op;
|
567 |
|
|
// conditional branch
|
568 |
|
|
if (branch & 1) {
|
569 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
570 |
|
|
t->returnType = 0x2000; // debug output jump taken
|
571 |
|
|
}
|
572 |
|
|
else t->returnType = 0x1000; // debug output jump taken
|
573 |
|
|
t->running = 2; // don't save result
|
574 |
|
|
return 0;
|
575 |
|
|
}
|
576 |
|
|
|
577 |
|
|
static uint64_t test_bits_and(CThread * t) {
|
578 |
|
|
// jump if (a & b) == b
|
579 |
|
|
SNum a = t->parm[1]; // first parameter
|
580 |
|
|
SNum b = t->parm[2]; // second parameter
|
581 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
582 |
|
|
int8_t branch = 0; // branch condition is inverted if op is odd
|
583 |
|
|
|
584 |
|
|
// branch condition
|
585 |
|
|
switch (t->operandType) {
|
586 |
|
|
case 0: // int8
|
587 |
|
|
branch = (a.b & b.b) == b.b; break;
|
588 |
|
|
case 1: // int16
|
589 |
|
|
branch = (a.s & b.s) == b.s; break;
|
590 |
|
|
case 2: // int32
|
591 |
|
|
case 5: // float
|
592 |
|
|
branch = (a.i & b.i) == b.i; break;
|
593 |
|
|
case 3: // int64
|
594 |
|
|
case 6: // double
|
595 |
|
|
branch = (a.q & b.q) == b.q; break;
|
596 |
|
|
default:
|
597 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
598 |
|
|
}
|
599 |
|
|
if (t->vect) t->vect = 4; // stop vector loop
|
600 |
|
|
|
601 |
|
|
// invert condition if op odd
|
602 |
|
|
branch ^= t->op;
|
603 |
|
|
// conditional branch
|
604 |
|
|
if (branch & 1) {
|
605 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
606 |
|
|
t->returnType = 0x2000; // debug output jump taken
|
607 |
|
|
}
|
608 |
|
|
else t->returnType = 0x1000; // debug output jump taken
|
609 |
|
|
t->running = 2; // don't save result
|
610 |
|
|
return 0;
|
611 |
|
|
}
|
612 |
|
|
|
613 |
|
|
static uint64_t test_bits_or(CThread * t) {
|
614 |
|
|
// jump if (a & b) != 0
|
615 |
|
|
SNum a = t->parm[1]; // first parameter
|
616 |
|
|
SNum b = t->parm[2]; // second parameter
|
617 |
|
|
if (t->fInstr->immSize) b = t->parm[4]; // avoid conversion of b to float
|
618 |
|
|
int8_t branch = 0; // branch condition is inverted if op is odd
|
619 |
|
|
// branch condition
|
620 |
|
|
switch (t->operandType) {
|
621 |
|
|
case 0: // int8
|
622 |
|
|
branch = (a.b & b.b) != 0; break;
|
623 |
|
|
case 1: // int16
|
624 |
|
|
branch = (a.s & b.s) != 0; break;
|
625 |
|
|
case 2: // int32
|
626 |
|
|
case 5: // float
|
627 |
|
|
branch = (a.i & b.i) != 0; break;
|
628 |
|
|
case 3: // int64
|
629 |
|
|
case 6: // double
|
630 |
|
|
branch = (a.q & b.q) != 0; break;
|
631 |
|
|
default:
|
632 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
633 |
|
|
}
|
634 |
|
|
if (t->vect) t->vect = 4; // stop vector loop
|
635 |
|
|
// invert condition if op odd
|
636 |
|
|
branch ^= t->op;
|
637 |
|
|
// conditional branch
|
638 |
|
|
if (branch & 1) {
|
639 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
640 |
|
|
t->returnType = 0x2000; // debug output jump taken
|
641 |
|
|
}
|
642 |
|
|
else t->returnType = 0x1000; // debug output jump taken
|
643 |
|
|
t->running = 2; // don't save result
|
644 |
|
|
return 0;
|
645 |
|
|
}
|
646 |
|
|
|
647 |
|
|
|
648 |
|
|
static uint64_t increment_compare_jump(CThread * t) {
|
649 |
|
|
// result = a + 1. Jump if condition
|
650 |
|
|
SNum a = t->parm[1]; // first parameter
|
651 |
|
|
SNum b = t->parm[2]; // second parameter
|
652 |
|
|
SNum result; // result
|
653 |
|
|
int8_t branch1 = 0; // jump if 1
|
654 |
|
|
int8_t branch2 = 0; // jump if 1
|
655 |
|
|
result.q = a.q + 1; // increment
|
656 |
|
|
|
657 |
|
|
// branch condition
|
658 |
|
|
switch (t->operandType) {
|
659 |
|
|
case 0: // int8
|
660 |
|
|
branch1 = result.bs < b.bs;
|
661 |
|
|
branch2 = result.bs > b.bs;
|
662 |
|
|
break;
|
663 |
|
|
case 1: // int16
|
664 |
|
|
branch1 = result.ss < b.ss;
|
665 |
|
|
branch2 = result.ss > b.ss;
|
666 |
|
|
break;
|
667 |
|
|
case 2: // int32
|
668 |
|
|
branch1 = result.is < b.is;
|
669 |
|
|
branch2 = result.is > b.is;
|
670 |
|
|
break;
|
671 |
|
|
case 3: // int64
|
672 |
|
|
branch1 = result.qs < b.qs;
|
673 |
|
|
branch2 = result.qs > b.qs;
|
674 |
|
|
break;
|
675 |
|
|
default:
|
676 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
677 |
|
|
}
|
678 |
|
|
// select instruction
|
679 |
|
|
if ((t->op & 0x3E) != II_INCREMENT_COMPARE_JBELOW) {
|
680 |
|
|
branch1 = branch2; // increment_compare/jump_above
|
681 |
|
|
}
|
682 |
|
|
// invert condition if opj odd
|
683 |
|
|
branch1 ^= t->op;
|
684 |
|
|
// conditional branch
|
685 |
|
|
if (branch1 & 1) {
|
686 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
687 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
688 |
|
|
}
|
689 |
|
|
return result.q;
|
690 |
|
|
}
|
691 |
|
|
|
692 |
|
|
static uint64_t sub_maxlen_jump_pos(CThread * t) {
|
693 |
|
|
// Subtract the maximum vector length (in bytes) from a general purpose register
|
694 |
|
|
// and jump if the result is positive. The 8-bit immediate operand indicates the
|
695 |
|
|
// operand type for which the maximum vector length is obtained.
|
696 |
|
|
// The register operand must be a 64-bit general purpose register.
|
697 |
|
|
SNum a = t->parm[1]; // first parameter
|
698 |
|
|
SNum b = t->parm[2]; // second parameter
|
699 |
|
|
SNum result; // result
|
700 |
|
|
int8_t branch = 0; // jump if 1
|
701 |
|
|
// b indicates the operand type for which the maximum vector length is used.
|
702 |
|
|
// to do: allow different maximum vector lengths for different operand types
|
703 |
|
|
if (b.q > 7) t->interrupt(INT_WRONG_PARAMETERS);
|
704 |
|
|
uint64_t maxlen = t->MaxVectorLength;
|
705 |
|
|
|
706 |
|
|
result.q = a.q - maxlen; // subtract maximum length
|
707 |
|
|
|
708 |
|
|
// branch condition
|
709 |
|
|
switch (t->operandType) {
|
710 |
|
|
case 0: // int8
|
711 |
|
|
branch = result.bs > 0; break;
|
712 |
|
|
case 1: // int16
|
713 |
|
|
branch = result.ss > 0; break;
|
714 |
|
|
case 2: // int32
|
715 |
|
|
branch = result.is > 0; break;
|
716 |
|
|
case 3: // int64. This is the preferred operant types.
|
717 |
|
|
branch = result.qs > 0; break;
|
718 |
|
|
default:
|
719 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
720 |
|
|
}
|
721 |
|
|
// invert condition if op odd
|
722 |
|
|
branch ^= t->op;
|
723 |
|
|
// conditional branch
|
724 |
|
|
if (branch & 1) {
|
725 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
726 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
727 |
|
|
}
|
728 |
|
|
return result.q;
|
729 |
|
|
}
|
730 |
|
|
/*
|
731 |
|
|
static uint64_t sub_jump(CThread * t) {
|
732 |
|
|
// subtract integers and jump unconditionally. optional
|
733 |
|
|
SNum a = t->parm[1]; // first parameter
|
734 |
|
|
SNum b = t->parm[2]; // second parameter
|
735 |
|
|
SNum result; // result
|
736 |
|
|
int8_t unsignedOverflow = 0; // unsigned overflow detected
|
737 |
|
|
int8_t signedOverflow = 0; // signed overflow detected
|
738 |
|
|
result.q = a.q - b.q; // subtract integers
|
739 |
|
|
// only integer types in g.p. registers allowed
|
740 |
|
|
if (t->operandType > 3) t->interrupt(INT_WRONG_PARAMETERS);
|
741 |
|
|
// overflow interrupts
|
742 |
|
|
if (signedOverflow) t->interrupt(INT_OVERFL_SIGN);
|
743 |
|
|
if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
|
744 |
|
|
|
745 |
|
|
// unconditional branch
|
746 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
747 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
748 |
|
|
return result.q; // return result
|
749 |
|
|
}
|
750 |
|
|
|
751 |
|
|
static uint64_t add_jump(CThread * t) {
|
752 |
|
|
// add integers and jump unconditionally. optional
|
753 |
|
|
SNum a = t->parm[1]; // first parameter
|
754 |
|
|
SNum b = t->parm[2]; // second parameter
|
755 |
|
|
SNum result; // result
|
756 |
|
|
int8_t unsignedOverflow = 0; // unsigned overflow detected
|
757 |
|
|
int8_t signedOverflow = 0; // signed overflow detected
|
758 |
|
|
result.q = a.q + b.q; // add integers
|
759 |
|
|
// only integer types in g.p. registers allowed
|
760 |
|
|
if (t->operandType > 3) t->interrupt(INT_WRONG_PARAMETERS);
|
761 |
|
|
// overflow interrupts
|
762 |
|
|
if (signedOverflow) t->interrupt(INT_OVERFL_SIGN);
|
763 |
|
|
if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
|
764 |
|
|
|
765 |
|
|
// unconditional branch
|
766 |
|
|
t->ip += t->addrOperand * 4; // add relative offset to IP
|
767 |
|
|
t->returnType |= 0x2000; // debug output jump taken
|
768 |
|
|
return result.q; // return result
|
769 |
|
|
}*/
|
770 |
|
|
|
771 |
|
|
static uint64_t jump_call_58(CThread * t) {
|
772 |
|
|
// op = 58: jump, 59: call
|
773 |
|
|
// Format 1.6 and 2.5.0: Indirect jump or call with memory operand
|
774 |
|
|
// Format 1.7 C, 2.5.4, and 3.1.0: Unconditional direct jump or call
|
775 |
|
|
uint64_t target = 0; // target address
|
776 |
|
|
|
777 |
|
|
// different instructions for different formats
|
778 |
|
|
switch (t->fInstr->format2) {
|
779 |
|
|
case 0x161: case 0x252: // Indirect jump or call with memory operand
|
780 |
|
|
target = t->readMemoryOperand(t->memAddress);
|
781 |
|
|
break;
|
782 |
|
|
case 0x172: case 0x254: // Unconditional direct jump or call with relative address
|
783 |
|
|
target = t->ip + t->addrOperand * 4; // add relative offset to IP
|
784 |
|
|
break;
|
785 |
|
|
case 0x310: // Unconditional direct jump or call with absolute address
|
786 |
|
|
target = t->addrOperand; // absolute address
|
787 |
|
|
break;
|
788 |
|
|
default:
|
789 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
790 |
|
|
return 0;
|
791 |
|
|
}
|
792 |
|
|
if (target & 3) { // misaligned jump target
|
793 |
|
|
t->interrupt(INT_MISALIGNED_JUMP);
|
794 |
|
|
return 0;
|
795 |
|
|
}
|
796 |
|
|
|
797 |
|
|
if (t->op & 1) {
|
798 |
|
|
// this is a call instruction. push return address
|
799 |
|
|
t->callStack.push(t->ip); // push return address on call stack
|
800 |
|
|
if (t->callStack.numEntries() > t->callDept) t->callDept = t->callStack.numEntries();
|
801 |
|
|
}
|
802 |
|
|
t->ip = target; // jump to new address
|
803 |
|
|
t->running = 2; // don't save result
|
804 |
|
|
return 0;
|
805 |
|
|
}
|
806 |
|
|
|
807 |
|
|
static uint64_t multiway_and_indirect(CThread * t) {
|
808 |
|
|
// op = 60: jump, 61: call
|
809 |
|
|
// Format 1.6 and 2.5.2: Multiway jump or call with table of relative addresses
|
810 |
|
|
// Format 1.7 C: Indirect jump or call to value of register
|
811 |
|
|
uint64_t target = 0; // target address
|
812 |
|
|
uint64_t offset; // offset relative to reference point
|
813 |
|
|
|
814 |
|
|
// different instructions for different formats
|
815 |
|
|
switch (t->fInstr->format2) {
|
816 |
|
|
case 0x162: case 0x252: // Indirect jump or call with memory operand
|
817 |
|
|
offset = t->readMemoryOperand(t->memAddress);
|
818 |
|
|
// sign extend table entry
|
819 |
|
|
switch (t->operandType) {
|
820 |
|
|
case 0: // int8
|
821 |
|
|
offset = (uint64_t)(int64_t)(int8_t)offset; break;
|
822 |
|
|
case 1: // int16
|
823 |
|
|
offset = (uint64_t)(int64_t)(int16_t)offset; break;
|
824 |
|
|
case 2: // int32
|
825 |
|
|
offset = (uint64_t)(int64_t)(int32_t)offset; break;
|
826 |
|
|
case 3: // int64
|
827 |
|
|
break;
|
828 |
|
|
default:
|
829 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
830 |
|
|
}
|
831 |
|
|
offset <<= 2; // scale by 4
|
832 |
|
|
target = t->parm[1].q + offset; // add reference point
|
833 |
|
|
break;
|
834 |
|
|
case 0x173: // Unconditional indirect jump or call to value of register
|
835 |
|
|
target = t->registers[t->operands[0]];
|
836 |
|
|
break;
|
837 |
|
|
default:
|
838 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
839 |
|
|
return 0;
|
840 |
|
|
}
|
841 |
|
|
if (target & 3) { // misaligned jump target
|
842 |
|
|
t->interrupt(INT_MISALIGNED_JUMP);
|
843 |
|
|
return 0;
|
844 |
|
|
}
|
845 |
|
|
|
846 |
|
|
if (t->op & 1) {
|
847 |
|
|
// this is a call instruction. push return address
|
848 |
|
|
t->callStack.push(t->ip); // push return address on call stack
|
849 |
|
|
if (t->callStack.numEntries() > t->callDept) t->callDept = t->callStack.numEntries();
|
850 |
|
|
}
|
851 |
|
|
t->ip = target; // jump to new address
|
852 |
|
|
t->returnType = 0x2000; // debug output jump taken
|
853 |
|
|
t->running = 2; // don't save result
|
854 |
|
|
return 0;
|
855 |
|
|
}
|
856 |
|
|
|
857 |
|
|
static uint64_t return_62(CThread * t) {
|
858 |
|
|
// Format 1.6: Normal function return
|
859 |
|
|
// Format 1.7 C: system return
|
860 |
|
|
uint64_t target = 0; // target address
|
861 |
|
|
switch (t->fInstr->format2) {
|
862 |
|
|
case 0x163: // return
|
863 |
|
|
if (t->callStack.numEntries() == 0) {
|
864 |
|
|
t->interrupt(INT_CALL_STACK); // call stack empty
|
865 |
|
|
target = t->entry_point; // return to program start
|
866 |
|
|
}
|
867 |
|
|
else {
|
868 |
|
|
target = t->callStack.pop(); // pop return address
|
869 |
|
|
}
|
870 |
|
|
break;
|
871 |
|
|
case 0x173: // system return
|
872 |
|
|
// to do!
|
873 |
|
|
target = t->ip;
|
874 |
|
|
break;
|
875 |
|
|
default:
|
876 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
877 |
|
|
}
|
878 |
|
|
t->ip = target; // go to return address
|
879 |
|
|
t->running = 2; // don't save result
|
880 |
|
|
return 0;
|
881 |
|
|
}
|
882 |
|
|
|
883 |
|
|
static uint64_t syscall_63(CThread * t) {
|
884 |
|
|
// Format 1.6: sys call. ID in register
|
885 |
|
|
// Format 2.5.1, 2.5.7 and 3.1.0: sys call. ID in constants
|
886 |
|
|
// Format 1.7 C: trap or filler
|
887 |
|
|
// Format 2.5.5: conditional traps
|
888 |
|
|
uint8_t rd = t->pInstr->a.rd;
|
889 |
|
|
uint8_t rs = t->pInstr->a.rs;
|
890 |
|
|
uint8_t rt = t->pInstr->a.rt;
|
891 |
|
|
uint32_t mod; // module id
|
892 |
|
|
uint32_t funcid; // function id
|
893 |
|
|
switch (t->fInstr->format2) {
|
894 |
|
|
case 0x163: // system call. ID in register
|
895 |
|
|
if (t->operandType == 2) { // 16+16 bit
|
896 |
|
|
mod = uint16_t(t->registers[rt] >> 16);
|
897 |
|
|
funcid = uint16_t(t->registers[rt]);
|
898 |
|
|
}
|
899 |
|
|
else if (t->operandType == 3) { // 32+32 bit
|
900 |
|
|
mod = uint32_t(t->registers[rt] >> 32);
|
901 |
|
|
funcid = uint32_t(t->registers[rt]);
|
902 |
|
|
}
|
903 |
|
|
else {t->interrupt(INT_WRONG_PARAMETERS); return 0;}
|
904 |
|
|
t->systemCall(mod, funcid, rd, rs);
|
905 |
|
|
break;
|
906 |
|
|
case 0x251: // system call. ID in constants
|
907 |
|
|
mod = t->pInstr->s[3];
|
908 |
|
|
funcid = t->pInstr->s[2];
|
909 |
|
|
t->systemCall(mod, funcid, rd, rs);
|
910 |
|
|
break;
|
911 |
|
|
case 0x257: // system call. ID in constants. no registers
|
912 |
|
|
mod = t->pInstr->i[1];
|
913 |
|
|
funcid = t->pInstr->s[0];
|
914 |
|
|
t->systemCall(mod, funcid, 0, 0);
|
915 |
|
|
break;
|
916 |
|
|
case 0x310: // system call. ID in constants
|
917 |
|
|
mod = t->pInstr->i[2];
|
918 |
|
|
funcid = t->pInstr->i[1];
|
919 |
|
|
t->systemCall(mod, funcid, rd, rs);
|
920 |
|
|
break;
|
921 |
|
|
case 0x174: case 0x175: // trap or filler
|
922 |
|
|
t->interrupt(t->pInstr->s[0]);
|
923 |
|
|
break;
|
924 |
|
|
case 0x255: // conditional traps
|
925 |
|
|
if (t->pInstr->b[1] != 40) t->interrupt(INT_WRONG_PARAMETERS); // the only condition supported is unsigned above
|
926 |
|
|
if (t->parm[1].i > t->parm[2].i) { // check condition, unsigned compare
|
927 |
|
|
t->interrupt(t->pInstr->b[0]); // generate interrupt
|
928 |
|
|
}
|
929 |
|
|
break;
|
930 |
|
|
default:
|
931 |
|
|
t->interrupt(INT_WRONG_PARAMETERS);
|
932 |
|
|
}
|
933 |
|
|
t->running = 2; // don't save result
|
934 |
|
|
t->returnType = 0; // debug output written by system function
|
935 |
|
|
return 0;
|
936 |
|
|
}
|
937 |
|
|
|
938 |
|
|
// Jump instructions, conditional and indirect
|
939 |
|
|
PFunc funcTab2[64] = {
|
940 |
|
|
sub_jump_generic, sub_jump_generic, sub_jump_generic, sub_jump_generic, // 0 - 3
|
941 |
|
|
sub_jump_generic, sub_jump_generic, sub_jump_generic, sub_jump_generic, // 4 - 7
|
942 |
|
|
sub_jump_generic, sub_jump_generic, and_jump_zero, and_jump_zero, // 8 - 11
|
943 |
|
|
or_jump_zero, or_jump_zero, xor_jump_zero, xor_jump_zero, // 12 - 15
|
944 |
|
|
add_jump_generic, add_jump_generic, add_jump_generic, add_jump_generic, // 16 - 19
|
945 |
|
|
add_jump_generic, add_jump_generic, add_jump_generic, add_jump_generic, // 20 - 23
|
946 |
|
|
add_jump_generic, add_jump_generic, test_bit_jump_true, test_bit_jump_true, // 24 - 27
|
947 |
|
|
test_bits_and, test_bits_and, test_bits_or, test_bits_or, // 28 - 31
|
948 |
|
|
compare_jump_generic, compare_jump_generic, compare_jump_generic, compare_jump_generic, // 32 - 35
|
949 |
|
|
compare_jump_generic, compare_jump_generic, compare_jump_generic, compare_jump_generic, // 36 - 39
|
950 |
|
|
compare_jump_generic, compare_jump_generic, 0, 0, // 40 - 43
|
951 |
|
|
0, 0, 0, 0, // 44 - 47
|
952 |
|
|
increment_compare_jump, increment_compare_jump, increment_compare_jump, increment_compare_jump,// 48 - 51
|
953 |
|
|
sub_maxlen_jump_pos, sub_maxlen_jump_pos, 0, 0, // 52 - 55
|
954 |
|
|
0, 0, jump_call_58, jump_call_58, // 56 - 59
|
955 |
|
|
multiway_and_indirect, multiway_and_indirect, return_62, syscall_63 // 60 - 63
|
956 |
|
|
};
|
957 |
|
|
|
958 |
|
|
// jump and call instructions with 24 bit offset
|
959 |
|
|
PFunc funcTab3[16] = {
|
960 |
|
|
f_jump, f_jump, f_jump, f_jump, f_jump, f_jump, f_jump, f_jump,
|
961 |
|
|
f_call, f_call, f_call, f_call, f_call, f_call, f_call, f_call
|
962 |
|
|
};
|