#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 void regop( cpu_operand *o, unsigned bits, unsigned address ) { memset( o, 0, sizeof( *o ) ); o->type = CPU_OPERAND_REGISTER; o->value.reg.bits = bits; o->value.reg.address = address; } static int do_bswap( unsigned bits, unsigned d, unsigned s ) { cpu_instruction i; memset( &i, 0, sizeof( i ) ); i.opcode = CPU_OP_BSWAP; regop( &i.operand[0], bits, d ); regop( &i.operand[1], bits, s ); return( __cpu_exec( &i ) ); } int main( void ) { cpu_asm_image im; char err[256]; __mpu_UNIT_t *src, *dst; unsigned i; __mpu_uint32_t psw; const char *asrc= ".text\n" "LDI r64@0x00000, 42\n" "BSWAP r64@0x00008, r64@0x00000\n" "BSWAP r64@0x00010, r64@0x00008\n" "HALT\n"; __cpu_init(); CHECK( cpu_assemble_text( asrc, &im, err, sizeof( err ) ) == 0, err ); CHECK( im.code_size == 31, "BSWAP machine size is OPCODE16 + 2*REG24" ); CHECK( __cpu_code_get_u16( im.code + 13 ) == CPU_OP_BSWAP, "first BSWAP opcode encoded" ); CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "set BSWAP program" ); CHECK( __cpu_run() == CPU_EXEC_SUCCESS, "run BSWAP program" ); CHECK( __cpu_data_get_u64( __cpu_reg_ptr( 64, 0x10 ) ) == 42, "double BSWAP round trip" ); cpu_asm_image_free( &im ); /* r8 is a defined identity operation. */ src = __cpu_reg_ptr( 8, 0x100 ); dst = __cpu_reg_ptr( 8, 0x101 ); *src = 0xa5; *dst = 0; CHECK( do_bswap( 8, 0x101, 0x100 ) == CPU_EXEC_SUCCESS, "BSWAP r8" ); CHECK( *dst == 0xa5, "BSWAP r8 identity" ); /* Arbitrary wide physical registers are reversed byte for byte. */ src = __cpu_reg_ptr( 256, 0x200 ); dst = __cpu_reg_ptr( 256, 0x220 ); for( i = 0; i < 32; i++ ) src[i] = (__mpu_UNIT_t)i; memset( dst, 0, 32 ); psw = PSW_CF_MASK | PSW_IF_MASK | PSW_TF_MASK; __cpu_set_psw( psw ); CHECK( do_bswap( 256, 0x220, 0x200 ) == CPU_EXEC_SUCCESS, "BSWAP r256" ); for( i = 0; i < 32; i++ ) CHECK( dst[i] == (__mpu_UNIT_t)( 31 - i ), "BSWAP r256 byte reversal" ); CHECK( __cpu_get_psw() == psw, "BSWAP preserves PSW" ); /* In-place BSWAP uses source-snapshot semantics. */ src = __cpu_reg_ptr( 64, 0x300 ); for( i = 0; i < 8; i++ ) src[i] = (__mpu_UNIT_t)( 0x10 + i ); CHECK( do_bswap( 64, 0x300, 0x300 ) == CPU_EXEC_SUCCESS, "in-place BSWAP" ); for( i = 0; i < 8; i++ ) CHECK( src[i] == (__mpu_UNIT_t)( 0x17 - i ), "in-place BSWAP snapshot result" ); /* Maximum physical width is supported. */ src = __cpu_reg_ptr( 65536, 0x0000 ); dst = __cpu_reg_ptr( 65536, 0x2000 ); for( i = 0; i < 8192; i++ ) src[i] = (__mpu_UNIT_t)( i & 0xffU ); CHECK( do_bswap( 65536, 0x2000, 0x0000 ) == CPU_EXEC_SUCCESS, "BSWAP r65536" ); CHECK( dst[0] == src[8191] && dst[8191] == src[0], "BSWAP r65536 endpoints" ); /* Width mismatch is rejected before modifying destination. */ { cpu_instruction x; __mpu_UNIT_t before[8]; memset( x.operand, 0, sizeof( x.operand ) ); x.opcode = CPU_OP_BSWAP; regop( &x.operand[0], 64, 0x400 ); regop( &x.operand[1], 32, 0x408 ); memset( __cpu_reg_ptr( 64, 0x400 ), 0x5a, 8 ); memcpy( before, __cpu_reg_ptr( 64, 0x400 ), 8 ); CHECK( __cpu_exec( &x ) == CPU_EXEC_WIDTH_FAULT, "BSWAP width mismatch" ); CHECK( memcmp( before, __cpu_reg_ptr( 64, 0x400 ), 8 ) == 0, "BSWAP width fault atomic" ); } /* Assembler syntax intentionally uses raw r views, not c. */ CHECK( cpu_assemble_text( ".text\nBSWAP c64@0x0, c64@0x8\nHALT\n", &im, err, sizeof( err ) ) != 0, "assembler rejects complex spelling for raw BSWAP"); __cpu_free_context(); puts( "libcpu BSWAP regression: PASS" ); return( 0 ); }