summaryrefslogtreecommitdiff
path: root/tests/tst-conversion-flags.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-conversion-flags.c')
-rw-r--r--tests/tst-conversion-flags.c204
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 );
+}