OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [emulator2.cpp] - Blame information for rev 80

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
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
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.