summaryrefslogtreecommitdiff
path: root/tests/tst-mpu-coverage.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-mpu-coverage.c')
-rw-r--r--tests/tst-mpu-coverage.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/tests/tst-mpu-coverage.c b/tests/tst-mpu-coverage.c
new file mode 100644
index 0000000..0c8e3a3
--- /dev/null
+++ b/tests/tst-mpu-coverage.c
@@ -0,0 +1,580 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libmcpu.h>
+
+static int failures;
+#define CHECK(c,m) do { if(!(c)){ fprintf(stderr,"FAIL: %s\n",(m)); ++failures; } } while(0)
+
+static cpu_operand
+R( unsigned bits, __mpu_uint32_t addr )
+{
+ cpu_operand o;
+ memset( &o, 0, sizeof( o ) );
+ o.type = CPU_OPERAND_REGISTER;
+ o.value.reg.bits = bits;
+ o.value.reg.address = addr;
+ return( o );
+}
+
+static void
+I( cpu_instruction *i, cpu_opcode op )
+{
+ memset( i, 0, sizeof( *i ) );
+ i->opcode = op;
+}
+
+static __mpu_UNIT_t *
+P( unsigned bits, __mpu_uint32_t addr )
+{
+ return( __cpu_reg_ptr( bits, addr ) );
+}
+
+static void
+put64( unsigned addr, __mpu_uint64_t v )
+{
+ __cpu_data_put_u64( P( 64, addr ), v );
+}
+
+static __mpu_uint64_t
+get64( unsigned addr )
+{
+ return( __cpu_data_get_u64( P( 64, addr ) ) );
+}
+
+static __mpu_int64_t
+geti64( unsigned addr )
+{
+ __mpu_uint64_t u = get64( addr );
+ __mpu_int64_t v;
+ memcpy( &v, &u, 8 );
+ return( v );
+}
+
+static void
+setreal( unsigned bits, unsigned addr, const char *s )
+{
+ int nb = (int)( bits / 8U );
+ CHECK( ascii_to_real( ( mpu_real * ) P( bits, addr ), (__mpu_char8_t *)s, nb ) >= 0, "ascii_to_real" );
+}
+
+int
+main( void )
+{
+ cpu_instruction x;
+ __cpu_init();
+
+ /* Integer shifts/rotates: compare CPU output with the matching LibMPU API. */
+ {
+ struct S
+ {
+ cpu_opcode op;
+ void( *fn )( mpu_int *, mpu_int *, int );
+ const char *n;
+ }
+ v[] =
+ {
+ {CPU_OP_ISHL,ishl,"ISHL"},{CPU_OP_ISHR,ishr,"ISHR"},{CPU_OP_ISAL,isal,"ISAL"},{CPU_OP_ISAR,isar,"ISAR"},
+ {CPU_OP_IROL,irol,"IROL"},{CPU_OP_IROR,iror,"IROR"},{CPU_OP_IRCL,ircl,"IRCL"},{CPU_OP_IRCR,ircr,"IRCR"}
+ };
+ unsigned k;
+ mpu_int8_t ref, src;
+ for( k = 0; k < sizeof( v ) / sizeof( v[0] ); k++ )
+ {
+ src[0] = 0x81;
+ ref[0] = 0;
+ if( v[k].op == CPU_OP_IRCL || v[k].op == CPU_OP_IRCR ) __mpu_stc();
+ else __mpu_clc();
+ v[k].fn( ( mpu_int * ) ref, ( mpu_int * ) src, 1 );
+ *P( 8, 0x100 ) = 0x81;
+ *P( 8, 0x101 ) = 0;
+ if( v[k].op == CPU_OP_IRCL || v[k].op == CPU_OP_IRCR ) __mpu_stc();
+ else __mpu_clc();
+ I( &x, v[k].op );
+ x.operand[0] = R( 8, 0x101 );
+ x.operand[1] = R( 8, 0x100 );
+ CHECK( __cpu_exec( &x ) == 0, v[k].n );
+ CHECK( *P( 8, 0x101 ) == ref[0], v[k].n );
+ }
+ }
+ {
+ struct N
+ {
+ cpu_opcode op;
+ void( *fn )( mpu_int *, mpu_int *, unsigned int, int );
+ const char *n;
+ }
+ v[] =
+ {
+ {CPU_OP_ISHLN,ishln,"ISHLN"},{CPU_OP_ISHRN,ishrn,"ISHRN"},{CPU_OP_ISALN,isaln,"ISALN"},{CPU_OP_ISARN,isarn,"ISARN"},
+ {CPU_OP_IROLN,iroln,"IROLN"},{CPU_OP_IRORN,irorn,"IRORN"},{CPU_OP_IRCLN,ircln,"IRCLN"},{CPU_OP_IRCRN,ircrn,"IRCRN"}
+ };
+ unsigned k;
+ mpu_int16_t ref, src;
+ for( k = 0; k < sizeof( v ) / sizeof( v[0] ); k++ )
+ {
+ __cpu_data_put_u16( src, 0x8123 );
+ if( v[k].op == CPU_OP_IRCLN || v[k].op == CPU_OP_IRCRN ) __mpu_stc();
+ else __mpu_clc();
+ v[k].fn( ( mpu_int * ) ref, ( mpu_int * ) src, 3, 2 );
+ __cpu_data_put_u16( P( 16, 0x120 ), 0x8123 );
+ put64( 0x128, 3 );
+ if( v[k].op == CPU_OP_IRCLN || v[k].op == CPU_OP_IRCRN ) __mpu_stc();
+ else __mpu_clc();
+ I( &x, v[k].op );
+ x.operand[0] = R( 16, 0x122 );
+ x.operand[1] = R( 16, 0x120 );
+ x.operand[2] = R( 64, 0x128 );
+ CHECK( __cpu_exec( &x ) == 0, v[k].n );
+ CHECK( memcmp( P( 16, 0x122 ), ref, 2 ) == 0, v[k].n );
+ }
+ }
+
+ /* INC/DEC/XCHG and width-changing integer copy/conversion. */
+ *P( 8, 0x140 ) = 41;
+ I( &x, CPU_OP_IINC );
+ x.operand[0] = R( 8, 0x141 );
+ x.operand[1] = R( 8, 0x140 );
+ CHECK( __cpu_exec( &x ) == 0, "IINC" );
+ CHECK( *P( 8, 0x141 ) == 42, "IINC result" );
+ I( &x, CPU_OP_IDEC );
+ x.operand[0] = R( 8, 0x142 );
+ x.operand[1] = R( 8, 0x141 );
+ CHECK( __cpu_exec( &x ) == 0, "IDEC" );
+ CHECK( *P( 8, 0x142 ) == 41, "IDEC result" );
+ *P( 8, 0x143 ) = 0x12;
+ *P( 8, 0x144 ) = 0x34;
+ I( &x, CPU_OP_IXCHG );
+ x.operand[0] = R( 8, 0x143 );
+ x.operand[1] = R( 8, 0x144 );
+ CHECK( __cpu_exec( &x ) == 0, "IXCHG" );
+ CHECK( *P( 8, 0x143 ) == 0x34 && *P( 8, 0x144 ) == 0x12, "IXCHG result" );
+ *P( 8, 0x145 ) = 0xff;
+ I( &x, CPU_OP_ICPY );
+ x.operand[0] = R( 16, 0x146 );
+ x.operand[1] = R( 8, 0x145 );
+ CHECK( __cpu_exec( &x ) == 0, "ICPY" );
+ CHECK( __cpu_data_get_u16( P( 16, 0x146 ) ) == 255, "ICPY zero extension" );
+ I( &x, CPU_OP_ICVT );
+ x.operand[0] = R( 16, 0x148 );
+ x.operand[1] = R( 8, 0x145 );
+ CHECK( __cpu_exec( &x ) == 0, "ICVT" );
+ CHECK( __cpu_data_get_u16( P( 16, 0x148 ) ) == 0xffff, "ICVT sign extension" );
+
+ /* Full products and quotient+remainder forms. */
+ __cpu_data_put_u16( P( 16, 0x160 ), 300 );
+ __cpu_data_put_u16( P( 16, 0x162 ), 200 );
+ I( &x, CPU_OP_IMUL );
+ x.operand[0] = R( 32, 0x164 );
+ x.operand[1] = R( 16, 0x160 );
+ x.operand[2] = R( 16, 0x162 );
+ CHECK( __cpu_exec( &x ) == 0, "IMUL" );
+ CHECK( __cpu_data_get_u32( P( 32, 0x164 ) ) == 60000, "IMUL result" );
+ __cpu_data_put_u16( P( 16, 0x168 ), (__mpu_uint16_t)-3 );
+ __cpu_data_put_u16( P( 16, 0x16a ), 7 );
+ I( &x, CPU_OP_ISMUL );
+ x.operand[0] = R( 32, 0x16c );
+ x.operand[1] = R( 16, 0x168 );
+ x.operand[2] = R( 16, 0x16a );
+ CHECK( __cpu_exec( &x ) == 0, "ISMUL" );
+ CHECK( (__mpu_int32_t)__cpu_data_get_u32( P( 32, 0x16c ) ) == -21, "ISMUL result" );
+ __cpu_data_put_u16( P( 16, 0x170 ), 100 );
+ __cpu_data_put_u16( P( 16, 0x172 ), 7 );
+ I( &x, CPU_OP_IDIV );
+ x.operand[0] = R( 16, 0x174 );
+ x.operand[1] = R( 16, 0x176 );
+ x.operand[2] = R( 16, 0x170 );
+ x.operand[3] = R( 16, 0x172 );
+ CHECK( __cpu_exec( &x ) == 0, "IDIV" );
+ CHECK( __cpu_data_get_u16( P( 16, 0x174 ) ) == 14 && __cpu_data_get_u16( P( 16, 0x176 ) ) == 2, "IDIV result" );
+ {
+ mpu_int16_t qref, rref, nref, dref;
+ __cpu_data_put_u16( nref, (__mpu_uint16_t)-100 );
+ __cpu_data_put_u16( dref, 7 );
+ isdiv( ( mpu_int * ) qref, ( mpu_int * ) rref, ( mpu_int * ) nref, ( mpu_int * ) dref, 2 );
+ memcpy( P( 16, 0x17a ), nref, 2 );
+ memcpy( P( 16, 0x17c ), dref, 2 );
+ I( &x, CPU_OP_ISDIV );
+ x.operand[0] = R( 16, 0x17e );
+ x.operand[1] = R( 16, 0x180 );
+ x.operand[2] = R( 16, 0x17a );
+ x.operand[3] = R( 16, 0x17c );
+ CHECK( __cpu_exec( &x ) == 0, "ISDIV" );
+ CHECK( memcmp( P( 16, 0x17e ), qref, 2 ) == 0 && memcmp( P( 16, 0x180 ), rref, 2 ) == 0, "ISDIV result" );
+ }
+ *P( 8, 0x188 ) = 0x80;
+ I( &x, CPU_OP_IBITSLEN );
+ x.operand[0] = R( 64, 0x190 );
+ x.operand[1] = R( 8, 0x188 );
+ CHECK( __cpu_exec( &x ) == 0, "IBITSLEN" );
+ CHECK( get64( 0x190 ) == 8, "IBITSLEN result" );
+
+ /* Real conversion/utility coverage. */
+ setreal( 64, 0x200, "-3.75" );
+ I( &x, CPU_OP_RABS );
+ x.operand[0] = R( 64, 0x208 );
+ x.operand[1] = R( 64, 0x200 );
+ CHECK( __cpu_exec( &x ) == 0, "RABS" );
+ {
+ mpu_real64_t ref;
+ memcpy( ref, P( 64, 0x200 ), 8 );
+ r_abs( ( mpu_real * ) ref, 8 );
+ CHECK( memcmp( P( 64, 0x208 ), ref, 8 ) == 0, "RABS result" );
+ }
+ I( &x, CPU_OP_RNEG );
+ x.operand[0] = R( 64, 0x210 );
+ x.operand[1] = R( 64, 0x200 );
+ CHECK( __cpu_exec( &x ) == 0, "RNEG" );
+ {
+ mpu_real64_t ref;
+ memcpy( ref, P( 64, 0x200 ), 8 );
+ r_neg( ( mpu_real * ) ref, 8 );
+ CHECK( memcmp( P( 64, 0x210 ), ref, 8 ) == 0, "RNEG result" );
+ }
+ setreal( 64, 0x218, "2.0" );
+ setreal( 64, 0x220, "3.0" );
+ I( &x, CPU_OP_RCMP );
+ x.operand[0] = R( 64, 0x228 );
+ x.operand[1] = R( 64, 0x218 );
+ x.operand[2] = R( 64, 0x220 );
+ CHECK( __cpu_exec( &x ) == 0, "RCMP" );
+ CHECK( geti64( 0x228 ) == -1, "RCMP result" );
+ I( &x, CPU_OP_RCPY );
+ x.operand[0] = R( 64, 0x230 );
+ x.operand[1] = R( 64, 0x218 );
+ CHECK( __cpu_exec( &x ) == 0, "RCPY" );
+ CHECK( memcmp( P( 64, 0x230 ), P( 64, 0x218 ), 8 ) == 0, "RCPY result" );
+ I( &x, CPU_OP_RCVT );
+ x.operand[0] = R( 128, 0x240 );
+ x.operand[1] = R( 64, 0x218 );
+ CHECK( __cpu_exec( &x ) == 0, "RCVT" );
+ {
+ mpu_real128_t ref;
+ r_cvt( ( mpu_real * ) ref, ( mpu_real * ) P( 64, 0x218 ), 16, 8 );
+ CHECK( memcmp( P( 128, 0x240 ), ref, 16 ) == 0, "RCVT result" );
+ }
+
+ /* floor/ceil/round, remain and the previously missing transcendental family. */
+ {
+ struct U
+ {
+ cpu_opcode op;
+ void( *fn )( mpu_real *, mpu_real *, int );
+ const char *n;
+ const char *src;
+ }
+ u[] =
+ {
+ {CPU_OP_RFLOOR,r_floor,"RFLOOR","3.75"},{CPU_OP_RCEIL,r_ceil,"RCEIL","3.25"},{CPU_OP_RROUND,r_round,"RROUND","3.60"},
+ {CPU_OP_RLOG1P,r_log1p,"RLOG1P","0.25"},{CPU_OP_REXPM1,r_expm1,"REXPM1","0.25"},
+ {CPU_OP_RASINH,r_asinh,"RASINH","0.25"},{CPU_OP_RACOSH,r_acosh,"RACOSH","2.0"},{CPU_OP_RATANH,r_atanh,"RATANH","0.25"}
+ };
+ unsigned k;
+ for( k = 0; k < sizeof( u ) / sizeof( u[0] ); k++ )
+ {
+ mpu_real64_t ref;
+ setreal( 64, 0x250, u[k].src );
+ u[k].fn( ( mpu_real * ) ref, ( mpu_real * ) P( 64, 0x250 ), 8 );
+ I( &x, u[k].op );
+ x.operand[0] = R( 64, 0x258 );
+ x.operand[1] = R( 64, 0x250 );
+ CHECK( __cpu_exec( &x ) == 0, u[k].n );
+ CHECK( memcmp( P( 64, 0x258 ), ref, 8 ) == 0, u[k].n );
+ }
+ }
+ setreal( 64, 0x260, "5.5" );
+ setreal( 64, 0x268, "2.0" );
+ {
+ mpu_real64_t ref;
+ r_remain( ( mpu_real * ) ref, ( mpu_real * ) P( 64, 0x260 ), ( mpu_real * ) P( 64, 0x268 ), 8 );
+ I( &x, CPU_OP_RREMAIN );
+ x.operand[0] = R( 64, 0x270 );
+ x.operand[1] = R( 64, 0x260 );
+ x.operand[2] = R( 64, 0x268 );
+ CHECK( __cpu_exec( &x ) == 0, "RREMAIN" );
+ CHECK( memcmp( P( 64, 0x270 ), ref, 8 ) == 0, "RREMAIN result" );
+ }
+
+ /* frexp/ldexp/logb/modf and integer<->real conversions. */
+ setreal( 64, 0x280, "6.5" );
+ I( &x, CPU_OP_RFREXP );
+ x.operand[0] = R( 64, 0x288 );
+ x.operand[1] = R( 64, 0x290 );
+ x.operand[2] = R( 64, 0x280 );
+ CHECK( __cpu_exec( &x ) == 0, "RFREXP" );
+ {
+ mpu_real64_t rs;
+ mpu_int64_t re;
+ r_frexp( ( mpu_real * ) rs, ( mpu_int * ) re, ( mpu_real * ) P( 64, 0x280 ), 8, 8 );
+ CHECK( memcmp( P( 64, 0x288 ), rs, 8 ) == 0 && memcmp( P( 64, 0x290 ), re, 8 ) == 0, "RFREXP result" );
+ }
+ I( &x, CPU_OP_RLDEXP );
+ x.operand[0] = R( 64, 0x298 );
+ x.operand[1] = R( 64, 0x288 );
+ x.operand[2] = R( 64, 0x290 );
+ CHECK( __cpu_exec( &x ) == 0, "RLDEXP" );
+ {
+ mpu_real64_t ref;
+ r_ldexp( ( mpu_real * ) ref, ( mpu_real * ) P( 64, 0x288 ), ( mpu_int * ) P( 64, 0x290 ), 8, 8 );
+ CHECK( memcmp( P( 64, 0x298 ), ref, 8 ) == 0, "RLDEXP result" );
+ }
+ I( &x, CPU_OP_RLOGB );
+ x.operand[0] = R( 64, 0x2a0 );
+ x.operand[1] = R( 64, 0x280 );
+ CHECK( __cpu_exec( &x ) == 0, "RLOGB" );
+ {
+ mpu_int64_t ri;
+ r_logb( ( mpu_int * ) ri, ( mpu_real * ) P( 64, 0x280 ), 8, 8 );
+ CHECK( memcmp( P( 64, 0x2a0 ), ri, 8 ) == 0, "RLOGB result" );
+ }
+ I( &x, CPU_OP_RMODF );
+ x.operand[0] = R( 64, 0x2a8 );
+ x.operand[1] = R( 64, 0x2b0 );
+ x.operand[2] = R( 64, 0x280 );
+ CHECK( __cpu_exec( &x ) == 0, "RMODF" );
+ {
+ mpu_real64_t rf, ri;
+ r_modf( ( mpu_real * ) rf, ( mpu_real * ) ri, ( mpu_real * ) P( 64, 0x280 ), 8 );
+ CHECK( memcmp( P( 64, 0x2a8 ), rf, 8 ) == 0 && memcmp( P( 64, 0x2b0 ), ri, 8 ) == 0, "RMODF result" );
+ }
+ put64( 0x2b8, 42 );
+ I( &x, CPU_OP_ITOR );
+ x.operand[0] = R( 64, 0x2c0 );
+ x.operand[1] = R( 64, 0x2b8 );
+ CHECK( __cpu_exec( &x ) == 0, "ITOR" );
+ {
+ mpu_real64_t ref;
+ ltor( ( mpu_real * ) ref, ( mpu_int * ) P( 64, 0x2b8 ), 8, 8 );
+ CHECK( memcmp( P( 64, 0x2c0 ), ref, 8 ) == 0, "ITOR result" );
+ }
+ put64( 0x2c8, (__mpu_uint64_t)1844674407370955161UL );
+ I( &x, CPU_OP_UITOR );
+ x.operand[0] = R( 128, 0x2d0 );
+ x.operand[1] = R( 64, 0x2c8 );
+ CHECK( __cpu_exec( &x ) == 0, "UITOR" );
+ {
+ mpu_real128_t ref;
+ ultor( ( mpu_real * ) ref, ( mpu_int * ) P( 64, 0x2c8 ), 16, 8 );
+ CHECK( memcmp( P( 128, 0x2d0 ), ref, 16 ) == 0, "UITOR result" );
+ }
+ I( &x, CPU_OP_RTOI );
+ x.operand[0] = R( 64, 0x2e0 );
+ x.operand[1] = R( 64, 0x2e8 );
+ x.operand[2] = R( 64, 0x280 );
+ CHECK( __cpu_exec( &x ) == 0, "RTOI" );
+ {
+ mpu_int64_t li;
+ mpu_real64_t fr;
+ rtol_frac( ( mpu_int * ) li, ( mpu_real * ) fr, ( mpu_real * ) P( 64, 0x280 ), 8, 8 );
+ CHECK( memcmp( P( 64, 0x2e0 ), li, 8 ) == 0 && memcmp( P( 64, 0x2e8 ), fr, 8 ) == 0, "RTOI result" );
+ }
+ setreal( 64, 0x2f0, "42.75" );
+ I( &x, CPU_OP_RTOUI );
+ x.operand[0] = R( 64, 0x2f8 );
+ x.operand[1] = R( 64, 0x300 );
+ x.operand[2] = R( 64, 0x2f0 );
+ CHECK( __cpu_exec( &x ) == 0, "RTOUI" );
+ {
+ mpu_int64_t li;
+ mpu_real64_t fr;
+ rtoul_frac( ( mpu_int * ) li, ( mpu_real * ) fr, ( mpu_real * ) P( 64, 0x2f0 ), 8, 8 );
+ CHECK( memcmp( P( 64, 0x2f8 ), li, 8 ) == 0 && memcmp( P( 64, 0x300 ), fr, 8 ) == 0, "RTOUI result" );
+ }
+
+ /* Complete RCONST generator audit: every LibMPU value generator exposed by RCONST. */
+ {
+ struct K
+ {
+ unsigned id;
+ void( *f )( mpu_real *, int );
+ const char *n;
+ }
+ ks[] =
+ {
+ {CPU_RCONST_ZERO,_m_zero,"ZERO"},{CPU_RCONST_HALF,_m_half,"HALF"},{CPU_RCONST_ONE,_m_one,"ONE"},
+ {CPU_RCONST_TWO,_m_two,"TWO"},{CPU_RCONST_TEN,_m_ten,"TEN"},{CPU_RCONST_MTEN,_m_mten,"MTEN"},{CPU_RCONST_32,_m_32,"32"},
+ {CPU_RCONST_PI,_m_PI,"PI"},{CPU_RCONST_E,_m_E,"E"},{CPU_RCONST_1_LN2,_m_1_ln2,"1_LN2"},{CPU_RCONST_LN2,_m_ln2,"LN2"},
+ {CPU_RCONST_1_LN10,_m_1_ln10,"1_LN10"},{CPU_RCONST_LN10,_m_ln10,"LN10"},{CPU_RCONST_1_LG2,_m_1_lg2,"1_LG2"},{CPU_RCONST_LG2,_m_lg2,"LG2"},
+ {CPU_RCONST_PI_2,_m_PI_2,"PI_2"},{CPU_RCONST_PI_3,_m_PI_3,"PI_3"},{CPU_RCONST_PI_4,_m_PI_4,"PI_4"},{CPU_RCONST_PI_5,_m_PI_5,"PI_5"},{CPU_RCONST_PI_6,_m_PI_6,"PI_6"},
+ {CPU_RCONST_1_PI,_m_1_PI,"1_PI"},{CPU_RCONST_2_PI,_m_2_PI,"2_PI"},{CPU_RCONST_3_PI,_m_3_PI,"3_PI"},{CPU_RCONST_4_PI,_m_4_PI,"4_PI"},{CPU_RCONST_5_PI,_m_5_PI,"5_PI"},
+ {CPU_RCONST_2PI,_m_2PI,"2PI"},{CPU_RCONST_3PI,_m_3PI,"3PI"},{CPU_RCONST_1_2PI,_m_1_2PI,"1_2PI"},{CPU_RCONST_1_3PI,_m_1_3PI,"1_3PI"},
+ {CPU_RCONST_1_4PI,_m_1_4PI,"1_4PI"},{CPU_RCONST_1_5PI,_m_1_5PI,"1_5PI"},{CPU_RCONST_1_6PI,_m_1_6PI,"1_6PI"},{CPU_RCONST_3PI_4,_m_3PI_4,"3PI_4"},
+ {CPU_RCONST_SQRTPI,_m_SQRTPI,"SQRTPI"},{CPU_RCONST_1_SQRTPI,_m_1_SQRTPI,"1_SQRTPI"},{CPU_RCONST_2_SQRTPI,_m_2_SQRTPI,"2_SQRTPI"},
+ {CPU_RCONST_SQRT2,_m_SQRT2,"SQRT2"},{CPU_RCONST_1_SQRT2,_m_1_SQRT2,"1_SQRT2"},{CPU_RCONST_SQRT3,_m_SQRT3,"SQRT3"},{CPU_RCONST_1_SQRT3,_m_1_SQRT3,"1_SQRT3"},
+ {CPU_RCONST_DEGREE,_m_DEGREE,"DEGREE"},{CPU_RCONST_1_DEGREE,_m_1_DEGREE,"1_DEGREE"},{CPU_RCONST_GOLDENRATIO,_m_GOLDENRATIO,"GOLDENRATIO"},
+ {CPU_RCONST_EULERGAMMA,_m_EULERGAMMA,"EULERGAMMA"},{CPU_RCONST_CATALAN,_m_CATALAN,"CATALAN"},
+ {CPU_RCONST_EPSILON,_real_epsilon,"EPSILON"},{CPU_RCONST_IND,_ind,"IND"}
+ };
+ unsigned k;
+ for( k = 0; k < sizeof( ks ) / sizeof( ks[0] ); k++ )
+ {
+ mpu_real64_t ref;
+ ks[k].f( ( mpu_real * ) ref, 8 );
+ I( &x, CPU_OP_RCONST );
+ x.operand[0] = R( 64, 0x420 );
+ x.operand[1].type = CPU_OPERAND_CONST8;
+ x.operand[1].value.const8 = (__mpu_uint8_t)ks[k].id;
+ CHECK( __cpu_exec( &x ) == 0, ks[k].n );
+ CHECK( memcmp( P( 64, 0x420 ), ref, 8 ) == 0, ks[k].n );
+ }
+ {
+ struct S
+ {
+ unsigned id;
+ void( *f )( mpu_real *, unsigned int, int );
+ unsigned sign;
+ const char *n;
+ }
+ sp[] =
+ {
+ {CPU_RCONST_PNAN,_nan,0,"PNAN"},{CPU_RCONST_NNAN,_nan,1,"NNAN"},
+ {CPU_RCONST_PNANMAX,_nan_max,0,"PNANMAX"},{CPU_RCONST_NNANMAX,_nan_max,1,"NNANMAX"},
+ {CPU_RCONST_PNANMIN,_nan_min,0,"PNANMIN"},{CPU_RCONST_NNANMIN,_nan_min,1,"NNANMIN"},
+ {CPU_RCONST_PINF,_inf,0,"PINF"},{CPU_RCONST_NINF,_inf,1,"NINF"},
+ {CPU_RCONST_PREALMIN,_real_min,0,"PREALMIN"},{CPU_RCONST_NREALMIN,_real_min,1,"NREALMIN"},
+ {CPU_RCONST_PREALMAX,_real_max,0,"PREALMAX"},{CPU_RCONST_NREALMAX,_real_max,1,"NREALMAX"},
+ {CPU_RCONST_PZERO,_signull,0,"PZERO"},{CPU_RCONST_NZERO,_signull,1,"NZERO"}
+ };
+ for( k = 0; k < sizeof( sp ) / sizeof( sp[0] ); k++ )
+ {
+ mpu_real64_t ref;
+ sp[k].f( ( mpu_real * ) ref, sp[k].sign, 8 );
+ I( &x, CPU_OP_RCONST );
+ x.operand[0] = R( 64, 0x428 );
+ x.operand[1].type = CPU_OPERAND_CONST8;
+ x.operand[1].value.const8 = (__mpu_uint8_t)sp[k].id;
+ CHECK( __cpu_exec( &x ) == 0, sp[k].n );
+ CHECK( memcmp( P( 64, 0x428 ), ref, 8 ) == 0, sp[k].n );
+ }
+ }
+ I( &x, CPU_OP_RCONST );
+ x.operand[0] = R( 64, 0x430 );
+ x.operand[1].type = CPU_OPERAND_CONST8;
+ x.operand[1].value.const8 = CPU_RCONST_NINF;
+ CHECK( __cpu_exec( &x ) == 0, "NINF predicate source" );
+ I( &x, CPU_OP_RISINF );
+ x.operand[0] = R( 64, 0x438 );
+ x.operand[1] = R( 64, 0x430 );
+ CHECK( __cpu_exec( &x ) == 0, "RISINF" );
+ CHECK( geti64( 0x438 ) == 1, "RISINF result" );
+ }
+
+ /* Complex extraction, generation, conversion, conjugation and predicates. */
+ setreal( 64, 0x500, "3.0" );
+ setreal( 64, 0x508, "4.0" );
+ I( &x, CPU_OP_CGEN );
+ x.operand[0] = R( 128, 0x510 );
+ x.operand[1] = R( 64, 0x500 );
+ x.operand[2] = R( 64, 0x508 );
+ CHECK( __cpu_exec( &x ) == 0, "CGEN" );
+ {
+ mpu_complex64_t ref;
+ c_gen_complex( ( mpu_complex * ) ref, ( mpu_real * ) P( 64, 0x500 ), ( mpu_real * ) P( 64, 0x508 ), 8 );
+ CHECK( memcmp( P( 128, 0x510 ), ref, 16 ) == 0, "CGEN result" );
+ }
+ I( &x, CPU_OP_CREAL );
+ x.operand[0] = R( 64, 0x520 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CREAL" );
+ CHECK( memcmp( P( 64, 0x520 ), P( 64, 0x500 ), 8 ) == 0, "CREAL result" );
+ I( &x, CPU_OP_CIMAG );
+ x.operand[0] = R( 64, 0x528 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CIMAG" );
+ CHECK( memcmp( P( 64, 0x528 ), P( 64, 0x508 ), 8 ) == 0, "CIMAG result" );
+ I( &x, CPU_OP_CRTOC );
+ x.operand[0] = R( 128, 0x530 );
+ x.operand[1] = R( 64, 0x500 );
+ CHECK( __cpu_exec( &x ) == 0, "CRTOC" );
+ {
+ mpu_complex64_t ref;
+ c_real_to_complex( ( mpu_complex * ) ref, ( mpu_real * ) P( 64, 0x500 ), 8 );
+ CHECK( memcmp( P( 128, 0x530 ), ref, 16 ) == 0, "CRTOC result" );
+ }
+ I( &x, CPU_OP_CCONJ );
+ x.operand[0] = R( 128, 0x540 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CCONJ" );
+ {
+ mpu_complex64_t ref;
+ c_conj( ( mpu_complex * ) ref, ( mpu_complex * ) P( 128, 0x510 ), 8 );
+ CHECK( memcmp( P( 128, 0x540 ), ref, 16 ) == 0, "CCONJ result" );
+ }
+ I( &x, CPU_OP_CABS );
+ x.operand[0] = R( 64, 0x550 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CABS" );
+ {
+ mpu_real64_t ref;
+ c_abs( ( mpu_real * ) ref, ( mpu_complex * ) P( 128, 0x510 ), 8 );
+ CHECK( memcmp( P( 64, 0x550 ), ref, 8 ) == 0, "CABS result" );
+ }
+ I( &x, CPU_OP_CNORM );
+ x.operand[0] = R( 64, 0x558 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CNORM" );
+ {
+ mpu_real64_t ref;
+ c_norm( ( mpu_real * ) ref, ( mpu_complex * ) P( 128, 0x510 ), 8 );
+ CHECK( memcmp( P( 64, 0x558 ), ref, 8 ) == 0, "CNORM result" );
+ }
+ I( &x, CPU_OP_CARG );
+ x.operand[0] = R( 64, 0x560 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CARG" );
+ {
+ mpu_real64_t ref;
+ c_arg( ( mpu_real * ) ref, ( mpu_complex * ) P( 128, 0x510 ), 8 );
+ CHECK( memcmp( P( 64, 0x560 ), ref, 8 ) == 0, "CARG result" );
+ }
+ I( &x, CPU_OP_CISEQ );
+ x.operand[0] = R( 64, 0x568 );
+ x.operand[1] = R( 128, 0x510 );
+ x.operand[2] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CISEQ" );
+ CHECK( geti64( 0x568 ) == 1, "CISEQ result" );
+ I( &x, CPU_OP_CISNE );
+ x.operand[0] = R( 64, 0x570 );
+ x.operand[1] = R( 128, 0x510 );
+ x.operand[2] = R( 128, 0x540 );
+ CHECK( __cpu_exec( &x ) == 0, "CISNE" );
+ CHECK( geti64( 0x570 ) == 1, "CISNE result" );
+ I( &x, CPU_OP_CCPY );
+ x.operand[0] = R( 128, 0x580 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CCPY" );
+ CHECK( memcmp( P( 128, 0x580 ), P( 128, 0x510 ), 16 ) == 0, "CCPY result" );
+ setreal( 64, 0x590, "5.0" );
+ setreal( 64, 0x598, "0.5" );
+ I( &x, CPU_OP_CPOLAR );
+ x.operand[0] = R( 128, 0x5a0 );
+ x.operand[1] = R( 64, 0x590 );
+ x.operand[2] = R( 64, 0x598 );
+ CHECK( __cpu_exec( &x ) == 0, "CPOLAR" );
+ {
+ mpu_complex64_t ref;
+ c_polar( ( mpu_complex * ) ref, ( mpu_real * ) P( 64, 0x590 ), ( mpu_real * ) P( 64, 0x598 ), 8 );
+ CHECK( memcmp( P( 128, 0x5a0 ), ref, 16 ) == 0, "CPOLAR result" );
+ }
+ I( &x, CPU_OP_CCVT );
+ x.operand[0] = R( 256, 0x5c0 );
+ x.operand[1] = R( 128, 0x510 );
+ CHECK( __cpu_exec( &x ) == 0, "CCVT" );
+ {
+ mpu_complex128_t ref;
+ c_cvt( ( mpu_complex * ) ref, ( mpu_complex * ) P( 128, 0x510 ), 16, 8 );
+ CHECK( memcmp( P( 256, 0x5c0 ), ref, 32 ) == 0, "CCVT result" );
+ }
+
+ __cpu_free_context();
+ if( failures )
+ {
+ fprintf( stderr, "libcpu LibMPU coverage regression: %d failure(s)\n", failures );
+ return( 1 );
+ }
+ puts( "libcpu extended LibMPU instruction coverage: PASS" );
+ return( 0 );
+}