summaryrefslogtreecommitdiff
path: root/tests/tst-pointer.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-pointer.c')
-rw-r--r--tests/tst-pointer.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/tests/tst-pointer.c b/tests/tst-pointer.c
new file mode 100644
index 0000000..ca0ff99
--- /dev/null
+++ b/tests/tst-pointer.c
@@ -0,0 +1,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 );
+}