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

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [emulator2.cpp] - Rev 76

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

/****************************  emulator2.cpp  ********************************
* Author:        Agner Fog
* date created:  2018-02-18
* Last modified: 2021-02-19
* Version:       1.11
* Project:       Binary tools for ForwardCom instruction set
* Description:
* Emulator: Execution functions for jump instructions
*
* Copyright 2018-2021 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
 
#include "stdafx.h"
 
static uint64_t f_jump(CThread * t) {
    // simple self-relative jump
    t->ip += t->addrOperand * 4;                           // add relative offset to IP
    t->running = 2;  t->returnType = 0;                    // no return value to save
    return 0;
}
 
static uint64_t f_call(CThread * t) {
    // simple self-relative call
    t->callStack.push(t->ip);                              // push return address on call stack
    if (t->callStack.numEntries() > t->callDept) t->callDept = t->callStack.numEntries();
    t->ip += t->addrOperand * 4;                           // add relative offset to IP
    t->running = 2;  t->returnType = 0;                    // no return value to save
    return 0;
}
 
static uint64_t compare_jump_generic(CThread * t) {
    // compare operands, jump on contition
    SNum a = t->parm[1];                                   // first parameter
    SNum b = t->parm[2];                                   // second parameter
    uint8_t branch = 0;                                    // jump if 1
    if (t->operandType < 4) {
        // all integer types
        uint64_t sizeMask = dataSizeMask[t->operandType];  // mask for data size
        uint64_t signBit = (sizeMask >> 1) + 1;            // sign bit
        a.q &= sizeMask;  b.q &= sizeMask;                 // limit to right number of bits
        // select condition
        switch (t->op & 0xE) {                             // mask out constant bits and invert bit
        case 0:  // jump if equal
            branch = a.q == b.q;  break;
        case 2:  // jump if signed below
            branch = (a.q ^ signBit) < (b.q ^ signBit);  break;            
        case 4:  // jump if signed above
            branch = (a.q ^ signBit) > (b.q ^ signBit);  break;            
        case 6:  // jump if unsigned below
            branch = a.q < b.q;  break;            
        case 8:  // jump if unsigned above
            branch = a.q > b.q;  break;            
        default: 
            t->interrupt(INT_WRONG_PARAMETERS);
        }
        branch ^= t->op;                                   // invert branch condition if op odd
    }
    else {
        // vector registers
        if (t->operandType != 5 && t->operandType != 6) {
            t->interrupt(INT_WRONG_PARAMETERS);                // unsupported operand type
            return 0;
        }
        if ((t->op & 0xFE) == 24) {
            // fp_category test
            if (t->fInstr->immSize) b = t->parm[4];        // avoid conversion of b to float
            bool mant0;                                    // mantissa is zero
            bool exp0;                                     // exponent is all zeroes
            bool exp1;                                     // exponent is all ones
            bool sign;                                     // sign bit
            if (t->operandType == 5) {                     // float
                mant0 = (a.i & 0x007FFFFF) == 0;           // mantissa is zero
                exp0 = (a.i & 0x7F800000) == 0;            // exponent is all zeroes
                exp1 = (a.i & 0x7F800000) == 0x7F800000;   // exponent is all ones
                sign = a.i >> 31 != 0;                     // sign bit
            }
            else {                                         // double
                mant0 = a.q << 12 == 0;                    // mantissa is zero
                exp0 = a.q << 1 >> 53 == 0;                // exponent is all zeroes
                exp1 = a.q << 1 >> 53 == 0xFFFFFFFFFFFFF;  // exponent is all ones
                sign = a.q >> 63 != 0;                     // sign bit
            }
            if (exp1) {
                if (b.b & 1)    branch |= !mant0;          // NAN
                if (b.b & 0x40) branch |= mant0 && sign;   // -INF
                if (b.b & 0x80) branch |= mant0 && !sign;  // +INF
            }
            else if (exp0) {
                if (b.b & 2)    branch |= uint8_t(mant0);  // +/- 0.0
                if (b.b & 4)    branch |= !mant0 && sign;  // - subnormal
                if (b.b & 8)    branch |= !mant0 && !sign; // + subnormal
            }
            else {
                if (b.b & 0x10) branch |= uint8_t(sign);   // - normal
                if (b.b & 0x20) branch |= !sign;           // + normal
            }
            branch ^= t->op;                               // invert branch condition if op odd
        }
        else {
            bool unordered;
            uint8_t opj = t->op;
            if (t->operandType == 5) {
                // float
                unordered = isnan_f(a.i) || isnan_f(b.i);  // check if unordered
                if (unordered) {
                    // a or b is NAN. Don't check the condition. Branch only if unordered version of instruction.
                    branch = t->op < 32;
                }
                else {
                    if ((opj & 0xE) > 5) {
                        // compare absolute values
                        a.i &= 0x7FFFFFFF;  b.i &= 0x7FFFFFFF;
                        opj -= 4;
                    }
                    // select condition, float
                    switch (opj & 0xE) {   // mask out bits for ordered/unordered and invert
                    case 0:    // jump if equal
                        branch = a.f == b.f;  break;
                    case 2:    // jump if below
                        branch = a.f < b.f;  break;
                    case 4:    // jump if above
                        branch = a.f > b.f;  break;
                    default:
                        t->interrupt(INT_WRONG_PARAMETERS);
                    }
                    branch ^= t->op;                               // invert branch condition if op odd
                }
            }
            else {
                // double
                unordered = isnan_d(a.q) || isnan_d(b.q);  // check if unordered
                if (unordered) {
                    // a or b is NAN. Don't check the condition. Branch only if unordered version of instruction.
                    branch = t->op < 32;
                }
                else {
                    if ((opj & 0xE) > 5) {
                        // compare absolute values
                        a.q &= 0x7FFFFFFFFFFFFFFF;  b.q &= 0x7FFFFFFFFFFFFFFF;
                        opj -= 4;
                    }
                    // select condition, float
                    switch (opj & 0xE) {                 // mask out bits for ordered/unordered and invert
                    case 0:    // jump if equal
                        branch = a.d == b.d;  break;
                    case 2:    // jump if below
                        branch = a.d < b.d;  break;
                    case 4:    // jump if above
                        branch = a.d > b.d;  break;
                    default:
                        t->interrupt(INT_WRONG_PARAMETERS);
                    }
                    branch ^= t->op;                       // invert branch condition if op odd
                }
            }
        }
    }
    if (branch & 1) {
        t->ip += t->addrOperand * 4;                       // add relative offset to IP
        t->returnType = 0x2000;                            // debug output jump taken
    }
    else t->returnType = 0x1000;                           // debug output jump taken
    if (t->vect) t->vect = 4;                              // stop vector loop
    t->running = 2;                                        // don't save result
    return 0; 
}
 
 
static uint64_t sub_jump_generic(CThread * t) {
    // subtract and jump on some condition
    if (t->operandType > 4) {  // floating point types have no add/jump
        // the opcode is used for floating point compare unordered
        return compare_jump_generic(t);
    }
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    int8_t unsignedOverflow = 0;                 // unsigned overflow detected
    int8_t signedOverflow = 0;                   // signed overflow detected
    int8_t op1 = t->op >> 1;                     // operation without toggle bit
    uint64_t sizeMask = dataSizeMask[t->operandType]; // mask for data size
    uint64_t signBit = (sizeMask >> 1) + 1;      // sign bit
    result.q = a.q - b.q;                        // subtract integers
 
    // detection of signed overflow 
    SNum overfl;  // overflow if a and b have opposite sign and result has opposite sign of a
    overfl.q = (a.q ^ b.q) & (a.q ^ result.q);
    signedOverflow = (overfl.q & signBit) != 0;
    // detection of borrow / unsigned overflow required
    unsignedOverflow = (result.q & sizeMask) > (a.q & sizeMask);
 
    // detect branch condition
    switch (op1) {
    case 0:  // jump if zero
        branch = (result.q & sizeMask) == 0;
        break;
    case 1:  // jump if negative
        branch = (result.q & signBit) != 0;
        break;
    case 2:  // jump if positive
        branch = (result.q & signBit) == 0 && (result.q & sizeMask) != 0;
        break;
    case 3:  // jump if signed overflow
        branch = signedOverflow;
        signedOverflow = unsignedOverflow = 0;   // no interrupt for this condition
        break;
    case 4:  // jump if borrow (unsigned overflow)
        branch = unsignedOverflow;
        signedOverflow = unsignedOverflow = 0;   // no interrupt for this condition
        break;
    default:
        err.submit(ERR_INTERNAL);
    }
    // only integer types in g.p. registers allowed
    if (t->operandType > 3) t->interrupt(INT_WRONG_PARAMETERS);
    // overflow interrupts
    //if (signedOverflow)   t->interrupt(INT_OVERFL_SIGN);
    //if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
 
    // invert condition if op odd
    branch ^= t->op;
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q;                             // return result
}
 
static uint64_t add_jump_generic(CThread * t) {
    // add and jump on some condition
    if (t->operandType > 4) {  // floating point types have no add/jump
        // the opcode is used for floating point compare unordered
        return compare_jump_generic(t);
    }
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    int8_t unsignedOverflow = 0;                 // unsigned overflow detected
    int8_t signedOverflow = 0;                   // signed overflow detected
    int8_t op1 = t->op >> 1;                     // operation without toggle bit
    uint64_t sizeMask = dataSizeMask[t->operandType]; // mask for data size
    uint64_t signBit = (sizeMask >> 1) + 1;      // sign bit
 
    // add integers
    result.q = a.q + b.q;
    // detection of signed overflow required
    SNum overfl;  // overflow if a and b have same sign and result has opposite sign of a
    overfl.q = ~(a.q ^ b.q) & (a.q ^ result.q);
    signedOverflow = (overfl.q & signBit) != 0;
    // detection of carry / unsigned overflow required
    unsignedOverflow = (result.q & sizeMask) < (a.q & sizeMask);
 
    // detect branch condition
    switch (op1) {
    case 8:  // jump if zero
        branch = (result.q & sizeMask) == 0;
        break;
    case 9:  // jump if negative
        branch = (result.q & signBit) != 0;
        break;
    case 10:  // jump if positive
        branch = (result.q & signBit) == 0 && (result.q & sizeMask) != 0;
        break;
    case 11:  // jump if signed overflow
        branch = signedOverflow;
        signedOverflow = unsignedOverflow = 0;   // no interrupt for this condition
        break;
    case 12:  // jump if borrow (unsigned overflow)
        branch = unsignedOverflow;
        signedOverflow = unsignedOverflow = 0;   // no interrupts for these conditions
        break;
    default:
        err.submit(ERR_INTERNAL);
    }
    // only integer types in g.p. registers allowed for add/jump instructions
    if (t->operandType > 3 && op1 < 12) t->interrupt(INT_WRONG_PARAMETERS);
    // overflow interrupts
    //if (signedOverflow)   t->interrupt(INT_OVERFL_SIGN);
    //if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
 
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q;                             // return result
}
/*
static uint64_t shift_left_jump_zero(CThread * t) {
    // shift left and jump if zero
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    result.q = 0;
 
    switch (t->operandType) {
    case 0:   // int8
        if (b.b < 8) result.b = a.b << b.b;
        branch = result.b == 0;
        break;
    case 1:   // int16
        if (b.s < 16) result.s = a.s << b.b;
        branch = result.s == 0;
        break;
    case 2: case 5:   // int32, float
        if (b.i < 32) result.i = a.i << b.b;
        branch = result.i == 0;
        break;
    case 3:   // int64, double
        if (b.q < 64) result.q = a.q << b.b;
        branch = result.q == 0;
        break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect) { // vector registers. make result scalar and stop vector loop
        t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];        
    }
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q; 
}
 
static uint64_t shift_right_u_jump_zero(CThread * t) {
    // shift right unsigned and jump if zero
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    result.q = 0;
 
    switch (t->operandType) {
    case 0:   // int8
        if (b.b < 8) result.b = a.b >> b.b;
        branch = result.b == 0;
        break;
    case 1:   // int16
        if (b.s < 16) result.s = a.s >> b.b;
        branch = result.s == 0;
        break;
    case 2: case 5:   // int32, float
        if (b.i < 32) result.i = a.i >> b.b;
        branch = result.i == 0;
        break;
    case 3:   // int64, double
        if (b.q < 64) result.q = a.q >> b.b;
        branch = result.q == 0;
        break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect) { // vector registers. make result scalar and stop vector loop
        t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];        
    }
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q; 
}
 
static uint64_t rotate_jump_carry(CThread * t) {
    // rotate left and jump if the last rotated bit is 1
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    result.q = 0;
 
    switch (t->operandType) {
    case 0:   // int8
        b.b &= 7;            
        result.b = (a.b << b.b) | (a.b >> (8 - b.b));
        branch = b.bs < 0 ? result.b >> 7 : result.b; // most or least significant bit
        break;
    case 1:   // int16
        b.b &= 15;            
        result.b = (a.s << b.b) | (a.s >> (16 - b.b));
        branch = uint8_t(b.ss < 0 ? result.s >> 15 : result.s); // most or least significant bit
        break;
    case 2: case 5:   // int32, float
        b.b &= 31;            
        result.i = (a.i << b.b) | (a.i >> (32 - b.b));
        branch = uint8_t(b.is < 0 ? result.i >> 31 : result.i); // most or least significant bit
        break;
    case 3:   // int64, double
        b.b &= 63;            
        result.q = (a.q << b.b) | (a.q >> (64 - b.b));
        branch = uint8_t(b.qs < 0 ? result.q >> 63 : result.q); // most or least significant bit
        break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect) { // vector registers. make result scalar and stop vector loop
        t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];        
    }
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q; 
} */
 
