implemented flag for comparison result

This commit is contained in:
Timerix 2025-04-18 03:03:20 +05:00
parent ba72dae68f
commit cf5ed7b601
8 changed files with 45 additions and 50 deletions

2
.vscode/launch.json vendored
View File

@ -7,7 +7,7 @@
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/bin/tcpu", "program": "${workspaceFolder}/bin/tcpu",
"windows": { "program": "${workspaceFolder}/bin/tcpu.exe" }, "windows": { "program": "${workspaceFolder}/bin/tcpu.exe" },
"args": [ "-c", "../examples/conditional_jump.tasm", "o.bin", "--debug", "-i", "o.bin" ], "args": [ "-c", "../examples/loop.tasm", "o.bin", "--debug", "-i", "o.bin" ],
"cwd": "${workspaceFolder}/bin", "cwd": "${workspaceFolder}/bin",
"preLaunchTask": "build_exec_dbg", "preLaunchTask": "build_exec_dbg",
"stopAtEntry": false, "stopAtEntry": false,

View File

@ -43,7 +43,7 @@ Machine code interpreter written in pure C. Can execute programs up to 1 MEGABYT
| EXIT | | stop the program with exit code in `eax` | | EXIT | | stop the program with exit code in `eax` |
| SYS | | call system function | | SYS | | call system function |
| | | |
| MOVC | `dst_register`, `value` | push constant value into `dst_register` | | MOVC | `dst_register`, `const_value` | push constant value into `dst_register` |
| MOVR | `dst_register`, `src_register` | copy value from `src_register` to `dst_register` | | MOVR | `dst_register`, `src_register` | copy value from `src_register` to `dst_register` |
| | | |
| ADD | `dst_register`, `src_register` | `dst += src` | | ADD | `dst_register`, `src_register` | `dst += src` |
@ -65,9 +65,9 @@ Machine code interpreter written in pure C. Can execute programs up to 1 MEGABYT
| XOR | `dst_register`, `src_register` | `dst = dst ^ src` | | XOR | `dst_register`, `src_register` | `dst = dst ^ src` |
| AND | `dst_register`, `src_register` | `dst = dst & src` | | AND | `dst_register`, `src_register` | `dst = dst & src` |
| | | |
| JMP | `dst_register` | goto `dst` | | JMP | `dst_address_const` | goto `dst` |
| JNZ | `dst_register` | if (`cmp_flag` != 0) goto `dst` | | JNZ | `dst_address_const` | if (`cmp_flag` != 0) goto `dst` |
| JZ | `dst_register` | if (`cmp_flag` == 0) goto `dst` | | JZ | `dst_address_const` | if (`cmp_flag` == 0) goto `dst` |
### System functions ### System functions
To call a system function you need to push values to registers and write `SYS` opcode. The return value of a function will will be avaliable in `ax` after call. To call a system function you need to push values to registers and write `SYS` opcode. The return value of a function will will be avaliable in `ax` after call.

View File

@ -5,9 +5,9 @@ Example of behavior change depending on some condition
.main: .main:
movc ax 1 movc ax 1
movc bx 2 movc bx 2
gt cx ax bx gt ax bx
jnz @true cx jnz @true
jz @false cx jz @false
.true: .true:
const8 true.msg "true\n" const8 true.msg "true\n"

View File

@ -3,6 +3,7 @@ Example of self-repeating code section
*/ */
.main: .main:
movc dx 0; // loop counter
.loop .loop
const8 datum "ITERATION!!! " const8 datum "ITERATION!!! "
@ -11,4 +12,11 @@ movc ah 1
movc rbx @datum movc rbx @datum
movc ecx #datum movc ecx #datum
sys sys
jmp @loop
movc cx 1
add dx cx
movc cx 8
lt dx cx
jnz @loop
movc rax 0
exit

View File

@ -31,6 +31,10 @@ typedef struct VM {
Register array[4]; Register array[4];
} registers; } registers;
struct {
bool cmp; // result of comparison operation
} flags;
VMState state; VMState state;
char* NULLABLE(error_message); // not null on if state == VMState_InternalError char* NULLABLE(error_message); // not null on if state == VMState_InternalError

View File

