#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 alias_src[]= ".text\n" " JZ end\n" " JNZ end\n" " JC end\n" " JNC end\n" " JO end\n" " JNO end\n" " JS end\n" " JNS end\n" "end:\n" " HALT\n"; static const char src[]= ".text\n" " JMP start\n" "dead:\n" " HALT\n" "start:\n" " LDI r64@0x00000, 3\n" " LDI r64@0x00008, 1\n" " CLR r64@0x00010\n" "loop:\n" " ISUB r64@0x00000, r64@0x00000, r64@0x00008\n" " ICMP r64@0x00000, r64@0x00010\n" " JNZ loop\n" " JSET ZF, done\n" " LDI r64@0x00018, 77\n" "done:\n" " LDI r64@0x00018, 42\n" " HALT\n"; int main( void ) { cpu_asm_image im, aliases; cpu_instruction insn; mpu_int64_t zero, forty_two; char err[256]; int rc; __cpu_init(); CHECK( cpu_assemble_text( alias_src, &aliases, err, sizeof( err ) ) == 0, err ); CHECK( aliases.code_size == 90, "all eight jump aliases assembled" ); cpu_asm_image_free( &aliases ); CHECK( cpu_assemble_text( src, &im, err, sizeof( err ) ) == 0, err ); CHECK( im.code_size > 0, "control-flow code produced" ); CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "program set" ); __cpu_pc = 0; CHECK( __cpu_decode( &insn ) == 0, "decode JMP" ); CHECK( insn.opcode == CPU_OP_JMP, "first opcode JMP" ); CHECK( insn.length == 10, "JMP length" ); CHECK( insn.operand[0].type == CPU_OPERAND_CODE64, "JMP CODE64 operand" ); CHECK( insn.operand[0].value.code64 < im.code_size, "JMP target in PROGRAM" ); rc = __cpu_run(); CHECK( rc == CPU_EXEC_SUCCESS, "control-flow run" ); CHECK( __cpu_pc == im.code_size, "PC after final HALT" ); CHECK( __cpu_gth() != 0, "HALT flag set" ); iatoi( ( mpu_int * ) zero, "0", NB_I64 ); iatoi( ( mpu_int * ) forty_two, "42", NB_I64 ); CHECK( !memcmp( __cpu_reg_ptr( 64, 0 ), zero, NB_I64 ), "backward JNZ loop reached zero" ); CHECK( !memcmp( __cpu_reg_ptr( 64, 24 ), forty_two, NB_I64 ), "forward JSET reached done label" ); cpu_asm_image_free( &im ); __cpu_free_context(); puts( "libcpu control-flow regression: PASS" ); return( 0 ); }