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
|
#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[]=
".data\n"
".align 8\n"
"global_value:\n"
" .integer 64, 41\n"
".text\n"
" LEA r64@0x00000, global_value\n"
" LOADP r64@0x00008, r64@0x00000\n"
" LDI r64@0x00010, 42\n"
" STOREP r64@0x00000, r64@0x00010\n"
" LOADP r64@0x00018, r64@0x00000\n"
" ADJSP -16\n"
" LDI r64@0x00020, 11\n"
" LDI r64@0x00028, 22\n"
" STSP 0, r64@0x00020\n"
" STSP 8, r64@0x00028\n"
" LEASP r64@0x00030, 0\n"
" LOADP r64@0x00038, r64@0x00030\n"
" LEASP r64@0x00040, 8\n"
" LOADP r64@0x00048, r64@0x00040\n"
" LDI r64@0x00050, 33\n"
" STOREP r64@0x00040, r64@0x00050\n"
" LDSP r64@0x00058, 8\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 ) );
}
static __mpu_uint64_t
reg_u64( unsigned address )
{
__mpu_uint64_t v = 0;
memcpy( &v, __cpu_reg_ptr( 64, address ), 8 );
return( v );
}
int
main( void )
{
cpu_asm_image im;
cpu_instruction i;
__mpu_uint64_t p;
__mpu_UNIT_t saved[8];
char err[256];
int rc;
__cpu_init();
CHECK( CPU_PTR_SEG_SHIFT == 60U, "PTR64 segment shift" );
CHECK( CPU_PTR_OFFSET_MASK == __mpu_UINT64_C( 0x0fffffffffffffff ), "PTR64 offset mask" );
CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 0x1234 ) == 0, "make DATA pointer" );
CHECK( p == __mpu_UINT64_C( 0x0000000000001234 ), "DATA pointer encoding" );
CHECK( __cpu_ptr_segment( p ) == CPU_PTR_SEG_DATA, "DATA pointer segment" );
CHECK( __cpu_ptr_offset( p ) == 0x1234, "DATA pointer offset" );
CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_STACK, 0x1234 ) == 0, "make STACK pointer" );
CHECK( p == __mpu_UINT64_C( 0x1000000000001234 ), "STACK pointer encoding" );
CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_PROGRAM, 0x1234 ) == 0, "make PROGRAM pointer" );
CHECK( p == __mpu_UINT64_C( 0x2000000000001234 ), "PROGRAM pointer encoding" );
CHECK( __cpu_ptr_make( &p, 0x10, 0 ) == -1, "reject segment wider than four bits" );
CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, CPU_PTR_OFFSET_MASK + 1 ) == -1, "reject offset wider than 60 bits" );
CHECK( cpu_assemble_text( src, &im, err, sizeof( err ) ) == 0, err );
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( 128 ) == 0, "stack alloc" );
__cpu_pc = 0;
CHECK( __cpu_run() == CPU_EXEC_SUCCESS, "PTR64 program run" );
p = reg_u64( 0x00000 );
CHECK( __cpu_ptr_segment( p ) == CPU_PTR_SEG_DATA, "LEA creates DATA pointer" );
CHECK( __cpu_ptr_offset( p ) == CPU_DATA_NULL_GUARD_SIZE, "LEA DATA label offset after NULL guard" );
CHECK( eq64( 0x00008, "41" ), "LOADP reads DATA" );
CHECK( eq64( 0x00018, "42" ), "STOREP writes DATA and LOADP reads it back" );
CHECK( eq64( 0x00038, "11" ), "LEASP/LOADP first local object field" );
CHECK( eq64( 0x00048, "22" ), "LEASP/LOADP second local object field" );
CHECK( eq64( 0x00058, "33" ), "STOREP writes STACK through PTR64" );
CHECK( __cpu_sp == 128, "stack frame released" );
p = reg_u64( 0x00030 );
CHECK( __cpu_ptr_segment( p ) == CPU_PTR_SEG_STACK, "LEASP segment selector" );
CHECK( __cpu_ptr_offset( p ) == 112, "LEASP absolute stack offset for SP+0" );
/* PROGRAM is readable through PTR64 but is not writable. */
CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_PROGRAM, 0 ) == 0, "make PROGRAM pointer for indirect access" );
memcpy( __cpu_reg_ptr( 64, 0x00060 ), &p, 8 );
memset( &i, 0, sizeof( i ) );
i.opcode = CPU_OP_LOADP;
i.operand[0].type = CPU_OPERAND_REGISTER;
i.operand[0].value.reg.bits = 16;
i.operand[0].value.reg.address = 0x00068;
i.operand[1].type = CPU_OPERAND_REGISTER;
i.operand[1].value.reg.bits = 64;
i.operand[1].value.reg.address = 0x00060;
CHECK( __cpu_exec( &i ) == CPU_EXEC_SUCCESS, "LOADP may read PROGRAM" );
CHECK( !memcmp( __cpu_reg_ptr( 16, 0x00068 ), __cpu_program_ptr(), 2 ), "LOADP PROGRAM bytes" );
memcpy( saved, __cpu_program_ptr(), sizeof( saved ) );
memset( &i, 0, sizeof( i ) );
i.opcode = CPU_OP_STOREP;
i.operand[0].type = CPU_OPERAND_REGISTER;
i.operand[0].value.reg.bits = 64;
i.operand[0].value.reg.address = 0x00060;
i.operand[1].type = CPU_OPERAND_REGISTER;
i.operand[1].value.reg.bits = 64;
i.operand[1].value.reg.address = 0x00010;
CHECK( __cpu_exec( &i ) == CPU_EXEC_MEMORY_FAULT, "STOREP rejects PROGRAM write" );
CHECK( !memcmp( saved, __cpu_program_ptr(), sizeof( saved ) ), "PROGRAM write fault is atomic" );
/* ABI NULL is all-zero PTR64 and is never dereferenceable. */
p = CPU_NULL_PTR;
memcpy( __cpu_reg_ptr( 64, 0x00060 ), &p, 8 );
memset( &i, 0, sizeof( i ) );
i.opcode = CPU_OP_LOADP;
i.operand[0].type = CPU_OPERAND_REGISTER;
i.operand[0].value.reg.bits = 8;
i.operand[0].value.reg.address = 0x00070;
i.operand[1].type = CPU_OPERAND_REGISTER;
i.operand[1].value.reg.bits = 64;
i.operand[1].value.reg.address = 0x00060;
CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "NULL PTR64 dereference faults" );
/* Reserved segment selectors decode but cannot currently be dereferenced. */
CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_FIRST_RESERVED, 0 ) == 0, "reserved segment fits PTR64" );
memcpy( __cpu_reg_ptr( 64, 0x00060 ), &p, 8 );
memset( &i, 0, sizeof( i ) );
i.opcode = CPU_OP_LOADP;
i.operand[0].type = CPU_OPERAND_REGISTER;
i.operand[0].value.reg.bits = 8;
i.operand[0].value.reg.address = 0x00070;
i.operand[1].type = CPU_OPERAND_REGISTER;
i.operand[1].value.reg.bits = 64;
i.operand[1].value.reg.address = 0x00060;
rc = __cpu_exec( &i );
CHECK( rc == CPU_EXEC_POINTER_FAULT, "reserved PTR64 segment faults on dereference" );
cpu_asm_image_free( &im );
__cpu_free_context();
puts( "libcpu PTR64/indirect-addressing regression: PASS" );
return( 0 );
}
|