use crate::emulator::constants::operand_indices;
use crate::emulator::core::OperandType;
use crate::emulator::instructions::functions::quad_word_not_supported;
use crate::emulator::{EmulatorInstruction, ForwardComEmulator};
use gpcas_isa::instruction_flags;
#[inline]
pub fn sub_jump_zero(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_sub(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * (value == 0) as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn sub_jump_neg(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_sub(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * ((value < 0) as u16);
emulator.operands.set_i64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn sub_jump_pos(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_sub(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * (value > 0) as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn sub_jump_overflow(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let (result, overflow) = emulator
.operands
.get_i64(operand_indices::INPUT1)
.overflowing_sub(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * overflow as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, result);
}
#[inline]
pub fn sub_jump_borrow(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let (result, borrow) = emulator
.operands
.get_u64(operand_indices::INPUT1)
.overflowing_sub(emulator.operands.get_u64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * borrow as u16;
emulator.operands.set_u64(operand_indices::OUTPUT, result);
}
#[inline]
pub fn add_jump_zero(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_add(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * (value == 0) as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn add_jump_neg(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_add(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * (value < 0) as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn add_jump_pos(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_add(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * (value > 0) as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn add_jump_overflow(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let (result, overflow) = emulator
.operands
.get_i64(operand_indices::INPUT1)
.overflowing_add(emulator.operands.get_i64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * overflow as u16;
emulator.operands.set_i64(operand_indices::OUTPUT, result);
}
#[inline]
pub fn add_jump_carry(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let (result, carry) = emulator
.operands
.get_u64(operand_indices::INPUT1)
.overflowing_add(emulator.operands.get_u64(operand_indices::INPUT2));
instruction.core.flags |= instruction_flags::BR_TAKEN * carry as u16;
emulator.operands.set_u64(operand_indices::OUTPUT, result);
}
#[inline]
pub fn and_jump_zero(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator.operands.get_u64(operand_indices::INPUT1)
& emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (value == 0) as u16;
emulator.operands.set_u64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn or_jump_zero(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator.operands.get_u64(operand_indices::INPUT1)
| emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (value == 0) as u16;
emulator.operands.set_u64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn xor_jump_zero(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let value = emulator.operands.get_u64(operand_indices::INPUT1)
^ emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (value == 0) as u16;
emulator.operands.set_u64(operand_indices::OUTPUT, value);
}
#[inline]
pub fn compare_jump_equal(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_i64(operand_indices::INPUT1);
let second = emulator.operands.get_i64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (first == second) as u16;
}
#[inline]
pub fn compare_jump_signed_below(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_i64(operand_indices::INPUT1);
let second = emulator.operands.get_i64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (first < second) as u16;
}
#[inline]
pub fn compare_jump_signed_above(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_i64(operand_indices::INPUT1);
let second = emulator.operands.get_i64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (first > second) as u16;
}
#[inline]
pub fn compare_jump_unsigned_below(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_u64(operand_indices::INPUT1);
let second = emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (first < second) as u16;
}
#[inline]
pub fn compare_jump_unsigned_above(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_u64(operand_indices::INPUT1);
let second = emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * (first > second) as u16;
}
#[inline]
pub fn test_bit_jump_true(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_u64(operand_indices::INPUT1);
let second = emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * ((first & (1 << second)) != 0) as u16;
}
#[inline]
pub fn test_bits_and_jump_true(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_u64(operand_indices::INPUT1);
let second = emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * ((first & second) == second) as u16;
}
#[inline]
pub fn test_bits_or_jump_true(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_u64(operand_indices::INPUT1);
let second = emulator.operands.get_u64(operand_indices::INPUT2);
instruction.core.flags |= instruction_flags::BR_TAKEN * ((first & second) != 0) as u16;
}
#[inline]
pub fn increment_compare_jump_below(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_i64(operand_indices::INPUT1);
let second = emulator.operands.get_i64(operand_indices::INPUT2);
let result = first.wrapping_add(1);
emulator.operands.set_i64(operand_indices::OUTPUT, result);
instruction.core.flags |= instruction_flags::BR_TAKEN * (result < second) as u16;
}
#[inline]
pub fn increment_compare_jump_above(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let first = emulator.operands.get_i64(operand_indices::INPUT1);
let second = emulator.operands.get_i64(operand_indices::INPUT2);
emulator
.operands
.set_i64(operand_indices::OUTPUT, first.wrapping_add(1));
instruction.core.flags |= instruction_flags::BR_TAKEN * (first >= second) as u16;
}
#[inline]
pub fn sub_max_len_jump_pos(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let result = emulator
.operands
.get_i64(operand_indices::INPUT1)
.wrapping_sub(emulator.operands.operand_size() as i64);
emulator.operands.set_i64(operand_indices::OUTPUT, result);
instruction.core.flags |= instruction_flags::BR_TAKEN * (result > 0) as u16;
}
pub fn indirect_jump(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
instruction.core.branch_address = instruction
.core
.branch_address
.wrapping_add(emulator.operands.get_u64(operand_indices::INPUT1) as usize);
}
pub fn multiway_jump(
emulator: &mut ForwardComEmulator,
instruction: &mut EmulatorInstruction,
_: usize,
) {
let base = emulator.operands.get_i64(operand_indices::INPUT1);
let offset = match instruction.operand_type {
OperandType::I8 => emulator.operands.get_i8(operand_indices::INPUT2) as i64,
OperandType::I16 => emulator.operands.get_i16(operand_indices::INPUT2) as i64,
OperandType::I32 => emulator.operands.get_i32(operand_indices::INPUT2) as i64,
OperandType::I128 => {
quad_word_not_supported(instruction);
0
}
_ => unimplemented!(),
};
instruction.core.branch_address = (base + (offset << 2)) as usize;
}