summaryrefslogtreecommitdiff
path: root/tests/tst-call.c
blob: 2fa0c166249cfdc213bea8438d4e6143d23c44f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#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 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 );
}