diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /cpu/cpu-instruction.c | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'cpu/cpu-instruction.c')
| -rw-r--r-- | cpu/cpu-instruction.c | 1649 |
1 files changed, 1649 insertions, 0 deletions
diff --git a/cpu/cpu-instruction.c b/cpu/cpu-instruction.c new file mode 100644 index 0000000..4a6b59e --- /dev/null +++ b/cpu/cpu-instruction.c @@ -0,0 +1,1649 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <string.h> +#include <libmcpu.h> +#include <cpu-context.h> +#include <cpu-registers.h> +#include <cpu-instruction.h> +#include <cpu-syscalls.h> + +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 ); + } +} |