static uint64_t and_jump_zero(CThread * t) {
    // bitwise AND, jump if zero
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    result.q = a.q & b.q;                        // bitwise AND
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch = result.b == 0;  break;
    case 1:   // int16
        branch = result.s == 0;  break;
    case 2: case 5:   // int32, float
        branch = result.i == 0;  break;
    case 3: case 6:  // int64, double
        branch = result.q == 0;  break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect) { // vector registers. make result scalar and stop vector loop
        t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];        
    }
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q; 
}
 
static uint64_t or_jump_zero(CThread * t) {
    // bitwise OR, jump if zero
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    result.q = a.q | b.q;                        // bitwise AND
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch = result.b == 0;  break;
    case 1:   // int16
        branch = result.s == 0;  break;
    case 2: case 5:   // int32, float
        branch = result.i == 0;  break;
    case 3: case 6:   // int64, double
        branch = result.q == 0;  break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect) { // vector registers. make result scalar and stop vector loop
        t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];        
    }
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q; 
}
 
static uint64_t xor_jump_zero(CThread * t) {
    // bitwise XOR, jump if zero
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    result.q = a.q ^ b.q;                        // bitwise AND
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch = result.b == 0;  break;
    case 1:   // int16
        branch = result.s == 0;  break;
    case 2: case 5:   // int32, float
        branch = result.i == 0;  break;
    case 3: case 6:  // int64, double
        branch = result.q == 0;  break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect) { // vector registers. make result scalar and stop vector loop
        t->vectorLength[t->operands[0]] = t->vectorLengthR = dataSizeTable[t->operandType];        
    }
    // invert condition if op odd
    branch ^= t->op;
 
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;             // add relative offset to IP
        t->returnType |= 0x2000;                 // debug output jump taken
    }
    return result.q; 
}
 
