summaryrefslogtreecommitdiff
path: root/cpu/cpu-instruction.c
diff options
context:
space:
mode:
authorkx <kx@radix-linux.su>2026-10-09 18:00:15 +0300
committerkx <kx@radix-linux.su>2026-10-09 18:00:15 +0300
commit065da3509019b15dd0e678072e6be629e5330bef (patch)
tree69c934c9e786ac048b4fbe8f4c4c5571661521f4 /cpu/cpu-instruction.c
parentd130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff)
downloadlibmcpu-0.4.0.tar.xz
Version 0.4.00.4.0
Diffstat (limited to 'cpu/cpu-instruction.c')
-rw-r--r--cpu/cpu-instruction.c1649
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 );
+ }
+}