#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 const char leaf_src[]= ".text\n" " CALL leaf\n" " HALT\n" "leaf:\n" " RET\n"; static const char add_src[]= ".text\n" " LDI r64@0x00000, 11\n" " LDI r64@0x00008, 22\n" " PUSH r64@0x00008\n" " PUSH r64@0x00000\n" " CALL add2\n" " ADJSP 16\n" " MOV r64@0x00010, r64@0x7fff8\n" " HALT\n" "add2:\n" " LDSP r64@0x00100, 8\n" " LDSP r64@0x00108, 16\n" " IADD r64@0x7fff8, r64@0x00100, r64@0x00108\n" " RET\n"; int main( void ) { cpu_asm_image im; cpu_register rr; mpu_int64_t thirty_three; __mpu_uint64_t saved_pc; __mpu_uint32_t psw; char err[256]; unsigned int widths[] = { 8, 16, 32, 64, 4096, 65536 }; size_t k; __cpu_init(); CHECK( CPU_RETURN_AREA_BEGIN == 0x0007e000U, "return area begin" ); CHECK( CPU_RETURN_AREA_END == 0x00080000U, "return area end" ); CHECK( CPU_RETURN_AREA_SIZE == 0x00002000U, "return area size" ); for( k = 0; k < sizeof( widths ) / sizeof( widths[0] ); k++ ) { __mpu_size_t n = __cpu_reg_size( widths[k] ); CHECK( __cpu_return_reg( &rr, widths[k] ) == 0, "canonical return register" ); CHECK( rr.bits == widths[k], "return register width" ); CHECK( rr.address == CPU_RETURN_AREA_END - (unsigned)n, "return register address formula" ); } CHECK( __cpu_return_reg( &rr, 7 ) != 0, "reject invalid return width" ); CHECK( cpu_assemble_text( leaf_src, &im, err, sizeof( err ) ) == 0, err ); CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "leaf program set" ); CHECK( __cpu_stack_alloc( 64 ) == 0, "leaf stack alloc" ); __cpu_pc = 0; __cpu_set_psw( PSW_CF_MASK | PSW_TF_MASK ); psw = __cpu_get_psw(); CHECK( __cpu_step() == CPU_EXEC_SUCCESS, "CALL step" ); CHECK( __cpu_pc == 12, "CALL target" ); CHECK( __cpu_sp == 56, "CALL pushed 8-byte return address" ); memcpy( &saved_pc, __cpu_stack_ptr() + __cpu_sp, 8 ); CHECK( saved_pc == 10, "CALL stored next PC" ); CHECK( __cpu_get_psw() == psw, "CALL preserves PSW" ); CHECK( __cpu_step() == CPU_EXEC_SUCCESS, "RET step" ); CHECK( __cpu_pc == 10, "RET restored PC" ); CHECK( __cpu_sp == 64, "RET popped return address" ); CHECK( __cpu_get_psw() == psw, "RET preserves PSW" ); cpu_asm_image_free( &im ); __cpu_program_free(); __cpu_stack_free(); memset( __cpu_registers, 0, CPU_REGISTERS_MEM_SIZE_IN_UNITS ); __cpu_clear_psw(); CHECK( cpu_assemble_text( add_src, &im, err, sizeof( err ) ) == 0, err ); CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "add program set" ); CHECK( __cpu_stack_alloc( 128 ) == 0, "add stack alloc" ); __cpu_pc = 0; CHECK( __cpu_run() == CPU_EXEC_SUCCESS, "CALL ABI run" ); CHECK( __cpu_sp == 128, "caller cleanup restored empty SP" ); iatoi( ( mpu_int * ) thirty_three, (__mpu_char8_t *)"33", NB_I64 ); CHECK( !memcmp( __cpu_reg_ptr( 64, 0x7fff8 ), thirty_three, NB_I64 ), "return value area result" ); CHECK( !memcmp( __cpu_reg_ptr( 64, 0x00010 ), thirty_three, NB_I64 ), "caller copied return value" ); cpu_asm_image_free( &im ); __cpu_free_context(); puts( "libcpu CALL ABI regression: PASS" ); return( 0 ); }