static uint64_t test_bit_jump_true(CThread * t) {
    // test bit number b in a, jump if zero
    // floating point operands are treated as integers with the same size
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    uint8_t branch = 0;                          // treat bits out of range as zero
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        if (b.b < 8) branch = a.b >> b.b;
        break;
    case 1:   // int16
        if (b.s < 16) branch = uint8_t(a.s >> b.b);
        break;
    case 2:   // int32
    case 5:   // float
        if (b.i < 32) branch = uint8_t(a.i >> b.b);
        break;
    case 3:   // int64
    case 6:   // double
        if (b.q < 64) branch = uint8_t(a.q >> b.b);
        break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect)  t->vect = 4;                             // stop vector loop
 
    // invert condition if op odd
    branch ^= t->op;
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;                       // add relative offset to IP
        t->returnType = 0x2000;                            // debug output jump taken
    }
    else t->returnType = 0x1000;                           // debug output jump taken
    t->running = 2;                                        // don't save result
    return 0; 
}
 
static uint64_t test_bits_and(CThread * t) {
    // jump if (a & b) == b
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    int8_t branch = 0;                           // branch condition is inverted if op is odd
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch = (a.b & b.b) == b.b;  break;
    case 1:   // int16
        branch = (a.s & b.s) == b.s;  break;
    case 2:   // int32
    case 5:   // float
        branch = (a.i & b.i) == b.i;  break;
    case 3:   // int64
    case 6:   // double
        branch = (a.q & b.q) == b.q;  break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect)  t->vect = 4;                             // stop vector loop
 
    // invert condition if op odd
    branch ^= t->op;
    // conditional branch 
    if (branch & 1) {
        t->ip += t->addrOperand * 4;                       // add relative offset to IP
        t->returnType = 0x2000;                            // debug output jump taken
    }
    else t->returnType = 0x1000;                           // debug output jump taken
    t->running = 2;                                        // don't save result
    return 0; 
}
 
static uint64_t test_bits_or(CThread * t) {
    // jump if (a & b) != 0
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    if (t->fInstr->immSize) b = t->parm[4];      // avoid conversion of b to float
    int8_t branch = 0;                           // branch condition is inverted if op is odd
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch = (a.b & b.b) != 0;  break;
    case 1:   // int16
        branch = (a.s & b.s) != 0;  break;
    case 2:   // int32
    case 5:   // float
        branch = (a.i & b.i) != 0;  break;
    case 3:   // int64
    case 6:   // double
        branch = (a.q & b.q) != 0;  break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    if (t->vect)  t->vect = 4;                             // stop vector loop
    // invert condition if op odd
    branch ^= t->op;
    // conditional branch 
    if (branch & 1) {
        t->ip += t->addrOperand * 4;                       // add relative offset to IP
        t->returnType = 0x2000;                            // debug output jump taken
    }
    else t->returnType = 0x1000;                           // debug output jump taken
    t->running = 2;                                        // don't save result
    return 0; 
} 
 
 
static uint64_t increment_compare_jump(CThread * t) {
    // result = a + 1. Jump if condition
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    SNum result;                                 // result
    int8_t branch1 = 0;                          // jump if 1
    int8_t branch2 = 0;                          // jump if 1
    result.q = a.q + 1;                          // increment
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch1 = result.bs < b.bs;
        branch2 = result.bs > b.bs;
        break;
    case 1:   // int16
        branch1 = result.ss < b.ss;
        branch2 = result.ss > b.ss;
        break;
    case 2:   // int32
        branch1 = result.is < b.is;
        branch2 = result.is > b.is;
        break;
    case 3:   // int64
        branch1 = result.qs < b.qs;
        branch2 = result.qs > b.qs;
        break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    // select instruction
    if ((t->op & 0x3E) != II_INCREMENT_COMPARE_JBELOW) {
        branch1 = branch2;       // increment_compare/jump_above
    }
    // invert condition if opj odd
    branch1 ^= t->op;
    // conditional branch
    if (branch1 & 1) {
        t->ip += t->addrOperand * 4;                       // add relative offset to IP
        t->returnType |= 0x2000;                           // debug output jump taken
    }
    return result.q; 
}
 
