Compare commits

...

1 Commits

Author SHA1 Message Date
zongor c961edeb00 try static frame size, not faster :( 2026-01-11 20:03:43 -08:00
4 changed files with 245 additions and 113 deletions

View File

@ -1,35 +1,38 @@
#include "../../../vm/vm.h" #include "../../../vm/vm.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#define FRAMES_SIZE 128
#define CODE_SIZE 8192 #define CODE_SIZE 8192
#define MEMORY_SIZE 65536 #define MEMORY_SIZE 65536
u8 lmem[MEMORY_SIZE] = {0}; u8 lmem[MEMORY_SIZE] = {0};
u32 lcode[CODE_SIZE] = {0}; u32 lcode[CODE_SIZE] = {0};
Frame lframes[FRAMES_SIZE] = {0};
bool init_vm() {
mem = lmem;
memset(mem, 0, MEMORY_SIZE*sizeof(u8));
code = lcode;
lc = 0;
mp = 0;
cp = 0;
pc = 0;
interrupt = 0;
status = 0;
return true;
}
u32 syscall(u32 id, u32 size, u32 mem_ptr) { u32 syscall(u32 id, u32 size, u32 mem_ptr) {
USED(size); USED(size);
switch(id) { switch(id) {
case SYSCALL_DBG_PRINT: { case SYSCALL_CONSOLE_WRITE: {
u32 val = READ_U32(mem_ptr); u32 size = *(u32 *)(mem + mem_ptr);
printf("%d\n", val); u32 ptr = mem_ptr + 4;
for (u32 i = 0; i < size; i++) {
putchar(mem[ptr + i]);
}
putchar('\n');
return 0;
}
case SYSCALL_CONSOLE_READ: {
for (u32 i = 0; i < size; i++) {
u8 ch = getchar();
if (ch == '\0')
break;
if (ch == '\n')
break;
mem[mem_ptr + i] = ch;
}
}
return 0; return 0;
} }
}
return 1; // generic error return 1; // generic error
} }
@ -40,10 +43,11 @@ void test_add_two_num() {
code[cp++] = ENCODE_B(OP_PUSH, 0, 0); code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 1); code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 1);
code[cp++] = ENCODE_B(OP_PUSH, 1, 0); code[cp++] = ENCODE_B(OP_PUSH, 1, 0);
i32 add = cp + 4; i32 add = cp + 5;
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, add); code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, add);
code[cp++] = ENCODE_A(OP_CALL, 2, 3, 3); code[cp++] = ENCODE_A(OP_CALL, 2, 3, 0);
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 3); code[cp++] = ENCODE_A(OP_INT_TO_STR, 4, 3, 0);
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_CONSOLE_WRITE, 1, 4);
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0); code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
/* add */ /* add */
@ -52,40 +56,47 @@ void test_add_two_num() {
} }
void test_fibonacci() { void test_fibonacci() {
i32 fib = 6;
i32 base_case = 20;
/* function main() */ /* function main() */
i32 main_local_count = 3; i32 fib = 7;
mp += (4 * main_local_count); i32 base_case = 21;
/* fib(35) */ /* fib(35) */
code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35); /*0*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 0, 35);
code[cp++] = ENCODE_B(OP_PUSH, 0, 0); /*1*/ code[cp++] = ENCODE_B(OP_PUSH, 0, 0);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib); /*2*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, fib);
code[cp++] = ENCODE_A(OP_CALL, 1, 9, 2); /*3*/ code[cp++] = ENCODE_A(OP_CALL, 1, 2, 0);
/* print */ /**/ /* print */
code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 2); /*4*/ code[cp++] = ENCODE_A(OP_INT_TO_STR, 3, 2, 0);
code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0); /*5*/ code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_CONSOLE_WRITE, 1, 3);
/* function fib (int n) int */ /*6*/ code[cp++] = ENCODE_A(OP_HALT, 0, 0, 0);
//code[cp++] = ENCODE_A(OP_SYSCALL, SYSCALL_DBG_PRINT, 1, 0); /**/ /* function fib (int n) int */
code[cp++] = ENCODE_B(OP_LOAD_IMM, 8, fib); /*9*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 8, fib);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2); /*10*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 1, 2);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, base_case); /*11*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 2, base_case);
code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1); /*12*/ code[cp++] = ENCODE_A(OP_JLT_INT, 2, 0, 1);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2); /*13*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 1);
code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); /*14*/ code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
code[cp++] = ENCODE_B(OP_PUSH, 4, 0); /*15*/ code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
code[cp++] = ENCODE_A(OP_CALL, 8, 9, 5); /*16*/ code[cp++] = ENCODE_A(OP_CALL, 8, 5, 0);
code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 1); /*17*/ code[cp++] = ENCODE_B(OP_LOAD_IMM, 3, 2);
code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3); /*18*/ code[cp++] = ENCODE_A(OP_SUB_INT, 4, 0, 3);
code[cp++] = ENCODE_B(OP_PUSH, 4, 0); /*19*/ code[cp++] = ENCODE_B(OP_PUSH, 4, 0);
code[cp++] = ENCODE_A(OP_CALL, 8, 9, 6); /*20*/ code[cp++] = ENCODE_A(OP_CALL, 8, 6, 0);
code[cp++] = ENCODE_A(OP_ADD_INT, 7, 6, 5); /*21*/ code[cp++] = ENCODE_A(OP_ADD_INT, 7, 6, 5);
code[cp++] = ENCODE_B(OP_RETURN, 7, 0); /*22*/ code[cp++] = ENCODE_B(OP_RETURN, 7, 0);
code[cp++] = ENCODE_B(OP_RETURN, 0, 0); /*23*/ code[cp++] = ENCODE_B(OP_RETURN, 0, 0);
} }
i32 main() { i32 main() {
init_vm(); mem = lmem;
code = lcode;
frames = lframes;
lc = 0;
mp = 0;
cp = 0;
pc = 0;
fp = 0;
interrupt = 0;
status = 0;
/* test_add_two_num(); */ /* test_add_two_num(); */
test_fibonacci(); test_fibonacci();

2
build
View File

@ -66,7 +66,7 @@ fi
# setup the build flags based on the build mode # setup the build flags based on the build mode
case $MODE in case $MODE in
"debug") "debug")
BUILD_FLAGS="-g -Wall -Wextra -Werror -pedantic" BUILD_FLAGS="-g -pg -Wall -Wextra -Werror -pedantic"
;; ;;
"release") "release")
BUILD_FLAGS="-O2 -Wall -Wextra -Werror -pedantic" BUILD_FLAGS="-O2 -Wall -Wextra -Werror -pedantic"

