summaryrefslogtreecommitdiff
path: root/tests/tst-byteorder.c
blob: 6346c9ebca4210aff6c3b6911f678238aae06b73 (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#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 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, "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, "1.5", NB_R64 ) >= 0, "build complex real component" );
  CHECK( ascii_to_real( ( mpu_real * ) ri, "-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 );
}