1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! Instructions related to Falcon code branching.

use faucon_asm::Instruction;

use super::{utils, Cpu, PC};

/// Performs a (long) subroutine call to an absolute target address.
pub fn call(cpu: &mut Cpu, insn: &Instruction) -> usize {
    // Extract the instruction operands (single register or immediate).
    let target = insn.operands()[0];

    // Push return address onto the stack.
    cpu.stack_push(cpu.registers[PC] + insn.raw_bytes().len() as u32);

    // Branch to the absolute address.
    cpu.registers[PC] = utils::get_value(cpu, insn.operand_size(), target);

    // Signal irregular PC increment to the CPU.
    cpu.increment_pc = false;

    4
}

/// Performs a (long) unconditional branch to an absolute target address.
pub fn bra(cpu: &mut Cpu, insn: &Instruction) -> usize {
    // Extract the instruction operands (single register or immediate).
    let target = insn.operands()[0];

    // Branch to the absolute address.
    cpu.registers[PC] = utils::get_value(cpu, insn.operand_size(), target);

    // Signal irregular PC increment to the CPU.
    cpu.increment_pc = false;

    4
}

/// Returns from a previous (long) call.
pub fn ret(cpu: &mut Cpu, _: &Instruction) -> usize {
    // Restore the return address from the stack.
    cpu.registers[PC] = cpu.stack_pop();

    // Signal irregular PC increment to the CPU.
    cpu.increment_pc = false;

    5
}