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