218
vm/vm.c
View File

@ -10,12 +10,32 @@ u8 status; /* status flag */
u8 interrupt; /* device interrupt */ u8 interrupt; /* device interrupt */
u32 *code; /* code */ u32 *code; /* code */
u8 *mem; /* memory */ u8 *mem; /* memory */
Frame *frames;/* stack frame */
#define MAX_LEN_INT32 11
#define MAX_INT32 2147483647
#define MIN_INT32 -2147483648
const char radix_set[11] = "0123456789";
u32 str_alloc(const char *str, u32 length) {
u32 str_addr = mp;
u32 i = 0;
mp += 4;
while (i < length) {
mem[mp++] = str[i++];
}
mem[mp++] = '\0';
WRITE_U32(str_addr, length);
return str_addr;
}
bool step_vm() { bool step_vm() {
u32 instruction = code[pc++]; u32 instruction = code[pc++];
u8 opcode = DECODE_OP(instruction); u8 opcode = DECODE_OP(instruction);
u32 *locals = (u32*)(&mem[fp]);
Frame *frame = &frames[fp];
u32 *globals = (u32*)(mem); u32 *globals = (u32*)(mem);
switch (opcode) { switch (opcode) {
@ -25,50 +45,40 @@ bool step_vm() {
} }
case OP_CALL: { case OP_CALL: {
DECODE_A(instruction) DECODE_A(instruction)
Frame *child_frame = &frames[fp + 1];
/* function to jump to */ /* function to jump to */
u32 fn_ptr = locals[dest]; u32 fn_ptr = frame->local[dest];
/* get mp in 'global indexing mode' */
u32 gmp = mp / 4;
/* reset child locals counter */ /* reset child locals counter */
lc = 0; lc = 0;
/* push parents frame value to reset the heap to */
globals[gmp] = fp;
/* push return address to child frame */ /* push return address to child frame */
globals[gmp + 1] = pc; child_frame->return_address = pc;
/* push local address to return the value to */ /* push local address to return the value to */
globals[gmp + 2] = fp + (src2 * 4); child_frame->parent_return_local = src1;
/* increase the mp to new size */
mp += FRAME_HEADER_SIZE;
/* now set the frame pointer, where the locals start */ /* now set the frame pointer, where the locals start */
fp = mp; child_frame->start_mp = mp;
/* move mp forward by count many locals */ /* increment frame pointer */
mp += (4 * src1); fp++;
/* jump to dest_ptr */ /* jump to dest_ptr */
pc = fn_ptr; pc = fn_ptr;
USED(src2);
return true; return true;
} }
case OP_RETURN: { case OP_RETURN: {
DECODE_B(instruction) DECODE_B(instruction)
u32 i, size = 0; u32 i, size = 0;
u32 return_value = locals[dest]; u32 return_value = frame->local[dest];
bool is_ptr = (((u32)(1)) << 15) & imm; Frame *child = frame;
bool replaces_value = (((u32)(1)) << 14) & imm; Frame *parent = &frames[fp - 1];
u32 parent_local_return_address = frame->parent_return_local;
USED(imm);
/* reset mp to saved mp, use header size to get "real" start of frame */ if (child->parent_return_local != 0xFF) {
u32 frame_start = (fp / 4) - 3;
u32 parent_fp = globals[frame_start];
u32 return_address = globals[frame_start + 1];
u32 parent_local_return_address = globals[frame_start + 2];
USED(replaces_value); }
/* reset memory to parents end of memory */
mp = fp - FRAME_HEADER_SIZE;
/* reset the frame pointer */
fp = parent_fp;
if (is_ptr) { if (false) {
/* copy value to end of mp if it is a pointer */ /* copy value to end of mp if it is a pointer */
WRITE_U32(parent_local_return_address, mp); parent->local[parent_local_return_address] = mp;
size = READ_U32(return_value); size = READ_U32(return_value);
WRITE_U32(mp, size); WRITE_U32(mp, size);
mp += 4; mp += 4;
@ -79,44 +89,48 @@ bool step_vm() {
} }
} else { } else {
/* otherwise just write the return value to its location */ /* otherwise just write the return value to its location */
WRITE_U32(parent_local_return_address, return_value); parent->local[parent_local_return_address] = return_value;
} }
/* jump to parent frame */ /* jump to parent frame */
pc = return_address; pc = frame->return_address;
/* reset memory to parents end of memory */
mp = frame->start_mp;
/* reset the frame pointer */
fp--;
return true; return true;
} }
case OP_SYSCALL: { case OP_SYSCALL: {
DECODE_A(instruction) DECODE_A(instruction)
u32 id = dest; /* syscall id */ u32 id = dest; /* syscall id */
u32 size = src1; /* size of heap at that pointer */ u32 size = src1; /* size of heap at that pointer */
u32 rd = fp + (src2 * 4); /* the pointer */ u32 rd = frame->local[src2]; /* the pointer */
status = syscall(id, size, rd); status = syscall(id, size, rd);
return true; return true;
} }
case OP_PUSH: { case OP_PUSH: {
DECODE_B(instruction) DECODE_B(instruction)
USED(imm); Frame *child_frame = &frames[fp + 1];
globals[(mp / 4) + lc + 3] = locals[dest]; child_frame->local[lc] = frame->local[dest];
lc++; lc++;
USED(imm);
return true; return true;
} }
case OP_POP: { case OP_POP: {
DECODE_C(instruction) DECODE_C(instruction)
USED(imm); USED(imm);
mp -= 4;
lc--; lc--;
return true; return true;
} }
case OP_LOAD_IMM: { case OP_LOAD_IMM: {
DECODE_B(instruction) DECODE_B(instruction)
locals[dest] = imm; frame->local[dest] = imm;
return true; return true;
} }
case OP_LOAD_UPPER_IMM: { case OP_LOAD_UPPER_IMM: {
DECODE_B(instruction) DECODE_B(instruction)
u32 value = locals[dest]; u32 value = frame->local[dest];
locals[dest] = (value | (((u32)(imm)) << 16)); frame->local[dest] = (value | (((u32)(imm)) << 16));
return true; return true;
} }
case OP_LOAD_IND_8: { case OP_LOAD_IND_8: {
@ -171,9 +185,9 @@ bool step_vm() {
case OP_MEM_CPY_8: { case OP_MEM_CPY_8: {
DECODE_A(instruction) DECODE_A(instruction)
u32 i = 0; u32 i = 0;
u32 mdest = locals[dest]; u32 mdest = frame->local[dest];
u32 msrc = locals[src1]; u32 msrc = frame->local[src1];
u32 count = locals[src2]; u32 count = frame->local[src2];
if (mdest + count >= mp) { if (mdest + count >= mp) {
status = 1; status = 1;
@ -190,9 +204,9 @@ bool step_vm() {
case OP_MEM_CPY_16: { case OP_MEM_CPY_16: {
DECODE_A(instruction) DECODE_A(instruction)
u32 i = 0; u32 i = 0;
u32 mdest = locals[dest]; u32 mdest = frame->local[dest];
u32 msrc = locals[src1]; u32 msrc = frame->local[src1];
u32 count = locals[src2] * 2; u32 count = frame->local[src2] * 2;
if (mdest + count >= mp) { if (mdest + count >= mp) {
status = 1; status = 1;
@ -210,9 +224,9 @@ bool step_vm() {
case OP_MEM_CPY_32: { case OP_MEM_CPY_32: {
DECODE_A(instruction) DECODE_A(instruction)
u32 i = 0; u32 i = 0;
u32 mdest = locals[dest]; u32 mdest = frame->local[dest];
u32 msrc = locals[src1]; u32 msrc = frame->local[src1];
u32 count = locals[src2]; u32 count = frame->local[src2];
if (mdest + count >= mp) { if (mdest + count >= mp) {
status = 1; status = 1;
@ -361,25 +375,25 @@ bool step_vm() {
case OP_MUL_REAL: { case OP_MUL_REAL: {
DECODE_A(instruction) DECODE_A(instruction)
i32 src1_whole = (i32)locals[src1] >> 16; i32 src1_whole = (i32)frame->local[src1] >> 16;
i32 src2_whole = (i32)locals[src2] >> 16; i32 src2_whole = (i32)frame->local[src2] >> 16;
i32 src1_decimal = (i32)locals[src1] & 16; i32 src1_decimal = (i32)frame->local[src1] & 16;
i32 src2_decimal = (i32)locals[src2] & 16; i32 src2_decimal = (i32)frame->local[src2] & 16;
i32 result = 0; i32 result = 0;
result += (src1_whole * src2_whole) << 16; result += (src1_whole * src2_whole) << 16;
result += (src1_whole * src2_decimal); result += (src1_whole * src2_decimal);
result += (src1_decimal * src2_whole); result += (src1_decimal * src2_whole);
result += ((src1_decimal * src2_decimal) >> 16) & 16; result += ((src1_decimal * src2_decimal) >> 16) & 16;
locals[dest] = result; frame->local[dest] = result;
return true; return true;
} }
case OP_DIV_REAL: { case OP_DIV_REAL: {
DECODE_A(instruction) DECODE_A(instruction)
i32 result; i32 result;
i32 src1_val = (i32)locals[src1]; i32 src1_val = (i32)frame->local[src1];
i32 src2_val = (i32)locals[src2]; i32 src2_val = (i32)frame->local[src2];
u32 src2_reciprocal = 1; u32 src2_reciprocal = 1;
src2_reciprocal <<= 31; src2_reciprocal <<= 31;
@ -388,7 +402,7 @@ bool step_vm() {
result = src1_val * src2_reciprocal; result = src1_val * src2_reciprocal;
result <<= 1; result <<= 1;
locals[dest] = result; frame->local[dest] = result;
return true; return true;
} }
case OP_INT_TO_REAL: { case OP_INT_TO_REAL: {
@ -500,7 +514,7 @@ bool step_vm() {
case OP_JMP_FLAG: { case OP_JMP_FLAG: {
DECODE_A(instruction) DECODE_A(instruction)
u32 mask; u32 mask;
u32 jmp_dest = locals[dest]; u32 jmp_dest = frame->local[dest];
if (jmp_dest > cp) { if (jmp_dest > cp) {
status = 1; status = 1;
return true; return true;
@ -566,9 +580,101 @@ bool step_vm() {
case OP_JLE_REAL: { case OP_JLE_REAL: {
COMPARE_AND_JUMP(i32, <=); COMPARE_AND_JUMP(i32, <=);
} }
case OP_INT_TO_STR: {
DECODE_A(instruction)
u32 i = MAX_LEN_INT32;
i32 v = (i32)frame->local[src1];
char buffer[MAX_LEN_INT32];
i32 n = v;
bool neg = n < 0;
USED(src2);
if (neg)
n = -n;
do {
buffer[--i] = radix_set[n % 10];
n /= 10;
} while (n > 0);
if (neg)
buffer[--i] = '-';
/* Ensure at least one digit is written for 0 */
if (v == 0)
buffer[--i] = '0';
/* Copy from buffer[i] to buffer + MAX_LEN_INT32 */
frame->local[dest] = str_alloc(buffer + i, MAX_LEN_INT32 - i);
return pc;
}
case OP_NAT_TO_STR: {
DECODE_A(instruction)
u32 v = (i32)frame->local[src1];
char buffer[MAX_LEN_INT32];
u32 n = v;
u32 i = MAX_LEN_INT32;
USED(src2);
do {
buffer[--i] = radix_set[n % 10];
n /= 10;
} while (n > 0);
/* Ensure at least one digit is written for 0 */
if (v == 0)
buffer[--i] = '0';
/* Copy from buffer[i] to buffer + MAX_LEN_INT32 */
frame->local[dest] = str_alloc(buffer + i, MAX_LEN_INT32 - i);
return pc;
}
case OP_REAL_TO_STR: {
DECODE_A(instruction)
u32 i = 0, j = 0;
i32 q = (i32)frame->local[src1];
char buffer[MAX_LEN_INT32];
u32 int_part, frac_part;
if (q < 0) {
buffer[i++] = '-';
q = -q;
}
int_part = q >> 16;
frac_part = q & 0xFFFF;
USED(src2);
if (int_part == 0) {
buffer[i++] = radix_set[0];
} else {
char tmp[16];
i32 tmp_i = 0;
while (int_part > 0) {
tmp[tmp_i++] = radix_set[int_part % 10];
int_part /= 10;
}
while (tmp_i > 0) {
buffer[i++] = tmp[--tmp_i];
}
}
buffer[i++] = '.';
for (j = 0; j < 6; j++) {
frac_part *= 10;
buffer[i++] = radix_set[frac_part >> 16];
frac_part &= 0xFFFF;
}
frame->local[dest] = str_alloc(buffer + i, MAX_LEN_INT32 - i);
return pc;
}
} }
/* something went very wrong */ /* something went very wrong */
status = 255; status = 255;
return false; return false;
} }

27
vm/vm.h
View File

@ -115,14 +115,28 @@ typedef enum {
OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */ OP_JGT_REAL, /* jump_gt_real : A : jump to locals[dest] if locals[src1] as real > locals[src2] as real */
OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */ OP_JLT_REAL, /* jump_lt_real : A : jump to locals[dest] if locals[src1] as real < locals[src2] as real */
OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */ OP_JLE_REAL, /* jump_le_real : A : jump to locals[dest] if locals[src1] as real <= locals[src2] as real */
OP_INT_TO_STR,
OP_NAT_TO_STR,
OP_REAL_TO_STR,
OP_MAX_OPCODE /* not an opcode count of instructions */ OP_MAX_OPCODE /* not an opcode count of instructions */
} Opcode; } Opcode;
typedef enum { typedef enum {
SYSCALL_DBG_PRINT, /* temporary debugging print, use tunnel later */ SYSCALL_CONSOLE_WRITE,
SYSCALL_CONSOLE_READ,
SYSCALL_MAX SYSCALL_MAX
} Syscall; } Syscall;
#define MAX_LOCALS 32
typedef struct frame_s Frame;
struct frame_s {
u32 return_address;
u32 parent_return_local;
u32 start_mp;
u32 local_is_ptr;
u32 local[MAX_LOCALS];
};
extern u32 pc; /* program counter */ extern u32 pc; /* program counter */
extern u32 cp; /* code pointer */ extern u32 cp; /* code pointer */
extern u32 mp; /* memory pointer */ extern u32 mp; /* memory pointer */
@ -132,6 +146,7 @@ extern u8 status; /* status flag */
extern u8 interrupt; /* device interrupt */ extern u8 interrupt; /* device interrupt */
extern u32 *code; /* code */ extern u32 *code; /* code */
extern u8 *mem; /* memory */ extern u8 *mem; /* memory */
extern Frame *frames; /* stack frame */
#define READ_U8(addr) (mem[addr]) #define READ_U8(addr) (mem[addr])
@ -165,14 +180,14 @@ extern u8 *mem; /* memory */
#define MATH_OP(type, op) \ #define MATH_OP(type, op) \
do { \ do { \
DECODE_A(instruction) \ DECODE_A(instruction) \
locals[dest] = ((type)locals[src1] op (type)locals[src2]); \ frame->local[dest] = ((type)frame->local[src1] op (type)frame->local[src2]); \
return true; \ return true; \
} while (0) } while (0)
#define MATH_OP_NO_CAST(op) \ #define MATH_OP_NO_CAST(op) \
do { \ do { \
DECODE_A(instruction) \ DECODE_A(instruction) \
locals[dest] = (locals[src1] op locals[src2]); \ frame->local[dest] = (frame->local[src1] op frame->local[src2]); \
return true; \ return true; \
} while (0) } while (0)
@ -181,9 +196,9 @@ extern u8 *mem; /* memory */
DECODE_A(instruction) \ DECODE_A(instruction) \
i32 cond; \ i32 cond; \
u32 mask; \ u32 mask; \
u32 target = locals[dest]; \ u32 target = frame->local[dest]; \
type value = (type)locals[src1]; \ type value = (type)frame->local[src1]; \
type value2 = (type)locals[src2]; \ type value2 = (type)frame->local[src2]; \
cond = !!(value op value2); \ cond = !!(value op value2); \
mask = -(u32)cond; \ mask = -(u32)cond; \
pc = (target & mask) | (pc & ~mask); \ pc = (target & mask) | (pc & ~mask); \