diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /tests/tst-stack.c | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'tests/tst-stack.c')
| -rw-r--r-- | tests/tst-stack.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/tests/tst-stack.c b/tests/tst-stack.c new file mode 100644 index 0000000..9c719ed --- /dev/null +++ b/tests/tst-stack.c @@ -0,0 +1,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 ); +} |
