diff options
Diffstat (limited to 'tests/tst-mpu-coverage.c')
| -rw-r--r-- | tests/tst-mpu-coverage.c | 580 |
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 ); +} |