@ -11,40 +11,26 @@ i32 JMP_impl(VM* vm){
} }
// JNZ [destination address] [condition register] // JNZ [destination address]
i32 JNZ_impl(VM* vm){ i32 JNZ_impl(VM* vm){
u64 dst_addr = 0; u64 dst_addr = 0;
readVar(dst_addr); readVar(dst_addr);
RegisterCode reg_code = 0; if(vm->flags.cmp != 0){
readRegisterCode(reg_code);
u64 cond_reg_value = 0;
VM_registerRead(vm, &cond_reg_value, reg_code);
if(cond_reg_value != 0){
vm->current_pos = dst_addr; vm->current_pos = dst_addr;
} }
return sizeof(dst_addr) + sizeof(reg_code); return sizeof(dst_addr);
} }
// JZ [destination address] [condition register] // JZ [destination address]
i32 JZ_impl(VM* vm){ i32 JZ_impl(VM* vm){
u64 dst_addr = 0; u64 dst_addr = 0;
{ readVar(dst_addr);
if(!VM_dataRead(vm, &dst_addr, vm->current_pos, sizeof(dst_addr)))
return -1;
vm->current_pos += sizeof(dst_addr);
};
RegisterCode reg_code = 0; if(vm->flags.cmp == 0){
readRegisterCode(reg_code);
u64 cond_reg_value = 0;
VM_registerRead(vm, &cond_reg_value, reg_code);
if(cond_reg_value == 0){
vm->current_pos = dst_addr; vm->current_pos = dst_addr;
} }
return sizeof(dst_addr) + sizeof(reg_code); return sizeof(dst_addr);
} }

View File

@ -45,18 +45,15 @@ i32 NAME##_impl (VM* vm) {\
return sizeof(dst_reg_code) + sizeof(src_reg_code);\ return sizeof(dst_reg_code) + sizeof(src_reg_code);\
} }
#define OPERATOR_IMPL_3(NAME, OPERATOR)\ #define OPERATOR_IMPL_CMP_FLAG(NAME, OPERATOR)\
i32 NAME##_impl (VM* vm) {\ i32 NAME##_impl (VM* vm) {\
RegisterCode dst_reg_code = 0, src0_reg_code = 0, src1_reg_code = 0;\ RegisterCode src0_reg_code = 0, src1_reg_code = 0;\
readRegisterCode(dst_reg_code);\
readRegisterCode(src0_reg_code);\ readRegisterCode(src0_reg_code);\
readRegisterCode(src1_reg_code);\ readRegisterCode(src1_reg_code);\
u64 dst_reg_value = 0, src0_reg_value = 0, src1_reg_value = 0;\ u64 src0_reg_value = 0, src1_reg_value = 0;\
VM_registerRead(vm, &dst_reg_value, dst_reg_code);\
VM_registerRead(vm, &src0_reg_value, src0_reg_code);\ VM_registerRead(vm, &src0_reg_value, src0_reg_code);\
VM_registerRead(vm, &src1_reg_value, src1_reg_code);\ VM_registerRead(vm, &src1_reg_value, src1_reg_code);\
\ \
dst_reg_value = src0_reg_value OPERATOR src1_reg_value;\ vm->flags.cmp = src0_reg_value OPERATOR src1_reg_value;\
VM_registerWrite(vm, &dst_reg_value, dst_reg_code);\ return sizeof(src0_reg_code) + sizeof(src1_reg_code);\
return sizeof(dst_reg_code) + sizeof(src0_reg_code) + sizeof(src1_reg_code);\
} }

View File

@ -17,20 +17,20 @@ OPERATOR_IMPL_2(XOR, ^)
OPERATOR_IMPL_2(AND, &) OPERATOR_IMPL_2(AND, &)
/// EQ [dst_register] [src0_register] [src1_register] /// EQ [src0_register] [src1_register]
OPERATOR_IMPL_3(EQ, ==) OPERATOR_IMPL_CMP_FLAG(EQ, ==)
/// NE [dst_register] [src0_register] [src1_register] /// NE [src0_register] [src1_register]
OPERATOR_IMPL_3(NE, !=) OPERATOR_IMPL_CMP_FLAG(NE, !=)
/// LT [dst_register] [src0_register] [src1_register] /// LT [src0_register] [src1_register]
OPERATOR_IMPL_3(LT, <) OPERATOR_IMPL_CMP_FLAG(LT, <)
/// LE [dst_register] [src0_register] [src1_register] /// LE [src0_register] [src1_register]
OPERATOR_IMPL_3(LE, <=) OPERATOR_IMPL_CMP_FLAG(LE, <=)
/// GT [dst_register] [src0_register] [src1_register] /// GT [src0_register] [src1_register]
OPERATOR_IMPL_3(GT, >) OPERATOR_IMPL_CMP_FLAG(GT, >)
/// GE [dst_register] [src0_register] [src1_register] /// GE [src0_register] [src1_register]
OPERATOR_IMPL_3(GE, >=) OPERATOR_IMPL_CMP_FLAG(GE, >=)