summaryrefslogtreecommitdiff
path: root/tests/tst-stack.c
blob: 9c719ed745e6bcfea38ff5a4a383295e1f6768c0 (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
101
102
103
104
#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 src[]=
".text\n"
"        LDI     r64@0x00000, 11\n"
"        LDI     r64@0x00008, 22\n"
"        PUSH    r64@0x00000\n"
"        PUSH    r64@0x00008\n"
"        LDSP    r64@0x00010, 8\n"
"        STSP    0, r64@0x00000\n"
"        POP     r64@0x00018\n"
"        POP     r64@0x00020\n"
"        ADJSP   -16\n"
"        STSP    0, r64@0x00008\n"
"        LDSP    r64@0x00028, 0\n"
"        ADJSP   16\n"
"        HALT\n";

static int
eq64( unsigned address, const char *text )
{
  mpu_int64_t x;
  iatoi( ( mpu_int * ) x, (__mpu_char8_t *)text, NB_I64 );
  return( !memcmp( __cpu_reg_ptr( 64, address ), x, NB_I64 ) );
}

int
main( void )
{
  cpu_asm_image im;
  cpu_instruction i;
  cpu_operand *o;
  char err[256];
  __mpu_uint64_t sp;
  __mpu_UNIT_t before[8];
  int rc;

  __cpu_init();
  CHECK( __cpu_stack_alloc( 128 ) == 0, "allocate STACK" );
  CHECK( __cpu_stack_ptr() != 0, "STACK pointer" );
  CHECK( __cpu_stack_size() == 128, "STACK size" );
  CHECK( __cpu_sp == 128, "empty STACK starts at stack_size" );

  CHECK( cpu_assemble_text( src, &im, err, sizeof( err ) ) == 0, err );
  CHECK( im.code_size > 0, "stack bytecode produced" );
  CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "program set" );

  rc = __cpu_run();
  CHECK( rc == CPU_EXEC_SUCCESS, "stack program run" );
  CHECK( __cpu_sp == 128, "SP restored after balanced stack operations" );
  CHECK( eq64( 16, "11" ), "LDSP reads SP+8" );
  CHECK( eq64( 24, "11" ), "STSP overwrites top before POP" );
  CHECK( eq64( 32, "11" ), "second POP value" );
  CHECK( eq64( 40, "22" ), "ADJSP frame with STSP/LDSP" );

  /* PUSH overflow/underflow faults are atomic. */
  memset( &i, 0, sizeof( i ) );
  i.opcode = CPU_OP_PUSH;
  i.operand[0].type = CPU_OPERAND_REGISTER;
  i.operand[0].value.reg.bits = 64;
  i.operand[0].value.reg.address = 0;
  __cpu_sp = 4;
  memcpy( before, __cpu_stack_ptr(), sizeof( before ) );
  sp = __cpu_sp;
  CHECK( __cpu_exec( &i ) == CPU_EXEC_STACK_FAULT, "PUSH stack overflow fault" );
  CHECK( __cpu_sp == sp, "PUSH fault preserves SP" );
  CHECK( !memcmp( before, __cpu_stack_ptr(), sizeof( before ) ), "PUSH fault preserves STACK" );

  memset( &i, 0, sizeof( i ) );
  i.opcode = CPU_OP_POP;
  o = &i.operand[0];
  o->type = CPU_OPERAND_REGISTER;
  o->value.reg.bits = 64;
  o->value.reg.address = 48;
  memset( __cpu_reg_ptr( 64, 48 ), 0xa5, 8 );
  __cpu_sp = 128;
  sp = __cpu_sp;
  CHECK( __cpu_exec( &i ) == CPU_EXEC_STACK_FAULT, "POP empty stack fault" );
  CHECK( __cpu_sp == sp, "POP fault preserves SP" );
  {
    __mpu_UNIT_t a5[8];
    memset( a5, 0xa5, sizeof( a5 ) );
    CHECK( !memcmp( __cpu_reg_ptr( 64, 48 ), a5, 8 ), "POP fault preserves destination" );
  }

  memset( &i, 0, sizeof( i ) );
  i.opcode = CPU_OP_ADJSP;
  i.operand[0].type = CPU_OPERAND_OFF64;
  i.operand[0].value.off64 = 1;
  __cpu_sp = 128;
  CHECK( __cpu_exec( &i ) == CPU_EXEC_STACK_FAULT, "ADJSP beyond stack end" );
  CHECK( __cpu_sp == 128, "ADJSP fault preserves SP" );

  cpu_asm_image_free( &im );
  __cpu_free_context();
  CHECK( __cpu_sp == 0, "SP cleared by free context" );
  puts( "libcpu stack/SP regression: PASS" );
  return( 0 );
}