#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include static int getreg( const cpu_operand *o, __mpu_UNIT_t **p, __mpu_size_t *n ) { if( !o || o->type != CPU_OPERAND_REGISTER ) return( CPU_EXEC_OPERAND_FAULT ); *n = __cpu_reg_size( o->value.reg.bits ); if( !*n ) return( CPU_EXEC_REGISTER_FAULT ); *p = __cpu_reg_ptr( o->value.reg.bits, o->value.reg.address ); return( *p ? 0 : CPU_EXEC_REGISTER_FAULT ); } static int reg2( const cpu_instruction *i, __mpu_UNIT_t **d, __mpu_UNIT_t **a, __mpu_size_t *n ) { __mpu_size_t nd, na; int rc = getreg( &i->operand[0], d, &nd ); if( rc ) return( rc ); rc = getreg( &i->operand[1], a, &na ); if( rc ) return( rc ); if( nd != na ) return( CPU_EXEC_WIDTH_FAULT ); *n = nd; return( 0 ); } static int reg3( const cpu_instruction *i, __mpu_UNIT_t **d, __mpu_UNIT_t **a, __mpu_UNIT_t **b, __mpu_size_t *n ) { __mpu_size_t nd, na, nb; int rc = getreg( &i->operand[0], d, &nd ); if( rc ) return( rc ); rc = getreg( &i->operand[1], a, &na ); if( rc ) return( rc ); rc = getreg( &i->operand[2], b, &nb ); if( rc ) return( rc ); if( nd != na || nd != nb ) return( CPU_EXEC_WIDTH_FAULT ); *n = nd; return( 0 ); } static int valid_real( __mpu_size_t n ) { return( n >= NB_R32 && n <= NB_R_MAX && ( n & ( n - 1 ) ) == 0 ); } static int valid_complex( __mpu_size_t n ) { return( n >= 8 && n <= NB_C_MAX && ( n & ( n - 1 ) ) == 0 && valid_real( n / 2 ) ); } /* * LibMPU conversion helpers such as icvt()/r_cvt() may modify the LibMPU * flag register as an implementation side effect. LibCPU conversion-class * instructions are architecturally PSW-neutral, so preserve PSW[15:0]. * * Do this through the public LibCPU/LibMPU flag facade instead of depending * on LibMPU's private __MPU_FLAGS/context implementation detail. */ static __mpu_uint32_t cpu_status_flags_save( void ) { return( __cpu_get_psw() & PSW_MPU_MASK ); } static void cpu_status_flags_restore( __mpu_uint32_t flags ) { __mpu_uint32_t psw = __cpu_get_psw(); __cpu_set_psw( ( psw & PSW_CPU_MASK ) | ( flags & PSW_MPU_MASK ) ); } static int stack_offset( __mpu_int64_t off, __mpu_uint64_t width, __mpu_uint64_t *pos ) { __mpu_uint64_t p; if( !__STACK || !__SSIZE || __SP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); if( off < 0 ) { __mpu_uint64_t mag = (__mpu_uint64_t)( - ( off + 1 ) ) + 1U; if( mag > __SP ) return( CPU_EXEC_STACK_FAULT ); p = __SP - mag; } else { __mpu_uint64_t add = (__mpu_uint64_t)off; if( add > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); p = __SP + add; } if( p > __SSIZE || width > __SSIZE - p ) return( CPU_EXEC_STACK_FAULT ); *pos = p; return( CPU_EXEC_SUCCESS ); } static int frame_offset( __mpu_int64_t off, __mpu_uint64_t width, __mpu_uint64_t *pos ) { __mpu_uint64_t p; if( !__STACK || !__SSIZE || __FP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); if( off < 0 ) { __mpu_uint64_t mag = (__mpu_uint64_t)( - ( off + 1 ) ) + 1U; if( mag > __FP ) return( CPU_EXEC_STACK_FAULT ); p = __FP - mag; } else { __mpu_uint64_t add = (__mpu_uint64_t)off; if( add > __SSIZE - __FP ) return( CPU_EXEC_STACK_FAULT ); p = __FP + add; } if( p > __SSIZE || width > __SSIZE - p ) return( CPU_EXEC_STACK_FAULT ); *pos = p; return( CPU_EXEC_SUCCESS ); } static int pointer_register( const cpu_operand *o, __mpu_UNIT_t **p ) { __mpu_size_t n; int rc = getreg( o, p, &n ); if( rc ) return( rc ); return( n == CPU_PTR64_SIZE ? CPU_EXEC_SUCCESS : CPU_EXEC_WIDTH_FAULT ); } static int pointer_resolve( __mpu_uint64_t ptr, __mpu_uint64_t width, int write, __mpu_UNIT_t **base, __mpu_uint64_t *offset) { unsigned int seg; /* ABI NULL is the all-zero PTR64. It is never dereferenceable even though its bit fields would otherwise decode as DATA offset zero. */ if( ptr == CPU_NULL_PTR ) return( CPU_EXEC_POINTER_FAULT ); seg = __cpu_ptr_segment( ptr ); __mpu_uint64_t off = __cpu_ptr_offset( ptr ), size = 0; __mpu_UNIT_t *mem = 0; switch( seg ) { case CPU_PTR_SEG_DATA: mem = __DATA; size = __DSIZE; break; case CPU_PTR_SEG_STACK: mem = __STACK; size = __SSIZE; break; case CPU_PTR_SEG_PROGRAM: if( write ) return( CPU_EXEC_MEMORY_FAULT ); mem = __PROGRAM; size = __PSIZE; break; case CPU_PTR_SEG_CONTROL: if( write ) return( CPU_EXEC_MEMORY_FAULT ); mem = __CONTROL; size = __CSIZE; break; case CPU_PTR_SEG_INPUT: if( write ) return( CPU_EXEC_MEMORY_FAULT ); mem = __INPUT; size = __ISIZE; break; case CPU_PTR_SEG_OUTPUT: mem = __OUTPUT; size = __OSIZE; break; case CPU_PTR_SEG_TRACE: mem = __TRACE; size = __TSIZE; break; case CPU_PTR_SEG_HEAP: mem = __HEAP; size = __HBRK; if( off < CPU_HEAP_BEGIN ) return( CPU_EXEC_MEMORY_FAULT ); break; default: return( CPU_EXEC_POINTER_FAULT ); } if( !mem || off > size || width > size - off ) return( CPU_EXEC_MEMORY_FAULT ); *base = mem; *offset = off; return( CPU_EXEC_SUCCESS ); } /* * Apply a signed byte displacement to a PTR64 offset while preserving the * four-bit segment selector. The arithmetic is deliberately performed on * the 60-bit offset field only; carry/borrow is never allowed to enter SEG. * `subtract' selects PTR - delta instead of PTR + delta. */ static int pointer_arith( __mpu_uint64_t ptr, __mpu_int64_t delta, int subtract, __mpu_uint64_t *result) { __mpu_uint64_t off = __cpu_ptr_offset( ptr ); __mpu_uint64_t mag; unsigned int seg = __cpu_ptr_segment( ptr ); int positive = ( delta >= 0 ); if( !result ) return( CPU_EXEC_POINTER_FAULT ); if( positive ) mag = (__mpu_uint64_t)delta; else mag = (__mpu_uint64_t)( - ( delta + 1 ) ) + __mpu_UINT64_C( 1 ); /* PTR - negative_delta is addition; PTR + negative_delta is subtraction. */ if( ( !subtract && positive ) || ( subtract && !positive ) ) { if( mag > CPU_PTR_OFFSET_MASK - off ) return( CPU_EXEC_POINTER_FAULT ); off+=mag; } else { if( mag > off ) return( CPU_EXEC_POINTER_FAULT ); off -= mag; } if( __cpu_ptr_make( result, seg, off ) ) return( CPU_EXEC_POINTER_FAULT ); return( CPU_EXEC_SUCCESS ); } static int reg_i64( const cpu_operand *o, __mpu_int64_t *v ) { __mpu_UNIT_t *p; __mpu_uint64_t bits; int rc = pointer_register( o, &p ); if( rc ) return( rc ); bits = __cpu_data_get_u64( p ); memcpy( v, &bits, sizeof( *v ) ); return( CPU_EXEC_SUCCESS ); } static int reg_ptr64( const cpu_operand *o, __mpu_uint64_t *v ) { __mpu_UNIT_t *p; int rc = pointer_register( o, &p ); if( rc ) return( rc ); *v = __cpu_data_get_u64( p ); return( CPU_EXEC_SUCCESS ); } static int reg_u64( const cpu_operand *o, __mpu_uint64_t *v ) { __mpu_UNIT_t *p; int rc = pointer_register( o, &p ); if( rc ) return( rc ); *v = __cpu_data_get_u64( p ); return( CPU_EXEC_SUCCESS ); } static int put_i64_result( const cpu_operand *o, __mpu_int64_t v ) { __mpu_UNIT_t *p; __mpu_uint64_t bits; int rc = pointer_register( o, &p ); if( rc ) return( rc ); memcpy( &bits, &v, sizeof( bits ) ); __cpu_data_put_u64( p, bits ); return( CPU_EXEC_SUCCESS ); } static int put_u64_result( const cpu_operand *o, __mpu_uint64_t v ) { __mpu_UNIT_t *p; int rc = pointer_register( o, &p ); if( rc ) return( rc ); __cpu_data_put_u64( p, v ); return( CPU_EXEC_SUCCESS ); } static int reg_count32( const cpu_operand *o, unsigned int *count ) { __mpu_uint64_t v; int rc = reg_u64( o, &v ); if( rc ) return( rc ); if( v > __mpu_UINT64_C( 0xffffffff ) ) return( CPU_EXEC_OPERAND_FAULT ); *count = (unsigned int)(__mpu_uint32_t)v; return( CPU_EXEC_SUCCESS ); } /* Resolve an indirect control-flow operand. The register must be a physical r64/PTR64 value selecting PROGRAM, and the byte offset must address the current architectural PROGRAM size. No host pointer is ever accepted. */ static int code_pointer_target( const cpu_operand *o, __mpu_uint64_t *target ) { __mpu_uint64_t ptr, off; int rc; if( !target ) return( CPU_EXEC_POINTER_FAULT ); rc = reg_ptr64( o, &ptr ); if( rc ) return( rc ); if( ptr == CPU_NULL_PTR || __cpu_ptr_segment( ptr ) != CPU_PTR_SEG_PROGRAM ) return( CPU_EXEC_POINTER_FAULT ); off = __cpu_ptr_offset( ptr ); if( !__PROGRAM || off >= __PSIZE ) return( CPU_EXEC_POINTER_FAULT ); *target = off; return( CPU_EXEC_SUCCESS ); } static int rconst( mpu_real *d, int nb, __mpu_uint8_t k ) { switch( k ) { #define K(x,f) case x: f(d,nb); return 0 K( CPU_RCONST_ZERO, _m_zero ); K( CPU_RCONST_HALF, _m_half ); K( CPU_RCONST_ONE, _m_one ); K( CPU_RCONST_TWO, _m_two ); K( CPU_RCONST_TEN, _m_ten ); K( CPU_RCONST_MTEN, _m_mten ); K( CPU_RCONST_32, _m_32 ); K( CPU_RCONST_PI, _m_PI ); K( CPU_RCONST_E, _m_E ); K( CPU_RCONST_1_LN2, _m_1_ln2 ); K( CPU_RCONST_LN2, _m_ln2 ); K( CPU_RCONST_1_LN10, _m_1_ln10 ); K( CPU_RCONST_LN10, _m_ln10 ); K( CPU_RCONST_1_LG2, _m_1_lg2 ); K( CPU_RCONST_LG2, _m_lg2 ); K( CPU_RCONST_PI_2, _m_PI_2 ); K( CPU_RCONST_PI_3, _m_PI_3 ); K( CPU_RCONST_PI_4, _m_PI_4 ); K( CPU_RCONST_PI_5, _m_PI_5 ); K( CPU_RCONST_PI_6, _m_PI_6 ); K( CPU_RCONST_1_PI, _m_1_PI ); K( CPU_RCONST_2_PI, _m_2_PI ); K( CPU_RCONST_3_PI, _m_3_PI ); K( CPU_RCONST_4_PI, _m_4_PI ); K( CPU_RCONST_5_PI, _m_5_PI ); K( CPU_RCONST_2PI, _m_2PI ); K( CPU_RCONST_3PI, _m_3PI ); K( CPU_RCONST_1_2PI, _m_1_2PI ); K( CPU_RCONST_1_3PI, _m_1_3PI ); K( CPU_RCONST_1_4PI, _m_1_4PI ); K( CPU_RCONST_1_5PI, _m_1_5PI ); K( CPU_RCONST_1_6PI, _m_1_6PI ); K( CPU_RCONST_3PI_4, _m_3PI_4 ); K( CPU_RCONST_SQRTPI, _m_SQRTPI ); K( CPU_RCONST_1_SQRTPI, _m_1_SQRTPI ); K( CPU_RCONST_2_SQRTPI, _m_2_SQRTPI ); K( CPU_RCONST_SQRT2, _m_SQRT2 ); K( CPU_RCONST_1_SQRT2, _m_1_SQRT2 ); K( CPU_RCONST_SQRT3, _m_SQRT3 ); K( CPU_RCONST_1_SQRT3, _m_1_SQRT3 ); K( CPU_RCONST_DEGREE, _m_DEGREE ); K( CPU_RCONST_1_DEGREE, _m_1_DEGREE ); K( CPU_RCONST_GOLDENRATIO, _m_GOLDENRATIO ); K( CPU_RCONST_EULERGAMMA, _m_EULERGAMMA ); K( CPU_RCONST_CATALAN, _m_CATALAN ); K( CPU_RCONST_EPSILON, _real_epsilon ); K( CPU_RCONST_IND, _ind ); case CPU_RCONST_PNAN: _nan( d, 0, nb ); return( 0 ); case CPU_RCONST_NNAN: _nan( d, 1, nb ); return( 0 ); case CPU_RCONST_PNANMAX: _nan_max( d, 0, nb ); return( 0 ); case CPU_RCONST_NNANMAX: _nan_max( d, 1, nb ); return( 0 ); case CPU_RCONST_PNANMIN: _nan_min( d, 0, nb ); return( 0 ); case CPU_RCONST_NNANMIN: _nan_min( d, 1, nb ); return( 0 ); case CPU_RCONST_PINF: _inf( d, 0, nb ); return( 0 ); case CPU_RCONST_NINF: _inf( d, 1, nb ); return( 0 ); case CPU_RCONST_PREALMIN: _real_min( d, 0, nb ); return( 0 ); case CPU_RCONST_NREALMIN: _real_min( d, 1, nb ); return( 0 ); case CPU_RCONST_PREALMAX: _real_max( d, 0, nb ); return( 0 ); case CPU_RCONST_NREALMAX: _real_max( d, 1, nb ); return( 0 ); case CPU_RCONST_PZERO: _signull( d, 0, nb ); return( 0 ); case CPU_RCONST_NZERO: _signull( d, 1, nb ); return( 0 ); #undef K default: return( CPU_EXEC_OPERAND_FAULT ); } } int __cpu_exec( const cpu_instruction *i ) { __mpu_UNIT_t *d, *a, *b; __mpu_size_t n; int rc; if( !i ) return( CPU_EXEC_INSTRUCTION_FAULT ); switch( i->opcode ) { case CPU_OP_NOP: return( 0 ); case CPU_OP_HALT: __cpu_sth(); return( 0 ); case CPU_OP_END: return( CPU_EXEC_END ); case CPU_OP_SETF: case CPU_OP_CLRF: { __mpu_uint32_t psw, mask; if( i->operand[0].type != CPU_OPERAND_PSWBIT8 ) return( CPU_EXEC_OPERAND_FAULT ); if( i->operand[0].value.pswbit8 > CPU_PSWBIT_WRITE_MAX ) return( CPU_EXEC_OPERAND_FAULT ); psw = __cpu_get_psw(); mask = (__mpu_uint32_t)1U << i->operand[0].value.pswbit8; if( i->opcode == CPU_OP_SETF ) psw |= mask; else psw &= ~mask; __cpu_set_psw( psw ); return( CPU_EXEC_SUCCESS ); } case CPU_OP_CLRCPUF: __cpu_set_psw( __cpu_get_psw() & ~PSW_CPUF_MASK ); return( CPU_EXEC_SUCCESS ); case CPU_OP_CLRMPUF: __cpu_set_psw( __cpu_get_psw() & ~PSW_MPUF_MASK ); return( CPU_EXEC_SUCCESS ); case CPU_OP_SYSCALL: __cpu_data_put_u64( __cpu_reg_ptr( 64, CPU_SYSCALL_RET_ADDR ), __cpu_syscall_dispatch() ); return( CPU_EXEC_SUCCESS ); case CPU_OP_EXIT: { __mpu_UNIT_t *p; __mpu_size_t z; __mpu_uint32_t u; __mpu_int32_t status; rc = getreg( &i->operand[0], &p, &z ); if( rc ) return( rc ); if( z != 4U ) return( CPU_EXEC_WIDTH_FAULT ); u = __cpu_data_get_u32( p ); memcpy( &status, &u, sizeof( status ) ); __EXIT_STATUS = status; return( CPU_EXEC_EXIT ); } case CPU_OP_CLR: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); memset( d, 0, n ); return( 0 ); case CPU_OP_MOV: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); memmove( d, a, n ); return( 0 ); case CPU_OP_SWAP: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); { __mpu_size_t k; for( k = 0; k < n; k++ ) { __mpu_UNIT_t t = d[k]; d[k] = a[k]; a[k] = t; } } return( 0 ); case CPU_OP_BSWAP: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); { __mpu_size_t k; /* Equal-width naturally aligned register views are either identical or disjoint. These two paths are therefore exactly equivalent to the architectural source-snapshot semantics without an 8 KiB temp. */ if( d == a ) { for( k = 0; k < n / 2U; k++ ) { __mpu_UNIT_t t = d[k]; d[k] = d[n - 1U - k]; d[n - 1U - k] = t; } } else { for( k = 0; k < n; k++ ) d[k] = a[n - 1U - k]; } } return( 0 ); case CPU_OP_LDI: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( i->operand[1].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); { mpu_int64_t s; __mpu_int64_t v = (__mpu_int64_t)i->operand[1].value.imm64; __mpu_uint32_t flags = cpu_status_flags_save(); memcpy( s, &v, 8 ); icvt( ( mpu_int * ) d, ( mpu_int * ) s, (int)n, NB_I64 ); cpu_status_flags_restore( flags ); } return( 0 ); case CPU_OP_LDR: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); if( i->operand[1].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); { mpu_real64_t s; __mpu_uint64_t u = i->operand[1].value.imm64; __mpu_real64_t v; __mpu_uint32_t flags = cpu_status_flags_save(); memcpy( &v, &u, 8 ); memcpy( s, &v, 8 ); r_cvt( ( mpu_real * ) d, ( mpu_real * ) s, (int)n, NB_R64 ); cpu_status_flags_restore( flags ); } return( 0 ); case CPU_OP_LDC: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( !valid_complex( n ) ) return( CPU_EXEC_WIDTH_FAULT ); if( i->operand[1].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); { mpu_real32_t sr, si; mpu_wide_real_t rr, ri; __mpu_uint32_t ur = (__mpu_uint32_t)( i->operand[1].value.imm64 >> 32 ), ui = (__mpu_uint32_t)i->operand[1].value.imm64; __mpu_real32_t fr, fi; int cn = (int)( n / 2 ); __mpu_uint32_t flags = cpu_status_flags_save(); memcpy( &fr, &ur, 4 ); memcpy( &fi, &ui, 4 ); memcpy( sr, &fr, 4 ); memcpy( si, &fi, 4 ); r_cvt( ( mpu_real * ) rr, ( mpu_real * ) sr, cn, NB_R32 ); r_cvt( ( mpu_real * ) ri, ( mpu_real * ) si, cn, NB_R32 ); c_gen_complex( ( mpu_complex * ) d, ( mpu_real * ) rr, ( mpu_real * ) ri, cn ); cpu_status_flags_restore( flags ); } return( 0 ); case CPU_OP_LOAD: case CPU_OP_STORE: { const cpu_operand *ro = ( i->opcode == CPU_OP_LOAD ) ? &i->operand[0] : &i->operand[1]; const cpu_operand *ao = ( i->opcode == CPU_OP_LOAD ) ? &i->operand[1] : &i->operand[0]; rc = getreg( ro, &d, &n ); if( rc ) return( rc ); if( ao->type != CPU_OPERAND_ADDR64 ) return( CPU_EXEC_OPERAND_FAULT ); if( ao->value.addr64 > __DSIZE || (__mpu_uint64_t)n > __DSIZE - ao->value.addr64 ) return( CPU_EXEC_MEMORY_FAULT ); if( i->opcode == CPU_OP_LOAD ) memmove( d, __DATA + ao->value.addr64, n ); else memmove( __DATA + ao->value.addr64, d, n ); return( 0 ); } case CPU_OP_LEA: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( n != CPU_PTR64_SIZE ) return( CPU_EXEC_WIDTH_FAULT ); if( i->operand[1].type != CPU_OPERAND_PTR64 ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint64_t ptr = i->operand[1].value.ptr64, off = __cpu_ptr_offset( ptr ), size = 0; unsigned int seg = __cpu_ptr_segment( ptr ); switch( seg ) { case CPU_PTR_SEG_DATA: size = __DSIZE; break; case CPU_PTR_SEG_STACK: size = __SSIZE; break; case CPU_PTR_SEG_PROGRAM: size = __PSIZE; break; case CPU_PTR_SEG_CONTROL: size = __CSIZE; break; case CPU_PTR_SEG_INPUT: size = __ISIZE; break; case CPU_PTR_SEG_OUTPUT: size = __OSIZE; break; case CPU_PTR_SEG_TRACE: size = __TSIZE; break; case CPU_PTR_SEG_HEAP: size = __HBRK; if( off < CPU_HEAP_BEGIN ) return( CPU_EXEC_MEMORY_FAULT ); break; default: return( CPU_EXEC_POINTER_FAULT ); } if( off > size ) return( CPU_EXEC_MEMORY_FAULT ); __cpu_data_put_u64( d, ptr ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_LEASP: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( n != CPU_PTR64_SIZE ) return( CPU_EXEC_WIDTH_FAULT ); if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint64_t pos, ptr; rc = stack_offset( i->operand[1].value.off64, 0, &pos ); if( rc ) return( rc ); if( pos > CPU_PTR_OFFSET_MASK ) return( CPU_EXEC_POINTER_FAULT ); if( __cpu_ptr_make( &ptr, CPU_PTR_SEG_STACK, pos ) ) return( CPU_EXEC_POINTER_FAULT ); __cpu_data_put_u64( d, ptr ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_LOADP: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); rc = pointer_register( &i->operand[1], &a ); if( rc ) return( rc ); { __mpu_uint64_t ptr, off; __mpu_UNIT_t *base; ptr = __cpu_data_get_u64( a ); rc = pointer_resolve( ptr, (__mpu_uint64_t)n, 0, &base, &off ); if( rc ) return( rc ); memmove( d, base + off, n ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_STOREP: rc = pointer_register( &i->operand[0], &a ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &d, &n ); if( rc ) return( rc ); { __mpu_uint64_t ptr, off; __mpu_UNIT_t *base; ptr = __cpu_data_get_u64( a ); rc = pointer_resolve( ptr, (__mpu_uint64_t)n, 1, &base, &off ); if( rc ) return( rc ); memmove( base + off, d, n ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_BMOV: case CPU_OP_BMOVI: { __mpu_uint64_t dstptr, srcptr, count, dstoff, srcoff; __mpu_UNIT_t *dstbase, *srcbase; rc = reg_ptr64( &i->operand[0], &dstptr ); if( rc ) return( rc ); rc = reg_ptr64( &i->operand[1], &srcptr ); if( rc ) return( rc ); if( i->opcode == CPU_OP_BMOV ) { rc = reg_u64( &i->operand[2], &count ); if( rc ) return( rc ); } else { if( i->operand[2].type != CPU_OPERAND_IMM64 ) return( CPU_EXEC_OPERAND_FAULT ); count = i->operand[2].value.imm64; } /* Resolve and validate both complete ranges before modifying memory. */ rc = pointer_resolve( srcptr, count, 0, &srcbase, &srcoff ); if( rc ) return( rc ); rc = pointer_resolve( dstptr, count, 1, &dstbase, &dstoff ); if( rc ) return( rc ); if( (__mpu_uint64_t)(size_t)count != count ) return( CPU_EXEC_MEMORY_FAULT ); memmove( dstbase + dstoff, srcbase + srcoff, (size_t)count ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_PADD: case CPU_OP_PSUB: { __mpu_uint64_t ptr, out; __mpu_int64_t delta; rc = pointer_register( &i->operand[0], &d ); if( rc ) return( rc ); rc = reg_ptr64( &i->operand[1], &ptr ); if( rc ) return( rc ); rc = reg_i64( &i->operand[2], &delta ); if( rc ) return( rc ); rc = pointer_arith( ptr, delta, i->opcode == CPU_OP_PSUB, &out ); if( rc ) return( rc ); __cpu_data_put_u64( d, out ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_PADDI: case CPU_OP_PSUBI: { __mpu_uint64_t ptr, out; __mpu_int64_t delta; rc = pointer_register( &i->operand[0], &d ); if( rc ) return( rc ); rc = reg_ptr64( &i->operand[1], &ptr ); if( rc ) return( rc ); if( i->operand[2].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); delta = i->operand[2].value.off64; rc = pointer_arith( ptr, delta, i->opcode == CPU_OP_PSUBI, &out ); if( rc ) return( rc ); __cpu_data_put_u64( d, out ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_PDIFF: { __mpu_uint64_t left, right; __mpu_int64_t diff; rc = pointer_register( &i->operand[0], &d ); if( rc ) return( rc ); rc = reg_ptr64( &i->operand[1], &left ); if( rc ) return( rc ); rc = reg_ptr64( &i->operand[2], &right ); if( rc ) return( rc ); if( __cpu_ptr_segment( left ) != __cpu_ptr_segment( right ) ) return( CPU_EXEC_POINTER_FAULT ); diff = (__mpu_int64_t)__cpu_ptr_offset( left ) - (__mpu_int64_t)__cpu_ptr_offset( right ); { __mpu_uint64_t bits; memcpy( &bits, &diff, sizeof( bits ) ); __cpu_data_put_u64( d, bits ); } } return( CPU_EXEC_SUCCESS ); #define I3(op,fn) case op: rc=reg3(i,&d,&a,&b,&n);if(rc)return rc;fn((mpu_int*)d,(mpu_int*)a,(mpu_int*)b,(int)n);return 0 I3( CPU_OP_IADD, iadd ); I3( CPU_OP_IADC, iadc ); I3( CPU_OP_ISUB, isub ); I3( CPU_OP_ISBB, isbb ); I3( CPU_OP_IAND, iand ); I3( CPU_OP_IOR, ior ); I3( CPU_OP_IXOR, ixor ); #undef I3 #define I2(op,fn) case op: rc=reg2(i,&d,&a,&n);if(rc)return rc;fn((mpu_int*)d,(mpu_int*)a,(int)n);return 0 I2( CPU_OP_INOT, inot ); I2( CPU_OP_INEG, ineg ); I2( CPU_OP_ISHL, ishl ); I2( CPU_OP_ISHR, ishr ); I2( CPU_OP_ISAL, isal ); I2( CPU_OP_ISAR, isar ); I2( CPU_OP_IROL, irol ); I2( CPU_OP_IROR, iror ); I2( CPU_OP_IRCL, ircl ); I2( CPU_OP_IRCR, ircr ); I2( CPU_OP_IINC, iinc ); I2( CPU_OP_IDEC, idec ); #undef I2 case CPU_OP_IXCHG: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); ixchg( ( mpu_int * ) d, ( mpu_int * ) a, (int)n ); return( 0 ); case CPU_OP_ICPY: case CPU_OP_ICVT: { __mpu_size_t nd, na; rc = getreg( &i->operand[0], &d, &nd ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); if( i->opcode == CPU_OP_ICPY ) icpy( ( mpu_int * ) d, ( mpu_int * ) a, (int)nd, (int)na ); else { __mpu_uint32_t flags = cpu_status_flags_save(); icvt( ( mpu_int * ) d, ( mpu_int * ) a, (int)nd, (int)na ); cpu_status_flags_restore( flags ); } } return( 0 ); case CPU_OP_ISHLN: case CPU_OP_ISHRN: case CPU_OP_ISALN: case CPU_OP_ISARN: case CPU_OP_IROLN: case CPU_OP_IRORN: case CPU_OP_IRCLN: case CPU_OP_IRCRN: { __mpu_size_t nd, na; unsigned int count; rc = getreg( &i->operand[0], &d, &nd ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); if( nd != na ) return( CPU_EXEC_WIDTH_FAULT ); rc = reg_count32( &i->operand[2], &count ); if( rc ) return( rc ); switch( i->opcode ) { case CPU_OP_ISHLN: ishln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; case CPU_OP_ISHRN: ishrn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; case CPU_OP_ISALN: isaln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; case CPU_OP_ISARN: isarn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; case CPU_OP_IROLN: iroln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; case CPU_OP_IRORN: irorn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; case CPU_OP_IRCLN: ircln( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; default: ircrn( ( mpu_int * ) d, ( mpu_int * ) a, count, (int)nd ); break; } } return( 0 ); case CPU_OP_IMUL: case CPU_OP_ISMUL: { __mpu_size_t np, na, nb; rc = getreg( &i->operand[0], &d, &np ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &b, &nb ); if( rc ) return( rc ); if( na != nb || np < 2U * na ) return( CPU_EXEC_WIDTH_FAULT ); if( i->opcode == CPU_OP_IMUL ) imul( ( mpu_int * ) d, ( mpu_int * ) a, ( mpu_int * ) b, (int)np, (int)na ); else ismul( ( mpu_int * ) d, ( mpu_int * ) a, ( mpu_int * ) b, (int)np, (int)na ); } return( 0 ); case CPU_OP_IDIV: case CPU_OP_ISDIV: { __mpu_UNIT_t *q, *r, *num, *den; __mpu_size_t nq, nr, nn, nd; rc = getreg( &i->operand[0], &q, &nq ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &r, &nr ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &num, &nn ); if( rc ) return( rc ); rc = getreg( &i->operand[3], &den, &nd ); if( rc ) return( rc ); if( nq != nr || nq != nn || nq != nd ) return( CPU_EXEC_WIDTH_FAULT ); if( i->opcode == CPU_OP_IDIV ) idiv( ( mpu_int * ) q, ( mpu_int * ) r, ( mpu_int * ) num, ( mpu_int * ) den, (int)nq ); else isdiv( ( mpu_int * ) q, ( mpu_int * ) r, ( mpu_int * ) num, ( mpu_int * ) den, (int)nq ); } return( 0 ); case CPU_OP_IBITSLEN: { __mpu_size_t na; int v; rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); v = ibits_len( ( mpu_int * ) a, (int)na ); return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); } case CPU_OP_ICMP: case CPU_OP_ITEST: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); if( i->opcode == CPU_OP_ICMP ) icmp( ( mpu_int * ) d, ( mpu_int * ) a, (int)n ); else itest( ( mpu_int * ) d, ( mpu_int * ) a, (int)n ); return( 0 ); #define R3(op,fn,limit) case op: rc=reg3(i,&d,&a,&b,&n);if(rc)return rc;if(!valid_real(n)||n>(limit))return CPU_EXEC_WIDTH_FAULT;fn((mpu_real*)d,(mpu_real*)a,(mpu_real*)b,(int)n);return 0 R3( CPU_OP_RADD, r_add, NB_R_MAX ); R3( CPU_OP_RSUB, r_sub, NB_R_MAX ); R3( CPU_OP_RMUL, r_mul, NB_R_MAX ); R3( CPU_OP_RDIV, r_div, NB_R_MAX ); R3( CPU_OP_RPOW, r_pow, NB_R16384 ); R3( CPU_OP_RHYPOT, r_hypot, NB_R16384 ); R3( CPU_OP_RATAN2, r_atan2, NB_R16384 ); R3( CPU_OP_RREMAIN, r_remain, NB_R_MAX ); #undef R3 #define R2(op,fn,limit) case op: rc=reg2(i,&d,&a,&n);if(rc)return rc;if(!valid_real(n)||n>(limit))return CPU_EXEC_WIDTH_FAULT;fn((mpu_real*)d,(mpu_real*)a,(int)n);return 0 R2( CPU_OP_RSQRT, r_sqrt, NB_R16384 ); R2( CPU_OP_RSIN, r_sin, NB_R16384 ); R2( CPU_OP_RCOS, r_cos, NB_R16384 ); R2( CPU_OP_RTAN, r_tan, NB_R16384 ); R2( CPU_OP_RASIN, r_asin, NB_R16384 ); R2( CPU_OP_RACOS, r_acos, NB_R16384 ); R2( CPU_OP_RATAN, r_atan, NB_R16384 ); R2( CPU_OP_RLOG, r_log, NB_R16384 ); R2( CPU_OP_RLOG10, r_log10, NB_R16384 ); R2( CPU_OP_RLOG2, r_log2, NB_R16384 ); R2( CPU_OP_REXP, r_exp, NB_R16384 ); R2( CPU_OP_RSINH, r_sinh, NB_R16384 ); R2( CPU_OP_RCOSH, r_cosh, NB_R16384 ); R2( CPU_OP_RTANH, r_tanh, NB_R16384 ); R2( CPU_OP_RFLOOR, r_floor, NB_R_MAX ); R2( CPU_OP_RCEIL, r_ceil, NB_R_MAX ); R2( CPU_OP_RROUND, r_round, NB_R_MAX ); R2( CPU_OP_RLOG1P, r_log1p, NB_R16384 ); R2( CPU_OP_REXPM1, r_expm1, NB_R16384 ); R2( CPU_OP_RASINH, r_asinh, NB_R16384 ); R2( CPU_OP_RACOSH, r_acosh, NB_R16384 ); R2( CPU_OP_RATANH, r_atanh, NB_R16384 ); #undef R2 case CPU_OP_RNEG: case CPU_OP_RABS: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); if( d != a ) r_cpy( ( mpu_real * ) d, ( mpu_real * ) a, (int)n ); if( i->opcode == CPU_OP_RNEG ) r_neg( ( mpu_real * ) d, (int)n ); else r_abs( ( mpu_real * ) d, (int)n ); return( 0 ); case CPU_OP_RCPY: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); r_cpy( ( mpu_real * ) d, ( mpu_real * ) a, (int)n ); return( 0 ); case CPU_OP_RCVT: { __mpu_size_t nd, na; rc = getreg( &i->operand[0], &d, &nd ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); if( !valid_real( nd ) || !valid_real( na ) ) return( CPU_EXEC_WIDTH_FAULT ); { __mpu_uint32_t flags = cpu_status_flags_save(); r_cvt( ( mpu_real * ) d, ( mpu_real * ) a, (int)nd, (int)na ); cpu_status_flags_restore( flags ); } } return( 0 ); case CPU_OP_RCMP: { __mpu_size_t na, nb; int v; rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &b, &nb ); if( rc ) return( rc ); if( na != nb || !valid_real( na ) ) return( CPU_EXEC_WIDTH_FAULT ); v = r_cmp( ( mpu_real * ) a, ( mpu_real * ) b, (int)na ); return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); } case CPU_OP_RFREXP: { __mpu_UNIT_t *sig, *exp, *src; __mpu_size_t nsig, nexp, nsrc; rc = getreg( &i->operand[0], &sig, &nsig ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &exp, &nexp ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &src, &nsrc ); if( rc ) return( rc ); if( nsig != nsrc || !valid_real( nsig ) ) return( CPU_EXEC_WIDTH_FAULT ); r_frexp( ( mpu_real * ) sig, ( mpu_int * ) exp, ( mpu_real * ) src, (int)nexp, (int)nsrc ); } return( 0 ); case CPU_OP_RLDEXP: { __mpu_UNIT_t *dst, *src, *exp; __mpu_size_t ndst, nsrc, nexp; rc = getreg( &i->operand[0], &dst, &ndst ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &src, &nsrc ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &exp, &nexp ); if( rc ) return( rc ); if( ndst != nsrc || !valid_real( ndst ) ) return( CPU_EXEC_WIDTH_FAULT ); r_ldexp( ( mpu_real * ) dst, ( mpu_real * ) src, ( mpu_int * ) exp, (int)ndst, (int)nexp ); } return( 0 ); case CPU_OP_RLOGB: { __mpu_UNIT_t *dst, *src; __mpu_size_t ndst, nsrc; rc = getreg( &i->operand[0], &dst, &ndst ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &src, &nsrc ); if( rc ) return( rc ); if( !valid_real( nsrc ) ) return( CPU_EXEC_WIDTH_FAULT ); r_logb( ( mpu_int * ) dst, ( mpu_real * ) src, (int)ndst, (int)nsrc ); } return( 0 ); case CPU_OP_RMODF: { __mpu_UNIT_t *frac, *integ, *src; __mpu_size_t nf, ni, ns; rc = getreg( &i->operand[0], &frac, &nf ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &integ, &ni ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &src, &ns ); if( rc ) return( rc ); if( nf != ni || nf != ns || !valid_real( nf ) ) return( CPU_EXEC_WIDTH_FAULT ); r_modf( ( mpu_real * ) frac, ( mpu_real * ) integ, ( mpu_real * ) src, (int)nf ); } return( 0 ); case CPU_OP_ITOR: case CPU_OP_UITOR: { __mpu_UNIT_t *rdst, *isrc; __mpu_size_t nr, ni; rc = getreg( &i->operand[0], &rdst, &nr ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &isrc, &ni ); if( rc ) return( rc ); if( !valid_real( nr ) ) return( CPU_EXEC_WIDTH_FAULT ); { __mpu_uint32_t flags = cpu_status_flags_save(); if( i->opcode == CPU_OP_ITOR ) ltor( ( mpu_real * ) rdst, ( mpu_int * ) isrc, (int)nr, (int)ni ); else ultor( ( mpu_real * ) rdst, ( mpu_int * ) isrc, (int)nr, (int)ni ); cpu_status_flags_restore( flags ); } } return( 0 ); case CPU_OP_RTOI: case CPU_OP_RTOUI: { __mpu_UNIT_t *idst, *frac, *src; __mpu_size_t ni, nf, ns; rc = getreg( &i->operand[0], &idst, &ni ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &frac, &nf ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &src, &ns ); if( rc ) return( rc ); if( nf != ns || !valid_real( nf ) ) return( CPU_EXEC_WIDTH_FAULT ); { __mpu_uint32_t flags = cpu_status_flags_save(); if( i->opcode == CPU_OP_RTOI ) rtol_frac( ( mpu_int * ) idst, ( mpu_real * ) frac, ( mpu_real * ) src, (int)ni, (int)ns ); else rtoul_frac( ( mpu_int * ) idst, ( mpu_real * ) frac, ( mpu_real * ) src, (int)ni, (int)ns ); cpu_status_flags_restore( flags ); } } return( 0 ); case CPU_OP_RISNEG: case CPU_OP_RSIGN: case CPU_OP_RISIND: case CPU_OP_RISNAN: case CPU_OP_RISNANMAX: case CPU_OP_RISNANMIN: case CPU_OP_RISINF: case CPU_OP_RISSIGNULL: { __mpu_size_t ns; int v; rc = getreg( &i->operand[1], &a, &ns ); if( rc ) return( rc ); if( !valid_real( ns ) ) return( CPU_EXEC_WIDTH_FAULT ); switch( i->opcode ) { case CPU_OP_RISNEG: v = r_is_neg( ( mpu_real * ) a, (int)ns ); break; case CPU_OP_RSIGN: v = r_sign( ( mpu_real * ) a, (int)ns ); break; case CPU_OP_RISIND: v = _is_ind( ( mpu_real * ) a, (int)ns ); break; case CPU_OP_RISNAN: v = _is_nans( ( mpu_real * ) a, (int)ns ); break; case CPU_OP_RISNANMAX: v = _is_nan_max( ( mpu_real * ) a, (int)ns ); break; case CPU_OP_RISNANMIN: v = _is_nan_min( ( mpu_real * ) a, (int)ns ); break; case CPU_OP_RISINF: v = _is_inf( ( mpu_real * ) a, (int)ns ); break; default: v = _is_signull( ( mpu_real * ) a, (int)ns ); break; } return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); } case CPU_OP_RCONST: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( !valid_real( n ) ) return( CPU_EXEC_WIDTH_FAULT ); if( i->operand[1].type != CPU_OPERAND_CONST8 ) return( CPU_EXEC_OPERAND_FAULT ); return( rconst( ( mpu_real * ) d, (int)n, i->operand[1].value.const8 ) ); #define C3(op,fn,limit) case op: rc=reg3(i,&d,&a,&b,&n);if(rc)return rc;if(!valid_complex(n)||n>(limit))return CPU_EXEC_WIDTH_FAULT;fn((mpu_complex*)d,(mpu_complex*)a,(mpu_complex*)b,(int)(n/2));return 0 C3( CPU_OP_CADD, c_add, NB_C_MAX ); C3( CPU_OP_CSUB, c_sub, NB_C_MAX ); C3( CPU_OP_CMUL, c_mul, NB_C_MAX ); C3( CPU_OP_CDIV, c_div, NB_C_MAX ); C3( CPU_OP_CPOW, c_pow, NB_C32768 ); #undef C3 #define C2(op,fn) case op: rc=reg2(i,&d,&a,&n);if(rc)return rc;if(!valid_complex(n)||n>NB_C32768)return CPU_EXEC_WIDTH_FAULT;fn((mpu_complex*)d,(mpu_complex*)a,(int)(n/2));return 0 C2( CPU_OP_CEXP, c_exp ); C2( CPU_OP_CSIN, c_sin ); C2( CPU_OP_CCOS, c_cos ); C2( CPU_OP_CSINH, c_sinh ); C2( CPU_OP_CCOSH, c_cosh ); C2( CPU_OP_CLOG, c_log ); C2( CPU_OP_CSQRT, c_sqrt ); #undef C2 case CPU_OP_CCONJ: case CPU_OP_CCPY: rc = reg2( i, &d, &a, &n ); if( rc ) return( rc ); if( !valid_complex( n ) ) return( CPU_EXEC_WIDTH_FAULT ); if( i->opcode == CPU_OP_CCONJ ) c_conj( ( mpu_complex * ) d, ( mpu_complex * ) a, (int)( n / 2 ) ); else c_cpy( ( mpu_complex * ) d, ( mpu_complex * ) a, (int)( n / 2 ) ); return( 0 ); case CPU_OP_CCVT: { __mpu_size_t nd, ns; rc = getreg( &i->operand[0], &d, &nd ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &ns ); if( rc ) return( rc ); if( !valid_complex( nd ) || !valid_complex( ns ) ) return( CPU_EXEC_WIDTH_FAULT ); { __mpu_uint32_t flags = cpu_status_flags_save(); c_cvt( ( mpu_complex * ) d, ( mpu_complex * ) a, (int)( nd / 2 ), (int)( ns / 2 ) ); cpu_status_flags_restore( flags ); } } return( 0 ); case CPU_OP_CREAL: case CPU_OP_CIMAG: case CPU_OP_CABS: case CPU_OP_CNORM: case CPU_OP_CARG: { __mpu_size_t nr, nc; rc = getreg( &i->operand[0], &d, &nr ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &nc ); if( rc ) return( rc ); if( !valid_real( nr ) || !valid_complex( nc ) || nc != 2U * nr ) return( CPU_EXEC_WIDTH_FAULT ); if( ( i->opcode == CPU_OP_CABS || i->opcode == CPU_OP_CARG ) && nr > NB_R16384 ) return( CPU_EXEC_WIDTH_FAULT ); switch( i->opcode ) { case CPU_OP_CREAL: c_real_part( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); break; case CPU_OP_CIMAG: c_imaginary( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); break; case CPU_OP_CABS: c_abs( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); break; case CPU_OP_CNORM: c_norm( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); break; default: c_arg( ( mpu_real * ) d, ( mpu_complex * ) a, (int)nr ); break; } } return( 0 ); case CPU_OP_CRTOC: { __mpu_size_t nc, nr; rc = getreg( &i->operand[0], &d, &nc ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &nr ); if( rc ) return( rc ); if( !valid_complex( nc ) || !valid_real( nr ) || nc != 2U * nr ) return( CPU_EXEC_WIDTH_FAULT ); { __mpu_uint32_t flags = cpu_status_flags_save(); c_real_to_complex( ( mpu_complex * ) d, ( mpu_real * ) a, (int)nr ); cpu_status_flags_restore( flags ); } } return( 0 ); case CPU_OP_CGEN: case CPU_OP_CPOLAR: { __mpu_size_t nc, nr, ni; rc = getreg( &i->operand[0], &d, &nc ); if( rc ) return( rc ); rc = getreg( &i->operand[1], &a, &nr ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &b, &ni ); if( rc ) return( rc ); if( nr != ni || !valid_real( nr ) || !valid_complex( nc ) || nc != 2U * nr ) return( CPU_EXEC_WIDTH_FAULT ); if( i->opcode == CPU_OP_CPOLAR && nr > NB_R16384 ) return( CPU_EXEC_WIDTH_FAULT ); if( i->opcode == CPU_OP_CGEN ) c_gen_complex( ( mpu_complex * ) d, ( mpu_real * ) a, ( mpu_real * ) b, (int)nr ); else c_polar( ( mpu_complex * ) d, ( mpu_real * ) a, ( mpu_real * ) b, (int)nr ); } return( 0 ); case CPU_OP_CISEQ: case CPU_OP_CISNE: { __mpu_size_t na, nb; int v; rc = getreg( &i->operand[1], &a, &na ); if( rc ) return( rc ); rc = getreg( &i->operand[2], &b, &nb ); if( rc ) return( rc ); if( na != nb || !valid_complex( na ) ) return( CPU_EXEC_WIDTH_FAULT ); v = ( i->opcode == CPU_OP_CISEQ ) ? c_is_equal( ( mpu_complex * ) a, ( mpu_complex * ) b, (int)( na / 2 ) ): c_is_nequal( ( mpu_complex * ) a, ( mpu_complex * ) b, (int)( na / 2 ) ); return( put_i64_result( &i->operand[0], (__mpu_int64_t)v ) ); } case CPU_OP_JMP: if( i->operand[0].type != CPU_OPERAND_CODE64 ) return( CPU_EXEC_OPERAND_FAULT ); if( i->operand[0].value.code64 >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); __PC = i->operand[0].value.code64; return( CPU_EXEC_BRANCH ); case CPU_OP_JMPP: { __mpu_uint64_t target; rc = code_pointer_target( &i->operand[0], &target ); if( rc ) return( rc ); __PC = target; } return( CPU_EXEC_BRANCH ); case CPU_OP_JSET: case CPU_OP_JCLR: if( i->operand[0].type != CPU_OPERAND_PSWBIT8 || i->operand[1].type != CPU_OPERAND_CODE64) return( CPU_EXEC_OPERAND_FAULT ); if( i->operand[0].value.pswbit8 > CPU_PSWBIT_MAX ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint32_t mask = (__mpu_uint32_t)1U << i->operand[0].value.pswbit8; int set = ( ( __cpu_get_psw() & mask ) != 0 ); int take = ( i->opcode == CPU_OP_JSET ) ? set : !set; if( take ) { if( i->operand[1].value.code64 >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); __PC = i->operand[1].value.code64; return( CPU_EXEC_BRANCH ); } } return( CPU_EXEC_SUCCESS ); case CPU_OP_CALL: if( i->operand[0].type != CPU_OPERAND_CODE64 ) return( CPU_EXEC_OPERAND_FAULT ); if( i->operand[0].value.code64 >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); if( __PC > __PSIZE || ( CPU_OPCODE_SIZE + CPU_CODE64_SIZE ) > __PSIZE - __PC ) return( CPU_EXEC_MEMORY_FAULT ); { __mpu_uint64_t ret = __PC + CPU_OPCODE_SIZE + CPU_CODE64_SIZE; __mpu_uint64_t p; if( ret >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_CODE64_SIZE > __SP ) return( CPU_EXEC_STACK_FAULT ); p = __SP - CPU_CODE64_SIZE; __cpu_data_put_u64( __STACK + p, ret ); __SP = p; __PC = i->operand[0].value.code64; } return( CPU_EXEC_BRANCH ); case CPU_OP_CALLP: { const __mpu_uint64_t ilen = CPU_OPCODE_SIZE + CPU_REG24_SIZE; __mpu_uint64_t target, ret, p; /* Validate every source of failure before touching STACK, SP or PC. */ rc = code_pointer_target( &i->operand[0], &target ); if( rc ) return( rc ); if( __PC > __PSIZE || ilen > __PSIZE - __PC ) return( CPU_EXEC_MEMORY_FAULT ); ret = __PC + ilen; if( ret >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_CODE64_SIZE > __SP ) return( CPU_EXEC_STACK_FAULT ); p = __SP - CPU_CODE64_SIZE; __cpu_data_put_u64( __STACK + p, ret ); __SP = p; __PC = target; } return( CPU_EXEC_BRANCH ); case CPU_OP_RET: { __mpu_uint64_t target; if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_CODE64_SIZE > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); target = __cpu_data_get_u64( __STACK + __SP ); if( target >= __PSIZE ) return( CPU_EXEC_MEMORY_FAULT ); __SP+=CPU_CODE64_SIZE; __PC = target; } return( CPU_EXEC_BRANCH ); case CPU_OP_PUSH: rc = getreg( &i->operand[0], &a, &n ); if( rc ) return( rc ); if( !__STACK || !__SSIZE || __SP > __SSIZE || (__mpu_uint64_t)n > __SP ) return( CPU_EXEC_STACK_FAULT ); { __mpu_uint64_t p = __SP - (__mpu_uint64_t)n; memmove( __STACK + p, a, n ); __SP = p; } return( CPU_EXEC_SUCCESS ); case CPU_OP_POP: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( !__STACK || !__SSIZE || __SP > __SSIZE || (__mpu_uint64_t)n > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); memmove( d, __STACK + __SP, n ); __SP += (__mpu_uint64_t)n; return( CPU_EXEC_SUCCESS ); case CPU_OP_LDSP: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint64_t p; rc = stack_offset( i->operand[1].value.off64, (__mpu_uint64_t)n, &p ); if( rc ) return( rc ); memmove( d, __STACK + p, n ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_STSP: if( i->operand[0].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); rc = getreg( &i->operand[1], &a, &n ); if( rc ) return( rc ); { __mpu_uint64_t p; rc = stack_offset( i->operand[0].value.off64, (__mpu_uint64_t)n, &p ); if( rc ) return( rc ); memmove( __STACK + p, a, n ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_ADJSP: if( i->operand[0].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint64_t p; rc = stack_offset( i->operand[0].value.off64, 0, &p ); if( rc ) return( rc ); __SP = p; } return( CPU_EXEC_SUCCESS ); case CPU_OP_PUSHFP: if( !__STACK || !__SSIZE || __SP > __SSIZE || __FP > __SSIZE || CPU_PTR64_SIZE > __SP ) return( CPU_EXEC_STACK_FAULT ); { __mpu_uint64_t p = __SP - CPU_PTR64_SIZE; __cpu_data_put_u64( __STACK + p, __FP ); __SP = p; } return( CPU_EXEC_SUCCESS ); case CPU_OP_SETFP: if( !__STACK || !__SSIZE || __SP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); __FP = __SP; return( CPU_EXEC_SUCCESS ); case CPU_OP_RESTSP: if( !__STACK || !__SSIZE || __FP > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); __SP = __FP; return( CPU_EXEC_SUCCESS ); case CPU_OP_POPFP: { __mpu_uint64_t oldfp; if( !__STACK || !__SSIZE || __SP > __SSIZE || CPU_PTR64_SIZE > __SSIZE - __SP ) return( CPU_EXEC_STACK_FAULT ); oldfp = __cpu_data_get_u64( __STACK + __SP ); if( oldfp > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); __FP = oldfp; __SP+=CPU_PTR64_SIZE; } return( CPU_EXEC_SUCCESS ); case CPU_OP_LDFP: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint64_t p; rc = frame_offset( i->operand[1].value.off64, (__mpu_uint64_t)n, &p ); if( rc ) return( rc ); memmove( d, __STACK + p, n ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_STFP: if( i->operand[0].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); rc = getreg( &i->operand[1], &a, &n ); if( rc ) return( rc ); { __mpu_uint64_t p; rc = frame_offset( i->operand[0].value.off64, (__mpu_uint64_t)n, &p ); if( rc ) return( rc ); memmove( __STACK + p, a, n ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_LEAFP: rc = getreg( &i->operand[0], &d, &n ); if( rc ) return( rc ); if( n != CPU_PTR64_SIZE ) return( CPU_EXEC_WIDTH_FAULT ); if( i->operand[1].type != CPU_OPERAND_OFF64 ) return( CPU_EXEC_OPERAND_FAULT ); { __mpu_uint64_t pos, ptr; rc = frame_offset( i->operand[1].value.off64, 0, &pos ); if( rc ) return( rc ); if( pos > CPU_PTR_OFFSET_MASK ) return( CPU_EXEC_POINTER_FAULT ); if( __cpu_ptr_make( &ptr, CPU_PTR_SEG_STACK, pos ) ) return( CPU_EXEC_POINTER_FAULT ); __cpu_data_put_u64( d, ptr ); } return( CPU_EXEC_SUCCESS ); case CPU_OP_SETSP: rc = pointer_register( &i->operand[0], &a ); if( rc ) return( rc ); { __mpu_uint64_t ptr, off; unsigned int seg; ptr = __cpu_data_get_u64( a ); seg = __cpu_ptr_segment( ptr ); off = __cpu_ptr_offset( ptr ); if( seg != CPU_PTR_SEG_STACK ) return( CPU_EXEC_POINTER_FAULT ); if( !__STACK || !__SSIZE || off > __SSIZE ) return( CPU_EXEC_STACK_FAULT ); __SP = off; } return( CPU_EXEC_SUCCESS ); default: return( CPU_EXEC_OPCODE_FAULT ); } } static int decode_need( __mpu_uint64_t program_size, __mpu_uint64_t pos, __mpu_uint64_t n ) { return( pos <= program_size && n <= program_size - pos ); } static int decode_reg( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, cpu_operand *o, __mpu_uint64_t *p ) { if( !decode_need( program_size, *p, 3 ) || __cpu_decode_reg24( &o->value.reg, program + *p ) ) return( -1 ); o->type = CPU_OPERAND_REGISTER; *p += 3; return( 0 ); } static int decode_u64( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, cpu_operand *o, __mpu_uint64_t *p, cpu_operand_type t ) { __mpu_uint64_t v; if( !decode_need( program_size, *p, 8 ) ) return( -1 ); v = __cpu_code_get_u64( program + *p ); *p += 8; o->type = t; if( t == CPU_OPERAND_IMM64 ) o->value.imm64 = v; else if( t == CPU_OPERAND_ADDR64 ) o->value.addr64 = v; else if( t == CPU_OPERAND_CODE64 ) o->value.code64 = v; else if( t == CPU_OPERAND_OFF64 ) memcpy( &o->value.off64, &v, sizeof( v ) ); else if( t == CPU_OPERAND_PTR64 ) o->value.ptr64 = v; else return( -1 ); return( 0 ); } static int decode_u8( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, cpu_operand *o, __mpu_uint64_t *p, cpu_operand_type t ) { __mpu_uint8_t v; if( !decode_need( program_size, *p, 1 ) ) return( -1 ); v = program[ ( *p )++]; o->type = t; if( t == CPU_OPERAND_CONST8 ) o->value.const8 = v; else if( t == CPU_OPERAND_PSWBIT8 ) o->value.pswbit8 = v; else return( -1 ); return( 0 ); } int __cpu_decode_at( const __mpu_UNIT_t *program, __mpu_uint64_t program_size, __mpu_uint64_t pc, cpu_instruction *i ) { __mpu_uint64_t p = pc, start = p; __mpu_uint16_t op; int k; if( !i || !program || !decode_need( program_size, p, 2 ) ) return( CPU_EXEC_DECODE_FAULT ); memset( i, 0, sizeof( *i ) ); op = __cpu_code_get_u16( program + p ); p += 2; i->opcode = (cpu_opcode)op; #define DR(n) do{for(k=0;k<(n);k++)if(decode_reg(program,program_size,&i->operand[k],&p))return CPU_EXEC_DECODE_FAULT;}while(0) switch( op ) { case CPU_OP_NOP:case CPU_OP_HALT:case CPU_OP_END:case CPU_OP_SYSCALL:case CPU_OP_RET: case CPU_OP_CLRCPUF:case CPU_OP_CLRMPUF: case CPU_OP_PUSHFP:case CPU_OP_SETFP:case CPU_OP_RESTSP:case CPU_OP_POPFP:break; case CPU_OP_SETF:case CPU_OP_CLRF: if( decode_u8( program, program_size, &i->operand[0], &p, CPU_OPERAND_PSWBIT8 ) ) return( CPU_EXEC_DECODE_FAULT ); if( i->operand[0].value.pswbit8 > CPU_PSWBIT_WRITE_MAX ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_CLR: case CPU_OP_EXIT: DR( 1 ); break; case CPU_OP_MOV:case CPU_OP_SWAP:case CPU_OP_BSWAP: case CPU_OP_INOT:case CPU_OP_INEG:case CPU_OP_ICMP:case CPU_OP_ITEST: case CPU_OP_ISHL:case CPU_OP_ISHR:case CPU_OP_ISAL:case CPU_OP_ISAR: case CPU_OP_IROL:case CPU_OP_IROR:case CPU_OP_IRCL:case CPU_OP_IRCR: case CPU_OP_IINC:case CPU_OP_IDEC:case CPU_OP_IXCHG:case CPU_OP_ICPY: case CPU_OP_ICVT:case CPU_OP_IBITSLEN: case CPU_OP_RSQRT:case CPU_OP_RSIN:case CPU_OP_RCOS:case CPU_OP_RTAN: case CPU_OP_RASIN:case CPU_OP_RACOS:case CPU_OP_RATAN: case CPU_OP_RLOG:case CPU_OP_RLOG10:case CPU_OP_RLOG2:case CPU_OP_REXP: case CPU_OP_RSINH:case CPU_OP_RCOSH:case CPU_OP_RTANH: case CPU_OP_RNEG:case CPU_OP_RABS:case CPU_OP_RCPY:case CPU_OP_RCVT: case CPU_OP_RFLOOR:case CPU_OP_RCEIL:case CPU_OP_RROUND:case CPU_OP_RLOGB: case CPU_OP_RLOG1P:case CPU_OP_REXPM1:case CPU_OP_RASINH:case CPU_OP_RACOSH:case CPU_OP_RATANH: case CPU_OP_ITOR:case CPU_OP_UITOR: case CPU_OP_RISNEG:case CPU_OP_RSIGN:case CPU_OP_RISIND:case CPU_OP_RISNAN: case CPU_OP_RISNANMAX:case CPU_OP_RISNANMIN:case CPU_OP_RISINF:case CPU_OP_RISSIGNULL: case CPU_OP_CEXP:case CPU_OP_CSIN:case CPU_OP_CCOS:case CPU_OP_CSINH: case CPU_OP_CCOSH:case CPU_OP_CLOG:case CPU_OP_CSQRT: case CPU_OP_CREAL:case CPU_OP_CIMAG:case CPU_OP_CRTOC:case CPU_OP_CCONJ: case CPU_OP_CABS:case CPU_OP_CNORM:case CPU_OP_CARG:case CPU_OP_CCPY:case CPU_OP_CCVT: DR( 2 ); break; case CPU_OP_IADD:case CPU_OP_IADC:case CPU_OP_ISUB:case CPU_OP_ISBB: case CPU_OP_IAND:case CPU_OP_IOR:case CPU_OP_IXOR: case CPU_OP_ISHLN:case CPU_OP_ISHRN:case CPU_OP_ISALN:case CPU_OP_ISARN: case CPU_OP_IROLN:case CPU_OP_IRORN:case CPU_OP_IRCLN:case CPU_OP_IRCRN: case CPU_OP_IMUL:case CPU_OP_ISMUL: case CPU_OP_RADD:case CPU_OP_RSUB:case CPU_OP_RMUL:case CPU_OP_RDIV: case CPU_OP_RPOW:case CPU_OP_RHYPOT:case CPU_OP_RATAN2:case CPU_OP_RCMP: case CPU_OP_RFREXP:case CPU_OP_RLDEXP:case CPU_OP_RMODF:case CPU_OP_RREMAIN: case CPU_OP_RTOI:case CPU_OP_RTOUI: case CPU_OP_CADD:case CPU_OP_CSUB:case CPU_OP_CMUL:case CPU_OP_CDIV:case CPU_OP_CPOW: case CPU_OP_CGEN:case CPU_OP_CPOLAR:case CPU_OP_CISEQ:case CPU_OP_CISNE: DR( 3 ); break; case CPU_OP_IDIV: case CPU_OP_ISDIV: DR( 4 ); break; case CPU_OP_LDI: case CPU_OP_LDR: case CPU_OP_LDC: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_IMM64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_LOAD: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_ADDR64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_STORE: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_ADDR64 ) ) return( CPU_EXEC_DECODE_FAULT ); if( decode_reg( program, program_size, &i->operand[1], &p ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_LEA: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_PTR64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_LEASP: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_LOADP: case CPU_OP_STOREP: DR( 2 ); break; case CPU_OP_PADD: case CPU_OP_PSUB: case CPU_OP_PDIFF: case CPU_OP_BMOV: DR( 3 ); break; case CPU_OP_BMOVI: DR( 2 ); if( decode_u64( program, program_size, &i->operand[2], &p, CPU_OPERAND_IMM64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_PADDI:case CPU_OP_PSUBI: DR( 2 ); if( decode_u64( program, program_size, &i->operand[2], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_RCONST: DR( 1 ); if( decode_u8( program, program_size, &i->operand[1], &p, CPU_OPERAND_CONST8 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_JMP: case CPU_OP_CALL: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_CODE64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_JMPP: case CPU_OP_CALLP: DR( 1 ); break; case CPU_OP_JSET:case CPU_OP_JCLR: if( decode_u8( program, program_size, &i->operand[0], &p, CPU_OPERAND_PSWBIT8 ) ) return( CPU_EXEC_DECODE_FAULT ); if( i->operand[0].value.pswbit8 > CPU_PSWBIT_MAX ) return( CPU_EXEC_DECODE_FAULT ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_CODE64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_PUSH: case CPU_OP_POP: DR( 1 ); break; case CPU_OP_LDSP: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_STSP: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); if( decode_reg( program, program_size, &i->operand[1], &p ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_ADJSP: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_LDFP: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_STFP: if( decode_u64( program, program_size, &i->operand[0], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); if( decode_reg( program, program_size, &i->operand[1], &p ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_LEAFP: DR( 1 ); if( decode_u64( program, program_size, &i->operand[1], &p, CPU_OPERAND_OFF64 ) ) return( CPU_EXEC_DECODE_FAULT ); break; case CPU_OP_SETSP: DR( 1 ); break; default: return( CPU_EXEC_OPCODE_FAULT ); } #undef DR i->length = p - start; return( 0 ); } int __cpu_decode( cpu_instruction *i ) { return( __cpu_decode_at( __PROGRAM, __PSIZE, __PC, i ) ); } /* End of __cpu_decode() */ int __cpu_step( void ) { cpu_instruction i; int rc = __cpu_decode( &i ); if( rc ) { __STOP_REASON = CPU_STOP_FAULT; return( rc ); } rc = __cpu_exec( &i ); if( rc == CPU_EXEC_BRANCH ) { if( __cpu_gth() ) { __STOP_REASON = CPU_STOP_HALT; return( CPU_EXEC_HALT ); } return( CPU_EXEC_SUCCESS ); } if( rc == CPU_EXEC_END ) { __PC += i.length; __STOP_REASON = CPU_STOP_END; return( rc ); } if( rc == CPU_EXEC_EXIT ) { __PC += i.length; __STOP_REASON = CPU_STOP_EXIT; return( rc ); } if( rc < 0 ) { __STOP_REASON = CPU_STOP_FAULT; return( rc ); } if( rc ) return( rc ); __PC+=i.length; if( __cpu_gth() ) { __STOP_REASON = CPU_STOP_HALT; return( CPU_EXEC_HALT ); } return( CPU_EXEC_SUCCESS ); } int __cpu_run( void ) { int rc; __cpu_clh(); __cpu_clear_stop_reason(); for( ; ; ) { rc = __cpu_step(); if( rc == CPU_EXEC_HALT ) return( CPU_EXEC_SUCCESS ); if( rc != CPU_EXEC_SUCCESS ) return( rc ); } }