Implementing another 40 CPU instructions
This commit is contained in:
		
							parent
							
								
									e31a5080c4
								
							
						
					
					
						commit
						2d380460a6
					
				
							
								
								
									
										2
									
								
								makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								makefile
								
								
								
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@ default:
 | 
			
		|||
	@echo
 | 
			
		||||
	@echo "Planet Virtual Boy Emulator"
 | 
			
		||||
	@echo "  https://www.planetvb.com/"
 | 
			
		||||
	@echo "  August 5, 2020"
 | 
			
		||||
	@echo "  August 11, 2020"
 | 
			
		||||
	@echo
 | 
			
		||||
	@echo "Intended build environment: Debian i386 or amd64"
 | 
			
		||||
	@echo "  gcc-multilib"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										892
									
								
								src/core/cpu.c
								
								
								
								
							
							
						
						
									
										892
									
								
								src/core/cpu.c
								
								
								
								
							| 
						 | 
				
			
			@ -68,27 +68,622 @@ static const int8_t CYCLES[] = {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *                            Instruction Helpers                            *
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Integer addition */
 | 
			
		||||
static int32_t cpuAdd(VUE *vue, int left, int right) {
 | 
			
		||||
    int32_t result = left + right;
 | 
			
		||||
    vue->cpu.psw_cy = (uint32_t) result < (uint32_t) left ? 1 : 0;
 | 
			
		||||
    vue->cpu.psw_s  = result >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_ov = (~(left ^ right) & (left ^ result)) >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = result ? 0 : 1;
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Bitwise operation */
 | 
			
		||||
static void cpuBitwise(VUE *vue, int32_t result) {
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = result;
 | 
			
		||||
    vue->cpu.psw_ov = 0;
 | 
			
		||||
    vue->cpu.psw_s  = result >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = result ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Reinterpret integer bits as a float promoted to double */
 | 
			
		||||
#define cpuFloat(x) ((double) *(float *)&(x))
 | 
			
		||||
 | 
			
		||||
/* Determine whether the floating-point operands are reserved values */
 | 
			
		||||
static vbool cpuFloatReserved(VUE *vue) {
 | 
			
		||||
    int32_t exponent; /* Operand exponent */
 | 
			
		||||
    int32_t operand;  /* Current operand */
 | 
			
		||||
    int     x;        /* Iterator */
 | 
			
		||||
 | 
			
		||||
    /* Operands */
 | 
			
		||||
    int32_t operands[2];
 | 
			
		||||
    operands[0] = vue->cpu.program[vue->cpu.inst.reg2];
 | 
			
		||||
    operands[1] = vue->cpu.program[vue->cpu.inst.reg1];
 | 
			
		||||
 | 
			
		||||
    /* Process both operands */
 | 
			
		||||
    for (x = 0; x < 2; x++) {
 | 
			
		||||
        operand  = operands[x];
 | 
			
		||||
        exponent = operand & 0x7F800000;
 | 
			
		||||
 | 
			
		||||
        /* Check for a reserved operand */
 | 
			
		||||
        if (!(
 | 
			
		||||
            exponent == 0x7F800000 ||                     /* Indefinite */
 | 
			
		||||
           (exponent == 0 && (operand & 0x007FFFFF) != 0) /* Denormal */
 | 
			
		||||
        )) continue;
 | 
			
		||||
 | 
			
		||||
        /* The value is a reserved operand */
 | 
			
		||||
        vue->cpu.exception.code = 0xFF60;
 | 
			
		||||
        vue->cpu.psw_fro        = 1;
 | 
			
		||||
        return VUE_TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Neither operand is a reserved value */
 | 
			
		||||
    return VUE_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Floating-point result */
 | 
			
		||||
static void cpuFloatResult(VUE *vue, double full) {
 | 
			
		||||
    int32_t bits   = 0x7F7FFFFF;      /* Binary representation of result */
 | 
			
		||||
    float   result = *(float *)&bits; /* Operation output */
 | 
			
		||||
 | 
			
		||||
    /* Overflow */
 | 
			
		||||
    if (full > result || full < -result) {
 | 
			
		||||
        vue->cpu.exception.code = 0xFF64;
 | 
			
		||||
        vue->cpu.psw_fov        = 1;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Process the result */
 | 
			
		||||
    result = (float) full;
 | 
			
		||||
    bits   = *(int32_t *)&result;
 | 
			
		||||
 | 
			
		||||
    /* Underflow */
 | 
			
		||||
    if ((bits & 0x7F800000) == 0 && (bits & 0x007FFFFF) != 0) {
 | 
			
		||||
        bits             = 0;
 | 
			
		||||
        result           = 0;
 | 
			
		||||
        vue->cpu.psw_fud = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Precision degradation */
 | 
			
		||||
    if (result != full)
 | 
			
		||||
        vue->cpu.psw_fpr = 1;
 | 
			
		||||
 | 
			
		||||
    /* Common processing */
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = bits;
 | 
			
		||||
    vue->cpu.psw_cy = vue->cpu.psw_s = bits >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_ov = 0;
 | 
			
		||||
    vue->cpu.psw_z  = bits ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read a system register */
 | 
			
		||||
static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) {
 | 
			
		||||
    switch (index) {
 | 
			
		||||
        case VUE_ADTRE: return vue->cpu.adtre;
 | 
			
		||||
        case VUE_EIPC : return vue->cpu.eipc;
 | 
			
		||||
        case VUE_EIPSW: return vue->cpu.eipsw;
 | 
			
		||||
        case VUE_FEPC : return vue->cpu.fepc;
 | 
			
		||||
        case VUE_FEPSW: return vue->cpu.fepsw;
 | 
			
		||||
        case VUE_ECR  : return vue->cpu.ecr_fecc << 16 | vue->cpu.ecr_eicc;
 | 
			
		||||
        case VUE_PIR  : return 0x00005346;
 | 
			
		||||
        case VUE_TKCW : return 0x000000E0;
 | 
			
		||||
        case VUE_CHCW : return vue->cpu.chcw_ice << 1;
 | 
			
		||||
        case 29       : return vue->cpu.sr29;
 | 
			
		||||
        case 30       : return 0x00000004;
 | 
			
		||||
        case 31       : return vue->cpu.sr31;
 | 
			
		||||
        case VUE_PSW  : return
 | 
			
		||||
            vue->cpu.psw_i   << 16 | vue->cpu.psw_fov <<  6 |
 | 
			
		||||
            vue->cpu.psw_np  << 15 | vue->cpu.psw_fud <<  5 |
 | 
			
		||||
            vue->cpu.psw_ep  << 14 | vue->cpu.psw_fpr <<  4 |
 | 
			
		||||
            vue->cpu.psw_ae  << 13 | vue->cpu.psw_cy  <<  3 |
 | 
			
		||||
            vue->cpu.psw_id  << 12 | vue->cpu.psw_ov  <<  2 |
 | 
			
		||||
            vue->cpu.psw_fro <<  9 | vue->cpu.psw_s   <<  1 |
 | 
			
		||||
            vue->cpu.psw_fiv <<  8 | vue->cpu.psw_z         |
 | 
			
		||||
            vue->cpu.psw_fzd <<  7
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        /* Remaining cases to encourage tableswitch */
 | 
			
		||||
        case  8: case  9: case 10: case 11: case 12: case 13: case 14:
 | 
			
		||||
        case 15: case 16: case 17: case 18: case 19: case 20: case 21:
 | 
			
		||||
        case 22: case 23: case 26: case 27: case 28:
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return 1; /* Unreachable */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Perform a bus read */
 | 
			
		||||
static vbool cpuRead(VUE *vue, int32_t address, int8_t type, int8_t fetch) {
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    vue->cpu.access.address = address;
 | 
			
		||||
    vue->cpu.access.fetch   = fetch;
 | 
			
		||||
    vue->cpu.access.type    = type;
 | 
			
		||||
    vue->cpu.access.value   = vueRead(vue, address, type);
 | 
			
		||||
 | 
			
		||||
    /* There is no application callback */
 | 
			
		||||
    if (vue->onRead == NULL)
 | 
			
		||||
        return VUE_FALSE;
 | 
			
		||||
 | 
			
		||||
    /* Call the application callback */
 | 
			
		||||
    vue->breakCode = vue->onRead(vue, &vue->cpu.access);
 | 
			
		||||
    return vue->breakCode != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write a system register */
 | 
			
		||||
static int32_t cpuSetSystemRegister(VUE *vue, int32_t index, int32_t value,
 | 
			
		||||
    vbool debug) {
 | 
			
		||||
    switch (index) {
 | 
			
		||||
        case VUE_ADTRE: return vue->cpu.adtre = value & 0xFFFFFFFE;
 | 
			
		||||
        case VUE_EIPC : return vue->cpu.eipc  = value & 0xFFFFFFFE;
 | 
			
		||||
        case VUE_EIPSW: return vue->cpu.eipsw = value & 0x000FF3FF;
 | 
			
		||||
        case VUE_FEPC : return vue->cpu.fepc  = value & 0xFFFFFFFE;
 | 
			
		||||
        case VUE_FEPSW: return vue->cpu.fepsw = value & 0x000FF3FF;
 | 
			
		||||
        case 29       : return vue->cpu.sr29  = value;
 | 
			
		||||
        case 31       : return vue->cpu.sr31  =
 | 
			
		||||
            debug || value >= 0 ? value : -value;
 | 
			
		||||
 | 
			
		||||
        case VUE_CHCW :
 | 
			
		||||
            vue->cpu.chcw_cen = value >> 20 & 0x00000FFF;
 | 
			
		||||
            vue->cpu.chcw_cec = value >>  8 & 0x00000FFF;
 | 
			
		||||
            vue->cpu.chcw_sa  = value >>  8 & 0x00FFFFFF;
 | 
			
		||||
            vue->cpu.chcw_icr = value >>  5 & 1;
 | 
			
		||||
            vue->cpu.chcw_icd = value >>  4 & 1;
 | 
			
		||||
            vue->cpu.chcw_ice = value >>  1 & 1;
 | 
			
		||||
            vue->cpu.chcw_icc = value       & 1;
 | 
			
		||||
 | 
			
		||||
            /* Only one of ICC, ICD or ICR is set */
 | 
			
		||||
            value &= 0x00000031;
 | 
			
		||||
            if ((value & (value - 1)) == 0) {
 | 
			
		||||
                /* Clear */
 | 
			
		||||
                /* Dump */
 | 
			
		||||
                /* Restore */
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return vue->cpu.chcw_ice << 1;
 | 
			
		||||
 | 
			
		||||
        case VUE_ECR:
 | 
			
		||||
            if (debug) {
 | 
			
		||||
                vue->cpu.ecr_fecc = value >> 16 & 0xFFFF;
 | 
			
		||||
                vue->cpu.ecr_eicc = value       & 0xFFFF;
 | 
			
		||||
            }
 | 
			
		||||
            return vue->cpu.ecr_fecc << 16 | vue->cpu.ecr_eicc;
 | 
			
		||||
 | 
			
		||||
        case VUE_PSW  :
 | 
			
		||||
            vue->cpu.psw_i   = value >> 16 & 15;
 | 
			
		||||
            vue->cpu.psw_np  = value >> 15 &  1;
 | 
			
		||||
            vue->cpu.psw_ep  = value >> 14 &  1;
 | 
			
		||||
            vue->cpu.psw_ae  = value >> 13 &  1;
 | 
			
		||||
            vue->cpu.psw_id  = value >> 12 &  1;
 | 
			
		||||
            vue->cpu.psw_fro = value >>  9 &  1;
 | 
			
		||||
            vue->cpu.psw_fiv = value >>  8 &  1;
 | 
			
		||||
            vue->cpu.psw_fzd = value >>  7 &  1;
 | 
			
		||||
            vue->cpu.psw_fov = value >>  6 &  1;
 | 
			
		||||
            vue->cpu.psw_fud = value >>  5 &  1;
 | 
			
		||||
            vue->cpu.psw_fpr = value >>  4 &  1;
 | 
			
		||||
            vue->cpu.psw_cy  = value >>  3 &  1;
 | 
			
		||||
            vue->cpu.psw_ov  = value >>  2 &  1;
 | 
			
		||||
            vue->cpu.psw_s   = value >>  1 &  1;
 | 
			
		||||
            vue->cpu.psw_z   = value       &  1;
 | 
			
		||||
            return value & 0x000FF3FF;
 | 
			
		||||
 | 
			
		||||
        /* Remaining cases to encourage tableswitch */
 | 
			
		||||
        case  6: case  7: case  8: case  9: case 10: case 11: case 12:
 | 
			
		||||
        case 13: case 14: case 15: case 16: case 17: case 18: case 19:
 | 
			
		||||
        case 20: case 21: case 22: case 23: case 26: case 27: case 28:
 | 
			
		||||
        case 30:
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return 1; /* Unreachable */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Arithmetic shift right */
 | 
			
		||||
static void cpuShiftArithmetic(VUE *vue, int32_t value, int32_t bits) {
 | 
			
		||||
    bits &= 31;
 | 
			
		||||
 | 
			
		||||
    /* Nothing to do */
 | 
			
		||||
    if (bits == 0)
 | 
			
		||||
        vue->cpu.psw_cy = 0;
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    else {
 | 
			
		||||
        vue->cpu.psw_cy = value >> (bits - 1) & 1;
 | 
			
		||||
        value >>= bits;
 | 
			
		||||
        bits    = 32 - bits;
 | 
			
		||||
        value   = SIGN_EXTEND(bits, value);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* Common processing */
 | 
			
		||||
    cpuBitwise(vue, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Logical shift left */
 | 
			
		||||
static void cpuShiftLeft(VUE *vue, int32_t value, int32_t bits) {
 | 
			
		||||
    bits &= 31;
 | 
			
		||||
 | 
			
		||||
    /* Nothing to do */
 | 
			
		||||
    if (bits == 0)
 | 
			
		||||
        vue->cpu.psw_cy = 0;
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    else {
 | 
			
		||||
        vue->cpu.psw_cy = value >> (32 - bits) & 1;
 | 
			
		||||
        value <<= bits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Commmon processing */
 | 
			
		||||
    cpuBitwise(vue, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Logical shift right */
 | 
			
		||||
static void cpuShiftRight(VUE *vue, int32_t value, int32_t bits) {
 | 
			
		||||
    bits &= 31;
 | 
			
		||||
 | 
			
		||||
    /* Nothing to do */
 | 
			
		||||
    if (bits == 0)
 | 
			
		||||
        vue->cpu.psw_cy = 0;
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    else {
 | 
			
		||||
        vue->cpu.psw_cy = value >> (bits - 1) & 1;
 | 
			
		||||
        value = value >> bits & ~((uint32_t) 0xFFFFFFFF << (32 - bits));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Commmon processing */
 | 
			
		||||
    cpuBitwise(vue, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Integer subtraction */
 | 
			
		||||
static int32_t cpuSubtract(VUE *vue, int left, int right) {
 | 
			
		||||
    int32_t result = left - right;
 | 
			
		||||
    vue->cpu.psw_cy = (uint32_t) result > (uint32_t) left ? 1 : 0;
 | 
			
		||||
    vue->cpu.psw_s  = result >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_ov = ((left ^ right) & (left ^ result)) >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = result ? 0 : 1;
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Test a condition */
 | 
			
		||||
static int8_t cpuTestCondition(VUE *vue, int32_t condition) {
 | 
			
		||||
    switch (condition) {
 | 
			
		||||
        case 0: return vue->cpu.psw_ov;
 | 
			
		||||
        case 1: return vue->cpu.psw_cy;
 | 
			
		||||
        case 2: return vue->cpu.psw_z;
 | 
			
		||||
        case 3: return vue->cpu.psw_cy | vue->cpu.psw_z;
 | 
			
		||||
        case 4: return vue->cpu.psw_s;
 | 
			
		||||
        case 5: return 1;
 | 
			
		||||
        case 6: return vue->cpu.psw_ov | vue->cpu.psw_s;
 | 
			
		||||
        case 7: return (vue->cpu.psw_ov ^ vue->cpu.psw_s) | vue->cpu.psw_z;
 | 
			
		||||
    }
 | 
			
		||||
    return cpuTestCondition(vue, condition & 7) ^ 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Perform a bus write */
 | 
			
		||||
static vbool cpuWrite(VUE *vue, int32_t address, int8_t type, int32_t value) {
 | 
			
		||||
 | 
			
		||||
    /* Prepare the operation */
 | 
			
		||||
    vue->cpu.access.address = address;
 | 
			
		||||
    vue->cpu.access.fetch   = -1;
 | 
			
		||||
    vue->cpu.access.type    = type;
 | 
			
		||||
    vue->cpu.access.value   = value;
 | 
			
		||||
 | 
			
		||||
    /* Application callback */
 | 
			
		||||
    if (vue->onWrite != NULL) {
 | 
			
		||||
        vue->breakCode = vue->onWrite(vue, &vue->cpu.access);
 | 
			
		||||
        if (vue->breakCode != 0)
 | 
			
		||||
            return VUE_TRUE;
 | 
			
		||||
        if (vue->cpu.access.type == VUE_CANCEL)
 | 
			
		||||
            return VUE_FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    vueWrite(vue, vue->cpu.access.address,
 | 
			
		||||
        vue->cpu.access.type, vue->cpu.access.value);
 | 
			
		||||
    return VUE_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Proxy for IN and LD */
 | 
			
		||||
#define cpuIN_LD(vue, type) \
 | 
			
		||||
    if (!cpuRead(vue, vue->cpu.program[vue->cpu.inst.reg1] + \
 | 
			
		||||
        vue->cpu.inst.disp, type, -1)) \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2] = vue->cpu.access.value
 | 
			
		||||
 | 
			
		||||
/* Proxy for OUT and ST */
 | 
			
		||||
#define cpuOUT_ST(vue, type) \
 | 
			
		||||
    cpuWrite(vue, vue->cpu.program[vue->cpu.inst.reg1] + \
 | 
			
		||||
        vue->cpu.inst.disp, type, vue->cpu.program[vue->cpu.inst.reg2])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *                           Instruction Functions                           *
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* JMP */
 | 
			
		||||
static void cpuJMP(VUE *vue) {
 | 
			
		||||
    vue->cpu.pc = vue->cpu.program[vue->cpu.inst.reg1] - 2;
 | 
			
		||||
/* Add Immediate */
 | 
			
		||||
#define cpuADD_IMM(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = cpuAdd(vue, \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2], vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Add Register */
 | 
			
		||||
#define cpuADD_REG(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = cpuAdd(vue, \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Add Floating Short */
 | 
			
		||||
#define cpuADDF_S(vue) \
 | 
			
		||||
    if (!cpuFloatReserved(vue)) cpuFloatResult(vue, \
 | 
			
		||||
        cpuFloat(vue->cpu.program[vue->cpu.inst.reg2]) + \
 | 
			
		||||
        cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
 | 
			
		||||
 | 
			
		||||
/* Add Immediate */
 | 
			
		||||
#define cpuADDI(vue) cpuADD_IMM(vue)
 | 
			
		||||
 | 
			
		||||
/* And */
 | 
			
		||||
#define cpuAND(vue) \
 | 
			
		||||
    cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] & \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* And Immediate */
 | 
			
		||||
#define cpuANDI(vue) \
 | 
			
		||||
    cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] & \
 | 
			
		||||
        vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Branch on Condition */
 | 
			
		||||
static void cpuBCOND(VUE *vue) {
 | 
			
		||||
    if (!cpuTestCondition(vue, vue->cpu.inst.cond & 15))
 | 
			
		||||
        return;
 | 
			
		||||
    vue->cpu.pc += vue->cpu.inst.disp - 2;
 | 
			
		||||
    vue->cpu.cycles = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* MOVEA */
 | 
			
		||||
static void cpuMOVEA(VUE *vue) {
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] =
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.imm;
 | 
			
		||||
/* Compare Immediate */
 | 
			
		||||
#define cpuCMP_IMM(vue) \
 | 
			
		||||
    cpuSubtract(vue, \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2], vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Compare Register */
 | 
			
		||||
#define cpuCMP_REG(vue) \
 | 
			
		||||
    cpuSubtract(vue, \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Divide */
 | 
			
		||||
static void cpuDIV(VUE *vue) {
 | 
			
		||||
    int32_t left  = vue->cpu.program[vue->cpu.inst.reg2];
 | 
			
		||||
    int32_t right = vue->cpu.program[vue->cpu.inst.reg1];
 | 
			
		||||
    int32_t result;
 | 
			
		||||
 | 
			
		||||
    /* Zero division */
 | 
			
		||||
    if (right == 0) {
 | 
			
		||||
        vue->cpu.exception.code = 0xFF80;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Special case */
 | 
			
		||||
    if ((left == (int32_t) 0x80000000) && (right == (int32_t) 0xFFFFFFFF)) {
 | 
			
		||||
        vue->cpu.program[30]                 = 0;
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2] = 0x80000000;
 | 
			
		||||
        vue->cpu.psw_ov = 1;
 | 
			
		||||
        vue->cpu.psw_s  = 1;
 | 
			
		||||
        vue->cpu.psw_z  = 0;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Regular case */
 | 
			
		||||
    result = left / right;
 | 
			
		||||
    vue->cpu.program[30]                 = left % right;
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = result;
 | 
			
		||||
    vue->cpu.psw_ov = 0;
 | 
			
		||||
    vue->cpu.psw_s  = result >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = result ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* MOVHI */
 | 
			
		||||
static void cpuMOVHI(VUE *vue) {
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] =
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1] + (vue->cpu.inst.imm << 16);
 | 
			
		||||
/* Divide Unsigned */
 | 
			
		||||
static void cpuDIVU(VUE *vue) {
 | 
			
		||||
    uint32_t left  = vue->cpu.program[vue->cpu.inst.reg2];
 | 
			
		||||
    uint32_t right = vue->cpu.program[vue->cpu.inst.reg1];
 | 
			
		||||
    uint32_t result;
 | 
			
		||||
 | 
			
		||||
    /* Zero division */
 | 
			
		||||
    if (right == 0) {
 | 
			
		||||
        vue->cpu.exception.code = 0xFF80;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Regular case */
 | 
			
		||||
    result = left / right;
 | 
			
		||||
    vue->cpu.program[30]                 = left % right;
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = result;
 | 
			
		||||
    vue->cpu.psw_ov = 0;
 | 
			
		||||
    vue->cpu.psw_s  = result >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = result ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Halt */
 | 
			
		||||
#define cpuHALT(vue) \
 | 
			
		||||
    vue->cpu.stage = CPU_HALT, vue->cpu.inst.size = 0
 | 
			
		||||
 | 
			
		||||
/* Input Byte from Port */
 | 
			
		||||
#define cpuIN_B(vue) cpuIN_LD(vue, VUE_U8)
 | 
			
		||||
 | 
			
		||||
/* Input Halfword from Port */
 | 
			
		||||
#define cpuIN_H(vue) cpuIN_LD(vue, VUE_U16)
 | 
			
		||||
 | 
			
		||||
/* Input Word from Port */
 | 
			
		||||
#define cpuIN_W(vue) cpuIN_LD(vue, VUE_S32)
 | 
			
		||||
 | 
			
		||||
/* Jump and Link */
 | 
			
		||||
#define cpuJAL(vue) \
 | 
			
		||||
    vue->cpu.program[31] = vue->cpu.pc + 4, \
 | 
			
		||||
    vue->cpu.pc += vue->cpu.inst.disp - 4
 | 
			
		||||
 | 
			
		||||
/* Jump Register */
 | 
			
		||||
#define cpuJMP(vue) \
 | 
			
		||||
    vue->cpu.pc = vue->cpu.program[vue->cpu.inst.reg1] - 2
 | 
			
		||||
 | 
			
		||||
/* Jump Relative */
 | 
			
		||||
#define cpuJR(vue) \
 | 
			
		||||
    vue->cpu.pc += vue->cpu.inst.disp - 4
 | 
			
		||||
 | 
			
		||||
/* Load Byte */
 | 
			
		||||
#define cpuLD_B(vue) cpuIN_LD(vue, VUE_S8)
 | 
			
		||||
 | 
			
		||||
/* Load Halfword */
 | 
			
		||||
#define cpuLD_H(vue) cpuIN_LD(vue, VUE_S16)
 | 
			
		||||
 | 
			
		||||
/* Load Word */
 | 
			
		||||
#define cpuLD_W(vue) cpuIN_LD(vue, VUE_S32)
 | 
			
		||||
 | 
			
		||||
/* Load to System Register */
 | 
			
		||||
#define cpuLDSR(vue) \
 | 
			
		||||
    cpuSetSystemRegister(vue, vue->cpu.inst.imm & 31, \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2], VUE_FALSE)
 | 
			
		||||
 | 
			
		||||
/* Move Immediate */
 | 
			
		||||
#define cpuMOV_IMM(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = vue->cpu.inst.imm
 | 
			
		||||
 | 
			
		||||
/* Move Register */
 | 
			
		||||
#define cpuMOV_REG(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1]
 | 
			
		||||
 | 
			
		||||
/* Multiply */
 | 
			
		||||
static void cpuMUL(VUE *vue) {
 | 
			
		||||
    int64_t full = (int64_t) vue->cpu.program[vue->cpu.inst.reg2] *
 | 
			
		||||
        (int64_t) vue->cpu.program[vue->cpu.inst.reg1];
 | 
			
		||||
    int32_t lower = (int32_t) full;
 | 
			
		||||
    vue->cpu.program[30]                 = (int32_t) (full >> 32);
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = lower;
 | 
			
		||||
    vue->cpu.psw_ov = (int64_t) lower != full ? 1 : 0;
 | 
			
		||||
    vue->cpu.psw_s  = lower >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = lower ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Multiply Unsigned */
 | 
			
		||||
static void cpuMULU(VUE *vue) {
 | 
			
		||||
    uint64_t full = (uint64_t)(uint32_t) vue->cpu.program[vue->cpu.inst.reg2] *
 | 
			
		||||
        (uint64_t)(uint32_t) vue->cpu.program[vue->cpu.inst.reg1];
 | 
			
		||||
    int32_t lower = (int32_t) full;
 | 
			
		||||
    vue->cpu.program[30]                 = (int32_t) (full >> 32);
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = lower;
 | 
			
		||||
    vue->cpu.psw_ov = full > (uint32_t) 0xFFFFFFFF ? 1 : 0;
 | 
			
		||||
    vue->cpu.psw_s  = lower >> 31 & 1;
 | 
			
		||||
    vue->cpu.psw_z  = lower ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Add */
 | 
			
		||||
#define cpuMOVEA(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.imm
 | 
			
		||||
 | 
			
		||||
/* Add */
 | 
			
		||||
#define cpuMOVHI(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1] + (vue->cpu.inst.imm << 16)
 | 
			
		||||
 | 
			
		||||
/* Not */
 | 
			
		||||
#define cpuNOT(vue) \
 | 
			
		||||
    cpuBitwise(vue, ~vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Output Byte to Port */
 | 
			
		||||
#define cpuOUT_B(vue) cpuOUT_ST(vue, VUE_U8)
 | 
			
		||||
 | 
			
		||||
/* Output Halfword to Port */
 | 
			
		||||
#define cpuOUT_H(vue) cpuOUT_ST(vue, VUE_U16)
 | 
			
		||||
 | 
			
		||||
/* Output Word to Port */
 | 
			
		||||
#define cpuOUT_W(vue) cpuOUT_ST(vue, VUE_S32)
 | 
			
		||||
 | 
			
		||||
/* Or */
 | 
			
		||||
#define cpuOR(vue) \
 | 
			
		||||
    cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] | \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Or Immediate */
 | 
			
		||||
#define cpuORI(vue) \
 | 
			
		||||
    cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] | \
 | 
			
		||||
        vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Return from Trap or Interrupt */
 | 
			
		||||
static void cpuRETI(VUE *vue) {
 | 
			
		||||
    if (vue->cpu.psw_np) {
 | 
			
		||||
        vue->cpu.pc = vue->cpu.fepc;
 | 
			
		||||
        cpuSetSystemRegister(vue, VUE_PSW, vue->cpu.fepsw, VUE_FALSE);
 | 
			
		||||
    } else {
 | 
			
		||||
        vue->cpu.pc = vue->cpu.eipc;
 | 
			
		||||
        cpuSetSystemRegister(vue, VUE_PSW, vue->cpu.eipsw, VUE_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Shift Arithmetic Right by Immediate */
 | 
			
		||||
#define cpuSAR_IMM(vue) \
 | 
			
		||||
    cpuShiftArithmetic(vue, vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Shift Arithmetic Right by Register */
 | 
			
		||||
#define cpuSAR_REG(vue) \
 | 
			
		||||
    cpuShiftArithmetic(vue, vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Shift Logical Left by Immediate */
 | 
			
		||||
#define cpuSHL_IMM(vue) \
 | 
			
		||||
    cpuShiftLeft(vue, vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Shift Logical Left by Register */
 | 
			
		||||
#define cpuSHL_REG(vue) \
 | 
			
		||||
    cpuShiftLeft(vue, vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Shift Logical Right by Immediate */
 | 
			
		||||
#define cpuSHR_IMM(vue) \
 | 
			
		||||
    cpuShiftRight(vue, vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
/* Shift Logical Right by Register */
 | 
			
		||||
#define cpuSHR_REG(vue) \
 | 
			
		||||
    cpuShiftRight(vue, vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Store Byte */
 | 
			
		||||
#define cpuST_B(vue) cpuOUT_ST(vue, VUE_S8)
 | 
			
		||||
 | 
			
		||||
/* Store Halfword */
 | 
			
		||||
#define cpuST_H(vue) cpuOUT_ST(vue, VUE_S16)
 | 
			
		||||
 | 
			
		||||
/* Store Word */
 | 
			
		||||
#define cpuST_W(vue) cpuOUT_ST(vue, VUE_S32)
 | 
			
		||||
 | 
			
		||||
/* Store Contents of System Register */
 | 
			
		||||
#define cpuSTSR(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = \
 | 
			
		||||
        cpuGetSystemRegister(vue, vue->cpu.inst.imm & 31)
 | 
			
		||||
 | 
			
		||||
/* Subtract */
 | 
			
		||||
#define cpuSUB(vue) \
 | 
			
		||||
    vue->cpu.program[vue->cpu.inst.reg2] = cpuSubtract(vue, \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg2], \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Trap */
 | 
			
		||||
#define cpuTRAP(vue) \
 | 
			
		||||
    vue->cpu.exception.code = 0xFFA0 | (vue->cpu.inst.imm & 15), \
 | 
			
		||||
    vue->cpu.pc += 2
 | 
			
		||||
 | 
			
		||||
/* Exclusive Or */
 | 
			
		||||
#define cpuXOR(vue) \
 | 
			
		||||
    cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
 | 
			
		||||
        vue->cpu.program[vue->cpu.inst.reg1])
 | 
			
		||||
 | 
			
		||||
/* Exclusive Or Immediate */
 | 
			
		||||
#define cpuXORI(vue) \
 | 
			
		||||
    cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
 | 
			
		||||
        vue->cpu.inst.imm)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
| 
						 | 
				
			
			@ -185,97 +780,97 @@ static vbool cpuExecute(VUE *vue) {
 | 
			
		|||
        vue->breakCode = vue->onExecute(vue, &vue->cpu.inst);
 | 
			
		||||
        if (vue->breakCode != 0)
 | 
			
		||||
            return VUE_TRUE;
 | 
			
		||||
        vue->cpu.inst.reg1 &= 31;
 | 
			
		||||
        vue->cpu.inst.reg2 &= 31;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Determine the default number of cycles for the instruction */
 | 
			
		||||
    if (vue->cpu.inst.id >= 0 && vue->cpu.inst.id <= 75)
 | 
			
		||||
        vue->cpu.cycles = CYCLES[vue->cpu.inst.id];
 | 
			
		||||
 | 
			
		||||
    /* Processing by instruction ID */
 | 
			
		||||
    switch (vue->cpu.inst.id) {
 | 
			
		||||
        /*case VUE_ADD_IMM: cpuADD_IMM(vue); break;*/
 | 
			
		||||
        /*case VUE_ADD_REG: cpuADD_REG(vue); break;*/
 | 
			
		||||
        /*case VUE_ADDF_S : cpuADDF_S (vue); break;*/
 | 
			
		||||
        /*case VUE_ADDI   : cpuADDI   (vue); break;*/
 | 
			
		||||
        /*case VUE_AND    : cpuAND    (vue); break;*/
 | 
			
		||||
        case VUE_ADD_IMM: cpuADD_IMM(vue); break;
 | 
			
		||||
        case VUE_ADD_REG: cpuADD_REG(vue); break;
 | 
			
		||||
        case VUE_ADDF_S : cpuADDF_S (vue); break;
 | 
			
		||||
        case VUE_ADDI   : cpuADDI   (vue); break;
 | 
			
		||||
        case VUE_AND    : cpuAND    (vue); break;
 | 
			
		||||
        /*case VUE_ANDBSU : cpuANDBSU (vue); break;*/
 | 
			
		||||
        /*case VUE_ANDI   : cpuANDI   (vue); break;*/
 | 
			
		||||
        case VUE_ANDI   : cpuANDI   (vue); break;
 | 
			
		||||
        /*case VUE_ANDNBSU: cpuANDNBSU(vue); break;*/
 | 
			
		||||
        /*case VUE_BCOND  : cpuBCOND  (vue); break;*/
 | 
			
		||||
        case VUE_BCOND  : cpuBCOND  (vue); break;
 | 
			
		||||
        /*case VUE_CAXI   : cpuCAXI   (vue); break;*/
 | 
			
		||||
        /*case VUE_CLI    : cpuCLI    (vue); break;*/
 | 
			
		||||
        /*case VUE_CMP_IMM: cpuCMP_IMM(vue); break;*/
 | 
			
		||||
        /*case VUE_CMP_REG: cpuCMP_REG(vue); break;*/
 | 
			
		||||
        case VUE_CMP_IMM: cpuCMP_IMM(vue); break;
 | 
			
		||||
        case VUE_CMP_REG: cpuCMP_REG(vue); break;
 | 
			
		||||
        /*case VUE_CMPF_S : cpuCMPF_S (vue); break;*/
 | 
			
		||||
        /*case VUE_CVT_SW : cpuCVT_SW (vue); break;*/
 | 
			
		||||
        /*case VUE_CVT_WS : cpuCVT_WS (vue); break;*/
 | 
			
		||||
        /*case VUE_DIV    : cpuDIV    (vue); break;*/
 | 
			
		||||
        case VUE_DIV    : cpuDIV    (vue); break;
 | 
			
		||||
        /*case VUE_DIVF_S : cpuDIVF_S (vue); break;*/
 | 
			
		||||
        /*case VUE_DIVU   : cpuDIVU   (vue); break;*/
 | 
			
		||||
        /*case VUE_HALT   : cpuHALT   (vue); break;*/
 | 
			
		||||
        /*case VUE_IN_B   : cpuIN_B   (vue); break;*/
 | 
			
		||||
        /*case VUE_IN_H   : cpuIN_H   (vue); break;*/
 | 
			
		||||
        /*case VUE_IN_W   : cpuIN_W   (vue); break;*/
 | 
			
		||||
        /*case VUE_JAL    : cpuJAL    (vue); break;*/
 | 
			
		||||
        case VUE_DIVU   : cpuDIVU   (vue); break;
 | 
			
		||||
        case VUE_HALT   : cpuHALT   (vue); break;
 | 
			
		||||
        case VUE_IN_B   : cpuIN_B   (vue); break;
 | 
			
		||||
        case VUE_IN_H   : cpuIN_H   (vue); break;
 | 
			
		||||
        case VUE_IN_W   : cpuIN_W   (vue); break;
 | 
			
		||||
        case VUE_JAL    : cpuJAL    (vue); break;
 | 
			
		||||
        case VUE_JMP    : cpuJMP    (vue); break;
 | 
			
		||||
        /*case VUE.JR     : cpuJR     (vue); break;*/
 | 
			
		||||
        /*case VUE.LD_B   : cpuLD_B   (vue); break;*/
 | 
			
		||||
        /*case VUE.LD_H   : cpuLD_H   (vue); break;*/
 | 
			
		||||
        /*case VUE.LD_W   : cpuLD_W   (vue); break;*/
 | 
			
		||||
        /*case VUE.LDSR   : cpuLDSR   (vue); break;*/
 | 
			
		||||
        /*case VUE.MOV_IMM: cpuMOV_IMM(vue); break;*/
 | 
			
		||||
        /*case VUE.MOV_REG: cpuMOV_REG(vue); break;*/
 | 
			
		||||
        /*case VUE.MOVBSU : cpuMOVBSU (vue); break;*/
 | 
			
		||||
        case VUE_JR     : cpuJR     (vue); break;
 | 
			
		||||
        case VUE_LD_B   : cpuLD_B   (vue); break;
 | 
			
		||||
        case VUE_LD_H   : cpuLD_H   (vue); break;
 | 
			
		||||
        case VUE_LD_W   : cpuLD_W   (vue); break;
 | 
			
		||||
        case VUE_LDSR   : cpuLDSR   (vue); break;
 | 
			
		||||
        case VUE_MOV_IMM: cpuMOV_IMM(vue); break;
 | 
			
		||||
        case VUE_MOV_REG: cpuMOV_REG(vue); break;
 | 
			
		||||
        /*case VUE_MOVBSU : cpuMOVBSU (vue); break;*/
 | 
			
		||||
        case VUE_MOVEA  : cpuMOVEA  (vue); break;
 | 
			
		||||
        case VUE_MOVHI  : cpuMOVHI  (vue); break;
 | 
			
		||||
        /*case VUE.MPYHW  : cpuMPYHW  (vue); break;*/
 | 
			
		||||
        /*case VUE.MUL    : cpuMUL    (vue); break;*/
 | 
			
		||||
        /*case VUE.MULF_S : cpuMULF_S (vue); break;*/
 | 
			
		||||
        /*case VUE.MULU   : cpuMULU   (vue); break;*/
 | 
			
		||||
        /*case VUE.NOT    : cpuNOT    (vue); break;*/
 | 
			
		||||
        /*case VUE.NOTBSU : cpuNOTBSU (vue); break;*/
 | 
			
		||||
        /*case VUE.OR     : cpuOR     (vue); break;*/
 | 
			
		||||
        /*case VUE.ORBSU  : cpuORBSU  (vue); break;*/
 | 
			
		||||
        /*case VUE.ORI    : cpuORI    (vue); break;*/
 | 
			
		||||
        /*case VUE.ORNBSU : cpuORNBSU (vue); break;*/
 | 
			
		||||
        /*case VUE.OUT_B  : cpuOUT_B  (vue); break;*/
 | 
			
		||||
        /*case VUE.OUT_H  : cpuOUT_H  (vue); break;*/
 | 
			
		||||
        /*case VUE.OUT_W  : cpuOUT_W  (vue); break;*/
 | 
			
		||||
        /*case VUE.RETI   : cpuRETI   (vue); break;*/
 | 
			
		||||
        /*case VUE.REV    : cpuREV    (vue); break;*/
 | 
			
		||||
        /*case VUE.SAR_IMM: cpuSAR_IMM(vue); break;*/
 | 
			
		||||
        /*case VUE.SAR_REG: cpuSAR_REG(vue); break;*/
 | 
			
		||||
        /*case VUE.SCH0BSD: cpuSCH0BSD(vue); break;*/
 | 
			
		||||
        /*case VUE.SCH0BSU: cpuSCH0BSU(vue); break;*/
 | 
			
		||||
        /*case VUE.SCH1BSD: cpuSCH1BSD(vue); break;*/
 | 
			
		||||
        /*case VUE.SCH1BSU: cpuSCH1BSU(vue); break;*/
 | 
			
		||||
        /*case VUE.SEI    : cpuSEI    (vue); break;*/
 | 
			
		||||
        /*case VUE.SETF   : cpuSETF   (vue); break;*/
 | 
			
		||||
        /*case VUE.SHL_IMM: cpuSHL_IMM(vue); break;*/
 | 
			
		||||
        /*case VUE.SHL_REG: cpuSHL_REG(vue); break;*/
 | 
			
		||||
        /*case VUE.SHR_IMM: cpuSHR_IMM(vue); break;*/
 | 
			
		||||
        /*case VUE.SHR_REG: cpuSHR_REG(vue); break;*/
 | 
			
		||||
        /*case VUE.ST_B   : cpuST_B   (vue); break;*/
 | 
			
		||||
        /*case VUE.ST_H   : cpuST_H   (vue); break;*/
 | 
			
		||||
        /*case VUE.ST_W   : cpuST_W   (vue); break;*/
 | 
			
		||||
        /*case VUE.STSR   : cpuSTSR   (vue); break;*/
 | 
			
		||||
        /*case VUE.SUB    : cpuSUB    (vue); break;*/
 | 
			
		||||
        /*case VUE.SUBF_S : cpuSUBF_S (vue); break;*/
 | 
			
		||||
        /*case VUE.TRAP   : cpuTRAP   (vue); break;*/
 | 
			
		||||
        /*case VUE.TRNC_SW: cpuTRNC_SW(vue); break;*/
 | 
			
		||||
        /*case VUE.XB     : cpuXB     (vue); break;*/
 | 
			
		||||
        /*case VUE.XH     : cpuXH     (vue); break;*/
 | 
			
		||||
        /*case VUE.XOR    : cpuXOR    (vue); break;*/
 | 
			
		||||
        /*case VUE.XORBSU : cpuXORBSU (vue); break;*/
 | 
			
		||||
        /*case VUE.XORI   : cpuXORI   (vue); break;*/
 | 
			
		||||
        /*case VUE.XORNBSU: cpuXORNBSU(vue); break;*/
 | 
			
		||||
        /*case VUE_MPYHW  : cpuMPYHW  (vue); break;*/
 | 
			
		||||
        case VUE_MUL    : cpuMUL    (vue); break;
 | 
			
		||||
        /*case VUE_MULF_S : cpuMULF_S (vue); break;*/
 | 
			
		||||
        case VUE_MULU   : cpuMULU   (vue); break;
 | 
			
		||||
        case VUE_NOT    : cpuNOT    (vue); break;
 | 
			
		||||
        /*case VUE_NOTBSU : cpuNOTBSU (vue); break;*/
 | 
			
		||||
        case VUE_OR     : cpuOR     (vue); break;
 | 
			
		||||
        /*case VUE_ORBSU  : cpuORBSU  (vue); break;*/
 | 
			
		||||
        case VUE_ORI    : cpuORI    (vue); break;
 | 
			
		||||
        /*case VUE_ORNBSU : cpuORNBSU (vue); break;*/
 | 
			
		||||
        case VUE_OUT_B  : cpuOUT_B  (vue); break;
 | 
			
		||||
        case VUE_OUT_H  : cpuOUT_H  (vue); break;
 | 
			
		||||
        case VUE_OUT_W  : cpuOUT_W  (vue); break;
 | 
			
		||||
        case VUE_RETI   : cpuRETI   (vue); break;
 | 
			
		||||
        /*case VUE_REV    : cpuREV    (vue); break;*/
 | 
			
		||||
        case VUE_SAR_IMM: cpuSAR_IMM(vue); break;
 | 
			
		||||
        case VUE_SAR_REG: cpuSAR_REG(vue); break;
 | 
			
		||||
        /*case VUE_SCH0BSD: cpuSCH0BSD(vue); break;*/
 | 
			
		||||
        /*case VUE_SCH0BSU: cpuSCH0BSU(vue); break;*/
 | 
			
		||||
        /*case VUE_SCH1BSD: cpuSCH1BSD(vue); break;*/
 | 
			
		||||
        /*case VUE_SCH1BSU: cpuSCH1BSU(vue); break;*/
 | 
			
		||||
        /*case VUE_SEI    : cpuSEI    (vue); break;*/
 | 
			
		||||
        /*case VUE_SETF   : cpuSETF   (vue); break;*/
 | 
			
		||||
        case VUE_SHL_IMM: cpuSHL_IMM(vue); break;
 | 
			
		||||
        case VUE_SHL_REG: cpuSHL_REG(vue); break;
 | 
			
		||||
        case VUE_SHR_IMM: cpuSHR_IMM(vue); break;
 | 
			
		||||
        case VUE_SHR_REG: cpuSHR_REG(vue); break;
 | 
			
		||||
        case VUE_ST_B   : cpuST_B   (vue); break;
 | 
			
		||||
        case VUE_ST_H   : cpuST_H   (vue); break;
 | 
			
		||||
        case VUE_ST_W   : cpuST_W   (vue); break;
 | 
			
		||||
        case VUE_STSR   : cpuSTSR   (vue); break;
 | 
			
		||||
        case VUE_SUB    : cpuSUB    (vue); break;
 | 
			
		||||
        /*case VUE_SUBF_S : cpuSUBF_S (vue); break;*/
 | 
			
		||||
        case VUE_TRAP   : cpuTRAP   (vue); break;
 | 
			
		||||
        /*case VUE_TRNC_SW: cpuTRNC_SW(vue); break;*/
 | 
			
		||||
        /*case VUE_XB     : cpuXB     (vue); break;*/
 | 
			
		||||
        /*case VUE_XH     : cpuXH     (vue); break;*/
 | 
			
		||||
        case VUE_XOR    : cpuXOR    (vue); break;
 | 
			
		||||
        /*case VUE_XORBSU : cpuXORBSU (vue); break;*/
 | 
			
		||||
        case VUE_XORI   : cpuXORI   (vue); break;
 | 
			
		||||
        /*case VUE_XORNBSU: cpuXORNBSU(vue); break;*/
 | 
			
		||||
        default: /* Invalid instruction */
 | 
			
		||||
            vue->cpu.exception.code = 0xFF90;
 | 
			
		||||
            vue->cpu.inst.size      = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Common processing */
 | 
			
		||||
    vue->cpu.pc        += vue->cpu.inst.size;
 | 
			
		||||
    if (vue->cpu.exception.code == 0) {
 | 
			
		||||
        vue->cpu.cycles += CYCLES[vue->cpu.inst.id];
 | 
			
		||||
        vue->cpu.pc     += vue->cpu.inst.size;
 | 
			
		||||
    }
 | 
			
		||||
    vue->cpu.program[0] = 0;
 | 
			
		||||
    cpuTestException(vue);
 | 
			
		||||
    if (vue->cpu.stage == CPU_EXECUTE)
 | 
			
		||||
| 
						 | 
				
			
			@ -293,17 +888,9 @@ static int32_t cpuSize(int32_t opcode) {
 | 
			
		|||
static vbool cpuFetch(VUE *vue) {
 | 
			
		||||
 | 
			
		||||
    /* Read the bits from the bus */
 | 
			
		||||
    vue->cpu.access.address = vue->cpu.pc + (vue->cpu.fetch << 1);
 | 
			
		||||
    vue->cpu.access.fetch   = vue->cpu.fetch;
 | 
			
		||||
    vue->cpu.access.type    = VUE_U16;
 | 
			
		||||
    vue->cpu.access.value   = vueRead(vue, vue->cpu.access.address, VUE_U16);
 | 
			
		||||
 | 
			
		||||
    /* Application callback */
 | 
			
		||||
    if (vue->onRead != NULL) {
 | 
			
		||||
        vue->breakCode = vue->onRead(vue, &vue->cpu.access);
 | 
			
		||||
        if (vue->breakCode != 0)
 | 
			
		||||
            return VUE_TRUE;
 | 
			
		||||
    }
 | 
			
		||||
    if (cpuRead(vue, vue->cpu.pc + (vue->cpu.fetch << 1),
 | 
			
		||||
        VUE_U16, vue->cpu.fetch))
 | 
			
		||||
        return VUE_TRUE;
 | 
			
		||||
 | 
			
		||||
    /* First unit */
 | 
			
		||||
    if (vue->cpu.fetch == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -326,41 +913,6 @@ static vbool cpuFetch(VUE *vue) {
 | 
			
		|||
    return VUE_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read a system register */
 | 
			
		||||
static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) {
 | 
			
		||||
    switch (index) {
 | 
			
		||||
        case VUE_ADTRE: return vue->cpu.adtre;
 | 
			
		||||
        case VUE_EIPC : return vue->cpu.eipc;
 | 
			
		||||
        case VUE_EIPSW: return vue->cpu.eipsw;
 | 
			
		||||
        case VUE_FEPC : return vue->cpu.fepc;
 | 
			
		||||
        case VUE_FEPSW: return vue->cpu.fepsw;
 | 
			
		||||
        case VUE_ECR  : return vue->cpu.ecr_fecc << 16 | vue->cpu.ecr_eicc;
 | 
			
		||||
        case VUE_PIR  : return 0x00005346;
 | 
			
		||||
        case VUE_TKCW : return 0x000000E0;
 | 
			
		||||
        case VUE_CHCW : return vue->cpu.chcw_ice << 1;
 | 
			
		||||
        case 29       : return vue->cpu.sr29;
 | 
			
		||||
        case 30       : return 0x00000004;
 | 
			
		||||
        case 31       : return vue->cpu.sr31;
 | 
			
		||||
        case VUE_PSW  : return
 | 
			
		||||
            vue->cpu.psw_i   << 16 | vue->cpu.psw_fov <<  6 |
 | 
			
		||||
            vue->cpu.psw_np  << 15 | vue->cpu.psw_fud <<  5 |
 | 
			
		||||
            vue->cpu.psw_ep  << 14 | vue->cpu.psw_fpr <<  4 |
 | 
			
		||||
            vue->cpu.psw_ae  << 13 | vue->cpu.psw_cy  <<  3 |
 | 
			
		||||
            vue->cpu.psw_id  << 12 | vue->cpu.psw_ov  <<  2 |
 | 
			
		||||
            vue->cpu.psw_fro <<  9 | vue->cpu.psw_s   <<  1 |
 | 
			
		||||
            vue->cpu.psw_fiv <<  8 | vue->cpu.psw_z         |
 | 
			
		||||
            vue->cpu.psw_fzd <<  7
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        /* Remaining cases to encourage tableswitch */
 | 
			
		||||
        case  8: case  9: case 10: case 11: case 12: case 13: case 14:
 | 
			
		||||
        case 15: case 16: case 17: case 18: case 19: case 20: case 21:
 | 
			
		||||
        case 22: case 23: case 26: case 27: case 28:
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return 1; /* Unreachable */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Operations for exception stage */
 | 
			
		||||
static vbool cpuException(VUE *vue) {
 | 
			
		||||
    vbool   isIRQ; /* The exception is an interrupt */
 | 
			
		||||
| 
						 | 
				
			
			@ -411,6 +963,8 @@ static vbool cpuException(VUE *vue) {
 | 
			
		|||
    if (isIRQ) {
 | 
			
		||||
        psw = vue->cpu.exception.code >> 4 & 15;
 | 
			
		||||
        vue->cpu.psw_i = psw < 15 ? psw : 15;
 | 
			
		||||
        if (vue->cpu.stage == CPU_HALT)
 | 
			
		||||
            vue->cpu.pc += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Common processing */
 | 
			
		||||
| 
						 | 
				
			
			@ -452,73 +1006,6 @@ vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write a system register */
 | 
			
		||||
static int32_t cpuSetSystemRegister(VUE *vue, int32_t index, int32_t value,
 | 
			
		||||
    vbool debug) {
 | 
			
		||||
    switch (index) {
 | 
			
		||||
        case VUE_ADTRE: return vue->cpu.adtre = value & 0xFFFFFFFE;
 | 
			
		||||
        case VUE_EIPC : return vue->cpu.eipc  = value & 0xFFFFFFFE;
 | 
			
		||||
        case VUE_EIPSW: return vue->cpu.eipsw = value & 0x000FF3FF;
 | 
			
		||||
        case VUE_FEPC : return vue->cpu.fepc  = value & 0xFFFFFFFE;
 | 
			
		||||
        case VUE_FEPSW: return vue->cpu.fepsw = value & 0x000FF3FF;
 | 
			
		||||
        case 29       : return vue->cpu.sr29  = value;
 | 
			
		||||
        case 31       : return vue->cpu.sr31  =
 | 
			
		||||
            debug || value >= 0 ? value : -value;
 | 
			
		||||
 | 
			
		||||
        case VUE_CHCW :
 | 
			
		||||
            vue->cpu.chcw_cen = value >> 20 & 0x00000FFF;
 | 
			
		||||
            vue->cpu.chcw_cec = value >>  8 & 0x00000FFF;
 | 
			
		||||
            vue->cpu.chcw_sa  = value >>  8 & 0x00FFFFFF;
 | 
			
		||||
            vue->cpu.chcw_icr = value >>  5 & 1;
 | 
			
		||||
            vue->cpu.chcw_icd = value >>  4 & 1;
 | 
			
		||||
            vue->cpu.chcw_ice = value >>  1 & 1;
 | 
			
		||||
            vue->cpu.chcw_icc = value       & 1;
 | 
			
		||||
 | 
			
		||||
            /* Only one of ICC, ICD or ICR is set */
 | 
			
		||||
            value &= 0x00000031;
 | 
			
		||||
            if ((value & (value - 1)) == 0) {
 | 
			
		||||
                /* Clear */
 | 
			
		||||
                /* Dump */
 | 
			
		||||
                /* Restore */
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return vue->cpu.chcw_ice << 1;
 | 
			
		||||
 | 
			
		||||
        case VUE_ECR:
 | 
			
		||||
            if (debug) {
 | 
			
		||||
                vue->cpu.ecr_fecc = value >> 16 & 0xFFFF;
 | 
			
		||||
                vue->cpu.ecr_eicc = value       & 0xFFFF;
 | 
			
		||||
            }
 | 
			
		||||
            return vue->cpu.ecr_fecc << 16 | vue->cpu.ecr_eicc;
 | 
			
		||||
 | 
			
		||||
        case VUE_PSW  :
 | 
			
		||||
            vue->cpu.psw_i   = value >> 16 & 15;
 | 
			
		||||
            vue->cpu.psw_np  = value >> 15 &  1;
 | 
			
		||||
            vue->cpu.psw_ep  = value >> 14 &  1;
 | 
			
		||||
            vue->cpu.psw_ae  = value >> 13 &  1;
 | 
			
		||||
            vue->cpu.psw_id  = value >> 12 &  1;
 | 
			
		||||
            vue->cpu.psw_fro = value >>  9 &  1;
 | 
			
		||||
            vue->cpu.psw_fiv = value >>  8 &  1;
 | 
			
		||||
            vue->cpu.psw_fzd = value >>  7 &  1;
 | 
			
		||||
            vue->cpu.psw_fov = value >>  6 &  1;
 | 
			
		||||
            vue->cpu.psw_fud = value >>  5 &  1;
 | 
			
		||||
            vue->cpu.psw_fpr = value >>  4 &  1;
 | 
			
		||||
            vue->cpu.psw_cy  = value >>  3 &  1;
 | 
			
		||||
            vue->cpu.psw_ov  = value >>  2 &  1;
 | 
			
		||||
            vue->cpu.psw_s   = value >>  1 &  1;
 | 
			
		||||
            vue->cpu.psw_z   = value       &  1;
 | 
			
		||||
            return value & 0x000FF3FF;
 | 
			
		||||
 | 
			
		||||
        /* Remaining cases to encourage tableswitch */
 | 
			
		||||
        case  6: case  7: case  8: case  9: case 10: case 11: case 12:
 | 
			
		||||
        case 13: case 14: case 15: case 16: case 17: case 18: case 19:
 | 
			
		||||
        case 20: case 21: case 22: case 23: case 26: case 27: case 28:
 | 
			
		||||
        case 30:
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return 1; /* Unreachable */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* System reset */
 | 
			
		||||
static void cpuReset(VUE *vue) {
 | 
			
		||||
    int32_t x;
 | 
			
		||||
| 
						 | 
				
			
			@ -546,21 +1033,6 @@ static void cpuReset(VUE *vue) {
 | 
			
		|||
    vue->cpu.psw_np   = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Test a condition */
 | 
			
		||||
static int8_t cpuTestCondition(VUE *vue, int32_t condition) {
 | 
			
		||||
    switch (condition) {
 | 
			
		||||
        case 0: return vue->cpu.psw_ov;
 | 
			
		||||
        case 1: return vue->cpu.psw_cy;
 | 
			
		||||
        case 2: return vue->cpu.psw_z;
 | 
			
		||||
        case 3: return vue->cpu.psw_cy | vue->cpu.psw_z;
 | 
			
		||||
        case 4: return vue->cpu.psw_s;
 | 
			
		||||
        case 5: return 1;
 | 
			
		||||
        case 6: return vue->cpu.psw_ov | vue->cpu.psw_s;
 | 
			
		||||
        case 7: return (vue->cpu.psw_ov ^ vue->cpu.psw_s) | vue->cpu.psw_z;
 | 
			
		||||
    }
 | 
			
		||||
    return cpuTestCondition(vue, condition & 7) ^ 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Determine the number of CPU cycles until something can happen */
 | 
			
		||||
static int32_t cpuUntil(VUE *vue, int32_t cycles) {
 | 
			
		||||
    if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,11 +24,12 @@ extern "C" {
 | 
			
		|||
#define VUE_TRUE  1
 | 
			
		||||
 | 
			
		||||
/* Memory access types */
 | 
			
		||||
#define VUE_S8  0
 | 
			
		||||
#define VUE_U8  1
 | 
			
		||||
#define VUE_S16 2
 | 
			
		||||
#define VUE_U16 3
 | 
			
		||||
#define VUE_S32 4
 | 
			
		||||
#define VUE_S8     0
 | 
			
		||||
#define VUE_U8     1
 | 
			
		||||
#define VUE_S16    2
 | 
			
		||||
#define VUE_U16    3
 | 
			
		||||
#define VUE_S32    4
 | 
			
		||||
#define VUE_CANCEL 5
 | 
			
		||||
 | 
			
		||||
/* System register indexes */
 | 
			
		||||
#define VUE_ADTRE 25
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,32 +112,27 @@ static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
 | 
			
		|||
    /* Common processing */
 | 
			
		||||
    address &= (~size + 1) & (datlen - 1);
 | 
			
		||||
 | 
			
		||||
    /* The host is little-endian */
 | 
			
		||||
    #ifndef VUE_BIGENDIAN
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case VUE_S8 : /* Fallthrough */
 | 
			
		||||
            case VUE_U8 : *(int8_t  *)&data[address] = (int8_t  ) value; break;
 | 
			
		||||
            case VUE_S16: /* Fallthrough */
 | 
			
		||||
            case VUE_U16: *(int16_t *)&data[address] = (int16_t ) value; break;
 | 
			
		||||
            case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    /* The host is big-endian */
 | 
			
		||||
    #else
 | 
			
		||||
    #ifdef VUE_BIGENDIAN
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case VUE_S32:
 | 
			
		||||
                data[address + 3] = (uint8_t) (value >> 24);
 | 
			
		||||
                data[address + 2] = (uint8_t) (value >> 16);
 | 
			
		||||
                value = (value & 0xFFFF0000) >> 16 | value << 16;
 | 
			
		||||
                /* Fallthrough */
 | 
			
		||||
            case VUE_S16: /* Fallthrough */
 | 
			
		||||
            case VUE_U16:
 | 
			
		||||
                data[address + 1] = (uint8_t) (value >>  8);
 | 
			
		||||
                /* Fallthrough */
 | 
			
		||||
            case VUE_S8 : /* Fallthrough */
 | 
			
		||||
            case VUE_U8 : value |=
 | 
			
		||||
                data[address    ] = (uint8_t)  value;
 | 
			
		||||
                value = (value & 0xFF00FF00) >> 8 | (value & 0x00FF00FF) << 8;
 | 
			
		||||
        }
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    /* Processing by data type */
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case VUE_S8 : /* Fallthrough */
 | 
			
		||||
        case VUE_U8 : *(int8_t  *)&data[address] = (int8_t  ) value; break;
 | 
			
		||||
        case VUE_S16: /* Fallthrough */
 | 
			
		||||
        case VUE_U16: *(int16_t *)&data[address] = (int16_t ) value; break;
 | 
			
		||||
        case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write bytes to a byte buffer */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -256,21 +256,6 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
			
		|||
        return 1; // Unreachable
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test a condition
 | 
			
		||||
    int test(int condition) {
 | 
			
		||||
        switch (condition) {
 | 
			
		||||
            case 0: return psw_ov;
 | 
			
		||||
            case 1: return psw_cy;
 | 
			
		||||
            case 2: return psw_z;
 | 
			
		||||
            case 3: return psw_cy | psw_z;
 | 
			
		||||
            case 4: return psw_s;
 | 
			
		||||
            case 5: return 1;
 | 
			
		||||
            case 6: return psw_ov | psw_s;
 | 
			
		||||
            case 7: return psw_ov ^ psw_s | psw_z;
 | 
			
		||||
        }
 | 
			
		||||
        return test(condition & 7) ^ 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Determine the number of CPU cycles until something can happen
 | 
			
		||||
    int until(int cycles) {
 | 
			
		||||
        if (stage == FATAL || stage == HALT)
 | 
			
		||||
| 
						 | 
				
			
			@ -294,8 +279,6 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
			
		|||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
 | 
			
		||||
 | 
			
		||||
        // Configure working variables
 | 
			
		||||
        exception.code &= 0xFFFF;
 | 
			
		||||
        boolean isIRQ   = (exception.code & 0xFF00) == 0xFE00;
 | 
			
		||||
| 
						 | 
				
			
			@ -331,8 +314,11 @@ System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        // Interrupt
 | 
			
		||||
        if (isIRQ)
 | 
			
		||||
        if (isIRQ) {
 | 
			
		||||
            psw_i = Math.min(15, exception.code >> 4 & 15);
 | 
			
		||||
            if (stage == HALT)
 | 
			
		||||
                pc += 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Common processing
 | 
			
		||||
        cycles         = 0; // TODO: Determine the actual number
 | 
			
		||||
| 
						 | 
				
			
			@ -353,63 +339,57 @@ System.out.printf("Exception %04X %d %d\n", exception.code, psw_ep, psw_np);
 | 
			
		|||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
System.out.printf("Execute %08X %d\n", pc, inst.id);
 | 
			
		||||
 | 
			
		||||
        // Determine the default number of cycles for the instruction
 | 
			
		||||
        if (inst.id >= 0 && inst.id <= 75)
 | 
			
		||||
            cycles = CYCLES[inst.id];
 | 
			
		||||
 | 
			
		||||
        // Processing by instruction ID
 | 
			
		||||
        switch (inst.id) {
 | 
			
		||||
            //case VUE.ADD_IMM: ADD_IMM(); break;
 | 
			
		||||
            //case VUE.ADD_REG: ADD_REG(); break;
 | 
			
		||||
            //case VUE.ADDF_S : ADDF_S (); break;
 | 
			
		||||
            //case VUE.ADDI   : ADDI   (); break;
 | 
			
		||||
            //case VUE.AND    : AND    (); break;
 | 
			
		||||
            case VUE.ADD_IMM: ADD_IMM(); break;
 | 
			
		||||
            case VUE.ADD_REG: ADD_REG(); break;
 | 
			
		||||
            case VUE.ADDF_S : ADDF_S (); break;
 | 
			
		||||
            case VUE.ADDI   : ADDI   (); break;
 | 
			
		||||
            case VUE.AND    : AND    (); break;
 | 
			
		||||
            //case VUE.ANDBSU : ANDBSU (); break;
 | 
			
		||||
            //case VUE.ANDI   : ANDI   (); break;
 | 
			
		||||
            case VUE.ANDI   : ANDI   (); break;
 | 
			
		||||
            //case VUE.ANDNBSU: ANDNBSU(); break;
 | 
			
		||||
            //case VUE.BCOND  : BCOND  (); break;
 | 
			
		||||
            case VUE.BCOND  : BCOND  (); break;
 | 
			
		||||
            //case VUE.CAXI   : CAXI   (); break;
 | 
			
		||||
            //case VUE.CLI    : CLI    (); break;
 | 
			
		||||
            //case VUE.CMP_IMM: CMP_IMM(); break;
 | 
			
		||||
            //case VUE.CMP_REG: CMP_REG(); break;
 | 
			
		||||
            case VUE.CMP_IMM: CMP_IMM(); break;
 | 
			
		||||
            case VUE.CMP_REG: CMP_REG(); break;
 | 
			
		||||
            //case VUE.CMPF_S : CMPF_S (); break;
 | 
			
		||||
            //case VUE.CVT_SW : CVT_SW (); break;
 | 
			
		||||
            //case VUE.CVT_WS : CVT_WS (); break;
 | 
			
		||||
            //case VUE.DIV    : DIV    (); break;
 | 
			
		||||
            case VUE.DIV    : DIV    (); break;
 | 
			
		||||
            //case VUE.DIVF_S : DIVF_S (); break;
 | 
			
		||||
            //case VUE.DIVU   : DIVU   (); break;
 | 
			
		||||
            //case VUE.HALT   : HALT   (); break;
 | 
			
		||||
            //case VUE.IN_B   : IN_B   (); break;
 | 
			
		||||
            //case VUE.IN_H   : IN_H   (); break;
 | 
			
		||||
            //case VUE.IN_W   : IN_W   (); break;
 | 
			
		||||
            //case VUE.JAL    : JAL    (); break;
 | 
			
		||||
            case VUE.DIVU   : DIVU   (); break;
 | 
			
		||||
            case VUE.HALT   : HALT   (); break;
 | 
			
		||||
            case VUE.IN_B   : IN_B   (); break;
 | 
			
		||||
            case VUE.IN_H   : IN_H   (); break;
 | 
			
		||||
            case VUE.IN_W   : IN_W   (); break;
 | 
			
		||||
            case VUE.JAL    : JAL    (); break;
 | 
			
		||||
            case VUE.JMP    : JMP    (); break;
 | 
			
		||||
            //case VUE.JR     : JR     (); break;
 | 
			
		||||
            //case VUE.LD_B   : LD_B   (); break;
 | 
			
		||||
            //case VUE.LD_H   : LD_H   (); break;
 | 
			
		||||
            //case VUE.LD_W   : LD_W   (); break;
 | 
			
		||||
            //case VUE.LDSR   : LDSR   (); break;
 | 
			
		||||
            //case VUE.MOV_IMM: MOV_IMM(); break;
 | 
			
		||||
            //case VUE.MOV_REG: MOV_REG(); break;
 | 
			
		||||
            case VUE.JR     : JR     (); break;
 | 
			
		||||
            case VUE.LD_B   : LD_B   (); break;
 | 
			
		||||
            case VUE.LD_H   : LD_H   (); break;
 | 
			
		||||
            case VUE.LD_W   : LD_W   (); break;
 | 
			
		||||
            case VUE.LDSR   : LDSR   (); break;
 | 
			
		||||
            case VUE.MOV_IMM: MOV_IMM(); break;
 | 
			
		||||
            case VUE.MOV_REG: MOV_REG(); break;
 | 
			
		||||
            //case VUE.MOVBSU : MOVBSU (); break;
 | 
			
		||||
            case VUE.MOVEA  : MOVEA  (); break;
 | 
			
		||||
            case VUE.MOVHI  : MOVHI  (); break;
 | 
			
		||||
            //case VUE.MPYHW  : MPYHW  (); break;
 | 
			
		||||
            //case VUE.MUL    : MUL    (); break;
 | 
			
		||||
            case VUE.MUL    : MUL    (); break;
 | 
			
		||||
            //case VUE.MULF_S : MULF_S (); break;
 | 
			
		||||
            //case VUE.MULU   : MULU   (); break;
 | 
			
		||||
            //case VUE.NOT    : NOT    (); break;
 | 
			
		||||
            case VUE.MULU   : MULU   (); break;
 | 
			
		||||
            case VUE.NOT    : NOT    (); break;
 | 
			
		||||
            //case VUE.NOTBSU : NOTBSU (); break;
 | 
			
		||||
            //case VUE.OR     : OR     (); break;
 | 
			
		||||
            case VUE.OR     : OR     (); break;
 | 
			
		||||
            //case VUE.ORBSU  : ORBSU  (); break;
 | 
			
		||||
            //case VUE.ORI    : ORI    (); break;
 | 
			
		||||
            case VUE.ORI    : ORI    (); break;
 | 
			
		||||
            //case VUE.ORNBSU : ORNBSU (); break;
 | 
			
		||||
            //case VUE.OUT_B  : OUT_B  (); break;
 | 
			
		||||
            //case VUE.OUT_H  : OUT_H  (); break;
 | 
			
		||||
            //case VUE.OUT_W  : OUT_W  (); break;
 | 
			
		||||
            //case VUE.RETI   : RETI   (); break;
 | 
			
		||||
            case VUE.OUT_B  : OUT_B  (); break;
 | 
			
		||||
            case VUE.OUT_H  : OUT_H  (); break;
 | 
			
		||||
            case VUE.OUT_W  : OUT_W  (); break;
 | 
			
		||||
            case VUE.RETI   : RETI   (); break;
 | 
			
		||||
            //case VUE.REV    : REV    (); break;
 | 
			
		||||
            //case VUE.SAR_IMM: SAR_IMM(); break;
 | 
			
		||||
            //case VUE.SAR_REG: SAR_REG(); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -423,27 +403,33 @@ System.out.printf("Execute %08X %d\n", pc, inst.id);
 | 
			
		|||
            //case VUE.SHL_REG: SHL_REG(); break;
 | 
			
		||||
            //case VUE.SHR_IMM: SHR_IMM(); break;
 | 
			
		||||
            //case VUE.SHR_REG: SHR_REG(); break;
 | 
			
		||||
            //case VUE.ST_B   : ST_B   (); break;
 | 
			
		||||
            //case VUE.ST_H   : ST_H   (); break;
 | 
			
		||||
            //case VUE.ST_W   : ST_W   (); break;
 | 
			
		||||
            //case VUE.STSR   : STSR   (); break;
 | 
			
		||||
            //case VUE.SUB    : SUB    (); break;
 | 
			
		||||
            case VUE.ST_B   : ST_B   (); break;
 | 
			
		||||
            case VUE.ST_H   : ST_H   (); break;
 | 
			
		||||
            case VUE.ST_W   : ST_W   (); break;
 | 
			
		||||
            case VUE.STSR   : STSR   (); break;
 | 
			
		||||
            case VUE.SUB    : SUB    (); break;
 | 
			
		||||
            //case VUE.SUBF_S : SUBF_S (); break;
 | 
			
		||||
            //case VUE.TRAP   : TRAP   (); break;
 | 
			
		||||
            case VUE.TRAP   : TRAP   (); break;
 | 
			
		||||
            //case VUE.TRNC_SW: TRNC_SW(); break;
 | 
			
		||||
            //case VUE.XB     : XB     (); break;
 | 
			
		||||
            //case VUE.XH     : XH     (); break;
 | 
			
		||||
            //case VUE.XOR    : XOR    (); break;
 | 
			
		||||
            case VUE.XOR    : XOR    (); break;
 | 
			
		||||
            //case VUE.XORBSU : XORBSU (); break;
 | 
			
		||||
            //case VUE.XORI   : XORI   (); break;
 | 
			
		||||
            case VUE.XORI   : XORI   (); break;
 | 
			
		||||
            //case VUE.XORNBSU: XORNBSU(); break;
 | 
			
		||||
            default: // Invalid instruction
 | 
			
		||||
                exception.code = 0xFF90;
 | 
			
		||||
                inst.size      = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // An application break was requested
 | 
			
		||||
        if (vue.breakCode != 0)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        // Common processing
 | 
			
		||||
        pc        += inst.size;
 | 
			
		||||
        if (exception.code == 0) {
 | 
			
		||||
            cycles += CYCLES[inst.id];
 | 
			
		||||
            pc     += inst.size;
 | 
			
		||||
        }
 | 
			
		||||
        program[0] = 0;
 | 
			
		||||
        testException();
 | 
			
		||||
        if (stage == EXECUTE)
 | 
			
		||||
| 
						 | 
				
			
			@ -455,19 +441,8 @@ System.out.printf("Execute %08X %d\n", pc, inst.id);
 | 
			
		|||
    private boolean fetch() {
 | 
			
		||||
 | 
			
		||||
        // Read the bits from the bus
 | 
			
		||||
        access.address = pc + (fetch << 1);
 | 
			
		||||
        access.fetch   = fetch;
 | 
			
		||||
        access.type    = VUE.U16;
 | 
			
		||||
        access.value   = vue.read(access.address, VUE.U16);
 | 
			
		||||
 | 
			
		||||
System.out.printf("Fetch %08X %04X\n", access.address, access.value);
 | 
			
		||||
 | 
			
		||||
        // Application callback
 | 
			
		||||
        if (vue.onRead != null) {
 | 
			
		||||
            vue.breakCode = vue.onRead.call(vue, access);
 | 
			
		||||
            if (vue.breakCode != 0)
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (read(pc + (fetch << 1), VUE.U16, fetch))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        // First unit
 | 
			
		||||
        if (fetch == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -490,6 +465,39 @@ System.out.printf("Fetch %08X %04X\n", access.address, access.value);
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Perform a bus read
 | 
			
		||||
    private boolean read(int address, int type, int fetch) {
 | 
			
		||||
 | 
			
		||||
        // Perform the operation
 | 
			
		||||
        access.address = address;
 | 
			
		||||
        access.fetch   = fetch;
 | 
			
		||||
        access.type    = type;
 | 
			
		||||
        access.value   = vue.read(address, type);
 | 
			
		||||
 | 
			
		||||
        // There is no application callback
 | 
			
		||||
        if (vue.onRead == null)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // Call the application callback
 | 
			
		||||
        vue.breakCode = vue.onRead.call(vue, access);
 | 
			
		||||
        return vue.breakCode != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test a condition
 | 
			
		||||
    private int testCondition(int condition) {
 | 
			
		||||
        switch (condition) {
 | 
			
		||||
            case 0: return psw_ov;
 | 
			
		||||
            case 1: return psw_cy;
 | 
			
		||||
            case 2: return psw_z;
 | 
			
		||||
            case 3: return psw_cy | psw_z;
 | 
			
		||||
            case 4: return psw_s;
 | 
			
		||||
            case 5: return 1;
 | 
			
		||||
            case 6: return psw_ov | psw_s;
 | 
			
		||||
            case 7: return psw_ov ^ psw_s | psw_z;
 | 
			
		||||
        }
 | 
			
		||||
        return testCondition(condition & 7) ^ 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check for an exception or interrupt
 | 
			
		||||
    private boolean testException() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -512,25 +520,463 @@ System.out.printf("Fetch %08X %04X\n", access.address, access.value);
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Perform a bus write
 | 
			
		||||
    private boolean write(int address, int type, int value) {
 | 
			
		||||
 | 
			
		||||
        // Prepare the operation
 | 
			
		||||
        access.address = address;
 | 
			
		||||
        access.fetch   = -1;
 | 
			
		||||
        access.type    = type;
 | 
			
		||||
        access.value   = value;
 | 
			
		||||
 | 
			
		||||
        // Application callback
 | 
			
		||||
        if (vue.onWrite != null) {
 | 
			
		||||
            vue.breakCode = vue.onWrite.call(vue, access);
 | 
			
		||||
            if (vue.breakCode != 0)
 | 
			
		||||
                return true;
 | 
			
		||||
            if (access.type == VUE.CANCEL)
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Perform the operation
 | 
			
		||||
        vue.write(access.address, access.type, access.value);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                          Instruction Helpers                          //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Integer addition
 | 
			
		||||
    private int add(int left, int right) {
 | 
			
		||||
        int result = left + right;
 | 
			
		||||
        psw_cy = Integer.compareUnsigned(result, left) < 0 ? 1 : 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_ov = (~(left ^ right) & (left ^ result)) >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Bitwise operation
 | 
			
		||||
    private void bitwise(int result) {
 | 
			
		||||
        program[inst.reg2] = result;
 | 
			
		||||
        psw_ov = 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Determine whether the floating-point operands are reserved values
 | 
			
		||||
    private boolean floatReserved() {
 | 
			
		||||
        for (int x = 0; x < 2; x++) {
 | 
			
		||||
            int operand = program[x == 0 ? inst.reg2 : inst.reg1];
 | 
			
		||||
            int exponent  = operand & 0x7F800000;
 | 
			
		||||
 | 
			
		||||
            // Check for a reserved operand
 | 
			
		||||
            if (!(
 | 
			
		||||
                exponent == 0x7F800000 ||                    // Indefinite
 | 
			
		||||
                exponent == 0 && (operand & 0x007FFFFF) != 0 // Denormal
 | 
			
		||||
            )) continue;
 | 
			
		||||
 | 
			
		||||
            // The value is a reserved operand
 | 
			
		||||
            exception.code = 0xFF60;
 | 
			
		||||
            psw_fro        = 1;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Floating-point result
 | 
			
		||||
    private void floatResult(double full) {
 | 
			
		||||
 | 
			
		||||
        // Overflow
 | 
			
		||||
        if (full > Float.MAX_VALUE || full < -Float.MAX_VALUE) {
 | 
			
		||||
            exception.code = 0xFF64;
 | 
			
		||||
            psw_fov        = 1;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Process the result
 | 
			
		||||
        float result = (float) full;
 | 
			
		||||
        int   bits   = Float.floatToRawIntBits(result);
 | 
			
		||||
 | 
			
		||||
        // Underflow
 | 
			
		||||
        if ((bits & 0x7F800000) == 0 && (bits & 0x007FFFFF) != 0) {
 | 
			
		||||
            bits    = 0;
 | 
			
		||||
            result  = 0;
 | 
			
		||||
            psw_fud = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Precision degradation
 | 
			
		||||
        if (result != full)
 | 
			
		||||
            psw_fpr = 1;
 | 
			
		||||
 | 
			
		||||
        // Common processing
 | 
			
		||||
        program[inst.reg2] = bits;
 | 
			
		||||
        psw_cy = psw_s = bits >>> 31;
 | 
			
		||||
        psw_ov = 0;
 | 
			
		||||
        psw_z  = bits == 0 ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Proxy for IN and LD
 | 
			
		||||
    private void IN_LD(int type) {
 | 
			
		||||
        if (!read(program[inst.reg1] + inst.disp, type, -1))
 | 
			
		||||
            program[inst.reg2] = access.value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Proxy for OUT and ST
 | 
			
		||||
    private void OUT_ST(int type) {
 | 
			
		||||
        write(program[inst.reg1] + inst.disp, type, program[inst.reg2]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Arithmetic shift right
 | 
			
		||||
    private void shiftArithmetic(int value, int bits) {
 | 
			
		||||
        bits  &= 31;
 | 
			
		||||
        psw_cy = bits == 0 ? 0 : value >> bits - 1 & 1;
 | 
			
		||||
        bitwise(value >> bits);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Logical shift left
 | 
			
		||||
    private void shiftLeft(int value, int bits) {
 | 
			
		||||
        bits  &= 31;
 | 
			
		||||
        psw_cy = bits == 0 ? 0 : value >> 32 - bits & 1;
 | 
			
		||||
        bitwise(value << bits);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Logical shift right
 | 
			
		||||
    private void shiftRight(int value, int bits) {
 | 
			
		||||
        bits  &= 31;
 | 
			
		||||
        psw_cy = bits == 0 ? 0 : value >> bits - 1 & 1;
 | 
			
		||||
        bitwise(value >>> bits);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Integer subtraction
 | 
			
		||||
    private int subtract(int left, int right) {
 | 
			
		||||
        int result = left - right;
 | 
			
		||||
        psw_cy = Integer.compareUnsigned(result, left) > 0 ? 1 : 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_ov = ((left ^ right) & (left ^ result)) >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                          Instruction Methods                          //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // JMP
 | 
			
		||||
    // Add Immediate
 | 
			
		||||
    private void ADD_IMM() {
 | 
			
		||||
        program[inst.reg2] = add(program[inst.reg2], inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add Register
 | 
			
		||||
    private void ADD_REG() {
 | 
			
		||||
        program[inst.reg2] = add(program[inst.reg2], program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add Floating Short
 | 
			
		||||
    private void ADDF_S() {
 | 
			
		||||
        if (!floatReserved()) floatResult(
 | 
			
		||||
            (double) Float.intBitsToFloat(program[inst.reg2]) +
 | 
			
		||||
            (double) Float.intBitsToFloat(program[inst.reg1]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add Immediate
 | 
			
		||||
    private void ADDI() {
 | 
			
		||||
        program[inst.reg2] = add(program[inst.reg2], inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // And
 | 
			
		||||
    private void AND() {
 | 
			
		||||
        bitwise(program[inst.reg2] & program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // And Immediate
 | 
			
		||||
    private void ANDI() {
 | 
			
		||||
        bitwise(program[inst.reg2] & inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Branch on Condition
 | 
			
		||||
    private void BCOND() {
 | 
			
		||||
        if (testCondition(inst.cond) == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        pc += inst.disp - 2;
 | 
			
		||||
        cycles = 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compare Immediate
 | 
			
		||||
    private void CMP_IMM() {
 | 
			
		||||
        subtract(program[inst.reg2], inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compare Register
 | 
			
		||||
    private void CMP_REG() {
 | 
			
		||||
        subtract(program[inst.reg2], program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Divide
 | 
			
		||||
    private void DIV() {
 | 
			
		||||
        int left  = program[inst.reg2];
 | 
			
		||||
        int right = program[inst.reg1];
 | 
			
		||||
 | 
			
		||||
        // Zero division
 | 
			
		||||
        if (right == 0) {
 | 
			
		||||
            exception.code = 0xFF80;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Special case
 | 
			
		||||
        if (left == 0x80000000 && right == 0xFFFFFFFF) {
 | 
			
		||||
            program[30]        = 0;
 | 
			
		||||
            program[inst.reg2] = 0x80000000;
 | 
			
		||||
            psw_ov = 1;
 | 
			
		||||
            psw_s  = 1;
 | 
			
		||||
            psw_z  = 0;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Regular case
 | 
			
		||||
        int result = left / right;
 | 
			
		||||
        program[30]        = left % right;
 | 
			
		||||
        program[inst.reg2] = result;
 | 
			
		||||
        psw_ov = 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Divide Unsigned
 | 
			
		||||
    private void DIVU() {
 | 
			
		||||
        long left  = program[inst.reg2] & 0xFFFFFFFFL;
 | 
			
		||||
        long right = program[inst.reg1] & 0xFFFFFFFFL;
 | 
			
		||||
 | 
			
		||||
        // Zero division
 | 
			
		||||
        if (right == 0) {
 | 
			
		||||
            exception.code = 0xFF80;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Regular case
 | 
			
		||||
        int result = (int) (left / right);
 | 
			
		||||
        program[30]        = (int) (left % right);
 | 
			
		||||
        program[inst.reg2] = result;
 | 
			
		||||
        psw_ov = 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Halt
 | 
			
		||||
    private void HALT() {
 | 
			
		||||
        stage = HALT;
 | 
			
		||||
        inst.size = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Input Byte from Port
 | 
			
		||||
    private void IN_B() {
 | 
			
		||||
        IN_LD(VUE.U8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Input Halfword from Port
 | 
			
		||||
    private void IN_H() {
 | 
			
		||||
        IN_LD(VUE.U16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Input Word from Port
 | 
			
		||||
    private void IN_W() {
 | 
			
		||||
        IN_LD(VUE.S32);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Jump and Link
 | 
			
		||||
    private void JAL() {
 | 
			
		||||
        program[31] = pc + 4;
 | 
			
		||||
        pc += inst.disp - 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Jump Register
 | 
			
		||||
    private void JMP() {
 | 
			
		||||
        pc = program[inst.reg1] - 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MOVEA
 | 
			
		||||
    // Jump Relative
 | 
			
		||||
    private void JR() {
 | 
			
		||||
        pc += inst.disp - 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load Byte
 | 
			
		||||
    private void LD_B() {
 | 
			
		||||
        IN_LD(VUE.S8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load Halfword
 | 
			
		||||
    private void LD_H() {
 | 
			
		||||
        IN_LD(VUE.S16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load Word
 | 
			
		||||
    private void LD_W() {
 | 
			
		||||
        IN_LD(VUE.S32);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load to System Register
 | 
			
		||||
    private void LDSR() {
 | 
			
		||||
        setSystemRegister(inst.imm & 31, program[inst.reg2], false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Move Immediate
 | 
			
		||||
    private void MOV_IMM() {
 | 
			
		||||
        program[inst.reg2] = inst.imm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Move Register
 | 
			
		||||
    private void MOV_REG() {
 | 
			
		||||
        program[inst.reg2] = program[inst.reg1];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add
 | 
			
		||||
    private void MOVEA() {
 | 
			
		||||
        program[inst.reg2] = program[inst.reg1] + inst.imm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MOVHI
 | 
			
		||||
    // Add
 | 
			
		||||
    private void MOVHI() {
 | 
			
		||||
        program[inst.reg2] = program[inst.reg1] + (inst.imm << 16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Multiply
 | 
			
		||||
    private void MUL() {
 | 
			
		||||
        long full   = (long) program[inst.reg2] * (long) program[inst.reg1];
 | 
			
		||||
        int  result = (int) full;
 | 
			
		||||
        program[30]        = (int) (full >> 32);
 | 
			
		||||
        program[inst.reg2] = result;
 | 
			
		||||
        psw_ov = (long) result != full ? 1 : 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Multiply Unsigned
 | 
			
		||||
    private void MULU() {
 | 
			
		||||
        long full   = (program[inst.reg2] & 0xFFFFFFFFL) *
 | 
			
		||||
            (program[inst.reg1] & 0xFFFFFFFFL);
 | 
			
		||||
        int  result = (int) full;
 | 
			
		||||
        program[30] = (int) (full >> 32);
 | 
			
		||||
        program[inst.reg2] = result;
 | 
			
		||||
        psw_ov = full > 0xFFFFFFFFL ? 1 : 0;
 | 
			
		||||
        psw_s  = result >>> 31;
 | 
			
		||||
        psw_z  = result == 0 ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Not
 | 
			
		||||
    private void NOT() {
 | 
			
		||||
        bitwise(~program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Or
 | 
			
		||||
    private void OR() {
 | 
			
		||||
        bitwise(program[inst.reg2] | program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Or Immediate
 | 
			
		||||
    private void ORI() {
 | 
			
		||||
        bitwise(program[inst.reg2] | inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Output Byte to Port
 | 
			
		||||
    private void OUT_B() {
 | 
			
		||||
        OUT_ST(VUE.U8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Output Halfword to Port
 | 
			
		||||
    private void OUT_H() {
 | 
			
		||||
        OUT_ST(VUE.U16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Output Word to Port
 | 
			
		||||
    private void OUT_W() {
 | 
			
		||||
        OUT_ST(VUE.S32);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return from Trap or Interrupt
 | 
			
		||||
    private void RETI() {
 | 
			
		||||
        if (psw_np == 1) {
 | 
			
		||||
            pc = fepc;
 | 
			
		||||
            setSystemRegister(VUE.PSW, fepsw, false);
 | 
			
		||||
        } else {
 | 
			
		||||
            pc = eipc;
 | 
			
		||||
            setSystemRegister(VUE.PSW, eipsw, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shift Arithmetic Right by Immediate
 | 
			
		||||
    private void SAR_IMM() {
 | 
			
		||||
        shiftArithmetic(program[inst.reg2], inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shift Arithmetic Right by Register
 | 
			
		||||
    private void SAR_REG() {
 | 
			
		||||
        shiftArithmetic(program[inst.reg2], program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shift Logical Left by Immediate
 | 
			
		||||
    private void SHL_IMM() {
 | 
			
		||||
        shiftLeft(program[inst.reg2], inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shift Logical Left by Register
 | 
			
		||||
    private void SHL_REG() {
 | 
			
		||||
        shiftLeft(program[inst.reg2], program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shift Logical Right by Immediate
 | 
			
		||||
    private void SHR_IMM() {
 | 
			
		||||
        shiftRight(program[inst.reg2], inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Shift Logical Right by Register
 | 
			
		||||
    private void SHR_REG() {
 | 
			
		||||
        shiftRight(program[inst.reg2], program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Store Byte
 | 
			
		||||
    private void ST_B() {
 | 
			
		||||
        OUT_ST(VUE.S8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Store Halfword
 | 
			
		||||
    private void ST_H() {
 | 
			
		||||
        OUT_ST(VUE.S16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Store Word
 | 
			
		||||
    private void ST_W() {
 | 
			
		||||
        OUT_ST(VUE.S32);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Store Contents of System Register
 | 
			
		||||
    private void STSR() {
 | 
			
		||||
        program[inst.reg2] = getSystemRegister(inst.imm & 31);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Subtract
 | 
			
		||||
    private void SUB() {
 | 
			
		||||
        program[inst.reg2] = subtract(program[inst.reg2], program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Trap
 | 
			
		||||
    private void TRAP() {
 | 
			
		||||
        exception.code = 0xFFA0 | inst.imm & 15;
 | 
			
		||||
        pc += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Exclusive Or
 | 
			
		||||
    private void XOR() {
 | 
			
		||||
        bitwise(program[inst.reg2] ^ program[inst.reg1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Exclusive Or Immediate
 | 
			
		||||
    private void XORI() {
 | 
			
		||||
        bitwise(program[inst.reg2] ^ inst.imm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue