summaryrefslogtreecommitdiff
path: root/tests/tst-control.c
diff options
context:
space:
mode:
authorkx <kx@radix-linux.su>2026-10-09 18:00:15 +0300
committerkx <kx@radix-linux.su>2026-10-09 18:00:15 +0300
commit065da3509019b15dd0e678072e6be629e5330bef (patch)
tree69c934c9e786ac048b4fbe8f4c4c5571661521f4 /tests/tst-control.c
parentd130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff)
downloadlibmcpu-0.4.0.tar.xz
Version 0.4.00.4.0
Diffstat (limited to 'tests/tst-control.c')
-rw-r--r--tests/tst-control.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/tests/tst-control.c b/tests/tst-control.c
new file mode 100644
index 0000000..7a3300f
--- /dev/null
+++ b/tests/tst-control.c
@@ -0,0 +1,80 @@
+#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 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 );
+}