static uint64_t sub_maxlen_jump_pos(CThread * t) {
    // Subtract the maximum vector length (in bytes) from a general purpose register 
    // and jump if the result is positive. The 8-bit immediate operand indicates the 
    // operand type for which the maximum vector length is obtained.
    // The register operand must be a 64-bit general purpose register.
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    SNum result;                                 // result
    int8_t branch = 0;                           // jump if 1
    // b indicates the operand type for which the maximum vector length is used.
    // to do: allow different maximum vector lengths for different operand types
    if (b.q > 7) t->interrupt(INT_WRONG_PARAMETERS);
    uint64_t maxlen = t->MaxVectorLength;
 
    result.q = a.q - maxlen;                     // subtract maximum length
 
    // branch condition
    switch (t->operandType) {
    case 0:   // int8
        branch = result.bs > 0;  break;
    case 1:   // int16
        branch = result.ss > 0;  break;
    case 2:   // int32
        branch = result.is > 0;  break;
    case 3:   // int64. This is the preferred operant types.
        branch = result.qs > 0;  break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    // invert condition if op odd
    branch ^= t->op;
    // conditional branch
    if (branch & 1) {
        t->ip += t->addrOperand * 4;                       // add relative offset to IP
        t->returnType |= 0x2000;                           // debug output jump taken
    }
    return result.q; 
}
/*
static uint64_t sub_jump(CThread * t) {
    // subtract integers and jump unconditionally. optional
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    SNum result;                                 // result
    int8_t unsignedOverflow = 0;                 // unsigned overflow detected
    int8_t signedOverflow = 0;                   // signed overflow detected
    result.q = a.q - b.q;                        // subtract integers
    // only integer types in g.p. registers allowed
    if (t->operandType > 3) t->interrupt(INT_WRONG_PARAMETERS);
    // overflow interrupts
    if (signedOverflow)   t->interrupt(INT_OVERFL_SIGN);
    if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
 
    // unconditional branch
    t->ip += t->addrOperand * 4;                 // add relative offset to IP
    t->returnType |= 0x2000;                     // debug output jump taken
    return result.q;                             // return result
}
 
static uint64_t add_jump(CThread * t) {
    // add integers and jump unconditionally. optional
    SNum a = t->parm[1];                         // first parameter
    SNum b = t->parm[2];                         // second parameter
    SNum result;                                 // result
    int8_t unsignedOverflow = 0;                 // unsigned overflow detected
    int8_t signedOverflow = 0;                   // signed overflow detected
    result.q = a.q + b.q;                        // add integers
    // only integer types in g.p. registers allowed
    if (t->operandType > 3) t->interrupt(INT_WRONG_PARAMETERS);
    // overflow interrupts
    if (signedOverflow)   t->interrupt(INT_OVERFL_SIGN);
    if (unsignedOverflow) t->interrupt(INT_OVERFL_UNSIGN);
 
    // unconditional branch
    t->ip += t->addrOperand * 4;                 // add relative offset to IP
    t->returnType |= 0x2000;                     // debug output jump taken
    return result.q;                             // return result
}*/
 
static uint64_t jump_call_58(CThread * t) {
    // op = 58: jump, 59: call
    // Format 1.6 and 2.5.0: Indirect jump or call with memory operand
    // Format 1.7 C, 2.5.4, and 3.1.0: Unconditional direct jump or call
    uint64_t target = 0;                         // target address
 
    // different instructions for different formats
    switch (t->fInstr->format2) {
    case 0x161: case 0x252: // Indirect jump or call with memory operand
        target = t->readMemoryOperand(t->memAddress);
        break;
    case 0x172: case 0x254: // Unconditional direct jump or call with relative address
        target = t->ip + t->addrOperand * 4;     // add relative offset to IP
        break;
    case 0x310: // Unconditional direct jump or call with absolute address
        target = t->addrOperand;                 // absolute address
        break;
    default: 
        t->interrupt(INT_WRONG_PARAMETERS);
        return 0;
    }
    if (target & 3) { // misaligned jump target
        t->interrupt(INT_MISALIGNED_JUMP);
        return 0;
    }
 
    if (t->op & 1) {
        // this is a call instruction. push return address
        t->callStack.push(t->ip);                // push return address on call stack
        if (t->callStack.numEntries() > t->callDept) t->callDept = t->callStack.numEntries();
    }
    t->ip = target;                              // jump to new address
    t->running = 2;                              // don't save result
    return 0;
}
 
static uint64_t multiway_and_indirect(CThread * t) {
    // op = 60: jump, 61: call
    // Format 1.6 and 2.5.2: Multiway jump or call with table of relative addresses
    // Format 1.7 C: Indirect jump or call to value of register 
    uint64_t target = 0;                         // target address
    uint64_t offset;                             // offset relative to reference point
 
    // different instructions for different formats
    switch (t->fInstr->format2) {
    case 0x162: case 0x252: // Indirect jump or call with memory operand
        offset = t->readMemoryOperand(t->memAddress);
        // sign extend table entry
        switch (t->operandType) {
        case 0:  // int8
            offset = (uint64_t)(int64_t)(int8_t)offset;  break;
        case 1:  // int16
            offset = (uint64_t)(int64_t)(int16_t)offset;  break;
        case 2:  // int32
            offset = (uint64_t)(int64_t)(int32_t)offset;  break;
        case 3:  // int64
            break;
        default:
            t->interrupt(INT_WRONG_PARAMETERS);
        }
        offset <<= 2;                            // scale by 4
        target = t->parm[1].q + offset;          // add reference point
        break;
    case 0x173: // Unconditional indirect jump or call to value of register
        target = t->registers[t->operands[0]];
        break;
    default: 
        t->interrupt(INT_WRONG_PARAMETERS);
        return 0;
    }
    if (target & 3) { // misaligned jump target
        t->interrupt(INT_MISALIGNED_JUMP);
        return 0;
    }
 
    if (t->op & 1) {
        // this is a call instruction. push return address
        t->callStack.push(t->ip);                // push return address on call stack
        if (t->callStack.numEntries() > t->callDept) t->callDept = t->callStack.numEntries();
    }
    t->ip = target;                              // jump to new address
    t->returnType = 0x2000;                      // debug output jump taken
    t->running = 2;                              // don't save result
    return 0;
}
 
static uint64_t return_62(CThread * t) {
    // Format 1.6: Normal function return
    // Format 1.7 C: system return
    uint64_t target = 0;                         // target address
    switch (t->fInstr->format2) {
    case 0x163: // return
        if (t->callStack.numEntries() == 0) {
            t->interrupt(INT_CALL_STACK);        // call stack empty
            target = t->entry_point;             // return to program start            
        }
        else {
            target = t->callStack.pop();         // pop return address
        }
        break;
    case 0x173: // system return
        // to do!
        target = t->ip;
        break;
    default:
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    t->ip = target;                              // go to return address
    t->running = 2;                              // don't save result
    return 0;
}
 
static uint64_t syscall_63(CThread * t) {
    // Format 1.6: sys call. ID in register
    // Format 2.5.1, 2.5.7 and 3.1.0: sys call. ID in constants
    // Format 1.7 C: trap or filler
    // Format 2.5.5: conditional traps
    uint8_t rd = t->pInstr->a.rd;
    uint8_t rs = t->pInstr->a.rs;
    uint8_t rt = t->pInstr->a.rt;
    uint32_t mod;                                // module id
    uint32_t funcid;                             // function id
    switch (t->fInstr->format2) {
    case 0x163: // system call. ID in register
        if (t->operandType == 2) { // 16+16 bit
            mod = uint16_t(t->registers[rt] >> 16);
            funcid = uint16_t(t->registers[rt]);
        }
        else if (t->operandType == 3) {  // 32+32 bit
            mod = uint32_t(t->registers[rt] >> 32);
            funcid = uint32_t(t->registers[rt]);
        }
        else {t->interrupt(INT_WRONG_PARAMETERS); return 0;}
        t->systemCall(mod, funcid, rd, rs);
        break;
    case 0x251:  // system call. ID in constants
        mod = t->pInstr->s[3];
        funcid = t->pInstr->s[2];
        t->systemCall(mod, funcid, rd, rs);
        break;
    case 0x257:  // system call. ID in constants. no registers
        mod = t->pInstr->i[1];
        funcid = t->pInstr->s[0];
        t->systemCall(mod, funcid, 0, 0);
        break;    
    case 0x310: // system call. ID in constants
        mod = t->pInstr->i[2];
        funcid = t->pInstr->i[1];
        t->systemCall(mod, funcid, rd, rs);
        break;
    case 0x174: case 0x175: // trap or filler
        t->interrupt(t->pInstr->s[0]);
        break;
    case 0x255: // conditional traps
        if (t->pInstr->b[1] != 40) t->interrupt(INT_WRONG_PARAMETERS); // the only condition supported is unsigned above
        if (t->parm[1].i > t->parm[2].i) {       // check condition, unsigned compare
            t->interrupt(t->pInstr->b[0]);       // generate interrupt
        }
        break;
    default: 
        t->interrupt(INT_WRONG_PARAMETERS);
    }
    t->running = 2;                              // don't save result
    t->returnType = 0;                           // debug output written by system function
    return 0;
}
 
// Jump instructions, conditional and indirect
PFunc funcTab2[64] = {
    sub_jump_generic, sub_jump_generic, sub_jump_generic, sub_jump_generic,                        // 0 - 3
    sub_jump_generic, sub_jump_generic, sub_jump_generic, sub_jump_generic,                        // 4 - 7
    sub_jump_generic, sub_jump_generic, and_jump_zero, and_jump_zero,                              // 8 - 11
    or_jump_zero, or_jump_zero, xor_jump_zero, xor_jump_zero,                                      // 12 - 15                                                                   
    add_jump_generic, add_jump_generic, add_jump_generic, add_jump_generic,                        // 16 - 19
    add_jump_generic, add_jump_generic, add_jump_generic, add_jump_generic,                        // 20 - 23
    add_jump_generic, add_jump_generic, test_bit_jump_true, test_bit_jump_true,                    // 24 - 27
    test_bits_and, test_bits_and, test_bits_or, test_bits_or,                                      // 28 - 31
    compare_jump_generic, compare_jump_generic, compare_jump_generic, compare_jump_generic,        // 32 - 35
    compare_jump_generic, compare_jump_generic, compare_jump_generic, compare_jump_generic,        // 36 - 39
    compare_jump_generic, compare_jump_generic, 0, 0,                                              // 40 - 43
    0, 0, 0, 0,                                                                                    // 44 - 47
    increment_compare_jump, increment_compare_jump, increment_compare_jump, increment_compare_jump,// 48 - 51
    sub_maxlen_jump_pos, sub_maxlen_jump_pos, 0, 0,                                                // 52 - 55
    0, 0, jump_call_58, jump_call_58,                                                              // 56 - 59
    multiway_and_indirect, multiway_and_indirect, return_62, syscall_63                            // 60 - 63
};
 
// jump and call instructions with 24 bit offset
PFunc funcTab3[16] = {
    f_jump, f_jump, f_jump, f_jump, f_jump, f_jump, f_jump, f_jump, 
    f_call, f_call, f_call, f_call, f_call, f_call, f_call, f_call
};
 

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

powered by: WebSVN 2.1.0

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