#ifdef HAVE_CONFIG_H #include #endif #include #include #include 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 ); }