diff options
Diffstat (limited to 'tests/tst-conversion-flags.c')
| -rw-r--r-- | tests/tst-conversion-flags.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/tests/tst-conversion-flags.c b/tests/tst-conversion-flags.c new file mode 100644 index 0000000..5244c1a --- /dev/null +++ b/tests/tst-conversion-flags.c @@ -0,0 +1,204 @@ +#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 cpu_operand +IMM( __mpu_uint64_t v ) +{ + cpu_operand o; + memset( &o, 0, sizeof( o ) ); + o.type = CPU_OPERAND_IMM64; + o.value.imm64 = v; + 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 __mpu_uint32_t +seed_psw( void ) +{ + __mpu_uint32_t p= + PSW_AF_MASK | PSW_OF_MASK | PSW_PF_MASK | PSW_RF_MASK | + PSW_DOMF_MASK | PSW_OVFF_MASK | PSW_TLSF_MASK | PSW_INDF_MASK | + PSW_TF_MASK | PSW_IF_MASK | + ( (__mpu_uint32_t)2U << PSW_MODE_SHIFT ); + __cpu_set_psw( p ); + return( p ); +} + +static void +preserved( const char *name ) +{ + __mpu_uint32_t expect = seed_psw(); + (void)name; + CHECK( __cpu_get_psw() == expect, "PSW seed" ); +} + +static void +check_after( const char *name, __mpu_uint32_t expect ) +{ + if( __cpu_get_psw() != expect ) + { + fprintf( stderr, "FAIL: %s changed PSW: got 0x%08x expected 0x%08x\n", + name, (unsigned)__cpu_get_psw(), (unsigned)expect); + ++failures; + } +} + +int +main( void ) +{ + cpu_instruction x; + __mpu_uint32_t psw; + __cpu_init(); + + /* LDI: runtime icvt is an implementation detail and must be flag-neutral. */ + I( &x, CPU_OP_LDI ); + x.operand[0] = R( 128, 0x000 ); + x.operand[1] = IMM( 42 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "LDI exec" ); + check_after( "LDI", psw ); + + /* LDR: runtime real64 -> destination conversion is also flag-neutral. */ + { + __mpu_real64_t v = 2.0; + __mpu_uint64_t bits; + memcpy( &bits, &v, 8 ); + I( &x, CPU_OP_LDR ); + x.operand[0] = R( 128, 0x020 ); + x.operand[1] = IMM( bits ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "LDR exec" ); + check_after( "LDR", psw ); + } + + /* LDC: two real32 components are widened internally, but PSW is preserved. */ + { + __mpu_real32_t vr = 1.0f, vi = 2.0f; + __mpu_uint32_t br, bi; + __mpu_uint64_t payload; + memcpy( &br, &vr, 4 ); + memcpy( &bi, &vi, 4 ); + payload = ( (__mpu_uint64_t)br << 32 ) | bi; + I( &x, CPU_OP_LDC ); + x.operand[0] = R( 256, 0x040 ); + x.operand[1] = IMM( payload ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "LDC exec" ); + check_after( "LDC", psw ); + } + + /* Explicit integer conversion. */ + *P( 8, 0x080 ) = 0xff; + I( &x, CPU_OP_ICVT ); + x.operand[0] = R( 16, 0x082 ); + x.operand[1] = R( 8, 0x080 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "ICVT exec" ); + check_after( "ICVT", psw ); + + /* Explicit Real conversion. */ + CHECK( ascii_to_real( ( mpu_real * ) P( 64, 0x090 ), (__mpu_char8_t *)"3.5", NB_R64 ) >= 0, "real source" ); + I( &x, CPU_OP_RCVT ); + x.operand[0] = R( 128, 0x0a0 ); + x.operand[1] = R( 64, 0x090 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "RCVT exec" ); + check_after( "RCVT", psw ); + + /* Integer <-> Real conversions. */ + __cpu_data_put_u64( P( 64, 0x0c0 ), 42 ); + I( &x, CPU_OP_ITOR ); + x.operand[0] = R( 64, 0x0c8 ); + x.operand[1] = R( 64, 0x0c0 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "ITOR exec" ); + check_after( "ITOR", psw ); + + __cpu_data_put_u64( P( 64, 0x0d0 ), 42 ); + I( &x, CPU_OP_UITOR ); + x.operand[0] = R( 128, 0x0e0 ); + x.operand[1] = R( 64, 0x0d0 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "UITOR exec" ); + check_after( "UITOR", psw ); + + CHECK( ascii_to_real( ( mpu_real * ) P( 64, 0x100 ), (__mpu_char8_t *)"42.5", NB_R64 ) >= 0, "RTOI source" ); + I( &x, CPU_OP_RTOI ); + x.operand[0] = R( 64, 0x108 ); + x.operand[1] = R( 64, 0x110 ); + x.operand[2] = R( 64, 0x100 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "RTOI exec" ); + check_after( "RTOI", psw ); + + CHECK( ascii_to_real( ( mpu_real * ) P( 64, 0x118 ), (__mpu_char8_t *)"42.5", NB_R64 ) >= 0, "RTOUI source" ); + I( &x, CPU_OP_RTOUI ); + x.operand[0] = R( 64, 0x120 ); + x.operand[1] = R( 64, 0x128 ); + x.operand[2] = R( 64, 0x118 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "RTOUI exec" ); + check_after( "RTOUI", psw ); + + /* Complex conversion and Real -> Complex construction. */ + { + mpu_real64_t rr, ri; + CHECK( ascii_to_real( ( mpu_real * ) rr, (__mpu_char8_t *)"3.0", NB_R64 ) >= 0, "complex real" ); + CHECK( ascii_to_real( ( mpu_real * ) ri, (__mpu_char8_t *)"4.0", NB_R64 ) >= 0, "complex imag" ); + c_gen_complex( ( mpu_complex * ) P( 128, 0x140 ), ( mpu_real * ) rr, ( mpu_real * ) ri, NB_R64 ); + } + I( &x, CPU_OP_CCVT ); + x.operand[0] = R( 256, 0x160 ); + x.operand[1] = R( 128, 0x140 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "CCVT exec" ); + check_after( "CCVT", psw ); + + CHECK( ascii_to_real( ( mpu_real * ) P( 64, 0x190 ), (__mpu_char8_t *)"5.0", NB_R64 ) >= 0, "CRTOC source" ); + I( &x, CPU_OP_CRTOC ); + x.operand[0] = R( 128, 0x1a0 ); + x.operand[1] = R( 64, 0x190 ); + psw = seed_psw(); + CHECK( __cpu_exec( &x ) == 0, "CRTOC exec" ); + check_after( "CRTOC", psw ); + + __cpu_free_context(); + if( failures ) + { + fprintf( stderr, "libcpu conversion flag regression: %d failure(s)\n", failures ); + return( 1 ); + } + puts( "libcpu conversion flag preservation regression: PASS" ); + return( 0 ); +} |
