#include #include #include #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, (__mpu_char8_t *)"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, (__mpu_char8_t *)"1.5", NB_R64 ) >= 0, "build complex real component" ); CHECK( ascii_to_real( ( mpu_real * ) ri, (__mpu_char8_t *)"-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 ); }