diff options
Diffstat (limited to 'tests/tst-byteorder.c')
| -rw-r--r-- | tests/tst-byteorder.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/tests/tst-byteorder.c b/tests/tst-byteorder.c new file mode 100644 index 0000000..6346c9e --- /dev/null +++ b/tests/tst-byteorder.c @@ -0,0 +1,170 @@ +#include <stdio.h> +#include <string.h> +#include <libmcpu.h> +#include "../utils/mcpu-asm.h" + +#define CHECK(c,m) do{if(!(c)){fprintf(stderr,"FAIL: %s\n",m);return 1;}}while(0) + +static int +raw_u64_matches_target( const __mpu_UNIT_t *p, __mpu_uint64_t v ) +{ + __mpu_UNIT_t x[8]; + __cpu_data_put_u64( x, v ); + return( memcmp( p, x, 8 ) == 0 ); +} + +int +main( void ) +{ + static const __mpu_UNIT_t canonical64[8] = + { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 + }; + static const char src[]= + ".data\n" + ".align 8\n" + "ival:\n" + " .integer 64, 1234605616436508552\n" + ".align 8\n" + "rval:\n" + " .real 64, 1.5\n" + ".align 16\n" + "zval:\n" + " .complex 128, 1.5, -2.0\n" + ".align 8\n" + "target_slot:\n" + " .cptr done\n" + ".align 8\n" + "copy:\n" + " .integer 64, 0\n" + ".text\n" + " LDI r64@0x00000, 1234605616436508552\n" + " LOAD r64@0x00008, ival\n" + " LEA r64@0x00010, ival\n" + " LEA r64@0x00018, copy\n" + " BMOVI r64@0x00018, r64@0x00010, 8\n" + " LOAD r64@0x00020, copy\n" + " CALL leaf\n" + " JMPP r64@0x00028\n" + "leaf:\n" + " RET\n" + "done:\n" + " HALT\n"; + static const char call_src[]= + ".text\n" + " CALL leaf\n" + " HALT\n" + "leaf:\n" + " RET\n"; + cpu_asm_image im, callim, alias; + __mpu_UNIT_t buf[8], real_expected[8], complex_expected[16]; + mpu_wide_real_t rr, ri; + mpu_wide_complex_t zz; + __mpu_uint64_t v = __mpu_UINT64_C( 0x1122334455667788 ), ptr, ret; + char err[256]; + int rc; + + __cpu_init(); + + /* The two byte-order domains are deliberately different concepts. */ + memset( buf, 0, sizeof( buf ) ); + __cpu_code_put_u64( buf, v ); + CHECK( !memcmp( buf, canonical64, 8 ), "CODE u64 is canonical MSB-first" ); + CHECK( __cpu_code_get_u64( buf ) == v, "CODE u64 round trip" ); + CHECK( CPU_CODE_BYTE_ORDER_MSB_FIRST == 1, "CODE byte-order ABI marker" ); + + memset( buf, 0, sizeof( buf ) ); + __cpu_data_put_u64( buf, v ); + CHECK( __cpu_data_get_u64( buf ) == v, "DATA/object u64 round trip" ); +#if CPU_DATA_BYTE_ORDER_LITTLE_ENDIAN == 1 + { + static const __mpu_UNIT_t le[8] = + { + 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 + }; + CHECK( !memcmp( buf, le, 8 ), "target data u64 little-endian bytes" ); + } +#elif CPU_DATA_BYTE_ORDER_BIG_ENDIAN == 1 + CHECK( !memcmp( buf, canonical64, 8 ), "target data u64 big-endian bytes" ); +#else +# error Unsupported LibMPU byte order for LibCPU byte-order regression +#endif + + CHECK( cpu_assemble_text( src, &im, err, sizeof( err ) ) == 0, err ); + + /* First instruction is LDI: OPCODE16 + REG24 + canonical IMM64. */ + CHECK( im.code_size > 13, "assembled bytecode exists" ); + CHECK( im.code[0] == 0x01 && im.code[1] == 0x10, "LDI opcode canonical bytes" ); + CHECK( !memcmp( im.code + 5, canonical64, 8 ), "LDI IMM64 is canonical MSB-first" ); + + /* DATA directives create target object representation, not bytecode order. */ + CHECK( im.data_size >= 64, "assembled DATA image size" ); + CHECK( __cpu_data_get_u64( im.data + 16 ) == v, ".integer64 target data object" ); + CHECK( raw_u64_matches_target( im.data + 16, v ), ".integer64 raw target bytes" ); + + memset( rr, 0, sizeof( rr ) ); + CHECK( ascii_to_real( ( mpu_real * ) rr, "1.5", NB_R64 ) >= 0, "build expected real64" ); + memcpy( real_expected, rr, 8 ); + CHECK( !memcmp( im.data + 24, real_expected, 8 ), ".real64 follows LibMPU object representation" ); + + memset( rr, 0, sizeof( rr ) ); + memset( ri, 0, sizeof( ri ) ); + memset( zz, 0, sizeof( zz ) ); + CHECK( ascii_to_real( ( mpu_real * ) rr, "1.5", NB_R64 ) >= 0, "build complex real component" ); + CHECK( ascii_to_real( ( mpu_real * ) ri, "-2.0", NB_R64 ) >= 0, "build complex imaginary component" ); + c_gen_complex( ( mpu_complex * ) zz, ( mpu_real * ) rr, ( mpu_real * ) ri, NB_R64 ); + memcpy( complex_expected, zz, 16 ); + CHECK( !memcmp( im.data + 32, complex_expected, 16 ), ".complex128 follows LibMPU object representation" ); + + ptr = __cpu_data_get_u64( im.data + 48 ); + CHECK( __cpu_ptr_segment( ptr ) == CPU_PTR_SEG_PROGRAM, ".cptr stores PROGRAM PTR64 data object" ); + CHECK( __cpu_ptr_offset( ptr ) < im.code_size, ".cptr PROGRAM offset in range" ); + + /* Compatibility spelling remains accepted, but .cptr is canonical. */ + CHECK( cpu_assemble_text( ".data\n .codeptr x\n.text\nx:\n HALT\n", &alias, err, sizeof( err ) ) == 0, "legacy .codeptr alias accepted" ); + cpu_asm_image_free( &alias ); + + CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "program set" ); + CHECK( __cpu_data_set( im.data, im.data_size ) == 0, "data set" ); + CHECK( __cpu_stack_alloc( 512 ) == 0, "stack alloc" ); + + /* Load source and BMOV destination preserve the complete object bytes. */ + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "step LDI" ); + CHECK( __cpu_data_get_u64( __cpu_reg_ptr( 64, 0x00000 ) ) == v, "LDI decoded canonical bits into target register object" ); + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "step LOAD source" ); + CHECK( !memcmp( __cpu_reg_ptr( 64, 0x00008 ), im.data + 16, 8 ), "LOAD preserves data object bytes" ); + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "step LEA source" ); + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "step LEA destination" ); + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "step BMOVI" ); + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "step LOAD copied object" ); + CHECK( !memcmp( __cpu_reg_ptr( 64, 0x00008 ), __cpu_reg_ptr( 64, 0x00020 ), 8 ), "LOAD-BMOV-LOAD is byte preserving" ); + CHECK( !memcmp( __cpu_data_ptr() + 56, im.data + 16, 8 ), "BMOV copied exact target object bytes" ); + + cpu_asm_image_free( &im ); + __cpu_program_free(); + __cpu_data_free(); + __cpu_stack_free(); + + /* CALL return PC is a STACK data object, not a canonical CODE64 field. */ + CHECK( cpu_assemble_text( call_src, &callim, err, sizeof( err ) ) == 0, err ); + CHECK( __cpu_program_set( callim.code, callim.code_size ) == 0, "call program set" ); + CHECK( __cpu_stack_alloc( 64 ) == 0, "call stack alloc" ); + __cpu_pc = 0; + rc = __cpu_step(); + CHECK( rc == CPU_EXEC_SUCCESS, "CALL step" ); + CHECK( __cpu_sp == 56, "CALL pushed 8-byte return object" ); + ret = __cpu_data_get_u64( __cpu_stack_ptr() + 56 ); + CHECK( ret == 10, "CALL return PC target data representation decodes to next PC" ); + CHECK( raw_u64_matches_target( __cpu_stack_ptr() + 56, 10 ), "CALL return PC raw stack bytes use target data order" ); + cpu_asm_image_free( &callim ); + + __cpu_free_context(); + puts( "libcpu byte-order/object-representation regression: PASS" ); + return( 0 ); +} |
