#include #include #include #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 ); }